Skip to content

feat(harness): per-session model + thinking/effort-level selection #254

Description

@oxoxDev

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

  1. 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.
  2. 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.
  3. 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.
  4. Surface on the stream — set ctx.model in v2Context() (harness-wrapper.ts) and emit SessionInfoPayload.model so consumers show the active model.
  5. Expose the catalog — advertise the per-provider catalog over the daemon protocol / a query so OpenHuman's UI can render a picker.

Acceptance criteria

  • TaskFrame carries optional model + effort; round-trips through encode/decode with a test.
  • buildRunArgs maps model+effort to the correct flag for every provider incl. claude; unit-tested per provider.
  • Per-provider catalog exists and is queryable; default model/effort applied when a task omits them.
  • event.model is populated end-to-end on the interactive stream (regression test asserts non-undefined).
  • No blanket model default silently overrides an explicit per-task choice.
  • Tests + typecheck + lint green; ready for openhuman vendor/tinyplace submodule bump.

Related

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions