fix(kilocode): model discovery overstates the usable context window - #118868
Conversation
The Kilocode gateway publishes an OpenRouter-shaped catalog in which `context_length` is the catalog-wide ceiling while `top_provider.context_length` describes the primary provider that actually serves the request. Discovery read only the catalog-wide value, so models whose primary provider offers a smaller window were registered with a context window larger than requests can use. Prefer the primary-provider window and fall back to the catalog-wide value, matching the precedence already owned by `extensions/openrouter/provider-catalog.ts`. Completion-token handling is left alone on purpose: the live Kilocode catalog exposes no top-level `max_completion_tokens` or `max_output_tokens`, so the existing `top_provider` read is already the only available source.
|
Codex review: needs maintainer review before merge. Reviewed August 3, 2026, 3:02 PM ET / 19:02 UTC. ClawSweeper reviewWhat this changesUpdates Kilocode model discovery to prefer a valid primary-provider context window over the catalog-wide ceiling, with fallback coverage for unusable provider values. Merge readinessKeep open: current main still registers Kilocode models from the catalog-wide context value, while this narrow patch applies the established primary-provider precedence and adds focused regression coverage. The branch remains necessary and has no actionable correctness or security finding from this review. Priority: P2 Review scores
Verification
How this fits togetherThe Kilocode provider plugin fetches its public model catalog and converts each row into OpenClaw model metadata used for context budgeting. The discovered context window then informs how much input OpenClaw considers usable for a selected Kilocode model. flowchart LR
A[Kilocode model catalog] --> B[Kilocode provider discovery]
B --> C[Validate context limits]
C --> D[Choose primary-provider limit]
D --> E[Fallback to catalog limit]
E --> F[OpenClaw model metadata]
F --> G[Context budgeting]
Before merge
Agent review detailsSecurityNone. PR surfaceSource +5, Tests +53. Total +58 across 2 files. View PR surface stats
Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Land the existing narrow precedence correction after the active checks finish, keeping the same positive-safe-integer fallback contract used by OpenRouter and model scanning. Do we have a high-confidence way to reproduce the issue? Yes, by source: a catalog row with a valid smaller Is this the best way to solve the issue? Yes. Reusing the already-shipped OpenRouter and model-scan precedence is the narrowest maintainable fix; it corrects the producer of the metadata without adding a configuration or compatibility path. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c37cfb0f260f. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
|
Land-ready for PR #118868.
Known proof gap: no separate Testbox lease was needed because the exact-head hosted CI gate was already green. The standard canonical squash path will attribute the merge to |
|
Merged via squash.
|
* commit 'efcced7207baa0b1b1db5e8e1836673a24212657': test(agents): prove process control roundtrip (#118843) test(qa): add memory redaction boundary coverage (#118916) fix(kilocode): model discovery overstates the usable context window (#118868) fix(media): isolate generated-provider text from delivery directives (#118780) test(gateway): add node control-plane QA coverage (#118784) fix(config): reject unsupported diagnostics otel grpc (#93087) fix(providers): recognize configured media credentials across provider boundaries (#118761) refactor: delete dead post-landing plugin/hooks scaffolding (#118920) fix(cron): deliver child results after heartbeat-only parent responses (#118743) fix(ci): keep Matrix chunk tests aligned with inventory (#118917) fix(tts): preserve hidden speech answers when synthesis fails (#118690)
…-worker-update-20260803 * origin/main: (48 commits) test(ui): add shell and PWA primary QA proof (#118788) test(qa): cover CLI distribution workflows (#118948) chore(i18n): refresh native locales (#118883) test(qa): prove plugin tool ownership in gateway flow (#118958) docs: correct onboarding risk flags and Google Chat credential shapes (#118936) fix(imessage): honor explicitly enabled accounts during startup (#118944) test(gateway): cover client transport defaults (#118798) fix(signal): normalize accounts during noninteractive setup (#118932) fix(msteams): enable channels for federated environment credentials (#118931) fix(openai): enforce final transcript bounds before callback delivery (#118928) test(tasks): cover plugin-managed flows (#118919) test(agents): prove process control roundtrip (#118843) test(qa): add memory redaction boundary coverage (#118916) fix(kilocode): model discovery overstates the usable context window (#118868) fix(media): isolate generated-provider text from delivery directives (#118780) test(gateway): add node control-plane QA coverage (#118784) fix(config): reject unsupported diagnostics otel grpc (#93087) fix(providers): recognize configured media credentials across provider boundaries (#118761) refactor: delete dead post-landing plugin/hooks scaffolding (#118920) fix(cron): deliver child results after heartbeat-only parent responses (#118743) ...
…penclaw#118868) The Kilocode gateway publishes an OpenRouter-shaped catalog in which `context_length` is the catalog-wide ceiling while `top_provider.context_length` describes the primary provider that actually serves the request. Discovery read only the catalog-wide value, so models whose primary provider offers a smaller window were registered with a context window larger than requests can use. Prefer the primary-provider window and fall back to the catalog-wide value, matching the precedence already owned by `extensions/openrouter/provider-catalog.ts`. Completion-token handling is left alone on purpose: the live Kilocode catalog exposes no top-level `max_completion_tokens` or `max_output_tokens`, so the existing `top_provider` read is already the only available source.
…penclaw#118868) The Kilocode gateway publishes an OpenRouter-shaped catalog in which `context_length` is the catalog-wide ceiling while `top_provider.context_length` describes the primary provider that actually serves the request. Discovery read only the catalog-wide value, so models whose primary provider offers a smaller window were registered with a context window larger than requests can use. Prefer the primary-provider window and fall back to the catalog-wide value, matching the precedence already owned by `extensions/openrouter/provider-catalog.ts`. Completion-token handling is left alone on purpose: the live Kilocode catalog exposes no top-level `max_completion_tokens` or `max_output_tokens`, so the existing `top_provider` read is already the only available source.
AI-assisted.
What Problem This Solves
Fixes an issue where users on the Kilocode provider would get model context
windows larger than the model can actually accept, whenever the primary
provider serving that model publishes a smaller window than the catalog-wide
ceiling.
Kilocode's gateway returns an OpenRouter-shaped catalog. In it,
context_lengthis the catalog-wide ceiling across all routing candidates, while
top_provider.context_lengthdescribes the primary provider that actuallyserves the request. Model discovery read only the catalog-wide value.
On the live public catalog this affects 33 of the 335 discovered models. The
overstatement is up to 3.8x, for example:
Why This Change Was Made
Discovery now prefers
top_provider.context_lengthand falls back to thecatalog-wide
context_length, then to the existing default. This is the sameprecedence already owned by
extensions/openrouter/provider-catalog.ts:197-200,so the two OpenRouter-shaped catalogs agree.
The same normalization was applied to
src/agents/model-scan.tsin8fa1b82e42a35447482f2722df75128916d0c059(#110855). The Kilocode reader wasnot covered there; this completes it.
Completion-token handling is deliberately left unchanged. The live Kilocode
catalog exposes no top-level
max_completion_tokensormax_output_tokensfield at all, so the existing
top_provider.max_completion_tokensread isalready the only available source and adding a fallback chain would encode a
field the data never carries.
No config, Plugin SDK, protocol, persistence, migration, or feature surface
changes.
User Impact
Kilocode models are registered with the context window the serving provider
actually offers, so context budgeting and model metadata stop overstating what
a request can use on the 33 affected models. Models whose primary provider
matches the catalog value are unchanged.
Evidence
Live public catalog, no key and no inference call:
curl -H "Accept: application/json" https://api.kilo.ai/api/gateway/modelsreturned 346 rows; 340 carry
top_provider.context_length.The real catalog response was then fed through the actual
discoverKilocodeModels()implementation, changing only the production filebetween the two runs.
registeredis thecontextWindowdiscovery assigns:Before (current
main):After (this branch):
Tests, run on Node 24.18.1:
extensions/kilocode/provider-models.test.ts: 13/13 pass.extensions/kilocode/folder: 35/35 pass across 4 files.mainand the new testskept, the precedence test fails with
contextWindow1048576 instead of524288, so the added coverage is load-bearing rather than self-confirming.
Regression coverage added: primary-provider precedence, and independent
fallback to the catalog-wide value when the provider value is zero, negative,
fractional, non-finite, null, or a string.
oxfmt --check, directoxlinton both touched files, andgit diff --checkare clean.
Scope
Production delta:
+6/-1inextensions/kilocode/provider-models.ts. Tests add53 lines. Changelog not required: this corrects existing internal catalog
normalization without changing commands or configuration.