mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 13:23:50 +03:00
* fix(sse): replay reasoning for Responses-API targets on plain turns and Anthropic clients
DeepSeek thinking mode requires the reasoning of every prior assistant turn
to be passed back once the request carries `tools`, including turns that
made no tool call. Since #10540 routed opencode-go/deepseek-v4-* to
`/responses`, the reasoning replay cache had two gaps on Responses-API
targets, and clients that drop `reasoning_content` hit intermittent
`400 The reasoning_text in the thinking mode must be passed back`.
1. Plain (non-tool-call) turns are keyed on a digest of the normalized
OpenAI transcript. Both capture sites used `translatedBody.messages` as
the history, which a Responses body (`input`) does not carry, so the
write-time digest never matched the read side. translateRequest now
reports the pivot transcript it digested via `onReasoningReplayHistory`,
and the streaming / non-streaming capture sites digest that transcript.
2. The Responses replay pass was gated on `sourceFormat === "openai"`, so
Anthropic Messages clients (Claude -> OpenAI -> Responses) got no replay
at all. The pass now runs on the OpenAI pivot for every source format,
right before the Responses conversion discards `messages`.
The reported transcript is a shallow snapshot of the digested fields only
and travels through a callback, not the body, so nothing new reaches the
upstream payload.
* docs(changelog): add fragment for #13031
* fix(sse): guard the Responses capture sites and skip plain-turn writes with no history
Review follow-ups for #13031:
- Add tests/unit/chatcore-reasoning-cache-write-guard-responses.test.ts:
runs the real handleChatCore against a mocked opencode-go/deepseek-v4-flash
Responses upstream (JSON and SSE), then asserts the next turn's upstream
body carries the replayed `reasoning` input item. Removing either capture
site fallback turns both cases red.
- Project the reported transcript down to the digested fields only
(tool_calls keep type/name/arguments, ids are dropped) and document that
`content` is shared by reference.
- Skip the plain-turn cache write when the history is empty: a real request
always has a prior user turn, so an empty history means the transcript
could not be recovered and a one-message digest can never match.
- Changelog wording: the pre-fix write digested only the assistant message.
* test(sse): select the /responses dispatch by URL in the Responses replay guard
Review follow-ups for #13031: the guard picks the upstream body by URL
(`/responses`) and asserts exactly one such dispatch per turn instead of
taking the last fetch, the streaming case asserts the same body shape as the
non-streaming one, and the `historyMessages` doc on
NonStreamingClientTranslateInput names the Responses-shaped fallback.
* docs(routing): name the replay-history hand-off without tripping the hook heuristic
The fabricated-docs gate treats any `onXxx` token in prose as a plugin hook
name and flagged `onReasoningReplayHistory` (a translateRequest option, not a
hook). Point at the option's home file instead.
* chore(quality): freeze chatCore.ts at 6159 for the Responses replay wiring
check:file-size in PR mode caps a frozen file at max(frozen, base). The rebase onto
the v3.8.51 tip (cde49c937) leaves chatCore.ts at 6159 lines against a 6146 ceiling:
the onReasoningReplayHistory callback on both Responses-capable translateRequest call
sites, reasoningReplayHistory on both non-streaming leg inputs, and the historyMessages
fallback at the streaming cache write. Record the growth with a justification key, as
#13033 did for the same file.
---------
Co-authored-by: jmche <jmche@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>