fix(status): comprehensive context window resolution — fixes slash-model 200K bug (closes #39857, #92760)#92772
Conversation
…ter /model switch All 8 post-turn reads of this.model in AgentSession (checkCompaction, isRetryableError, getContextUsage, getAvailableThinkingLevels, supportsThinking, clampThinkingLevel, compact, generateBranchSummary) now resolve the model fresh from sessionModelRegistry instead of reading the stale agent.state.model snapshot. This ensures contextWindow, reasoning, and thinkingLevelMap reflect the current model after a /model switch. Fixes openclaw#92415
…ts in resolve-fresh-model test
- Remove dead code: use resolveFreshModel()! in getAvailableThinkingLevels since the early return guarantees this.model is truthy - Add JSDoc explaining why resolveFreshModel() does not use refreshCurrentModelFromRegistry() (mutation vs transient read) - Add defensive test for registry returning different provider/id - Add integration test verifying compaction uses fresh contextWindow
… OpenRouter proxy models)
Remove the `!ref.model.includes("/")` guard in `resolveContextTokensForModel()` which blocked qualified cache key lookup for models like `anthropic/claude-sonnet-4` accessed through proxy providers.
Two call sites fixed:
1. Explicit provider path (params.provider && ref) -- safe because provider is explicitly given
2. Last resort implicit provider path (!params.provider && ref) -- bare key already failed, trying qualified key has no downside
Fixes: max context showing DEFAULT_CONTEXT_TOKENS (200K) instead of actual model's context window for proxy models
…t window resolution When a session entry has model="openrouter/anthropic/claude-sonnet-4" but entry.modelProvider is empty, buildStatusMessage() previously set contextLookupProvider = undefined, causing resolveContextTokensForModel() to skip the provider-qualified cache key lookup. Now extract the embedded provider (first slash segment) and pass it to the resolution chain so the correct context window is found. Combined with PR openclaw#92424's resolveFreshModel() fix and PR openclaw#92709's slash-guard removal in resolveContextTokensForModel(), this gives comprehensive coverage for proxy model context window resolution. Refs: openclaw#39857, openclaw#90889, openclaw#92424, openclaw#92709
…ensForModel to populate provider-qualified cache keys
…real context.ts function
… cover all resolver paths
|
Codex review: needs real behavior proof before merge. Reviewed June 13, 2026, 2:44 PM ET / 18:44 UTC. Summary PR surface: Source -16, Tests +118. Total +102 across 5 files. Reproducibility: yes. Source and adjacent tests show the patch would change existing model-only slash-ID status behavior, and current resolver code documents that allowAsyncLoad:false paths must not start background discovery or models.json writes. Review metrics: 1 noteworthy metric.
Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Repair the branch so status keeps raw model-only slash IDs unless provider ownership is proven, and move context-window cache warmup to an allowAsyncLoad/lifecycle-owned path instead of read-only resolver calls. Do we have a high-confidence way to reproduce the issue? Yes. Source and adjacent tests show the patch would change existing model-only slash-ID status behavior, and current resolver code documents that allowAsyncLoad:false paths must not start background discovery or models.json writes. Is this the best way to solve the issue? No. Delegating CLI status to the shared resolver is a good direction, but the PR is not the best fix until it preserves the slash-ID ownership invariant and keeps cache discovery out of read-only resolver calls. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 13a079b3f846. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source -16, Tests +118. Total +102 across 5 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Superseded — committing a narrower branch focused on status display only. |
…/status on first call The first /status after gateway restart shows DEFAULT_CONTEXT_TOKENS (200K) for ALL providers because async model discovery hasn't completed yet. resolveStatusRuntimeContextTokens already has a lazy guard (await ensureContextWindowCacheLoaded()) but the first call still pays cold-start latency on the user-facing /status path. Fix: fire the warmup eagerly during gateway startup inside startGatewayEarlyRuntime(), before the HTTP server starts listening. The call uses void semantics (fire-and-forget) to avoid blocking the startup sequence. The function is already idempotent via a singleton loadPromise guard and catches all errors internally. This is a companion optimization to the lazy-guard already present in resolveStatusRuntimeContextTokens (src/status/status-text.ts). Together they ensure: - First /status: cache already warm from startup - Subsequent /status: shares resolved singleton promise (microtask) - Mid-session /model switch: lazy guard triggers re-check via config primeConfiguredContextWindows with backoff - Concurrent /status calls: all share one discovery pass Relates to: openclaw#39857, openclaw#92760 Companion to: openclaw#92775 (CLI fix) Supersedes: openclaw#92772 (comprehensive branch)
…/status on first call The first /status after gateway restart shows DEFAULT_CONTEXT_TOKENS (200K) for ALL providers because async model discovery hasn't completed yet. resolveStatusRuntimeContextTokens already has a lazy guard (await ensureContextWindowCacheLoaded()) but the first call still pays cold-start latency on the user-facing /status path. Fix: fire the warmup eagerly during gateway startup inside startGatewayEarlyRuntime(), before the HTTP server starts listening. The call uses void semantics (fire-and-forget) to avoid blocking the startup sequence. The function is already idempotent via a singleton loadPromise guard and catches all errors internally. This is a companion optimization to the lazy-guard already present in resolveStatusRuntimeContextTokens (src/status/status-text.ts). Together they ensure: - First /status: cache already warm from startup - Subsequent /status: shares resolved singleton promise (microtask) - Mid-session /model switch: lazy guard triggers re-check via config primeConfiguredContextWindows with backoff - Concurrent /status calls: all share one discovery pass Relates to: openclaw#39857, openclaw#92760 Companion to: openclaw#92775 (CLI fix) Supersedes: openclaw#92772 (comprehensive branch)
Description
Comprehensive fix for /status showing ?/200k (DEFAULT_CONTEXT_TOKENS) for proxy/aggregator models with slash-containing IDs (e.g., opencode-go/deepseek-v4-flash, openrouter/anthropic/claude-sonnet-4).
Diagnosis: 7-layer fix stack �X 6 code patches in context.ts/status-message.ts/status.summary.runtime.ts + 1 config gap.
Root Cause
The discovery cache (
untime.json registry) was never populated during normal gateway operation. All callers pass cfg (truthy), setting skipRuntimeConfigLoad = true, which bypasses ensureContextWindowCacheLoaded(). The cache only contained bare-key entries from primeConfiguredContextWindows(), causing cache miss �� DEFAULT_CONTEXT_TOKENS (200K).
Even if the cache had been populated:
Fixes (11 commits on ix/comprehensive-context-window-resolution)
Verification
Subagent audit (source ? dist alignment)
All 7 patches confirmed present in both ~/projects/openclaw/src/ and installed dist (context-ClaruzGd.js).
Manual test (user, 2026-06-14 02:35)
\
?? Session: opencode/nemotron-3-ultra-free
?? Context: 401/1.0m (0%) �� Correct 1.0M for this model
?? Session: opencode-go/deepseek-v4-flash
?? Context: 0/1.0m (0%) �� WAS 200K, NOW 1.0M ? FIXED
?? Session: opencode/deepseek-v4-flash-free
?? Context: 611/200k (0%) �� Correct 200K for free tier
\\
TUI verification
TUI correctly shows live context tracking (no ? placeholder) and correct window for each model.
Related Issues