Conversation
…supported parameter
Three robustness gaps seen while benchmarking local models on hard context windows.
1. Compaction fired when the real prompt was already at the window. On a 32K llama-server the
reply was then cut off in the middle of a tool call and the server answered HTTP 500
"Failed to parse tool call arguments" on every retry, ending the session.
- Conversation keeps completion_reserve_tokens (new setting, default 4096, capped at a
quarter of the window) free when deciding to compact (usable_tokens).
- Conversation learns the estimate's overhead (chat-template markup, tool schemas, tokenizer
drift) from the provider's reported prompt size (observe_prompt_tokens), carried forward as
a fixed offset; the loop feeds it after every response.
- A tool-call parse failure near the limit is treated like a context overflow: the existing
one-shot compaction + retry runs instead of retrying the identical prompt.
2. LiteLLM raised UnsupportedParamsError for one optional parameter (reasoning_effort on
openai/gpt-oss-20b), which failed every call and ended each task with llm_error before a
token was generated. LLMClient._acompletion now drops the rejected parameter with one
warning, retries once, and leaves it out of later calls. Essential keys (model, messages,
timeout, tools, tool_choice, stream) are never dropped; other errors propagate unchanged.
Matched by exception class name so it works with mocked LiteLLM.
Tests: tests/test_context_headroom.py, tests/test_llm_unsupported_params.py.
Docs: profile and docs/local_qwen38_27b.md now describe the reserve instead of a threshold
workaround; CHANGELOG.
🤖 Godspeed Review
SecurityNo secrets detected in changed files. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Two failure modes seen while benchmarking local models (details in the Qwen3.8-27B run notes; the token-estimator half was started in #232).
1. Context headroom. On a hard 32K llama-server window, compaction fired only when the real prompt was already at the limit. The reply was then cut off in the middle of a tool call and llama-server answered HTTP 500
Failed to parse tool call arguments as JSONon every retry, ending the session (llm_error). Server-side evidence:stop processing: n_tokens = 32767, truncated = 1(5 times in one KAT-REAP-50 run, 2 more at 65535 with a 64K window). Even after #232 the estimate is ~1.1x low on real Qwen3.8 requests, and nothing left room for the reply.2. One unsupported optional parameter killed every call.
reasoning_effort: mediumwithopenai/gpt-oss-20bmade LiteLLM raiseUnsupportedParamsError: openai does not support parameters: ['reasoning_effort']on every call, so all 8 tasks of a benchmark arm endedllm_errorafter 0 iterations.Changes
Conversation:completion_reserve_tokens(new setting, default 4096, capped at a quarter of the window) is subtracted from the budget compaction uses (usable_tokens);observe_prompt_tokenslearns the estimate's overhead (template markup, tool schemas, tokenizer drift) from the provider's reported prompt size as a fixed offset, and the agent loop feeds it after each response (bothinput_tokensandprompt_tokensusage shapes). A reported size above twice the window is ignored; the overhead is capped at half the window and cleared when the estimate already over-counts.LLMClient._acompletion: onUnsupportedParamsError(matched by class name, so it works with mocked LiteLLM) drop the rejected optional parameter with one warning, retry once, and leave it out of later calls. Essential keys (model,messages,timeout,tools,tool_choice,stream) are never dropped; other errors propagate unchanged.Behavior change to review
completion_reserve_tokensdefaults to 4096, so compaction happens up to 4096 tokens (at most 25% of the window) earlier than before for every model. Set it to 0 to restore the old behaviour.Verification
tests/test_context_headroom.py(calibration incl. large early overhead, both usage shapes, reserve arithmetic and cap, compaction firing earlier with a reserve, truncated-tool-call matching near/far from the limit, setting validation) andtests/test_llm_unsupported_params.py(parsing, essential keys never dropped, retry-once + later calls stripped + single warning, unrelated errors and repeated rejections propagate). 25 tests.ruff check .andruff format --check .clean.Not verified