mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-14 03:02:14 +03:00
fix(streaming): honor body stream intent for early heartbeats (#10127)
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
ANTHROPIC_PING_FRAME,
|
||||
} from "@omniroute/open-sse/utils/earlyStreamKeepalive";
|
||||
import { resolveKeepaliveThreshold } from "@omniroute/open-sse/utils/keepaliveThreshold";
|
||||
import { resolveStreamFlag } from "@omniroute/open-sse/utils/aiSdkCompat";
|
||||
|
||||
let initialized = false;
|
||||
|
||||
@@ -54,22 +55,27 @@ async function postHandler(request: any, context: any, preParsedBody: any = null
|
||||
// /v1/responses (#2544). Anthropic clients ignore SSE comments for their watchdog, so
|
||||
// emit a real `event: ping` (ANTHROPIC_PING_FRAME). Non-streaming callers keep the
|
||||
// verbatim path.
|
||||
const accept = String(request.headers?.get?.("accept") || "").toLowerCase();
|
||||
if (accept.includes("text/event-stream")) {
|
||||
let model;
|
||||
let body = preParsedBody;
|
||||
if (body == null) {
|
||||
try {
|
||||
const body = preParsedBody ?? (await request.clone().json().catch(() => null));
|
||||
model = body?.model;
|
||||
body = await request
|
||||
.clone()
|
||||
.json()
|
||||
.catch(() => null);
|
||||
} catch {
|
||||
// body unavailable / non-JSON — fall back to the default keepalive threshold
|
||||
// body unavailable / non-JSON — handleChat will return its normal validation error
|
||||
}
|
||||
return await withEarlyStreamKeepalive(handleChat(request, null, preParsedBody), {
|
||||
}
|
||||
const accept = String(request.headers?.get?.("accept") || "");
|
||||
const wantsStreaming = resolveStreamFlag(body?.stream, accept, "claude");
|
||||
if (wantsStreaming) {
|
||||
return await withEarlyStreamKeepalive(handleChat(request, null, body), {
|
||||
signal: request.signal,
|
||||
thresholdMs: resolveKeepaliveThreshold(model),
|
||||
thresholdMs: resolveKeepaliveThreshold(body?.model),
|
||||
keepaliveFrame: ANTHROPIC_PING_FRAME,
|
||||
});
|
||||
}
|
||||
return await handleChat(request, null, preParsedBody);
|
||||
return await handleChat(request, null, body);
|
||||
}
|
||||
|
||||
export const POST = withInjectionGuard(postHandler);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { resolveResponsesApiModel } from "@/app/api/internal/codex-responses-ws/
|
||||
import { getModelInfo } from "@/sse/services/model";
|
||||
import { getComboByName } from "@/lib/db/combos";
|
||||
import { resolveKeepaliveThreshold } from "@omniroute/open-sse/utils/keepaliveThreshold";
|
||||
import { resolveStreamFlag } from "@omniroute/open-sse/utils/aiSdkCompat";
|
||||
|
||||
// NOTE: We do NOT call initTranslators() here — the translator registry is
|
||||
// bootstrapped at module level inside open-sse/translator/index.ts when it
|
||||
@@ -92,8 +93,9 @@ async function postHandler(request: any, context: any, preParsedBody: any = null
|
||||
request,
|
||||
preParsedBody
|
||||
);
|
||||
const accept = String(request.headers?.get?.("accept") || "").toLowerCase();
|
||||
if (accept.includes("text/event-stream")) {
|
||||
const accept = String(request.headers?.get?.("accept") || "");
|
||||
const wantsStreaming = resolveStreamFlag(resolvedBody?.stream, accept, "openai-responses");
|
||||
if (wantsStreaming) {
|
||||
// Adaptive threshold: web-session and anonymous-fallback providers are slower
|
||||
// to produce the first byte, so use a longer keepalive threshold (15s vs 2s).
|
||||
// Reuse resolvedBody.model — no extra clone/parse needed (#4041).
|
||||
|
||||
Reference in New Issue
Block a user