9.1 KiB
9.1 KiB
Adapter And Repository Internals
Purpose
This document describes implemented adapter/repository boundaries and their current behavior.
Adapter Map
internal/adapter/cli: CLI command parsing, app wiring, stdout/stderr handling, exit codes.internal/adapter/http: HTTP request/response mapping forPOST /v1/runs.- root package
scriptorium: public Go library facade for preparing and running prompt requests. internal/promptdef: filesystem andfs.FSprompt-definition repositories.internal/profile: filesystem,fs.FS, and overlay execution-profile repositories.internal/filecatalog: shared YAML discovery and display-path helpers for prompt/profile repositories.internal/profile/builtin: embedded built-in execution-profile repository.internal/artifact: input artifact reader.internal/prompt: Go-template renderer.internal/llm: OpenAI-compatible LLM client implementation.internal/validate: filesystem andfs.FSoutput validators.internal/format: prepared-run formatters forrenderoutput.
Inputs And Outputs
CLI adapter:
- Input: process args, filesystem config/assets, environment.
- Output: exit code, stdout artifact/prepared output, stderr summaries/errors.
runsummaries include cache usage counters only when either parsed cache counter is non-zero.
HTTP adapter:
- Input: JSON request body (
runRequestDTO). - Output: JSON success/error body with mapped status codes.
- Success metadata includes token usage plus cache usage counters.
Public library facade:
- Input: typed
scriptorium.RunRequestvalues. - Output: typed
PreparedRunandRunResultvalues plus public sentinel errors. - Custom LLM behavior is injected with
WithLLMClient; otherwise the default OpenAI-compatible client is used. RunRequest.APIKeyis a request-scoped Go value only; it is converted into internal execution state for LLM generation and stripped from public result types.- Prompt, profile, and schema source options can use directories, single files, or
fs.FSroots. Explicit source options override the matchingConfigdirectory field. - Public types are facade types converted at the package boundary; internal domain types remain internal.
Prompt/profile repositories:
- Input: prompt/profile YAML files under configured directories or
fs.FSroots. - Output: normalized domain definitions/profiles or typed errors.
- Shared YAML catalog helpers provide recursive discovery, extension filtering, deterministic ordering, file stems, and
fs.FSdisplay paths. - Single-file public sources are represented as
fs.FSroots containing one YAML file; lookup still uses YAMLidvalues.
Profile repository composition:
- Built-in profiles are embedded and loaded through the same profile validation rules as filesystem profiles.
- When no custom profile directory is configured, the runner receives the built-in profile repository.
- When a custom profile directory/file/
fs.FSsource is configured, the runner receives an overlay repository with custom profiles as primary and built-ins as fallback. - Overlay lookup falls back only after custom profile-not-found errors; custom load/validation/raw-key errors are returned directly.
Artifact reader:
- Input:
domain.ArtifactRef. - Output: loaded
domain.Artifact.
LLM adapter:
- Input:
domain.GenerateRequest. - Output:
domain.GenerateResponse. - Direct API-key values are preferred when present; otherwise
api_key_envis resolved from the process environment.
Validator:
- Input: artifact body + output contract.
- Output: validation result or runtime validation error.
- Schema documents may be loaded from a directory, single file, or
fs.FSroot in the public package. CLI and HTTP continue to use directory-backed schema loading.
Boundaries
- Adapters convert external representations to domain requests and back.
- Use-case decisions remain in
internal/usecase. - External dependency details stay scoped to adapter packages.
Config Fields Used
Primary app settings consumed by adapters:
prompt_dirprofile_dir(optional custom profile source)schema_dirserver.addrserver.artifact_root(HTTPservefile input root)defaults.render_format
Execution profile/request settings used through runner:
endpoint,model,temperature,max_tokens,top_p,timeout_seconds,service_tier,api_key_env,reasoning_effort,extra_params- CLI and HTTP request adapters preserve caller intent for numeric runtime overrides. Omitted values remain absent; explicit zero values are mapped as explicit overrides.
- HTTP
extra_paramsaccepts JSON-compatible values and maps them to domain request overrides without provider-specific adapter logic.
External Dependencies
- YAML decoding:
gopkg.in/yaml.v3(strict known-fields mode in config/prompt/profile loaders). - JSON Schema validation:
github.com/santhosh-tekuri/jsonschema/v6. - HTTP client/server: Go standard library.
Failure Behavior
Strict decoding and input checks:
- config/prompt/profile loaders reject unknown YAML fields.
- prompt/profile repositories scan nested subdirectories recursively.
- prompt/profile lookup uses YAML
idvalues; subdirectory paths are organizational only. - prompt
content_filepaths resolve relative to the prompt YAML file within the same source. - duplicate prompt/profile IDs are invalid and fail instead of using first-match behavior.
- duplicate profile IDs across custom and built-in sources are allowed; the custom source overrides the built-in profile.
- HTTP DTO decoder rejects unknown JSON fields.
- raw API key payload fields are rejected by strict decoding in profile/http paths.
Artifact refs:
- Supported reference types:
inline,file. - Unsupported types return
ErrUnsupportedRefType. - CLI
runandrenderuse direct filesystem file reads forfilereferences. - HTTP
serveuses a restricted artifact reader:inlinereferences work without a root, whilefilereferences requireserver.artifact_rootor--artifact-rootand must stay inside that root. - HTTP file paths are resolved with clean absolute paths and containment checks, not string-prefix checks.
- Symlinks inside the root are followed by the operating system; the configured root must not be writable by untrusted users.
LLM adapter:
- endpoint appends
/chat/completions. - rendered messages without cache control serialize with string
content. - rendered messages with cache control serialize as one text content block with
cache_control. - non-empty
reasoning_effortserializes as a top-level provider request field. extra_paramsflatten into provider-specific top-level JSON request fields.- reserved
extra_paramskeys are rejected before the provider call:model,session_id,messages,temperature,max_tokens,top_p,service_tier,reasoning_effort, andresponse_format. - empty
extra_paramskeys and values that cannot be JSON-encoded are rejected before the provider call. - compatible cache usage response fields are parsed into domain token usage.
- non-2xx responses map to request failure errors.
- malformed responses (including missing/empty first choice content) are errors.
- direct API-key values are never serialized in provider request bodies.
Validator:
basic,json,json_schemacontent failures returnValidationFailedresults.- schema load/compile/path failures are runtime errors.
- schema lookup uses explicit
schema_pathvalues relative toschema_dir; it does not recursively search by basename.
HTTP error mapping:
- maps domain/use-case errors to stable HTTP code + error code/message.
- distinguishes missing profile selection and missing
api_key_envvariable using stable use-case sentinel errors. - avoids returning internal wrapped-cause details in response payload.
CLI Adapter Semantics
Implemented commands:
runrenderserve
Behavior highlights:
runexit2indicates validation failed after generation.renderdoes not call the LLM.serveexposes HTTP handler only; no built-in auth.rendersupports--format text|json;renderdoes not expose--schema-dir.- deprecated aliases
--prompt-idand--profile-idare still accepted.
Tests To Inspect Before Changing
internal/adapter/cli/run_test.gointernal/adapter/http/handler_test.gointernal/promptdef/repository_test.gointernal/profile/repository_test.gointernal/artifact/reader_test.gointernal/prompt/renderer_test.gointernal/llm/openai_compatible_client_test.gointernal/validate/standard_validator_test.gointernal/format/prepared_run_test.go
Architectural Invariants
- Adapter packages do not own runner decision logic.
- External request/response strictness is part of contract stability.
- Prepared-render output never includes resolved API key values.
- Outbound OpenAI-compatible request includes currently serialized first-class fields (
model, optionalsession_id,messages, optionaltemperature,max_tokens,top_p, optionalservice_tier, optionalreasoning_effort, optionalresponse_format) plus validatedextra_paramsflattened as provider-specific top-level fields. - Outbound cache control is message-level only; no top-level cache-control field is serialized.