fix(openai): trim context for small-window models instead of hard-failing #2
No reviewers
Labels
No labels
area/engine
clarity/clear
enhancement
security
size/M
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
basepeak-ai/gptscript!2
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/context-window-overflow"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Self-hosted RAG bots (dor-ai-stack, vLLM behind KubeAI) frequently hit:
Root cause is a context-window overflow that surfaces as a confusing vLLM error:
--max-model-len(e.g. 32768 formistral-small-3.1-24b).maxTokens, sogetBudget()fell back to the hardcodedDefaultMaxTokens = 400_000("GPT-5") anddropMessagesOverCountnever trimmed the oversized context — it believed there was a 400k budget.max_tokens(0 →omitempty), so vLLM defaults it tomax_model_len − prompt_tokens. When the prompt already overflows the window, that default is negative (-3461is literally the overage) and vLLM rejects.context_length_exceededcode, so vLLM'sBadRequestErrorslipped through as non-retriable → hard fail.Notably, dor-ai-stack already ships
GPTSCRIPT_DEFAULT_MAX_TOKENS: "32000"in its env, but the code never read it — it was dead config, which is why trimming never happened.Fix
Two changes in
pkg/openai:getBudget()honorsGPTSCRIPT_DEFAULT_MAX_TOKENS(positive int) as the default budget when a tool/model declares nomaxTokens. This activates the already-deployed config so trimming assumes the real window instead of 400k. An explicitly-set per-toolmaxTokensstill wins.isContextLengthError()recognizes vLLM's overflow errors (max_tokens must be at least 1,maximum context length,reduce the length) in addition to OpenAI'scontext_length_exceeded, so overflow trims-and-retries instead of failing non-retriably.Both are needed: (1) makes the first attempt fit; (2) self-heals when the tiktoken (o200k_base) estimate diverges from the server's real tokenizer (German on Mistral runs ~15-25% higher than tiktoken).
Per-model note
The retry loop is inherently per-request/per-model — it reacts to the actual overflow from whichever model a thread uses, so mixed models across agents/threads are handled automatically.
GPTSCRIPT_DEFAULT_MAX_TOKENSis a coarse per-process floor (set it to the smallest window in use). A future bpai change could feed each model's real context window intotool.MaxTokens(the plumbing already exists viaengine.gopopulateMessageParams→getBudget(tool.MaxTokens)) to make the proactive budget exact per model; the retry loop remains the durable correctness layer regardless.Tests
pkg/openai/contextlimit_test.go— env override / fallback / explicit-wins forgetBudget, and error-detection matrix (vLLM negative max_tokens, wrapped errors, OpenAI code, maximum-context message, unrelated/nil/plain negatives). Fullpkg/openaipackage green;go vet,gofmt, and whole-modulego buildclean.Fresh-context review (two independent subagents: general code-review + silent-failure hunter). Findings addressed in
06769b7:Fixed
isContextLengthErrormatched the generic"reduce the length"substring with no status guard, so unrelated 400s (parameter validation) — and even non-400 errors — could be funneled into the trim-and-retry loop, silently discarding chat history. Now gated on HTTP 400 and the redundant"reduce the length"needle removed (real overflow messages already contain "maximum context length"). +2 regression tests (non-context 400,non-400 context message→ both expectfalse).GPTSCRIPT_DEFAULT_MAX_TOKENS.Verified:
go test ./pkg/openai -count=1,go vet,gofmt, and whole-modulego buildall clean. (Repo CI is red pre-existing onmain— gofmt/staticcheck debt from the hard-fork rename, unrelated to this PR; none of the flagged files are touched here.)Dismissed: none — all findings were real and fixed.