Skip to content

fix(status): comprehensive context window resolution — fixes slash-model 200K bug (closes #39857, #92760)#92772

Closed
samson910022 wants to merge 11 commits into
openclaw:mainfrom
samson910022:fix/comprehensive-context-window-resolution
Closed

fix(status): comprehensive context window resolution — fixes slash-model 200K bug (closes #39857, #92760)#92772
samson910022 wants to merge 11 commits into
openclaw:mainfrom
samson910022:fix/comprehensive-context-window-resolution

Conversation

@samson910022

Copy link
Copy Markdown
Contributor

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:

  • The !ref.model.includes("/") guard blocked qualified key lookup for slash-containing model IDs
  • status-message.ts did not extract embedded provider from slash-model IDs
  • The CLI status.summary.runtime.ts had its own standalone copy of the resolution function

Fixes (11 commits on ix/comprehensive-context-window-resolution)

Commit Fix File
980f60a PR #92424: Fix stale session modelProvider after /model switch agent-session.ts
c89b83d PR #92709: Remove !ref.model.includes("/") guard blocking qualified key lookup context.ts
d6be5de Fix A: Extract embedded provider from slash model ID in legacy sessions status-message.ts
60b5bc2 Fix B: Store provider-qualified keys (provider/model) in discovery cache context.ts
5295b09 Fix D: Kick off background discovery on first model ref resolution context.ts
9736c88 Move discovery kickoff inside if(ref) guard per code review context.ts
58270ec IMP-1: Move kickoff to TOP of if(ref) �X fires for ALL resolver paths context.ts
44ffb37 CRIT-1/2: CLI status delegation �X remove standalone copy, import from context module status.summary.runtime.ts

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

liuhao1024 and others added 11 commits June 13, 2026 23:38
…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
- 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
@clawsweeper

clawsweeper Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 13, 2026, 2:44 PM ET / 18:44 UTC.

Summary
This PR combines AgentSession fresh-model reads, shared context-window cache/provider-qualified lookup changes, CLI status resolver delegation, and status-message slash-model provider extraction for context-window reporting.

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.

  • Read-only resolver side effect: 1 unguarded warmup call added. This matters because current resolver code explicitly separates allowAsyncLoad:false read-only lookups from background discovery and models.json writes.

Stored data model
Persistent data-model change detected: persistent cache schema: src/agents/context.ts, serialized state: src/agents/sessions/agent-session.resolve-fresh-model.test.ts, unknown-data-model-change: src/agents/sessions/agent-session.resolve-fresh-model.test.ts, unknown-data-model-change: src/agents/sessions/agent-session.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦪 silver shellfish
Patch quality: 🧂 unranked krab
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix the two blocking resolver/status findings and keep or add regression tests for both invariants.
  • [P1] Add exact after-fix real behavior proof with redacted terminal output or screenshots showing the command, model setup, and observed status result.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The body includes copied after-fix status output, but it lacks exact commands/environment or an inspectable artifact and does not cover the side-effect-sensitive read-only paths; add redacted terminal output or screenshots and update the PR body to trigger re-review.

Risk before merge

  • [P1] Merging as-is can misreport OpenRouter-style slash model IDs by treating the first model segment as an OpenClaw provider and applying another provider's configured context window.
  • [P1] Merging as-is can make read-only status/summary paths start background model discovery, credential-backed registry loading, and models.json/plugin-catalog writes.
  • [P1] The body includes copied after-fix output, but the contributor still needs exact real behavior proof with commands, environment, and redacted terminal output or screenshots.

Maintainer options:

  1. Fix the resolver and slash-id invariants first (recommended)
    Keep model-only slash IDs raw unless selected/fallback state proves provider ownership, and preserve allowAsyncLoad:false as a no-discovery/no-models-json-write path with regression coverage.
  2. Accept status-side side effects deliberately
    Maintainers could explicitly decide that /status should warm model discovery, but the PR should then document and test the new operator-visible models.json/auth-registry behavior.
  3. Split the combined branch
    If the combined stack is too risky, keep the AgentSession and CLI delegation pieces as narrower PRs and leave slash-model cache discovery for a focused follow-up.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Preserve model-only slash IDs in status-message unless fallback/selected model state proves provider ownership, move context-window discovery kickoff behind allowAsyncLoad true or a lifecycle-owned warmup, and add regression tests for OpenRouter-style slash IDs plus read-only no models.json side effects.

Next step before merge

  • [P1] The remaining blockers are concrete code/test repairs in the touched files and do not require a product decision.

Security
Cleared: No new dependencies, workflows, package metadata, or secret-output paths were introduced; the credential/discovery side effect is handled as a functional merge risk.

Review findings

  • [P1] Preserve model-only slash IDs in status — src/status/status-message.ts:628-629
  • [P1] Honor read-only context lookups — src/agents/context.ts:397
Review details

Best 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:

  • [P1] Preserve model-only slash IDs in status — src/status/status-message.ts:628-629
    This branch changes the missing-modelProvider slash case to pass provider as the first segment and model as the remainder. Current status code and tests deliberately keep those entries as model-only when the slash can be part of an upstream model ID; for google/gemini-2.5-pro with no modelProvider, the new path scans models.providers.google and reports Google's configured window instead of the raw OpenRouter-style cache entry. Keep the existing selected/fallback proof before splitting the model string.
    Confidence: 0.93
  • [P1] Honor read-only context lookups — src/agents/context.ts:397
    resolveContextTokensForModel now kicks off ensureContextWindowCacheLoaded() whenever ref exists, including callers that pass cfg and allowAsyncLoad: false. Current lookupContextTokens documents that those read-only callers must not start background model discovery or models.json writes, and ensureContextWindowCacheLoaded can call ensureOpenClawModelsJson plus credential-backed model discovery. Gate this behind allowAsyncLoad or a lifecycle-owned warmup path.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 13a079b3f846.

Label changes

Label changes:

  • add P2: This is a normal-priority status/context-window correctness PR with limited blast radius but real user-facing diagnostics impact.
  • add merge-risk: 🚨 compatibility: The PR changes established slash-model lookup semantics and read-only status side effects that existing users may rely on.
  • add merge-risk: 🚨 session-state: Incorrect context-window resolution can affect displayed and persisted session context accounting.
  • add merge-risk: 🚨 auth-provider: The PR infers provider identity from slash-containing model IDs and can select the wrong provider context/auth-discovery path.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🧂 unranked krab.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The body includes copied after-fix status output, but it lacks exact commands/environment or an inspectable artifact and does not cover the side-effect-sensitive read-only paths; add redacted terminal output or screenshots and update the PR body to trigger re-review.

Label justifications:

  • P2: This is a normal-priority status/context-window correctness PR with limited blast radius but real user-facing diagnostics impact.
  • merge-risk: 🚨 compatibility: The PR changes established slash-model lookup semantics and read-only status side effects that existing users may rely on.
  • merge-risk: 🚨 session-state: Incorrect context-window resolution can affect displayed and persisted session context accounting.
  • merge-risk: 🚨 auth-provider: The PR infers provider identity from slash-containing model IDs and can select the wrong provider context/auth-discovery path.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The body includes copied after-fix status output, but it lacks exact commands/environment or an inspectable artifact and does not cover the side-effect-sensitive read-only paths; add redacted terminal output or screenshots and update the PR body to trigger re-review.
Evidence reviewed

PR surface:

Source -16, Tests +118. Total +102 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 4 63 79 -16
Tests 1 118 0 +118
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 181 79 +102

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/auto-reply/status.test.ts src/agents/context.lookup.test.ts src/commands/status.summary.runtime.test.ts.
  • [P1] node scripts/run-vitest.mjs src/agents/context.test.ts src/agents/sessions/agent-session.resolve-fresh-model.test.ts.

What I checked:

  • PR changes model-provider splitting in status rendering: The PR changes the missing-modelProvider slash-model branch to split the first segment into contextLookupProvider and pass the remainder as contextLookupModel, which changes current model-only lookup behavior for upstream model IDs that contain slashes. (src/status/status-message.ts:628, 58270ec96e98)
  • Current main preserves raw model-only slash IDs: Current status-message code keeps raw model-only lookup for OpenRouter-style slash IDs unless the slash ID is proven to be the selected model or active fallback target. (src/status/status-message.ts:612, 13a079b3f846)
  • Adjacent status test encodes the invariant: Existing status coverage expects a missing-modelProvider runtime model like google/gemini-2.5-pro to use the raw model-only cache entry and not Google's configured provider window. (src/auto-reply/status.test.ts:2220, 13a079b3f846)
  • PR adds unguarded background discovery in the resolver: The PR calls ensureContextWindowCacheLoaded whenever a model ref is resolvable, before checking allowAsyncLoad or read-only status-call semantics. (src/agents/context.ts:397, 58270ec96e98)
  • Current resolver documents the read-only contract: Current lookupContextTokens explicitly says allowAsyncLoad:false callers should not start background model discovery or models.json writes. (src/agents/context.ts:217, 13a079b3f846)
  • Background discovery can write models.json: ensureContextWindowCacheLoaded reaches ensureOpenClawModelsJson, whose implementation may create the agent directory and write models.json/plugin catalog sidecars. (src/agents/models-config.ts:445, 13a079b3f846)

Likely related people:

  • steipete: Recent GitHub commit history shows repeated work on context-window, status-message, and model-runtime behavior in the same surfaces. (role: recent area contributor; confidence: high; commits: 0e7b5c34292c, 9ead0ae9219e, edb920b857ce; files: src/agents/context.ts, src/status/status-message.ts)
  • RomneyDa: Authored the context-cache warmup removal that stopped ensureOpenClawModelsJson/provider discovery from running on TUI/status-style imports. (role: perf/runtime side-effect contributor; confidence: high; commits: b79effefee92, d91ef6bb171d; files: src/agents/context.ts, src/agents/context.lookup.test.ts)
  • zhangguiping-xydt: The checked-out shallow history blames the current context/status/status-summary implementations to the latest main commit touching agent runtime prompt/session identity surfaces. (role: current-main adjacent contributor; confidence: medium; commits: 78c66742ab97; files: src/agents/context.ts, src/status/status-message.ts, src/commands/status.summary.runtime.ts)
  • giodl73-repo: Recent status-message history shows this author added estimated context budget status behavior adjacent to the status context display path. (role: status context-budget contributor; confidence: medium; commits: 05c6e7a55391; files: src/status/status-message.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 13, 2026
@samson910022

Copy link
Copy Markdown
Contributor Author

Superseded — committing a narrower branch focused on status display only.

samson910022 pushed a commit to samson910022/openclaw that referenced this pull request Jun 13, 2026
…/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)
samson910022 pushed a commit to samson910022/openclaw that referenced this pull request Jun 14, 2026
…/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)
@samson910022
samson910022 deleted the fix/comprehensive-context-window-resolution branch June 16, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling commands Command implementations rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

3 participants