Skip to content

fix(status): use full provider/model key for context window lookup#27500

Closed
AaronL725 wants to merge 1 commit intoopenclaw:mainfrom
AaronL725:fix/27394-context-window-provider-key
Closed

fix(status): use full provider/model key for context window lookup#27500
AaronL725 wants to merge 1 commit intoopenclaw:mainfrom
AaronL725:fix/27394-context-window-provider-key

Conversation

@AaronL725
Copy link
Copy Markdown

Summary

When different providers expose the same model id with different context windows (e.g. openai/gpt-codex-5.3 at 400k vs openai-codex/gpt-codex-5.3 at 272k), the /status command always showed the same context window value regardless of which provider was active.

Root cause

applyDiscoveredContextWindows and resolveContextTokensForModel used 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

  • Store context window values under both provider/model (qualified) and model (unqualified) cache keys.
  • At lookup time, prefer the qualified key (provider/model) when a provider ref is available, falling back to the unqualified key.
  • Backward-compatible: single-provider setups are unaffected.

Files changed

  • src/agents/context.ts — 1 file, ~40 lines added/modified

Fixes #27394

Copilot AI review requested due to automatic review settings February 26, 2026 12:13
@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: XS labels Feb 26, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 resolveContextTokensForModel to 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() : "";
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
const provider = typeof model.providerId === "string" ? model.providerId.trim() : "";
const provider =
typeof model.providerId === "string" ? model.providerId.trim().toLowerCase() : "";

Copilot uses AI. Check for mistakes.
Comment on lines 66 to +83
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) {
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
const rawModel = modelId.slice(slash + 1).trim();
if (provider && rawModel) {
params.cache.set(`${provider}/${rawModel}`, contextWindow);
params.cache.set(rawModel, contextWindow);
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
params.cache.set(rawModel, contextWindow);
const existing = params.cache.get(rawModel);
if (existing === undefined || contextWindow < existing) {
params.cache.set(rawModel, contextWindow);
}

Copilot uses AI. Check for mistakes.
Comment on lines +218 to +227
// 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
);
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 26, 2026

Greptile Summary

This PR fixes a bug where different providers exposing the same model ID with different context windows (e.g., openai/gpt-codex-5.3 vs openai-codex/gpt-codex-5.3) would always show the same context window value in /status, regardless of which provider was active.

The fix stores context window values under both provider-qualified keys (provider/model) and unqualified keys (model), then prefers the qualified key during lookups when a provider is available. This is backward-compatible since unqualified lookups still work for single-provider scenarios.

Key changes:

  • applyDiscoveredContextWindows: Now stores context windows under both provider/model and model keys
  • applyConfiguredContextWindows: Enhanced to parse provider-qualified IDs from config and store under both formats
  • resolveContextTokensForModel: Attempts qualified key lookup first, falls back to unqualified key

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

  • Safe to merge with high confidence - the changes are well-structured and backward-compatible
  • The logic is correct and addresses the stated problem. The implementation maintains backward compatibility by storing both qualified and unqualified keys. Edge cases are handled properly (null checks, trimming, empty strings). Minor point: test coverage could be enhanced with cases specifically testing multi-provider scenarios with the same model ID, but existing tests verify the core functionality.
  • No files require special attention - the single file change is focused and well-implemented

Last reviewed commit: e6c680e

@AaronL725
Copy link
Copy Markdown
Author

Closing as duplicate — #27439 covers the same fix with broader scope. Thanks @paul-tian!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: context window size not updated per provider/model

2 participants