Skip to content

Agent model selection + gpt-5.6-luna dropdown#232

Merged
Calmingstorm merged 3 commits into
masterfrom
feat/agent-model
Jul 15, 2026
Merged

Agent model selection + gpt-5.6-luna dropdown#232
Calmingstorm merged 3 commits into
masterfrom
feat/agent-model

Conversation

@Calmingstorm

Copy link
Copy Markdown
Owner

What

  1. openai_codex.agent_model — spawned agents can run a different Codex model than main chat (null = inherit), mirroring agent_reasoning_effort end to end.
  2. gpt-5.6-luna added to the WebUI Codex model dropdown, under Terra and above 5.5 (live-verified: plain-header requests serve it; all five reasoning efforts accepted).
  3. Codex block re-layout — Model | Agent Model / Reasoning | Agent Reasoning as semantic pairs, Max Tokens on its own full-width row.

Design (as settled in the pre-code design review)

  • Single resolved snapshot: the agent iteration callbacks resolve agent_model ?? model from ONE config read, pass the RESOLVED value to chat_with_tools(model=...) even when inheriting, and stamp that exact value into the per-iteration trajectory metadata — the request body and the stamp cannot diverge under a live config change. A shared _agent_llm_policy() helper keeps both callbacks (spawn_agent, spawn_loop_agents) on one resolver.
  • Uniform provider contract: keyword-only model on the LLMProvider ABC; codex resolves it locally (never mutates self); ollama/kimi accept-and-ignore. An ignored override is never stamped — non-codex iterations stamp the provider's actual model.
  • PUT semantics: presence-checked key; null/""/whitespace = inherit; free string like model (the dropdown is the UI constraint); agent-only changes persist without a codex client reload; a combined model+agent_model change still reloads once. /api/llm/status exposes agent_model + effective_agent_model (codex-scoped: agent_model ?? model).
  • UI: one ordered CODEX_MODELS list renders both selects (no drift); an unknown configured value renders as a temporary option instead of a blank select the next save would silently replace; the new select rides the existing debounce + pending-guard machinery.

Gates

  • Full suite: 7,460 passed, 4 skipped (+22 new tests)
  • ruff check src/ tests/: 0 findings · mypy src/: 0 errors (227 files)
  • npm run check: templates validated, ui/dist rebuilt and committed

Deploy note

The tracked config.yml template gains agent_model: null → the live-install deploy needs the skip-worktree config dance.

🤖 Generated with Claude Code

Spawned agents can now run a different Codex model than main chat,
mirroring agent_reasoning_effort end to end:

- schema: agent_model (null = inherit model; ""/whitespace normalize to
  inherit so a hand-edited config can't carry a visually-empty override)
- chat_with_tools gains keyword-only model across the LLMProvider ABC:
  codex resolves it into a LOCAL body value (never mutates self — the
  same concurrency rule as the effort override); ollama/kimi accept and
  ignore it for signature parity
- both agent iteration callbacks resolve agent_model ?? model from ONE
  config read at call time and pass the RESOLVED value even when
  inheriting, then stamp that exact value into the per-iteration
  trajectory metadata — the request body and the stamp cannot diverge
  under a live config change; a provider that pins its model stamps what
  actually answered, never the ignored Codex setting
- PUT /api/llm/codex/config: presence-checked agent_model (null/"" =
  inherit, whitespace stripped, free string like model); agent-only
  changes persist without a codex client reload, while a combined
  model+agent_model change still reloads; persist allowlist extended;
  /api/llm/status exposes agent_model + effective_agent_model
  (codex-scoped: agent_model ?? model)
- config template + docs document the new key

24 new tests pin the contract (schema normalization, PUT semantics,
no-reload + combined-reload, persistence, per-request override locality
incl. concurrent-call isolation, callback resolution/stamping across
codex, non-codex, live-change, and loop-agent paths).
- new Agent Model select (default: Inherit chat model), paired layout
  per design review: Model | Agent Model / Reasoning | Agent Reasoning,
  Max Tokens on its own full-width row (input width capped)
- gpt-5.6-luna added under Terra, above 5.5 (verified live: plain-header
  requests serve it and all five reasoning efforts are accepted)
- one ordered CODEX_MODELS list renders both selects so the dropdowns
  cannot drift; an unknown configured value (free string server-side)
  renders as a temporary option instead of a blank select that the next
  save would silently replace
- agent_model rides the existing debounced save + pending-guard flow
- ui/dist rebuilt via npm run check
@Calmingstorm

Copy link
Copy Markdown
Owner Author

Reviewed at 1c35fd7b84644dd20c298c363ab169e06b9234a6.

No blocking issues. Ready to merge.

The implementation matches the agreed design:

  • agent_model is normalized consistently across schema, API, persistence, tracked config, and docs.
  • Both agent callback paths resolve one per-iteration policy snapshot, pass the resolved model into the request, and stamp the same model into trajectory data.
  • Codex applies the override locally without mutating shared client state; Ollama and Kimi accept and ignore it while trajectories report their actual model.
  • Agent-only PUTs avoid a Codex reload; combined base-model plus agent-model PUTs still reload once.
  • Status exposes configured and effective Codex-scoped values.
  • The UI uses one ordered model catalog, places Luna under Terra and above 5.5, preserves unknown configured values in both selects, retains the debounce/pending behavior, and gives Max Tokens its own full-width row.
  • The rebuilt ui/dist is byte-stable against a fresh local build.

Independent validation:

  • Full suite: 7,460 passed, 4 skipped
  • Focused changed-area suite: 267 passed
  • Ruff: clean
  • Mypy: 0 issues in 227 source files
  • npm run check: 38 templates, 0 failures, production build successful
  • git diff --check: clean
  • All five GitHub checks green; PR mergeable; reviewed checkout clean at the exact head

npm audit --omit=dev reports one moderate DOMPurify advisory, but dependencies and lockfile are unchanged by this PR, so it is pre-existing and non-blocking here.

…ation stamps

Chat and loop trajectory iterations have recorded empty provider/model/
reasoning_effort since the fields were added in v3.59.0 (agent paths only
populated them). Root fix per design review: the RESPONSE is the single
authority for what actually served a request — it is the only layer that
stays truthful across gateway aux-router diversions, CircuitOpen retries,
and live config reloads, where any call-site snapshot becomes a guess.

- LLMResponse gains provenance_provider/provenance_model/
  provenance_reasoning_effort, documented as the frozen provider and the
  serialized model/effort of the successful outbound request; None effort
  means not-sent, distinct from the literal Codex effort "none"
- each provider stamps them from the SAME immutable pre-await locals the
  request body is built from (ollama/kimi no longer re-read self.model
  after network I/O; codex echoes its resolved model/effort locals)
- both chat/loop ToolIteration sites and both agent iteration callbacks
  now stamp exclusively from response provenance; missing provenance is
  recorded as unknown (+ warning) — never replaced by a call-site guess,
  and the agent resolver (_agent_llm_policy) remains the request-policy
  source only, so there is exactly one stamp path
- gateway passthrough of child response metadata pinned by tests (incl.
  aux-router diversion reporting the auxiliary client's model)
- FakeLLM stamps provenance like a compliant provider (scripted responses
  with explicit provenance win)
- ToolIteration/context_trace comments clarified: context_trace.provider =
  turn-entry policy context; iteration fields = authoritative execution
  provenance; historical records left untouched

11 new tests: provider body==provenance pins (inherited + overridden +
none-vs-not-sent), gateway preservation + diversion, both tool_loop sites
(present + missing provenance), agent stamp-from-response +
missing-provenance-stays-unknown.
@Calmingstorm

Copy link
Copy Markdown
Owner Author

Reviewed the provenance follow-up at 1817f381a858a009d85bf77fa61f30e993b2a491.

No blocking issues. Ready to merge.

Confirmed:

  • LLMResponse.provenance_* has the intended unknown/default semantics, including None for effort not sent versus literal Codex "none".
  • Codex, Ollama, and Kimi freeze the model/effort before the await and build both the outbound body and returned provenance from that snapshot.
  • Codex request overrides remain local; Ollama/Kimi correctly report their pinned models rather than ignored Codex overrides.
  • Both agent callbacks retain _agent_llm_policy() solely as request policy and stamp exclusively from response provenance, with no resolver/client fallback.
  • Both chat and autonomous-loop ToolIteration construction sites consume response provenance, while context_trace.provider is now documented as turn-entry policy context.
  • Gateway paths preserve the child response unchanged, including auxiliary-model diversion; provider retry paths return provenance for the request that successfully completed.
  • FakeLLM is compliant while allowing explicitly scripted provenance to remain authoritative.
  • No UI or ui/dist files moved.

Independent validation on the exact head:

  • Full suite: 7,470 passed, 5 skipped in my checkout; GitHub reports the same count. The submitted 7,471/4 split appears environment-dependent and is non-blocking.
  • Focused provenance/provider/agent/trajectory suite: 347 passed
  • Ruff clean
  • Mypy: 0 issues across 227 source files
  • git diff --check clean
  • All five GitHub checks green
  • PR head unchanged, mergeable, and review checkout clean

This closes the attribution hole cleanly: policy decides what to ask for; only the successful response says what actually answered.

@Calmingstorm Calmingstorm merged commit ae89bce into master Jul 15, 2026
5 checks passed
@Calmingstorm Calmingstorm deleted the feat/agent-model branch July 15, 2026 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant