fix(model-metadata): extend Kimi 32k guard to Nous OpenRouter suffix-match - #24066
fix(model-metadata): extend Kimi 32k guard to Nous OpenRouter suffix-match#24066briandevans wants to merge 1 commit into
Conversation
…match OpenRouter reports 32768 for moonshotai/kimi-k2.6, even though the model supports 262144. PR NousResearch#23980 added a Kimi-family guard to the step-6 OpenRouter fallback in get_model_context_length, but that guard is gated on `not effective_provider`. When provider='nous', the resolver hits step 5b's `_resolve_nous_context_length` first — which suffix-matches the same OpenRouter cache and returned 32768 directly, tripping the 64k minimum-context guard at run_agent.py and blocking boot for any Nous Portal config using a Kimi model. This applies the same narrow guard inside the nous resolver: if the suffix-matched entry returns exactly 32768 and the model name suggests Kimi, reject it and let the resolver fall through to the curated DEFAULT_CONTEXT_LENGTHS table (where "kimi" → 262144 wins via longest-substring match). All non-Kimi paths are unchanged: a real 32k non-Kimi model still resolves correctly. Fixes NousResearch#24000 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Extends the existing “Kimi-family 32K underreport” guard so that provider: nous (which resolves context length via OpenRouter suffix-match) no longer returns OpenRouter’s stale 32768 value for Kimi models and instead falls through to the curated defaults (e.g. 262,144 for kimi).
Changes:
- Add a narrow
ctx == 32768 && _model_name_suggests_kimi(model)filter inside_resolve_nous_context_length()to treat that OpenRouter value as “not found” for Nous-routed Kimi models. - Add regression tests covering the Nous+Kimi fallthrough to defaults and a negative case ensuring legitimate non-Kimi 32K models are preserved.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
agent/model_metadata.py |
Applies the Kimi 32K-underreport guard to the Nous/OpenRouter suffix-match resolver so later resolution paths (defaults) can run. |
tests/agent/test_model_metadata.py |
Adds targeted tests validating the new fallthrough behavior and guarding against overbroad filtering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
CI audit — all 3 failures on this PR are pre-existing baselines on clean
PR is otherwise green and isolated to the Kimi 32k Nous-suffix path. |
|
Closing — superseded on main.
Net effect on main is strictly broader than this PR. Thanks @rob-maron. |
Summary
provider: nouswith a Kimi-family model (e.g.moonshotai/kimi-k2.6) cannot boot Hermes Agent:get_model_context_length()resolves the model to 32,768 tokens, which trips the 64K minimum-context guard atrun_agent.py:2254. The user-facing message claims the model has a 32k window, but kimi-k2.6 actually supports 262,144.Fixes #24000.
The bug
PR #23980 (Kimi-family 32k guard) and the related #23950 / e2b713c (skip OpenRouter for known providers, add
kimi/moonshottoPROVIDER_TO_MODELS_DEV) landed a guard that rejects OpenRouter's stalemoonshotai/kimi-k2.6 → 32768metadata. But that guard lives inside the step-6 OpenRouter fallback inget_model_context_length, gated onif not effective_provider:.provider: nousis a known provider that intentionally piggybacks on OpenRouter via suffix-match (Nous Portal doesn't appear in models.dev, and adding it would be wrong). For nous, the resolver hits step 5b's_resolve_nous_context_lengthfirst — which queries the same OpenRouter cache and returned the 32,768 value directly. The step-6 guard never gets a chance to run because step 5b's return is non-None.Trace for
provider=nous, model=moonshotai/kimi-k2.6:The fix
Apply the same narrow Kimi guard inside
_resolve_nous_context_length: when a suffix-matched entry yields exactly 32768 AND_model_name_suggests_kimi(model)matches, treat the entry as not found and let later resolution paths fire. The resolver then falls through toDEFAULT_CONTEXT_LENGTHS["kimi"] = 262144via the existing longest-substring match.The filter is intentionally narrow:
32768, not other context values OpenRouter might report.kimior containingmoonshot(existing helper).If OpenRouter ever updates its metadata for kimi-k2.6, the filter becomes dead code with no impact, matching the existing comment on the step-6 guard.
Why this is the right scope
Adding
noustoPROVIDER_TO_MODELS_DEVwould not help: Nous Portal is documented as suffix-matching against OpenRouter, not as a first-class models.dev entry. The suffix-match path is the correct flow; the fix is to make it as robust as the step-6 fallback that #23980 already hardened.Test plan
test_nous_kimi_32k_guard_falls_through_to_default— mocksfetch_model_metadatato return the stale{"moonshotai/kimi-k2.6": 32768}entry, asserts result is 262144.test_nous_non_kimi_32k_is_preserved— verifies a legitimate 32k non-Kimi model still resolves to 32k (the guard is narrow).tests/agent/test_model_metadata.py(96 passed),tests/agent/test_nous_rate_guard.py(32 passed),tests/hermes_cli/test_runtime_provider_resolution.py(109 passed).test_nous_kimi_32k_guard_falls_through_to_defaultfails withassert 32768 == 262144— confirms the test actually exercises the new code path.Related
provider: kimi/moonshot/ollama-cloud/kimi-codingroutes. This PR closes the remaining gap forprovider: nous, which uses the OR cache via a separate suffix-match resolver.