* fix(context_management): run clear_tool_uses in the gateway on the Responses API path
/v1/messages to openai/ models goes through the Responses API, which translated
only compact_20260112 (to its native compaction) and dropped every other edit
without a warning, so clear_tool_uses_20250919 never cleared anything. Edits
without a Responses API form now run in the same polyfill as the chat completions
path, before the call, and their applied_edits come back on the response and the
final message_delta. compact stays native.
* fix(context_management): check the sync polyfill result instead of casting it
The strict ruff gate (TID251) bans typing.cast.
* test(context_management): cover the Responses path's polyfill error handling
A polyfill crash is a 500 before the call, a rejected edit under drop_params is
skipped, and the sync stream reports its edits. normalize_spec never raises for
a dict spec, so its guard is gone.
* fix(context_management): count unreadable blocks and check tool_result text before clearing
clear_tool_uses now maps blocks the token counter cannot read (server tool, compaction) to JSON text, so an input_tokens trigger no longer 500s on that history. The Responses API path checks malformed tool_result text on the original messages before clearing, as the chat completions path does.
Also removes comments that repeated the code and makes the test fixtures immutable.
* fix(context_management): count only blocks the model receives and keep list specs unsent
clear_tool_uses now leaves blocks token_counter cannot read, like server tool
results and compaction, out of its count instead of counting them as JSON text.
No adapter sends them to the model, so an input_tokens trigger no longer fires
on tokens the model never sees.
On the Responses API path, an OpenAI-style list context_management stays unsent,
as it was before, instead of reaching OpenAI's native compaction, where a
threshold under 1000 is a 400.
On the chat completions path, a clear edit listed before compact_20260112 now
runs on the turns after the latest compaction block, as Anthropic does, instead
of counting and clearing turns the compaction block drops.
The crash test that replaced apply_context_management with a mock is removed.
* fix(context_management): apply clear edits in OpenAI count_tokens and skip nested off-spec blocks when counting
* fix(context_management): run edits on the history drop_params sends, so count_tokens and /v1/messages clear alike
* fix(context_management): count clear_at_least freed tokens over sent blocks only
* fix(context_management): count tools with JSON Schema shorthands and reject a non-object trigger or keep
A tool whose schema has an array without items, a boolean subschema, or a search_result block without a title made the token counter raise, so a clear edit answered 500. A string trigger or keep also answered 500, even under drop_params. Both now count or get the API's 400, and drop_params drops the malformed field.
* fix(token_counter): count a malformed tool schema keyword as absent and move shorthand framed-estimate cases
* fix(count_tokens): pass the system prompt into clearing so count_tokens matches inference
* fix(context_management): keep a malformed system prompt from failing clear_tool_uses on the Responses API
A number, an object, or a list holding non-object items as system made the
polyfill answer 500. The polyfill now keeps a list's object items and treats
any other shape as no system, on both /v1/messages and count_tokens, so the
two paths still count the same text
---------
Co-authored-by: AlonSoko <25619863+AlonSoko@users.noreply.github.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>