Fix contextWindow collision across providers#9382
Fix contextWindow collision across providers#9382wbuntu wants to merge 4 commits intoopenclaw:mainfrom
Conversation
| // If caller passed a fully-qualified ref already. | ||
| if (raw.includes("/")) { | ||
| return MODEL_CACHE_BY_REF.get(raw); | ||
| } |
There was a problem hiding this comment.
Ref key normalization mismatch
lookupContextTokens() treats any modelIdOrRef containing / as a fully-qualified ref and does MODEL_CACHE_BY_REF.get(raw) without normalizing whitespace/case, but the cache keys are built via modelRefKey(provider.trim(), id) during load. If callers pass refs with extra spaces (e.g. from config/user input), lookups will fail even though the model exists. Consider normalizing the ref path (trim segments / maybe normalize provider) before get() to match how keys are stored.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/context.ts
Line: 75:78
Comment:
**Ref key normalization mismatch**
`lookupContextTokens()` treats any `modelIdOrRef` containing `/` as a fully-qualified ref and does `MODEL_CACHE_BY_REF.get(raw)` without normalizing whitespace/case, but the cache keys are built via `modelRefKey(provider.trim(), id)` during load. If callers pass refs with extra spaces (e.g. from config/user input), lookups will fail even though the model exists. Consider normalizing the ref path (trim segments / maybe normalize provider) before `get()` to match how keys are stored.
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
In the transcript-usage fallback, Also appears in Prompt To Fix With AIThis is a comment left during a code review.
Path: src/auto-reply/status.ts
Line: 313:316
Comment:
**Provider-less lookup reintroduces collision**
In the transcript-usage fallback, `contextTokens = lookupContextTokens(logUsage.model) ?? contextTokens;` drops the provider, so if `logUsage.model` is a bare id that exists across providers, this can still pick the wrong cached context window (or now return `undefined` if ambiguous). This undermines the PR’s goal when `includeTranscriptUsage` is enabled and the session’s provider differs.
Also appears in `src/commands/status.summary.ts:77-101`, `src/commands/sessions.ts:193-231`, `src/auto-reply/reply/model-selection.ts:504-510`, `src/auto-reply/reply/memory-flush.ts:62-68`, `src/auto-reply/reply/directive-handling.persist.ts:223-227`.
How can I resolve this? If you propose a fix, please make it concise. |
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical bug where OpenClaw's context window cache could collide when different providers expose the same model ID. The previous implementation cached context windows only by model ID, allowing one provider's value to overwrite another's.
Changes:
- Refactored context window caching to use two caches: one keyed by fully-qualified model references (
provider/id) and one for bare IDs that are unambiguous across providers - Updated all relevant call sites to pass provider information to
lookupContextTokens - Added collision detection logic to identify model IDs with conflicting context window values across providers
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/agents/context.ts | Core fix: implements dual-cache strategy with provider-qualified keys and ambiguity detection |
| src/gateway/session-utils.ts | Passes provider to context token lookup for session defaults |
| src/cron/isolated-agent/run.ts | Passes provider to context token lookup for cron agent runs |
| src/commands/sessions.ts | Passes provider to context token lookup for sessions command |
| src/commands/agent/session-store.ts | Passes provider to context token lookup when updating session store |
| src/auto-reply/status.ts | Passes provider to context token lookup in status message building |
| src/auto-reply/reply/followup-runner.ts | Passes provider to context token lookup for followup runs |
| src/auto-reply/reply/agent-runner.ts | Passes provider to context token lookup for agent runs |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const modelUsed = runResult.meta.agentMeta?.model ?? fallbackModel ?? defaultModel; | ||
| const contextTokensUsed = | ||
| agentCfgContextTokens ?? | ||
| lookupContextTokens(modelUsed) ?? | ||
| lookupContextTokens(modelUsed, fallbackProvider) ?? |
There was a problem hiding this comment.
Inconsistent provider resolution compared to other files. In agent-runner.ts (line 370), cron/isolated-agent/run.ts (line 388), and commands/agent/session-store.ts (line 41), the providerUsed is determined by checking runResult.meta.agentMeta?.provider first before falling back to fallbackProvider. However, in this file, fallbackProvider is used directly without checking if runResult.meta.agentMeta?.provider exists.
For consistency and correctness, consider adding a providerUsed variable similar to line 196's modelUsed pattern.
lookupContextTokens previously keyed context windows by bare model id, which breaks when different providers expose the same id (e.g. bigmodel/glm-4.7 vs ark/glm-4.7). Cache by provider/id and only fall back to bare ids when unambiguous.
77e55e0 to
894a4c7
Compare
- Avoid single-line if statements without braces (curly) - Remove unused import in cron runner
|
macOS runner still queued/running on CI (macos-app build/lint/test + checks-macos). Waiting for macOS capacity. |
|
Closing as duplicate of #14744. If this is incorrect, comment and we can reopen. |
Problem
When different providers expose the same model id (e.g.
bigmodel/glm-4.7andark/glm-4.7), OpenClaw's context window inference could cachecontextWindowby bare model id and effectively let one provider overwrite the other's value.This can cause the wrong
contextTokensto be persisted/displayed/used.Root cause
lookupContextTokenspopulated an in-memory cache keyed only bymodel.idfrom the pi-coding-agent model registry. Provider was not part of the key, so ids could collide across providers.Fix
<provider>/<id>) when provider is available.Verification
A minimal container repro with fake providers that both define
glm-4.7but with differentcontextWindowvalues confirms that:lookupContextTokens("glm-4.7", "bigmodel")returns200000lookupContextTokens("glm-4.7", "ark")returns128000and no longer collides.
Greptile Overview
Greptile Summary
This PR updates context-window inference to avoid collisions when multiple providers share the same model id. It changes the in-memory cache in
src/agents/context.tsto key context windows by fully-qualifiedprovider/modelrefs when available, while keeping a fallback bare-id cache only for ids that are unambiguous across providers. Call sites that already know the provider (auto-reply runner, status, session store updates, cron isolated agent, gateway defaults, sessions command) now pass the provider intolookupContextTokens()so the correct context window is persisted and displayed per provider.Confidence Score: 3/5
lookupContextTokens()without a provider, which can reintroduce incorrect context windows or return undefined for ambiguous ids. There is also a key normalization inconsistency for ref strings containing whitespace.(2/5) Greptile learns from your feedback when you react with thumbs up/down!
Greptile Overview
Greptile Summary
This PR updates context-window inference to avoid collisions when multiple providers share the same model id. It changes the in-memory cache in
src/agents/context.tsto key context windows by fully-qualifiedprovider/modelrefs when available, while keeping a fallback bare-id cache only for ids that are unambiguous across providers. Call sites that already know the provider (agent run persistence, followups, status, sessions, gateway defaults, cron isolated agent) now pass the provider intolookupContextTokens()so the correct context window is persisted and displayed per provider.Confidence Score: 4/5