2026-05-26 03:28:28 +00:00
# Runner Internals
## Purpose
`internal/usecase.Runner` is the core use case orchestrator for prompt preparation and execution.
It owns request validation, prompt/profile resolution, runtime-parameter merge, artifact loading, prompt rendering, structured-output setup, LLM invocation, output validation, and result metadata.
## Inputs And Outputs
Primary input type:
- `domain.RunRequest`
Primary output types:
- `domain.PreparedRun` from `Prepare`
- `domain.RunResult` from `Run`
LLM boundary types:
- `domain.GenerateRequest`
- `domain.GenerateResponse`
## Boundaries
`Runner` coordinates the following interfaces:
- `promptdef.Repository`
- `profile.Repository`
- `artifact.Reader`
- `prompt.Renderer`
- `llm.Client`
- `validate.Validator`
- optional `usecase.OutputRepairer`
Transport concerns (CLI flags, HTTP DTO parsing, status-code mapping) stay outside runner.
## Config Fields Used
`Runner` does not read app config files directly.
It receives fully constructed repositories/readers/validators from adapters. Effective behavior depends on adapter wiring, including:
- prompt/profile directories
- schema base directory
- selected profile/runtime overrides in request
## External Adapters Used
`Runner` works with adapter implementations via interfaces. Current wiring from CLI/HTTP uses:
- filesystem prompt/profile repositories
- composite artifact reader
- Go-template prompt renderer
- OpenAI-compatible LLM client
- standard validator
## State And Resume Behavior
`Runner` is stateless across requests.
- No durable run-state storage.
- No built-in resume/skip checkpoints.
- Each `Run` /`Prepare` executes from request inputs and current repositories.
## Failure Behavior
2026-05-26 15:00:06 +00:00
Primary runner error classes:
2026-05-26 03:28:28 +00:00
2026-05-26 15:00:06 +00:00
- `ErrInvalidRequest` : invalid run request envelope.
- `ErrProfileRequired` : specific invalid-request reason when neither request `profile_id` nor prompt `default_profile` is available.
- `ErrAPIKeyEnvMissing` : specific invalid-request reason when `api_key_env` is set but the named environment variable is unset/empty.
2026-07-04 23:09:23 +00:00
- `ErrPromptLoad` : prompt-definition repository load failures.
- `ErrProfileLoad` : execution-profile repository load failures.
2026-05-26 03:28:28 +00:00
- `ErrArtifactLoad` : artifact read failures.
- `ErrPromptRender` : template render failures.
2026-05-26 15:00:06 +00:00
- `ErrLLMGenerate` : outbound model request failures.
- `ErrValidation` : validation runtime failures (including structured-output schema load/compile failures).
Reason sentinel behavior:
- `ErrProfileRequired` and `ErrAPIKeyEnvMissing` are wrapped with `ErrInvalidRequest` .
- Adapters can use `errors.Is` for stable reason mapping without matching runner prose.
2026-05-26 03:28:28 +00:00
Validation content failures are not run errors:
- `Run` can succeed with `Validation.Status == failed` .
- CLI maps this to exit code `2` .
- HTTP returns `200` with failed validation details.
## Prepare Flow
`Prepare` performs:
1. validate request basics (prompt ID present).
2. load prompt definition by ID/version.
3. select profile ID:
- explicit request profile ID
- prompt `default_profile`
2026-05-26 15:00:06 +00:00
- otherwise return an invalid request with `ErrProfileRequired`
2026-05-26 03:28:28 +00:00
4. load execution profile.
5. merge effective runtime target:
- built-in execution defaults
- selected profile values
- request overrides
2026-07-04 13:29:38 +00:00
- request numeric overrides are presence-aware, so omitted values preserve the current effective value and explicit zero values override it
2026-07-04 16:55:01 +00:00
6. verify credentials when the effective target names `api_key_env` :
- a request-scoped direct API key satisfies the credential requirement
- otherwise a missing/empty env value returns an invalid request with `ErrAPIKeyEnvMissing`
- only the environment-variable name is returned in public output; secret values are never returned
2026-05-26 03:28:28 +00:00
7. resolve output contract and structured-output schema payload when `json_schema` mode is active.
8. read input artifacts.
2026-07-02 23:10:24 +00:00
9. render prompt messages, including any normalized message cache-control metadata.
2026-05-26 03:28:28 +00:00
10. compute prompt/input/render hashes and return `PreparedRun` .
2026-07-02 23:10:24 +00:00
`rendered_prompt_hash` includes cache-control metadata when present because it affects the outbound provider request. Prompts without cache control keep the role/content hash behavior.
2026-05-26 03:28:28 +00:00
`Prepare` does not call the LLM.
2026-07-04 13:29:38 +00:00
Runtime target notes:
- Profile `extra_params` and request `extra_params` carry JSON-compatible values through prepared output, run metadata, and `domain.GenerateRequest.Target` .
- The OpenAI-compatible client serializes non-empty `reasoning_effort` as a top-level provider request field.
- The OpenAI-compatible client flattens `extra_params` into provider-specific top-level JSON request fields.
- Empty `extra_params` keys, reserved outbound field names, and values that cannot be JSON-encoded fail before the provider request.
2026-07-04 16:55:01 +00:00
- Resolved API-key values are never serialized in prepared/run output, public results, logs, or HTTP responses.
- Public direct API-key values are carried only far enough to call the configured LLM client and are excluded from JSON/YAML serialization.
2026-07-04 13:29:38 +00:00
2026-05-26 03:28:28 +00:00
## Run Flow
`Run` performs:
1. generate run ID.
2. call `Prepare` .
3. call LLM with prepared messages/effective target/structured-output spec.
4. build output artifact content type from output format.
5. validate output.
6. optionally attempt bounded repair when repairer is injected and contract allows it.
2026-07-02 23:10:24 +00:00
7. return `RunResult` with artifact, raw output, validation, hashes, profile/model metadata, token/cache usage, and timestamps.
2026-05-26 03:28:28 +00:00
## Repair Hook Boundary
Repair attempts occur only when all are true:
- repairer is injected
- `repair_attempts > 0`
- validation status is `failed`
- validation mode is `json` or `json_schema`
Current production wiring boundary:
- CLI and HTTP adapters call `usecase.NewRunner(...)` (no repairer argument).
- Therefore normal CLI/HTTP execution does not perform repair attempts today.
## Tests To Inspect Before Changing
- `internal/usecase/runner_test.go`
- `internal/usecase/integration_test.go`
- `internal/adapter/cli/run_test.go`
- `internal/adapter/http/handler_test.go`
## Architectural Invariants
- `Run` reuses `Prepare` ; prepare logic is not duplicated.
- Effective API-key environment-variable name may appear; resolved secret value must not.
- Structured-output schema document must load before LLM call for `json_schema` mode.
- Repair loops are bounded by `repair_attempts` and repairer presence.
- Runner stays transport-agnostic.