[AI] fix(model): /model <default> writes override when session runs non-default model#96368
Conversation
…on-default model Strip isDefault from model selections before applying overrides in the directive-handling paths. When a user explicitly switches to the configured default model via /model, the selection must write an override so the session actually transitions — clearing overrides left the session pinned to the stale runtime model. Related to openclaw#96269
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Close as superseded: this branch changes directive-only model persistence, but the linked webchat bug runs through Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Canonical path: Use #96318 or an equivalent helper-level fix that preserves default-reset storage while recording live switch intent, then verify the gateway path before closing the linked issue. So I’m closing this here and keeping the remaining discussion on #96318. Review detailsBest possible solution: Use #96318 or an equivalent helper-level fix that preserves default-reset storage while recording live switch intent, then verify the gateway path before closing the linked issue. Do we have a high-confidence way to reproduce the issue? Yes at source level: webchat Is this the best way to solve the issue? No. The best fix is the shared helper or gateway path used by Security review: Security review cleared: The diff only changes TypeScript session/directive code and a test; it does not touch dependencies, CI, secrets, permissions, network calls, or package execution surfaces. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against e9720c27fa69. |
|
ClawSweeper applied the proposed close for this PR.
|
Summary 📌 required
/model <default>silently fails when the session is currently running a non-default model. StripisDefaultfrom model selections in directive-handling paths so user-requested model switches always write an explicit override./model, fallback, or steering) and the user types/model <default>, the selection getsisDefault=true. This clears overrides inapplyModelOverrideToSessionEntryinstead of writing them, leaving the session pinned to the stale runtime model.isDefaultflag fromModelDirectiveSelectionbefore passing it toapplyModelOverrideToSessionEntryin the two directive-handling call sites. KeepisDefaulton the selection object for display/sorting purposes.src/auto-reply/reply/directive-handling.impl.ts(+8/-1),src/auto-reply/reply/directive-handling.persist.ts(+4/-1),src/sessions/model-overrides.test.ts(+32 regression test)applyModelOverrideToSessionEntryitself, repair/cleanup paths (agent-command, model-selection reset, repairProviderWrappedModelOverride),isDefaultdisplay semantics in model picker/suggestionsChange Type (select all) 📌 required
Scope (select all) 📌 required
Linked Issue/PR 📌 required
Motivation 📌 required
When a session is running a non-default model (set via
/model, fallback, or steering) and the user explicitly issues/model <default-model>, the session should switch to the configured default model. Instead, the switch silently fails becauseisDefault=truecausesapplyModelOverrideToSessionEntryto clear overrides rather than writing the default as an explicit override. The session remains on the old model with no error or feedback.This is a regression in behaviour — prior versions handled this correctly because the model-override path did not distinguish between "explicit user selection" and "system reset to default."
Real behavior proof (required for external PRs) 📌 required
/model <default>switching to the configured default model when the session is currently running a different modelfix/model-default-switch-96269Observed result after fix:
isDefault, the override is written even when the session currently has a non-default overrideisDefault=trueclearing behaviour for repair/cleanup paths/modelcommand resolution pipelineWhat was not tested:
/modelroundtrip with a live gateway (requires real provider credentials)isDefaultdisplay behaviour in the model picker UI (the flag is preserved on the selection object for display)Root Cause (if applicable) ✅ optional
In
resolveModelSelectionFromDirective(directive-handling.model-selection.ts), when the user types/model <default-model>, the resolvedModelDirectiveSelectioncarriesisDefault: truebecause the selected model matches the configuredagents.defaults.model.primary. This flag flows toapplyModelOverrideToSessionEntry, where theisDefaultbranch unconditionally clears provider/model overrides — even when the session is currently running a different model. Clearing overrides leaves the session pinned to the stale runtime model without triggering a switch.The fix strips
isDefaultbefore the selection reachesapplyModelOverrideToSessionEntry, so user-initiated model switches always write an explicit override. TheisDefaultflag is preserved on themodelSelectionobject for display purposes (model picker sorting, switch event messages).Regression Test Plan (if applicable) ✅ optional
Added
model-overrides.test.ts: "writes default model override when selected without isDefault flag (#96269)" — verifies that a selection matching the configured default without theisDefaultflag writesproviderOverrideandmodelOverrideeven when the session entry currently holds a different override.User-visible / Behavior Changes 📌 required
/model <default>now correctly switches the session to the configured default model when the session is currently running a non-default model. Previously the switch silently failed —/statuswould still show the old model with no error feedback.Diagram (if applicable) ✅ optional
Security Impact (required) 📌 required
Repro + Verification ✅ optional
Environment
Steps
agents.defaults.model.primary: "minimax/MiniMax-M3"/model tencent-token-plan/glm-5.1/model minimax/MiniMax-M3/status— should showminimax/MiniMax-M3Expected
Session switches to
minimax/MiniMax-M3.Actual (before fix)
Session stays on
tencent-token-plan/glm-5.1. No error or feedback.Human Verification (required) 📌 required
isDefault=trueclearing behaviour preserved for repair/cleanup paths; test forisDefault=truewith already-matching override still clears correctly/modelroundtripCompatibility / Migration 📌 required
Best-fix Verdict 📌 required (from Review Contract)
isDefaultat the directive-handling boundary is the right fix because:isDefaultfor model picker sorting) from the behavioural concern (explicit model switch)applyModelOverrideToSessionEntry, preserving existing semantics for repair/cleanup pathsapplyModelOverrideToSessionEntryisDefaultbranch: Adding ahasNonDefaultOverridecheck inside the callee would also work, but it would change behaviour for all callers including repair/cleanup paths where clearing is the correct intent. The callee lacks enough context to distinguish user-initiated switches from system-initiated cleanup.isDefaultfromresolveModelDirectiveSelection: Would affect model picker display/sorting sinceisDefaultis consumed downstream for UI purposes.AI Assistance 🤖 (required for AI-assisted PRs)
Risks and Mitigations 📌 required
isDefault=trueclearing behaviour from the directive-handling path. Previously, if a user typed/model <default>while already on the default model, overrides would be cleared (no-op since none existed). Now an explicit override is written. This is a semantic change but the practical effect is identical — the session runs the default model either way.Related to #96269