Agent model selection + gpt-5.6-luna dropdown#232
Merged
Conversation
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
Owner
Author
|
Reviewed at No blocking issues. Ready to merge. The implementation matches the agreed design:
Independent validation:
|
…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.
Owner
Author
|
Reviewed the provenance follow-up at No blocking issues. Ready to merge. Confirmed:
Independent validation on the exact head:
This closes the attribution hole cleanly: policy decides what to ask for; only the successful response says what actually answered. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
openai_codex.agent_model— spawned agents can run a different Codex model than main chat (null = inherit), mirroringagent_reasoning_effortend to end.Design (as settled in the pre-code design review)
agent_model ?? modelfrom ONE config read, pass the RESOLVED value tochat_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.modelon the LLMProvider ABC; codex resolves it locally (never mutatesself); ollama/kimi accept-and-ignore. An ignored override is never stamped — non-codex iterations stamp the provider's actual model.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/statusexposesagent_model+effective_agent_model(codex-scoped:agent_model ?? model).CODEX_MODELSlist 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
ruff check src/ tests/: 0 findings ·mypy src/: 0 errors (227 files)npm run check: templates validated,ui/distrebuilt and committedDeploy note
The tracked
config.ymltemplate gainsagent_model: null→ the live-install deploy needs the skip-worktree config dance.🤖 Generated with Claude Code