Skip to content

Read context windows and effort levels from gateways like OpenCode - #6

Merged
stawan15 merged 1 commit into
mainfrom
fix/gateway-context-and-effort
Nov 1, 2026
Merged

stawan15 merged 1 commit into
mainfrom
fix/gateway-context-and-effort

Conversation

@stawan15

@stawan15 stawan15 commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Two bugs that bite hardest through OpenCode, and both confirmed against a live /models reply.

1. Every model reported a context window of zero

OpenCode nests its metadata; OpenRouter is flat:

OpenRouter OpenCode
window context_length limit.context
prices pricing.prompt (string) cost.text.input.price
effort — capabilities.reasoning.effort

Only the first shape was parsed. contextLimit() returned 0, and auto-compaction is gated on window > 0 (engine.go:864), so compaction never ran and a long session kept growing until the API refused it. Prices were blank in the picker for the same reason.

2. max effort never reached a model that takes it

Capped three times over: the protocol ceiling (protocolEffort), the request builder (openaiEffort mapped max → high), and the picker. DeepSeek publishes [low, high, max] and got high every time.

Now, when a provider lists a model's levels, that list wins over the protocol guess — in the engine and in the UI, so what the picker shows is what is sent. A level the model doesn't list drops to the highest one it does that is still below what was asked (xhigh → high, not max, since max ranks higher).

Verified against the real endpoint rather than only mocks — 78 of 78 models parse a window now, and DeepSeek V4.1 Flash reads as 1,000,000 tokens, $0.30/$1.20, [low high max].

New tests in gateway_test.go: the nested-payload parse, the effort-list clamping (including fallback to the protocol when no list is published), and that the window actually reaches contextLimit, which is what gates compaction.

Verified: go vet, go test ./..., go test -race ./..., gofmt -l (clean), staticcheck@v0.8.2 (clean).

OpenCode nests a model's limits and prices and lists the reasoning
levels it takes:

  limit.context                         1000000
  cost.text.{input,output}.price        0.30 / 1.20
  capabilities.reasoning.effort         [low, high, max]

Only OpenRouter's flat context_length and string prices were read, so
through OpenCode every model came back with a context window of zero.
Compaction is gated on window > 0, so it never ran and a session grew
until the API refused it; the picker showed no price for the same
reason.

Effort had the mirror problem: max was lowered to high by the protocol
ceiling, again by openaiEffort, so a model that publishes max never got
it. When a provider lists a model's levels, that list is now used
instead of the protocol guess, and the UI clamps against the same list.
The list is carried to the picker on ModelInfo, so what it says a model
takes is what gets sent.

Verified against a live /models reply: 78 of 78 models now report a
window, and DeepSeek V4.1 Flash parses as 1000000 tokens at 0.30/1.20
with [low high max].
@stawan15
stawan15 force-pushed the fix/gateway-context-and-effort branch from f338ecc to 18b5a91 Compare November 1, 2026 05:16
@stawan15
stawan15 merged commit f2d5932 into main Nov 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant