fix(status): use full provider/model key for context window lookup#27500
fix(status): use full provider/model key for context window lookup#27500AaronL725 wants to merge 1 commit intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes /status context window reporting when multiple providers expose the same model id by making context-window cache keys provider-aware, so lookups can differentiate provider/model variants.
Changes:
- Extend discovered model metadata to optionally include
providerId, and store discovered context windows under both qualified (provider/model) and unqualified (model) cache keys. - Add additional mapping logic for configured context windows when the configured model id contains a
/. - Update
resolveContextTokensForModelto prefer a provider-qualified cache lookup when a provider ref is available.
|
|
||
| // Prefer provider-qualified keys when available so same model ids can have | ||
| // different limits per provider. | ||
| const provider = typeof model.providerId === "string" ? model.providerId.trim() : ""; |
There was a problem hiding this comment.
applyDiscoveredContextWindows builds the provider-qualified cache key using model.providerId.trim() without normalizing case. resolveContextTokensForModel / resolveProviderModelRef lower-case the provider, so if providerId in models.json is e.g. "OpenAI" the lookup will miss and /status will fall back to the unqualified key again. Normalize the provider before composing fullKey (ideally via the shared normalizeProviderId helper) so cache keys are consistent.
| const provider = typeof model.providerId === "string" ? model.providerId.trim() : ""; | |
| const provider = | |
| typeof model.providerId === "string" ? model.providerId.trim().toLowerCase() : ""; |
| for (const provider of Object.values(providers)) { | ||
| if (!Array.isArray(provider?.models)) { | ||
| continue; | ||
| } | ||
| for (const model of provider.models) { | ||
| const modelId = typeof model?.id === "string" ? model.id : undefined; | ||
| const contextWindow = | ||
| typeof model?.contextWindow === "number" ? model.contextWindow : undefined; | ||
| if (!modelId || !contextWindow || contextWindow <= 0) { | ||
| continue; | ||
| } | ||
| params.cache.set(modelId, contextWindow); | ||
| // Also map provider-qualified ids when the configured id includes one. | ||
| const slash = modelId.indexOf("/"); | ||
| if (slash > 0) { | ||
| const provider = modelId.slice(0, slash).trim().toLowerCase(); | ||
| const rawModel = modelId.slice(slash + 1).trim(); | ||
| if (provider && rawModel) { |
There was a problem hiding this comment.
applyConfiguredContextWindows can only populate provider-qualified keys when model.id already contains a /. In config, models are already scoped under models.providers[providerKey], and IDs are commonly unqualified (e.g. "MiniMax-M2.1"). With two providers defining the same bare model id, this code still can’t store distinct ${provider}/${model} keys, so the original bug remains for config-sourced context windows. Consider iterating Object.entries(providers) to get providerKey and always storing a qualified key for each entry.
| const rawModel = modelId.slice(slash + 1).trim(); | ||
| if (provider && rawModel) { | ||
| params.cache.set(`${provider}/${rawModel}`, contextWindow); | ||
| params.cache.set(rawModel, contextWindow); |
There was a problem hiding this comment.
This new code writes params.cache.set(rawModel, contextWindow) for any configured id containing a /. If multiple providers configure the same rawModel with different windows, the unqualified entry becomes last-wins (and could overestimate token budgets). To keep the existing “fail-safe” behavior used in discovery, the unqualified mapping should be set only if it’s smaller than the existing value (or avoid writing the unqualified key from provider-qualified config altogether).
| params.cache.set(rawModel, contextWindow); | |
| const existing = params.cache.get(rawModel); | |
| if (existing === undefined || contextWindow < existing) { | |
| params.cache.set(rawModel, contextWindow); | |
| } |
| // Use the most specific lookup key available. | ||
| // Some providers expose the same model id with different context windows. | ||
| // In that case, we need to include the provider prefix in the cache key | ||
| // (e.g. openai/gpt-codex-5.3 vs openai-codex/gpt-codex-5.3). | ||
| const fullKey = ref ? `${ref.provider}/${ref.model}` : undefined; | ||
| return ( | ||
| lookupContextTokens(fullKey) ?? | ||
| lookupContextTokens(params.model) ?? | ||
| params.fallbackContextTokens | ||
| ); |
There was a problem hiding this comment.
There’s no test coverage for the new provider-qualified behavior (e.g. two providers exposing the same model id with different contextWindows, and resolveContextTokensForModel preferring ${provider}/${model}). Adding a focused test that seeds the cache with both qualified/unqualified keys and asserts the qualified key is preferred would prevent regressions for /status (issue #27394).
Greptile SummaryThis PR fixes a bug where different providers exposing the same model ID with different context windows (e.g., The fix stores context window values under both provider-qualified keys ( Key changes:
The implementation is sound and maintains backward compatibility. The fail-safe behavior (preferring smaller context windows when multiple values exist) is preserved for discovered models. Confidence Score: 4/5
Last reviewed commit: e6c680e |
|
Closing as duplicate — #27439 covers the same fix with broader scope. Thanks @paul-tian! |
Summary
When different providers expose the same model id with different context windows (e.g.
openai/gpt-codex-5.3at 400k vsopenai-codex/gpt-codex-5.3at 272k), the/statuscommand always showed the same context window value regardless of which provider was active.Root cause
applyDiscoveredContextWindowsandresolveContextTokensForModelused only the bare model id as cache key, ignoring the provider prefix. When two providers offered the same model id with different limits, the last-written value won.Fix
provider/model(qualified) andmodel(unqualified) cache keys.provider/model) when a provider ref is available, falling back to the unqualified key.Files changed
src/agents/context.ts— 1 file, ~40 lines added/modifiedFixes #27394