fix(agent): scope model.context_length override to config default model - #62153
fix(agent): scope model.context_length override to config default model#62153TheTom wants to merge 2 commits into
Conversation
52f2128 to
cddecbc
Compare
Competing-PR cluster for #62152 (model.context_length override leaking onto a session running a different model). This PR and #62124 both scope the override in |
Context-window override leak (NousResearch#62153, fixed here), session model switches persisting globally (NousResearch#61192), and bare custom endpoints hidden in the picker (NousResearch#59808, cherry-pick branch on this fork).
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating the initialization leak; current main still reads the override unconditionally at agent/agent_init.py:1632-1639, so the underlying bug is real.
Problems
agent/agent_init.py:280compares raw identifiers, but current main normalizesagent.modelfor non-aggregator providers atagent/agent_init.py:464-471. A valid configured default such aszai/glm-4.6can therefore compare unequal to normalizedglm-4.6and lose its intended override.- The gateway hygiene path remains unscoped:
gateway/run.py:11050-11056reads the config override before resolving session runtime atgateway/run.py:11079-11087, then passes it to context resolution atgateway/run.py:11093-11099. This can still size pre-agent compression for an overridden session with the default model's window.
Suggested changes
- Normalize the configured identifier with the same provider-aware normalization used for
agent.model, with a prefixed-model regression test. - Scope the gateway hygiene override after session-runtime resolution and cover that path with a regression test.
Automated hermes-sweeper review.
| return config_context_length | ||
| _default_model = str(model_cfg.get("default", model_cfg.get("name", "")) or "").strip() | ||
| _agent_model = str(agent_model or "").strip() | ||
| if _default_model and _agent_model and _agent_model != _default_model: |
There was a problem hiding this comment.
agent.model has already been normalized for non-aggregator providers in the init path, while _default_model remains raw config text. Normalize the config value with the same provider-aware normalizer before comparing; otherwise a valid value such as zai/glm-4.6 mismatches normalized glm-4.6 and drops the intended override.
The explicit model.context_length in config.yaml is written for the config's default model, but init_agent applied it unconditionally to every agent build. A session created with a per-session model_override (desktop/mobile picker choosing a different provider/model) inherited the override and reported the wrong context window, e.g. a Codex gpt-5.6 session (372k) showing a local model's 131072. The in-session /model switch path already guards against this by clearing _config_context_length on swap (agent_runtime_helpers.py). This applies the same scoping at build time: if the config block names a default model and the agent's model differs, drop the override so get_model_context_length auto-detects the real window. Per-model context_length entries under custom_providers are unaffected and still resolve after the scoped override falls through to None.
…ssion model Two follow-ups from review on the model.context_length scoping fix. _scope_config_context_length_to_default_model compared the raw config.yaml default against agent.model, which has already been provider-normalized (e.g. zai/glm-4.6 stripped to glm-4.6) elsewhere in init_agent. A default written with a provider prefix therefore never matched and lost its override even when the session was actually on that model. The helper now runs the same normalize_model_for_provider logic on the default before comparing. Separately, gateway hygiene's pre-agent compression sizing read model.context_length from the raw config before resolving which model the session was actually running via _resolve_session_agent_runtime. A session with a per-session model override kept the default model's context window for hygiene sizing even though it was on a different model. The override is now re-scoped with the same helper after runtime resolution, using the resolved session model and provider.
|
Both findings addressed, thanks for the precise pointers.
Also rebased onto current main. On the competing-PR note from triage: #62124 covers the CLI/skill/fallback trigger in |
cddecbc to
6d1cc63
Compare
|
Closing as superseded — the core mechanism here (scope a global
This PR was opened before that landed and correctly identified the bug (#62152) and the fix direction — thank you for the detailed analysis and tests; the normalization-aware default-model comparison you implemented is exactly the shape that ended up on main. |
Closes #62152
Problem
The explicit
model.context_lengthin config.yaml is written for the config's default model, butinit_agentapplied it to every agent build unconditionally. A new session created with a per-session model override (desktop/mobile picker choosing a different provider/model) inherited the override and reported the wrong context window: e.g. a Codex gpt-5.6 session (real window 372k) showing a local default model's 131072, with the compressor threshold firing accordingly.The in-session
/modelswitch path already guards against exactly this by clearing_config_context_lengthon swap (agent_runtime_helpers.py). The build path had no equivalent, so switching mid-session gave the correct window while picking the same model for a new chat did not.Fix
New pure helper
_scope_config_context_length_to_default_modelinagent/agent_init.py, wired in right after the existing int-parse of the override:hermes_cli/web_server.py::get_model_infodoes (default, falling back toname)agent.modeldiffers, returns None soget_model_context_length()auto-detects the real window for the actual modelPer-model
context_lengthentries undercustom_providersare untouched and still resolve after the scoped override falls through to None (that block already keys on model + base_url).Tests
tests/run_agent/test_config_context_length_model_scoping.py(new, 11 tests):AIAgent, mirroringtest_invalid_context_length_warning.py): override applies when the session model matches the config default; override does not leak onto a session with a different model (auto-detection wins); plain-string model config unchangednamefallback, whitespace, missing default, missing agent model, non-dict configtests/run_agent/test_invalid_context_length_warning.py: two tests incidentally built the agent with a model that mismatched the config default while asserting the override applied; they now pass the matching model explicitly, with a comment noting the scoping constraint.python3 -m pytest tests/run_agent/test_config_context_length_model_scoping.py tests/run_agent/test_invalid_context_length_warning.pypasses 16/16 on this branch.ruff checkclean on the touched files.