feat(api): aceitar aliases explícitos para resposta sem stream (#1036)

Adds support for non-standard stream aliases (non_stream, disable_stream, disable_streaming, streaming=false). Includes unit tests. Integrated into release/v3.5.4.
This commit is contained in:
Wellington Fonseca
2026-04-07 17:27:16 -03:00
committed by GitHub
parent 47d188541b
commit 58c5f7e373
3 changed files with 72 additions and 3 deletions

View File

@@ -106,7 +106,11 @@ import {
isFallbackDecision,
EMERGENCY_FALLBACK_CONFIG,
} from "../services/emergencyFallback.ts";
import { resolveStreamFlag, stripMarkdownCodeFence } from "../utils/aiSdkCompat.ts";
import {
resolveExplicitStreamAlias,
resolveStreamFlag,
stripMarkdownCodeFence,
} from "../utils/aiSdkCompat.ts";
import { generateRequestId } from "@/shared/utils/requestId";
import { normalizePayloadForLog } from "@/lib/logPayloads";
import { extractFacts } from "@/lib/memory/extraction";
@@ -782,6 +786,22 @@ export async function handleChatCore({
? clientRawRequest.headers.get("accept") || clientRawRequest.headers.get("Accept")
: (clientRawRequest?.headers || {})["accept"] || (clientRawRequest?.headers || {})["Accept"];
const explicitStreamAlias = resolveExplicitStreamAlias(body);
// Remove non-standard non-stream aliases before provider translation/execution.
// They are accepted for compatibility at the OmniRoute API boundary only.
if (body && typeof body === "object") {
const b = body as Record<string, unknown>;
if (explicitStreamAlias !== undefined) {
b.stream = explicitStreamAlias;
}
delete b.non_stream;
delete b.disable_stream;
delete b.disable_streaming;
delete b.streaming;
}
const stream = resolveStreamFlag(body?.stream, acceptHeader);
// ── Phase 9.1: Semantic cache check (non-streaming, temp=0 only) ──

View File

@@ -26,6 +26,33 @@ export function resolveStreamFlag(bodyStream: unknown, acceptHeader: unknown): b
return !clientWantsJsonResponse(acceptHeader);
}
/**
* Resolves explicit stream aliases used by non-standard clients.
* Returns:
* - `true` -> explicit streaming intent
* - `false` -> explicit non-stream intent
* - `undefined` -> no explicit alias present
*/
export function resolveExplicitStreamAlias(body: unknown): boolean | undefined {
if (!body || typeof body !== "object") return undefined;
const b = body as Record<string, unknown>;
if (b.streaming === true) return true;
if (b.streaming === false) return false;
if (b.non_stream === true) return false;
if (b.disable_stream === true) return false;
if (b.disable_streaming === true) return false;
return undefined;
}
/**
* Backward-compatible helper used by tests/legacy call sites.
*/
export function hasExplicitNoStreamParam(body: unknown): boolean {
return resolveExplicitStreamAlias(body) === false;
}
/**
* Removes surrounding markdown code fences when Claude wraps JSON payloads.
* Example: ```json\n{"ok":true}\n``` -> {"ok":true}

View File

@@ -1,8 +1,13 @@
import test from "node:test";
import assert from "node:assert/strict";
const { clientWantsJsonResponse, resolveStreamFlag, stripMarkdownCodeFence } =
await import("../../open-sse/utils/aiSdkCompat.ts");
const {
clientWantsJsonResponse,
resolveStreamFlag,
resolveExplicitStreamAlias,
hasExplicitNoStreamParam,
stripMarkdownCodeFence,
} = await import("../../open-sse/utils/aiSdkCompat.ts");
test("T26: explicit stream:true takes priority over Accept application/json (#656)", () => {
assert.equal(clientWantsJsonResponse("application/json"), true);
@@ -42,3 +47,20 @@ test("T26: explicit stream:false always prevents streaming", () => {
assert.equal(resolveStreamFlag(false, "text/event-stream"), false);
assert.equal(resolveStreamFlag(false, undefined), false);
});
test("T26: explicit non-stream aliases are detected", () => {
assert.equal(hasExplicitNoStreamParam({ non_stream: true }), true);
assert.equal(hasExplicitNoStreamParam({ disable_stream: true }), true);
assert.equal(hasExplicitNoStreamParam({ disable_streaming: true }), true);
assert.equal(hasExplicitNoStreamParam({ streaming: false }), true);
assert.equal(hasExplicitNoStreamParam({ streaming: true }), false);
assert.equal(hasExplicitNoStreamParam({ stream: false }), false);
assert.equal(hasExplicitNoStreamParam({}), false);
});
test("T26: explicit stream aliases resolve true/false correctly", () => {
assert.equal(resolveExplicitStreamAlias({ streaming: true }), true);
assert.equal(resolveExplicitStreamAlias({ streaming: false }), false);
assert.equal(resolveExplicitStreamAlias({ disable_streaming: true }), false);
assert.equal(resolveExplicitStreamAlias({}), undefined);
});