Capability: models
One LLM interface over the providers' official SDKs (OpenAI Responses API first, Chat Completions for OpenAI-compatible servers, Anthropic Messages API beside it) and a System One interface designed against Jev.
What it is
Provider choice as configuration. The LLM entity has invoke and streaming operations, tool-call extraction and structured output; durable execution owns retrying, so the clients' own retries are off. Lives in tiny_harness/harness/models/.
Current behaviour
- An
LLMRequestSHALL carry the static prefix (instructions), the per-turn input items, the tool definitions and an optional structured-output schema; anLLMResponsethe text, the tool calls, the usage (input, output and cached tokens), the model and the finish reason (stop,tool_calls,length,refusal). - An
LLMRequestSHALL also carry an optionalmodelandreasoning_effort(low,medium,high); each adapter usesrequest.modelor its configured model. Every model request of a task (the turn, the compaction summary, help routing) SHALL take them fromModelCatalog.settings_for(the task's/modeland/effortchoice, else the configured default). The effort SHALL be sent only when set, so an unset effort keeps requests byte-identical:reasoning={"effort": v}on the Responses API,reasoning_effort=von Chat Completions,output_config={"effort": v}on Anthropic. ModelCatalog(models/catalog.py) SHALL hold the default model, the selectable models (models, else the default alone), the default effort and each model's context window; compaction looks the window up for the task's current model when it decides. The chat span'sgen_ai.request.modelis the per-request model andtiny_harness.llm.reasoning_effortis set when an effort is.- The OpenAI adapter SHALL use the Responses API with
instructionsas the cached prefix,prompt_cache_key= the task id,store=false,max_retries=0; the default model isgpt-6.1-sol(the only e2e model). A 429, 5xx, timeout or connection failure SHALL be raised asRetryableProviderError, any other provider error asProviderError. - The OpenAI adapter SHALL send every request to
[openai] base_url(defaulthttps://api.openai.com/v1) and to no other host: the client is always built with an explicit URL, soOPENAI_BASE_URLis never read (the runtime logs one WARNING, without its value, when it is set), and a custom endpoint's redirects are refused. A custom endpoint SHALL receive noOpenAI-Organization/OpenAI-Projectheaders, and with no key noAuthorizationheader. - WHERE
api = "chat_completions"the adapter SHALL call/chat/completions: the prefix as the leadingsystemmessage, the calls of a turn grouped in oneassistantmessage, tool results astoolmessages,max_tokens,json_schemastructured output, nostoreorprompt_cache_key; streamed tool-call fragments are assembled and emitted when the stream ends; absent usage or call ids read as zero /call_<n>. The finish reason isrefusal(a refusal orcontent_filter), elsetool_callswhen any call is present, elselength, elsestop. - A 2xx body either wire API cannot parse SHALL be raised as
ProviderError(status=200), including JSON nested too deeply to decode and a Chat Completions stream that ends without afinish_reason, which emits no tool call and nodone. LLMModelInfoSHALL carrycontext_window_tokens([openai] context_window_tokens, else the table, else 400 000),endpoint(scheme://host[:port]) andapi; the runtime logsmodel endpoint <endpoint> api=<api> model=<model>at startup, and the chat span carriesserver.address,server.portandtiny_harness.llm.api.- The Anthropic adapter SHALL use the Messages API with the system block marked
cache_control: ephemeral, the same retry contract, and is configurable but not exercised end to end. - Tool names SHALL be encoded per request into provider-safe names and decoded on the calls that come back.
- The System One entity SHALL answer typed questions about a state (
noulwith a probability,choicewith the option, its confidence and every option's probability,scorewith a rubric level) with a timeout; a deterministic fake ships and the core loop does not call it in this work item. - Provider credentials SHALL come only from
OPENAI_API_KEY(optional with abase_url) andANTHROPIC_API_KEY. FakeLLMSHALL be the scripted implementation tests use.
Design
History
| Work item | What changed | Links |
|---|---|---|
| issue-3 | LLM and System One entities, OpenAI and Anthropic adapters, the fake (Layer 3); provider-safe wire names (Layer 9) | spec, PR #9 |
| issue-19 | base_url, the Chat Completions wire API, the keyless client, context_window_tokens, parse failures as ProviderError, endpoint observability | spec, PR #22, decision-006 |
| issue-25 | Per-request model and reasoning_effort on LLMRequest, the provider effort mappings, ModelCatalog and the per-model context window, for /model and /effort | spec, PR #26, decision-007 |