177 lines
9.8 KiB
Markdown
177 lines
9.8 KiB
Markdown
# Library API Production Roadmap
|
|
|
|
This roadmap defines the target state for making Scriptorium's public Go package production-ready for downstream applications while preserving the existing CLI and HTTP behavior.
|
|
|
|
The library remains an additional adapter surface. It should not replace the subprocess, CLI, or HTTP contracts that already exist.
|
|
|
|
## Motivation
|
|
|
|
Many Go applications can use Scriptorium more cleanly as an imported package than as a subprocess. A downstream developer should be able to keep prompt assets in standard Scriptorium format, pass application data through a small adapter, and receive a typed response without reimplementing prompt rendering, profile resolution, validation, or OpenAI-compatible request construction.
|
|
|
|
The core consumer story is:
|
|
|
|
- the downstream app owns one or more `prompt.yml` files in standard Scriptorium format;
|
|
- those prompts may use inline content, `content_file` references, variables, cache-control markers, and structured-output schemas;
|
|
- the app may provide its own `profile.yml`, or select a standard built-in/profile-template configuration;
|
|
- the app supplies an API key as a normal Go value when the selected profile requires one;
|
|
- the app calls the public Go package to prepare or run the request and receives typed results.
|
|
|
|
## Current State
|
|
|
|
The public package already provides the first library facade:
|
|
|
|
- root package import;
|
|
- typed engine construction;
|
|
- typed prepare/run requests and results;
|
|
- file and inline artifact references;
|
|
- execution overrides;
|
|
- custom LLM injection for testing or alternate execution;
|
|
- public error categories that map internal failures to stable caller-facing errors.
|
|
|
|
The remaining production-readiness gaps are mostly about consumer ergonomics and asset sourcing:
|
|
|
|
- callers are still oriented around filesystem prompt/profile/schema directories;
|
|
- embedded prompt/profile/schema assets are not a first-class public use case;
|
|
- standard or built-in profile selection is not yet available;
|
|
- library credential supply is still tightly coupled to environment-variable lookup rather than direct API-key values;
|
|
- public documentation and examples need to show the intended downstream app adapter pattern.
|
|
|
|
## Target State
|
|
|
|
The public package should let a downstream Go application use standard Scriptorium assets without temporary directories, subprocess invocation, or internal package imports.
|
|
|
|
### Prompt Assets
|
|
|
|
The library should support prompt definitions from:
|
|
|
|
- existing prompt directories;
|
|
- a single prompt file;
|
|
- `fs.FS`, including `embed.FS`.
|
|
|
|
Prompt syntax should remain the standard Scriptorium prompt YAML format. `content_file` references should continue to be supported and should resolve relative to the prompt definition's source location within the same asset source.
|
|
|
|
The public API should not introduce a separate in-code prompt DSL as the primary path. YAML remains the canonical authoring format so prompts can be shared between CLI, HTTP, subprocess, and library usage.
|
|
|
|
### Schema Assets
|
|
|
|
Structured-output schemas should be loadable from the same kinds of sources as prompt definitions:
|
|
|
|
- existing schema directories;
|
|
- a single schema file where appropriate;
|
|
- `fs.FS`, including `embed.FS`.
|
|
|
|
Schema references should retain the existing prompt-format semantics. A schema referenced by a prompt should resolve through the configured schema source, not through ad hoc caller code.
|
|
|
|
### Profile Assets
|
|
|
|
The library should support both custom and standard profile configuration:
|
|
|
|
- existing profile directories;
|
|
- a single profile file;
|
|
- `fs.FS`, including `embed.FS`;
|
|
- direct public profile values for applications that already have profile configuration in memory;
|
|
- built-in/profile-template helpers for common OpenAI-compatible targets.
|
|
|
|
Custom profiles and built-in/template profiles should flow through the same internal profile resolution and request-construction path. The built-in path should not become a separate execution mode.
|
|
|
|
### Built-In Profile Templates
|
|
|
|
Built-in support should favor stable profile templates over a large registry of fixed model IDs.
|
|
|
|
For example, the public package should make it easy to construct or select an OpenAI-compatible profile by supplying the durable parts of the profile:
|
|
|
|
- profile ID or name;
|
|
- base URL;
|
|
- model;
|
|
- whether the profile requires an API key;
|
|
- default numeric parameters where desired;
|
|
- structured-output and extra-parameter behavior consistent with normal profiles.
|
|
|
|
The package may include a small set of named helpers for common OpenAI-compatible services, but those helpers should avoid hard-coding a broad and fast-changing list of model names.
|
|
|
|
### Credentials
|
|
|
|
The public package must keep raw API keys out of prompt/profile YAML, prepared-run output, run results, logs, and examples.
|
|
|
|
For the public library API, the single supported credential-supply method should be a direct API-key value passed by the consuming Go application. The consuming application is responsible for loading and managing its own secrets before calling Scriptorium.
|
|
|
|
This may be exposed as a field such as `Config.APIKey`, an option such as `WithAPIKey`, or an equivalent request/engine-level value that is easy to pass through an application adapter. The exact API should avoid accidental serialization in prepared output, run results, logs, and examples.
|
|
|
|
The public package should not encourage raw API-key storage in prompt/profile YAML. Existing CLI behavior may continue to use environment-variable references for compatibility, but the production library path should not introduce a separate credential resolver or secret-manager abstraction.
|
|
|
|
### Public API Shape
|
|
|
|
The public API should remain narrow, idiomatic, and stable. Recommended additions include:
|
|
|
|
- engine options for prompt/profile/schema directories;
|
|
- engine options for prompt/profile/schema `fs.FS` sources;
|
|
- engine options for single prompt/profile/schema files where useful;
|
|
- public profile/template constructors that map to internal profile definitions;
|
|
- a direct API-key value for profiles that require authentication;
|
|
- examples showing `embed.FS`, custom profile files, template profile selection, and fake LLM testing.
|
|
|
|
The public package should continue to expose facade types rather than exporting internal package types. Internal package layout should remain free to evolve.
|
|
|
|
## Scope
|
|
|
|
In scope:
|
|
|
|
- first-class `fs.FS` support for public library prompt, profile, and schema sources;
|
|
- ergonomic single-file asset options where they reduce caller boilerplate;
|
|
- built-in/profile-template helpers for common OpenAI-compatible usage;
|
|
- in-memory public profile values where appropriate;
|
|
- direct API-key value support for the public library path;
|
|
- consumer-facing examples under `examples/`;
|
|
- consumer package documentation under `docs/consumers/` once behavior is implemented;
|
|
- tests proving library behavior matches existing CLI/use-case behavior.
|
|
|
|
Out of scope:
|
|
|
|
- changing standard prompt, profile, or schema file formats;
|
|
- exposing internal packages as public API;
|
|
- replacing or removing CLI, HTTP, or subprocess support;
|
|
- adding a multi-step workflow engine;
|
|
- adding non-Go bindings;
|
|
- maintaining a comprehensive provider/model catalog;
|
|
- accepting raw API keys in serialized YAML/JSON configuration;
|
|
- adding a credential resolver or secret-manager abstraction.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- A Go caller can import the root package and run a standard Scriptorium prompt without invoking a subprocess.
|
|
- A Go caller can use prompt definitions from `embed.FS`, including prompts with `content_file` references.
|
|
- A Go caller can use structured-output schemas from `embed.FS` or filesystem sources.
|
|
- A Go caller can provide a custom profile from filesystem, `fs.FS`, or public in-memory profile values.
|
|
- A Go caller can select a standard OpenAI-compatible profile template without writing a full profile file.
|
|
- A Go caller can supply an API key as a normal Go value without raw secrets appearing in serialized config, prepared output, or results.
|
|
- Public library behavior remains consistent with CLI/HTTP semantics for rendering, validation, profile resolution, runtime overrides, structured output, cache control, and LLM invocation.
|
|
- Existing CLI and HTTP behavior remains unchanged.
|
|
- Library tests use fake or local LLM boundaries and do not require real provider credentials.
|
|
- Public docs outside `docs/roadmap/` describe only implemented behavior after the feature is built.
|
|
|
|
## Design Decisions
|
|
|
|
### Asset Source API
|
|
|
|
Add first-class `fs.FS` options for prompt, profile, and schema sources while keeping existing directory-based configuration. Also add single-file convenience options where they remove meaningful caller boilerplate. Resolve `content_file` references relative to the prompt file's location inside the same source.
|
|
|
|
Reasoning:
|
|
|
|
This is the most idiomatic path for production Go libraries because it supports `embed.FS`, `os.DirFS`, tests, and in-memory fixture files through the same abstraction. It also avoids requiring downstream applications to unpack embedded assets into temporary directories.
|
|
|
|
### Built-In Profile Strategy
|
|
|
|
Provide stable profile-template helpers for OpenAI-compatible endpoints rather than a broad registry of fixed provider/model profiles. Let callers choose the model and endpoint where those values are service-specific or fast-changing.
|
|
|
|
Reasoning:
|
|
|
|
Endpoint shape and credential mechanics are relatively stable; model catalogs change frequently. Templates give consumers a short, correct path without making Scriptorium responsible for tracking every provider's model list.
|
|
|
|
### In-Memory Profile Values
|
|
|
|
Expose a small public profile facade type for in-memory profile configuration and map it to internal profile definitions. Keep it intentionally aligned with the existing profile YAML contract.
|
|
|
|
Reasoning:
|
|
|
|
Many applications already hold configuration in typed structs and should not need to generate YAML files just to call Scriptorium. A public facade keeps internal types private while making the library practical for production use.
|