4.5 KiB
Runner Internals
Purpose
internal/usecase.Runner is the prompt-execution orchestrator. It prepares
domain requests, invokes an injected LLM client, validates output, and returns
domain results. Transport parsing, response mapping, and public type conversion
remain outside this package.
The configuration reference owns prompt, profile, schema, and runtime-setting definitions. Public error behavior is defined by the HTTP API and Go package contracts.
Dependencies And Construction
Runner receives these collaborators:
promptdef.Repository;profile.Repository;artifact.Reader;prompt.Renderer;llm.Client;validate.Validator; and- an optional
OutputRepairer.
NewRunner constructs a runner without a repairer. NewRunnerWithRepairer
accepts one explicitly. The public engine chooses concrete repositories and
readers; executable adapters reach the runner only through that engine. The
runner does not load application configuration.
Prepare Flow
Prepare performs one deterministic preparation pass for a request:
- validate the prompt ID and load the prompt definition;
- hash the definition and select the explicit or default profile;
- load the profile and resolve effective execution settings;
- validate endpoint, model, and credential availability;
- resolve the output contract and, for JSON Schema output, load a structured schema document before model execution;
- read and hash input artifacts;
- render messages and the session ID; and
- return a
PreparedRuncontaining the effective state and rendered-prompt hash.
Execution settings merge defaults, profile values, and a request override. Numeric override presence is retained so explicit zero values are not confused with omissions.
Run And Validation Flow
Run creates a run ID and timestamps, then calls Prepare rather than
duplicating preparation. It sends the prepared prompt, effective target,
target-presence state, and optional structured-output specification to the LLM
client. It converts the returned content to an output artifact, validates it,
and returns the artifact, validation, hashes, usage, and timing metadata.
A validator can return a content result or an operational error. Content
failures stay in the result; schema loading, compilation, and validator
operational failures are returned as ErrValidation. The canonical distinction
for callers is documented by the public contracts.
Repair Boundary
Repair is an internal optional loop. It starts only when a repairer is present, the output contract permits one or more attempts, validation failed, and the validation mode is JSON or JSON Schema. Each repair receives the previous output, validation errors, effective target, structured-output specification, and attempt metadata; every repaired result is validated again.
NewDefaultOutputRepairer delegates to the injected LLM client. The public
engine, and therefore CLI and HTTP, uses NewRunner and does not inject this
repairer.
Error Translation
Runner sentinels identify failure categories for adapters:
ErrInvalidRequestErrProfileRequiredErrAPIKeyEnvMissingandErrAPIKeyRequiredErrPromptLoad,ErrProfileLoad, andErrArtifactLoadErrPromptRenderErrLLMGenerateErrValidation
Wrap errors with those sentinels and preserve their identities through
errors.Is; adapters must not classify errors by message text. The runner
passes direct keys only to the LLM boundary and never includes resolved key
values in prepared or run results.
Package-Local Guarantees
Runalways reusesPrepare.- Schema documents are loaded before the initial LLM call when structured output is required.
- Output validation records attempts used, including repair attempts.
- Runner state is per request; the package does not create a durable run store or manifest.
- Source, renderer, validator, and LLM implementations remain injected boundaries.
Verification And Change Recipe
Inspect:
internal/usecase/runner_test.goengine_test.go
When changing orchestration:
- identify the collaborator boundary and the affected
PrepareorRunstate; - preserve the
Run-through-Preparepath and error identity; - add focused runner or integration tests for changed state transitions, validation, or repair behavior; and
- update the owning external contract and any affected source or LLM internal document.
The testing policy owns global test sufficiency.