# Package `scriptorium` Import path: ```go import "gitea.maximumdirect.net/eric/scriptorium" ``` This is the canonical public Go contract for in-process prompt preparation and execution. Prompt, profile, and schema file formats are defined in the [configuration reference](../config.md). ## Engine Construction `NewEngine(Config, ...Option)` constructs an engine. `Config` has these fields: | Field | Meaning | | --- | --- | | `PromptDir` | Prompt-definition directory, required unless a prompt source option is supplied. | | `ProfileDir` | Optional custom profile directory over built-ins. | | `SchemaDir` | Schema directory; empty uses `.`. | | `Timeout` | Transport-wide safety cap for the built-in OpenAI-compatible client when `HTTPClient` is absent or has a non-positive timeout. A non-positive value uses the internal ten-minute default. | | `HTTPClient` | Optional HTTP client for that built-in client. It is cloned; a positive `Timeout` on it is the transport cap and takes precedence over `Config.Timeout`. A non-positive client timeout is treated as unset. | Nil options are ignored. Invalid construction, including `WithLLMClient(nil)` and `WithArtifactReader(nil)`, returns an error matching `ErrInvalidConfig`. Profile and request `timeout_seconds` values select a per-generation-call deadline independently of the transport cap. An explicit request override of zero disables that generation deadline only. The complete interaction with the caller context is defined in the [OpenAI-compatible integration contract](../integrations/openai-compatible-chat.md#authentication-and-timeout). Source options replace their matching directory source: - prompts: `WithPromptFS(fsys, root)`, `WithPromptFile(path)`; - profiles: `WithProfileFS(fsys, root)`, `WithProfileFile(path)`, and `WithProfiles(profiles...)`; - schemas: `WithSchemaFS(fsys, root)`, `WithSchemaFile(path)`; and - LLM client: `WithLLMClient(client)`; and - artifact reader: `WithArtifactReader(reader)`. `fs.FS` prompt-content and schema paths stay inside their configured roots. Single-file prompt and profile sources are selected by their YAML `id`, not their file names. `WithPromptFile` resolves relative `content_file` paths from the prompt file's directory. `WithSchemaFile` exposes its schema by the schema file's base name. In-memory profiles take precedence over an explicit or directory-backed profile source, which in turn takes precedence over built-ins. File and filesystem sources use the format and credential rules in the [configuration reference](../config.md). ## Prepare And Run `Prepare(ctx, request)` resolves the prompt, profile, input artifacts, validation contract, and rendered messages without calling an LLM. `Run(ctx, request)` performs that preparation, calls the configured client, and validates generated content. ```go engine, err := scriptorium.NewEngine(scriptorium.Config{ PromptDir: "./examples/prompts", ProfileDir: "./examples/profiles", }) if err != nil { return err } prepared, err := engine.Prepare(ctx, scriptorium.RunRequest{ PromptID: "generic.markdown_summary", Inputs: map[string]scriptorium.ArtifactRef{ "transcript": scriptorium.File("./examples/fixtures/transcript.md"), }, }) if err != nil { return err } _ = prepared.Messages ``` The maintained package example is [`examples/go-library/prepare`](../../examples/go-library/prepare). `PreparedRun` exposes prompt, selected-profile, effective-model, output contract, structured-output, input-hash, rendered-message, and timing information. It does not include a resolved API key, model output, validation result, or target-presence metadata. `RunResult` adds run ID, artifact, raw output, validation, model metadata, usage, and duration. Generated-content validation failures return a result with `Validation.Status == ValidationFailed`; schema or validator runtime failures return an error matching `ErrValidation`. ## Public Values `ArtifactRef` has `Type`, `URI`, and `Body`; `Artifact` has `Name`, `ContentType`, `Body`, `URI`, `Size`, and `Hash`. `ExecutionTarget` exposes the effective endpoint, model, numeric settings, credential-environment name, service tier, reasoning effort, and extra parameters. `ValidationResult` contains status, mode, errors, schema path, repair attempts, and validity. The exported constants define these serialized values: - artifact types: `inline` and `file`; - output formats: `text`, `markdown`, and `json`; - validation modes: `none`, `basic`, `json`, and `json_schema`; and - validation statuses: `passed`, `failed`, and `skipped`. `TokenUsage` reports prompt, completion, total, cached, and cache-write token counts. `RenderedPrompt`, `RenderedMessage`, `CacheControl`, and `StructuredOutputSpec` are the public shapes used by injected LLM clients. `ArtifactReader` implements `Read(context.Context, ArtifactRef) (*Artifact, error)`. Supplying it through `WithArtifactReader` replaces, rather than extends, the engine's default inline and file reader for every input. Omitting the option retains that default; `WithArtifactReader(nil)` makes engine construction fail with `ErrInvalidConfig`. Reader failures are surfaced as errors matching `ErrArtifactLoad` while preserving the reader's original error identity for `errors.Is`. A `(nil, nil)` reader response is also an artifact-load failure. Readers are responsible for artifact metadata, although the engine assigns the input-map name when the returned name is empty; readers should not retain or mutate caller values. ## Requests, Inputs, And Overrides `RunRequest` fields are `PromptID`, `PromptVersion`, `ProfileID`, `APIKey`, `Inputs`, `Vars`, `Execution`, `Validation`, and `Metadata`. Input helpers are: - `File(path)` for a file-backed artifact; - `Inline(body)` for inline content; and - `InlineWithURI(uri, body)` for inline content with URI metadata. Required declared inputs must be supplied. Template rendering must also resolve every input name the prompt actually references. Extra entries in `Inputs` are not rejected solely because they are undeclared. `ExecutionTargetOverride` supplies endpoint, model, credential-environment, service-tier, reasoning-effort, and extra-parameter overrides. Its numeric fields (`Temperature`, `MaxTokens`, `TopP`, and `TimeoutSeconds`) are pointers so explicit zero values are preserved. `OutputContract` supplies `Format`, `ValidationMode`, `SchemaPath`, and `RepairAttempts`. `ExtraParams` accepts JSON-compatible values: strings, booleans, finite numbers, objects with string keys, arrays or slices, and nil. Unsupported values, non-string map keys, non-finite floats, and cycles return `ErrInvalidConfig` for profiles or `ErrInvalidRequest` for request overrides. ## Profiles And Credentials `OpenAICompatibleProfile(OpenAICompatibleProfileConfig)` creates an in-memory `Profile`. Its public fields are `ID`, `Endpoint`, `Model`, `Temperature`, `MaxTokens`, `TopP`, `TimeoutSeconds`, `ServiceTier`, `ReasoningEffort`, `APIKeyRequired`, and `ExtraParams`. `WithProfiles` rejects duplicate IDs in one call. A direct `RunRequest.APIKey` is request-scoped and takes precedence over `api_key_env` for the built-in client. It is excluded from JSON output and from `PreparedRun` and `RunResult`. The package's `String` and `GoString` methods report only whether a direct key is set. Do not use reflection-based dumps of request structs, which can bypass that redaction. ## Injected LLM Clients `LLMClient` implements: ```go Generate(context.Context, GenerateRequest) (*GenerateResponse, error) ``` Injected clients receive the rendered prompt, effective execution target, numeric target-presence metadata, optional structured-output specification, and direct request API key. `GenerateResponse` returns content and `TokenUsage`. Custom clients should avoid logging raw prompts or credentials. ## Errors Public methods preserve these sentinel checks through `errors.Is`: - `ErrInvalidConfig` - `ErrInvalidRequest` - `ErrPromptNotFound` - `ErrProfileNotFound` - `ErrProfileRequired` - `ErrPromptLoad` - `ErrProfileLoad` - `ErrAPIKeyEnvMissing` - `ErrArtifactLoad` - `ErrPromptRender` - `ErrLLMGenerate` - `ErrValidation` `ErrProfileRequired` and `ErrAPIKeyEnvMissing` each also match `ErrInvalidRequest`, so callers can select either the broad request category or the specific condition. For the HTTP interface, see the [HTTP API reference](../api.md).