feat(config): per-model context_length and provider_routing overrides - #24495
feat(config): per-model context_length and provider_routing overrides#24495samplesabotage wants to merge 1 commit into
Conversation
Add two overlay schemas that let a single config declare model-specific profile-globals without mutating the flat defaults other models inherit: * `model.models.<id>.context_length` — wins over flat `model.context_length` when the active model is <id>. Resolution order is now: per-model override → flat → custom_providers per-model → auto-detect. * `provider_routing.models.<id>.<key>` — wins over flat `provider_routing.<key>` when the active model is <id>. Unspecified per-model keys fall through to flat defaults, so callers can override e.g. just `only:` for one model without restating the rest. Motivating case: on OpenRouter, some providers serve a given model with a smaller context window than the model's native size. Pinning providers via `provider_routing.only` fixes routing, and a matching `context_length` override pins the harness's expectations — but today both settings are profile-global, so switching the active model without flipping both yields sporadic tool-call failures when the harness's context check runs against the larger flat default. With this patch the two settings travel together per model. Schema precedent already exists: `model.custom_providers.<name>.models.<id>.context_length` and `providers.<name>.models.<id>.timeout_seconds`. These overlays follow the same pattern, scoped to keys that are otherwise flat. Tests: 10 new (6 context_length, 4 provider_routing); 129 pre-existing tests across the touched modules continue to pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Good stuff but this is for |
|
Heads-up: I've opened #37720 for the per-request router-swap case. Your config and |
|
Thanks for the focused configuration proposal. The flat-only gap is real on current main: startup reads Problems
Suggested changes
Automated hermes-sweeper review. |
What does this PR do?
Adds two opt-in, fully backward-compatible overlay schemas that let a single config declare model-specific profile-globals without mutating the flat defaults other models inherit:
model.models.<id>.context_length— wins over flatmodel.context_lengthwhen the active model is<id>. Resolution order: per-model override → flat →custom_providersper-model → auto-detect.provider_routing.models.<id>.<key>— wins over flatprovider_routing.<key>when the active model is<id>. Unspecified per-model keys fall through to flat defaults.Why this approach
On OpenRouter, some providers serve a given model with a smaller context window than its native size — e.g. certain providers ship Kimi K2.6 with a 32K window despite the model's native 256K. The workaround is two profile-global settings travelling together:
provider_routing.only: [...]to pin providers that serve the full window.model.context_length: <native>so the harness's expectation matches.Both are flat in the current schema, so switching the active model without flipping both yields sporadic tool-call failures when the harness's context check runs against the larger flat default. With this patch the two settings travel together per model:
The overlay shape is consistent with precedent already in the codebase:
model.custom_providers.<name>.models.<id>.context_lengthandproviders.<name>.models.<id>.timeout_seconds.Related Issues and PRs
Fixes #24493.
Also searched open issues + PRs; this PR is related to the following but not a duplicate of any:
model_metadata.pyfor the specific kimi models; this PR adds a user-configurable per-model override that works for any model OpenRouter mis-reports, plus the provider-pinning angle (provider_routing.models.<id>.only) which Wrong context length for kimi-k2.6 family: OpenRouter returns 32K, overrides correct hardcoded 256K default #24268 doesn't address. Both could land independently.model.context_lengthpersists across/modelprovider switches #24072 (P2) + companion PR fix: clear stale _config_context_length when switching providers #24079 — mid-session/modelswitching doesn't re-resolve_config_context_length. This is exactly the scope-note below: this PR resolves overlays at agent-init time only; fix: clear stale _config_context_length when switching providers #24079 addresses the live-switch path and is complementary, not conflicting.model.custom_providers.<name>.models.<id>.context_lengthresolution order. Different code path; no conflict with this PR's newmodel.models.<id>overlay.max_tokensin custom_providers. Adjacent: the overlay pattern introduced here naturally extends tomax_tokensand other model-globals as future work.Type of Change
Changes Made
run_agent.py: per-modelmodel.models.<id>.context_lengthresolved before flatmodel.context_length; existing custom_providers branch and warning behavior preserved.cli.py: per-modelprovider_routing.models.<id>.*overlay on top of flat keys; unspecified per-model keys fall through.cli-config.yaml.example: schema docs for both new overlays with motivating examples.tests/run_agent/test_per_model_context_length.py(new): 6 tests covering per-model wins, flat fallback, invalid-value warns + falls back, missingmodels:no-op, string-int parsing.tests/cli/test_cli_provider_resolution.py: 4 new tests covering per-model overlay wins, no-leak to other models, empty-list honored, no-overlay no-op.How to Test
pytest tests/run_agent/test_per_model_context_length.py tests/cli/test_cli_provider_resolution.py -q— all 10 new tests pass.pytest tests/run_agent/test_invalid_context_length_warning.py tests/run_agent/test_switch_model_context.py tests/run_agent/test_compression_feasibility.py tests/cli/test_cli_provider_resolution.py tests/agent/test_model_metadata.py -q— all 146 tests pass (10 new + 136 pre-existing).context_lengthoverride, and verify via/info(or equivalent) that the effective context_length reflects the override, not the flat default.Checklist
Code
feat(config): ...)pytest tests/ -qon the touched modules and all tests passDocumentation & Housekeeping
cli-config.yaml.example)cli-config.yaml.examplefor the new config keysScope note
Both overlays resolve at agent-init time, so the active value is correct from container/process start. Mid-session
/modelswitching does not currently re-resolve these overlays (would require touching theswitch_modelpath) — happy to follow up if maintainers want it.