Summary
Add per-session model + thinking/effort-level selection to the coding-agent harness/daemon. Today an agent launches with a single daemon-global model and no notion of effort/thinking level; this makes model choice a first-class, per-task property with a per-provider catalog, threads it into each agent's real CLI flag, and surfaces the active model on the event stream.
Implementation home for the [OpenHuman] agent-runtime abstraction epic (tinyhumansai/openhuman#4731). Reference pattern only — clean-room, no third-party source copied.
Problem (current state, sdk/typescript/src/cli/)
- Model is daemon-global.
--model (daemon.ts) → DaemonRuntimeDeps.model → merged into every runTask. There is no model field on TaskFrame (daemon/protocol.ts), so the protocol cannot carry a per-task model.
- No effort / thinking / reasoning-level control anywhere.
- claude never receives a model flag.
buildRunArgs (daemon/providers.ts) threads -m for codex/opencode only; the claude arm omits it entirely.
- No model catalog. No per-provider list of available models or effort levels for a UI to offer.
event.model is dead. Declared on SessionEnvelopeV2.event (types/harness.ts) and honored by buildEventEnvelopeV2, but HarnessSessionTailer.v2Context() never sets ctx.model, so it is always undefined. SessionInfoPayload.model is likewise never emitted.
Approach
- Catalog — a new per-provider table (e.g.
daemon/models.ts) of { models[], effortLevels[], defaultModel }. Static tables first (claude/codex/opencode + future providers); self-report probing is a follow-up.
- Per-task carry — add optional
model + effort to TaskFrame (daemon/protocol.ts, plus encodeTaskFrame/decodeTaskFrame); read frame.model/frame.effort in handleTask (daemon/runtime.ts) instead of the daemon-global.
- Flag mapping — extend
buildRunArgs (daemon/providers.ts) to map model+effort → each provider's real flag: add the missing claude --model, codex reasoning-effort (-c model_reasoning_effort=…), opencode -m. Single site.
- Surface on the stream — set
ctx.model in v2Context() (harness-wrapper.ts) and emit SessionInfoPayload.model so consumers show the active model.
- Expose the catalog — advertise the per-provider catalog over the daemon protocol / a query so OpenHuman's UI can render a picker.
Acceptance criteria
Related
Summary
Add per-session model + thinking/effort-level selection to the coding-agent harness/daemon. Today an agent launches with a single daemon-global model and no notion of effort/thinking level; this makes model choice a first-class, per-task property with a per-provider catalog, threads it into each agent's real CLI flag, and surfaces the active model on the event stream.
Implementation home for the [OpenHuman] agent-runtime abstraction epic (tinyhumansai/openhuman#4731). Reference pattern only — clean-room, no third-party source copied.
Problem (current state,
sdk/typescript/src/cli/)--model(daemon.ts) →DaemonRuntimeDeps.model→ merged into everyrunTask. There is nomodelfield onTaskFrame(daemon/protocol.ts), so the protocol cannot carry a per-task model.buildRunArgs(daemon/providers.ts) threads-mfor codex/opencode only; the claude arm omits it entirely.event.modelis dead. Declared onSessionEnvelopeV2.event(types/harness.ts) and honored bybuildEventEnvelopeV2, butHarnessSessionTailer.v2Context()never setsctx.model, so it is alwaysundefined.SessionInfoPayload.modelis likewise never emitted.Approach
daemon/models.ts) of{ models[], effortLevels[], defaultModel }. Static tables first (claude/codex/opencode + future providers); self-report probing is a follow-up.model+efforttoTaskFrame(daemon/protocol.ts, plusencodeTaskFrame/decodeTaskFrame); readframe.model/frame.effortinhandleTask(daemon/runtime.ts) instead of the daemon-global.buildRunArgs(daemon/providers.ts) to map model+effort → each provider's real flag: add the missing claude--model, codex reasoning-effort (-c model_reasoning_effort=…), opencode-m. Single site.ctx.modelinv2Context()(harness-wrapper.ts) and emitSessionInfoPayload.modelso consumers show the active model.Acceptance criteria
TaskFramecarries optionalmodel+effort; round-trips through encode/decode with a test.buildRunArgsmaps model+effort to the correct flag for every provider incl. claude; unit-tested per provider.event.modelis populated end-to-end on the interactive stream (regression test asserts non-undefined).vendor/tinyplacesubmodule bump.Related
session/set_modelconsumes the per-task model field this adds).