-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
Bug: MODEL_CACHE context window collision when same model ID exists across multiple providers #14708
Description
Bug Description
When the same model ID (e.g., claude-opus-4-6) is defined in multiple custom providers with different context windows, the MODEL_CACHE in src/agents/context.ts silently overwrites entries — whichever provider loads last wins. This causes sessions to use the wrong context window, leading to premature context limit errors and compaction failures.
Root Cause
In src/agents/context.ts, the model cache is a simple Map<string, number> keyed by model ID only:
const MODEL_CACHE = new Map();
// ...
for (const m of models) {
if (!m?.id) continue;
if (typeof m.contextWindow === "number" && m.contextWindow > 0)
MODEL_CACHE.set(m.id, m.contextWindow); // Last write wins!
}The lookup in resolveContextTokens() then uses just the model ID:
function resolveContextTokens(params) {
return params.agentCfg?.contextTokens
?? lookupContextTokens(params.model) // Only checks model ID
?? DEFAULT_CONTEXT_TOKENS; // Falls back to 200K
}Reproduction
- Define two providers with the same model ID but different context windows:
{
"models": {
"providers": {
"anthropic-1m": {
"headers": { "anthropic-beta": "context-1m-2025-08-07" },
"models": [{
"id": "claude-opus-4-6",
"contextWindow": 1048576
}]
},
"anthropic-beta": {
"models": [{
"id": "claude-opus-4-6",
"contextWindow": 200000
}]
}
}
}
}- Set the primary model to
anthropic-1m/claude-opus-4-6(expecting 1M context) - Observe that sessions use 200K context limit instead of 1M (because
anthropic-betaloads afteranthropic-1mand overwrites the cache entry)
Impact
- Sessions hit context limits at 200K instead of 1M
- Auto-compaction triggers repeatedly but cannot recover (compacts based on config's 1M window, but runtime enforces 200K)
- Safeguard mode resets the conversation, losing all context
- Users see: "Context limit exceeded. I've reset our conversation to start fresh"
Suggested Fix
Option A (minimal): Use provider/modelId as the composite cache key:
MODEL_CACHE.set(`${m.provider}/${m.id}`, m.contextWindow);And update lookupContextTokens to accept the full provider/model ref.
Option B (defensive): When duplicate model IDs exist, take the max context window:
const existing = MODEL_CACHE.get(m.id);
if (!existing || m.contextWindow > existing) {
MODEL_CACHE.set(m.id, m.contextWindow);
}Option A is more correct (respects per-provider differences). Option B is simpler and prevents the "wrong direction" failure mode.
Workaround
Set agents.defaults.contextTokens explicitly in config to bypass the cache lookup entirely:
{
"agents": {
"defaults": {
"contextTokens": 1048576
}
}
}Environment
- OpenClaw version: 2026.2.9 (stable)
- File:
src/agents/context.ts(compiled indist/reply-*.js) - Function:
resolveContextTokens()at line ~4533 in compiled output