mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-20 05:42:19 +03:00
fix(sse): treat "length" stop_reason as legitimate in detectMalformedNonStream for Claude messages (#12935)
* fix(sse): treat "length" stop_reason as legitimate in detectMalformedNonStream for Claude messages * docs(changelog): add fragment for length stop_reason fix Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: jasminsehic <jasminsehic@users.noreply.github.com>
This commit is contained in:
1
changelog.d/fixes/ollama-qwen3-length-stop-reason.md
Normal file
1
changelog.d/fixes/ollama-qwen3-length-stop-reason.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(sse):** `detectMalformedNonStream` no longer flags a Claude-format message as malformed when the content array only contains empty text blocks or the `(empty response)` sentinel and `stop_reason` is `"length"` — a legitimate truncation (e.g. `ollama/qwen3:1.7b` exhausting its reasoning budget before producing visible text), not a real 502-worthy empty response.
|
||||
@@ -291,7 +291,11 @@ export function detectMalformedNonStream(
|
||||
// text:""}] — one block, just with no visible text — which is the exact
|
||||
// same legitimate truncated-completion shape, so the exemption must apply
|
||||
// whenever there is no visible output, not only when content is [].
|
||||
if (stopReason === "max_tokens" || stopReason === "tool_use") return null;
|
||||
// "length" is the OpenAI-style spelling some Claude-compatible shims
|
||||
// (ollama qwen3 with the reasoning budget exhausted) emit for the same
|
||||
// truncated-completion case — sentinel content + stop_reason "length".
|
||||
if (stopReason === "max_tokens" || stopReason === "tool_use" || stopReason === "length")
|
||||
return null;
|
||||
// content:[] with no stop_reason at all is non-terminal, not empty (#9971).
|
||||
if (content.length === 0 && stopReason.length === 0) return null;
|
||||
return "empty_choices";
|
||||
|
||||
@@ -56,6 +56,19 @@ test("synthOpenAIErrorChunk references provider in message", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("detectMalformedNonStream allows Claude message with (empty response) + stop_reason=length (ollama qwen3)", () => {
|
||||
const resp = {
|
||||
type: "message",
|
||||
content: [{ type: "text", text: "(empty response)" }],
|
||||
stop_reason: "length",
|
||||
};
|
||||
assert.strictEqual(
|
||||
detectMalformedNonStream(resp),
|
||||
null,
|
||||
"ollama reasoning truncation should not be empty_choices"
|
||||
);
|
||||
});
|
||||
|
||||
// ── (b) synthResponsesFailure matches a response.failed event ────────────────
|
||||
|
||||
test("synthResponsesFailure produces a response.failed SSE event", () => {
|
||||
|
||||
Reference in New Issue
Block a user