perf(sse): defer cloneLogPayload until after SSE collector cap check (#12243)

* perf(sse): defer cloneLogPayload until after SSE collector cap check

Dropped SSE events no longer pay the structuredClone cost. The clone now
runs only for events that survive the maxEvents/maxBytes cap, eliminating
~9,800 wasted deep clones per streaming response (65-71% faster push).

Reducer snapshot isolation restored:
- OpenAI reducer stores first-chunk primitives instead of a chunk reference
- Responses reducer snapshots only needed fields, deep-cloning nested output/metadata
- getEvents() keeps defensive-copy semantics via cloneLogPayload

* chore: add changelog fragment for #12241
This commit is contained in:
Paulo Oliveira
2026-09-01 00:47:34 -03:00
committed by GitHub
parent a4b4bca2ee
commit 3383adbbd1
3 changed files with 285 additions and 35 deletions

View File

@@ -0,0 +1 @@
- **perf(sse):** defer `cloneLogPayload()` in the structured SSE collector until after the `maxEvents`/`maxBytes` cap check, eliminating ~9,800 wasted `structuredClone` calls per streaming response (6571% faster `push()`). Reducer snapshot isolation restored for OpenAI and Responses summaries ([#12241](https://github.com/diegosouzapw/OmniRoute/pull/12241)) — thanks @PauloHSOliveira

View File

@@ -1,4 +1,5 @@
import { cloneLogPayload } from "@/lib/logPayloads";
import { toNumber } from "@/shared/utils/numeric";
import { FORMATS } from "../translator/formats.ts";
type StructuredSSEEvent = {
@@ -58,15 +59,6 @@ function toString(value: unknown, fallback = ""): string {
return typeof value === "string" ? value : fallback;
}
function toNumber(value: unknown, fallback = 0): number {
if (typeof value === "number" && Number.isFinite(value)) return value;
if (typeof value === "string" && value.trim().length > 0) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : fallback;
}
return fallback;
}
function normalizeFormat(format?: string | null): string {
if (!format) return "";
if (format === FORMATS.OPENAI_RESPONSE) return FORMATS.OPENAI_RESPONSES;
@@ -205,7 +197,13 @@ export function splitConcatenatedToolCallArguments(raw: string): string[] | null
// once the collector's storage cap is hit.
function createOpenAIReducer(fallbackModel?: string | null): SummaryReducer {
let first: JsonRecord | null = null;
let sawAny = false;
// Snapshot of primitive fields from the first chunk — finalized in finalize().
// Storing primitives (not the chunk reference) avoids retaining a reference to
// the original payload, so caller mutation after push() cannot change the summary.
let firstId: string | null = null;
let firstCreated: number | null = null;
let firstModel: string | null = null;
const contentParts: string[] = [];
const reasoningParts: string[] = [];
type ToolCall = {
@@ -245,7 +243,12 @@ function createOpenAIReducer(fallbackModel?: string | null): SummaryReducer {
return {
ingest(chunk: JsonRecord) {
if (Object.keys(chunk).length === 0) return;
if (!first) first = chunk;
sawAny = true;
if (firstId === null) {
firstId = toString(chunk.id) || null;
firstCreated = toNumber(chunk.created) || null;
firstModel = toString(chunk.model) || null;
}
const choice = asRecord(Array.isArray(chunk.choices) ? chunk.choices[0] : null);
const delta = asRecord(choice.delta);
@@ -319,7 +322,7 @@ function createOpenAIReducer(fallbackModel?: string | null): SummaryReducer {
},
finalize(): unknown {
if (!first) return null;
if (!sawAny) return null;
const joinedContent = contentParts.length > 0 ? contentParts.join("").trim() : null;
const joinedReasoning = reasoningParts.length > 0 ? reasoningParts.join("").trim() : null;
@@ -359,10 +362,10 @@ function createOpenAIReducer(fallbackModel?: string | null): SummaryReducer {
}
const result: JsonRecord = {
id: toString(first.id, `chatcmpl-${Date.now()}`),
id: firstId || `chatcmpl-${Date.now()}`,
object: "chat.completion",
created: toNumber(first.created, Math.floor(Date.now() / 1000)),
model: toString(first.model, fallbackModel || "unknown"),
created: firstCreated || Math.floor(Date.now() / 1000),
model: firstModel || fallbackModel || "unknown",
choices: [
{
index: 0,
@@ -381,10 +384,23 @@ function createOpenAIReducer(fallbackModel?: string | null): SummaryReducer {
};
}
type ResponseSnapshot = {
id: string;
model: string;
status: string;
created_at: number;
output: unknown;
usage: JsonRecord | null;
metadata: JsonRecord;
};
function createResponsesReducer(fallbackModel?: string | null): SummaryReducer {
let sawAny = false;
let completed: JsonRecord | null = null;
let latestResponse: JsonRecord | null = null;
// Snapshot of response fields — primitives only, nested objects deep-cloned.
// Avoids retaining a reference to the original payload so caller mutation
// after push() cannot change the summary.
let completedSnapshot: ResponseSnapshot | null = null;
let latestSnapshot: ResponseSnapshot | null = null;
let usage: JsonRecord | null = null;
const textParts: string[] = [];
const buildOutputFromText = () =>
@@ -398,6 +414,16 @@ function createResponsesReducer(fallbackModel?: string | null): SummaryReducer {
]
: [];
const snapshotResponse = (resp: JsonRecord): ResponseSnapshot => ({
id: toString(resp.id),
model: toString(resp.model),
status: toString(resp.status),
created_at: toNumber(resp.created_at),
output: cloneLogPayload(Array.isArray(resp.output) ? resp.output : []),
usage: resp.usage && typeof resp.usage === "object" ? { ...asRecord(resp.usage) } : null,
metadata: cloneLogPayload(asRecord(resp.metadata)),
});
return {
ingest(payload: JsonRecord) {
if (Object.keys(payload).length === 0) return;
@@ -409,12 +435,12 @@ function createResponsesReducer(fallbackModel?: string | null): SummaryReducer {
payload.response &&
typeof payload.response === "object"
) {
completed = asRecord(payload.response);
completedSnapshot = snapshotResponse(asRecord(payload.response));
}
if (payload.response && typeof payload.response === "object") {
latestResponse = asRecord(payload.response);
latestSnapshot = snapshotResponse(asRecord(payload.response));
} else if (payload.object === "response") {
latestResponse = payload;
latestSnapshot = snapshotResponse(payload);
}
if (
eventType === "response.output_text.delta" &&
@@ -433,18 +459,18 @@ function createResponsesReducer(fallbackModel?: string | null): SummaryReducer {
finalize(): unknown {
if (!sawAny) return null;
const picked = completed || latestResponse;
if (picked && Object.keys(picked).length > 0) {
const picked = completedSnapshot || latestSnapshot;
if (picked) {
const pickedOutput = Array.isArray(picked.output) ? picked.output : [];
return {
id: toString(picked.id, `resp_${Date.now()}`),
id: picked.id || `resp_${Date.now()}`,
object: "response",
model: toString(picked.model, fallbackModel || "unknown"),
model: picked.model || fallbackModel || "unknown",
output: pickedOutput.length > 0 ? pickedOutput : buildOutputFromText(),
usage: picked.usage ?? usage ?? null,
status: toString(picked.status, completed ? "completed" : "in_progress"),
created_at: toNumber(picked.created_at, Math.floor(Date.now() / 1000)),
metadata: asRecord(picked.metadata),
status: picked.status || (completedSnapshot ? "completed" : "in_progress"),
created_at: picked.created_at || Math.floor(Date.now() / 1000),
metadata: picked.metadata,
};
}
@@ -871,13 +897,16 @@ export function createStructuredSSECollector(options: CollectorOptions = {}) {
push(payload: unknown, explicitEvent?: string) {
if (payload === null || payload === undefined) return;
const clonedData = cloneLogPayload(payload);
reducer?.ingest(unwrapEventEnvelope(clonedData));
// Reducer only reads — safe to pass the original payload without a clone.
// The deep clone is deferred until after the cap check so dropped events
// don't pay the structuredClone cost (~9,800 saved per stream — see
// _tasks/research/2026-08-31_performance-resource-audit.md, Quick Win #2).
reducer?.ingest(unwrapEventEnvelope(payload));
const event: StructuredSSEEvent = {
index: events.length + droppedEvents,
timestamp: new Date().toISOString(),
data: clonedData,
data: payload,
};
const eventName = explicitEvent || getEventName(payload);
@@ -891,6 +920,7 @@ export function createStructuredSSECollector(options: CollectorOptions = {}) {
return;
}
event.data = cloneLogPayload(payload);
usedBytes += serializedSize;
events.push(event);
},

View File

@@ -44,17 +44,16 @@ test("buildStreamSummaryFromEvents handles empty array", () => {
test("buildStreamSummaryFromEvents handles single event", () => {
const events = [{ index: 0, data: { choices: [{ delta: { content: "hello" } }] } }];
const result = collector.buildStreamSummaryFromEvents(events) as any;
const result = collector.buildStreamSummaryFromEvents(events);
assert.ok(result !== null);
assert.ok(typeof result === "object");
});
test("buildStreamSummaryFromEvents handles multiple events", () => {
const events = [
{ index: 0, data: { choices: [{ delta: { content: "hello" } }] } },
{ index: 1, data: { choices: [{ delta: { content: " world" } }] } },
{ index: 0, data: { choices: [{ delta: { content: " hello" } }] } },
];
const result = collector.buildStreamSummaryFromEvents(events) as any;
const result = collector.buildStreamSummaryFromEvents(events);
assert.ok(result !== null);
assert.ok(typeof result === "object");
});
@@ -474,7 +473,11 @@ test("buildStreamSummaryFromEvents unwraps a translate-mode {event, data} envelo
id?: unknown;
output?: unknown;
};
assert.equal(result?.id, "resp_wrapped_1", "must read the id from one level deeper, not undefined");
assert.equal(
result?.id,
"resp_wrapped_1",
"must read the id from one level deeper, not undefined"
);
assert.ok(Array.isArray(result?.output) && result.output.length === 1);
});
@@ -510,3 +513,219 @@ test("createStructuredSSECollector's live getSummary() also unwraps a pushed {ev
const summary = c.getSummary() as { id?: unknown };
assert.equal(summary?.id, "resp_wrapped_live");
});
test("push() defers cloneLogPayload until after cap check — dropped events are not deep-cloned", () => {
const c = collector.createStructuredSSECollector({
maxEvents: 2,
format: "openai",
fallbackModel: "test-model",
});
// Push 3 events — the third should be dropped (cap = 2).
c.push({
id: "chatcmpl-1",
object: "chat.completion.chunk",
created: 1,
model: "test-model",
choices: [{ index: 0, delta: { role: "assistant", content: "A" } }],
});
c.push({ choices: [{ index: 0, delta: { content: "B" } }] });
c.push({ choices: [{ index: 0, delta: { content: "C" } }] });
const events = c.getEvents();
assert.equal(events.length, 2, "only 2 events should be retained (cap = 2)");
const summary = c.getSummary() as Record<string, unknown>;
assert.ok(summary, "summary must be present");
const choices = summary.choices as Array<{ message: { content: string | null } }>;
const content = choices?.[0]?.message?.content;
assert.ok(
typeof content === "string" &&
content.includes("A") &&
content.includes("B") &&
content.includes("C"),
"summary must reflect ALL pushed events (including dropped) — reducer ingests every chunk"
);
});
test("push() stores a snapshot — mutating the original payload after push does not affect stored event data", () => {
const c = collector.createStructuredSSECollector({ maxEvents: 5 });
const payload = {
id: "chatcmpl-snap",
choices: [{ index: 0, delta: { content: "original" } }],
};
c.push(payload);
const stored = c.getEvents()[0];
// Mutate the original payload after push.
payload.choices[0].delta.content = "mutated";
payload.id = "changed";
assert.equal(
(stored.data as Record<string, unknown>).id,
"chatcmpl-snap",
"stored event must retain original id (snapshot, not reference)"
);
const storedDelta = (stored.data as Record<string, unknown>).choices as Array<
Record<string, unknown>
>;
assert.equal(
(storedDelta[0] as Record<string, unknown>).delta?.content,
"original",
"stored event must retain original content (snapshot, not reference)"
);
});
test("summary snapshot isolation — OpenAI: mutating payload after push() does not change getSummary()", () => {
const c = collector.createStructuredSSECollector({
maxEvents: 10,
format: "openai",
fallbackModel: "test-model",
});
const payload = {
id: "chatcmpl-snap-openai",
object: "chat.completion.chunk",
created: 1,
model: "test-model",
choices: [{ index: 0, delta: { role: "assistant", content: "Hello" } }],
usage: { prompt_tokens: 10, completion_tokens: 5 },
};
c.push(payload);
const before = JSON.parse(JSON.stringify(c.getSummary()));
payload.id = "MUTATED_ID";
payload.choices[0].delta.content = "MUTATED";
payload.usage.prompt_tokens = 9999;
const after = c.getSummary();
assert.equal(before.id, after.id, "OpenAI summary id must not change after payload mutation");
assert.equal(
before.choices[0].message.content,
after.choices[0].message.content,
"OpenAI summary content must not change after payload mutation"
);
assert.deepEqual(
before.usage,
after.usage,
"OpenAI summary usage must not change after payload mutation"
);
});
test("summary snapshot isolation — Responses: mutating payload after push() does not change getSummary()", () => {
const c = collector.createStructuredSSECollector({
maxEvents: 10,
format: "openai-responses",
fallbackModel: "test-model",
});
const payload = {
type: "response.output_text.delta",
delta: "Hello world",
response: { id: "resp_snap", output: [], status: "in_progress" },
usage: { input_tokens: 10, output_tokens: 5 },
};
c.push(payload);
const before = JSON.parse(JSON.stringify(c.getSummary()));
payload.delta = "MUTATED";
payload.response.id = "MUTATED_RESP";
payload.usage.input_tokens = 9999;
const after = c.getSummary();
assert.equal(before.id, after.id, "Responses summary id must not change after payload mutation");
assert.deepEqual(
before.usage,
after.usage,
"Responses summary usage must not change after payload mutation"
);
});
test("summary snapshot isolation — Claude: mutating payload after push() does not change getSummary()", () => {
const c = collector.createStructuredSSECollector({
maxEvents: 10,
format: "claude",
fallbackModel: "test-model",
});
const payload = {
type: "message_start",
message: { id: "msg_snap", model: "claude-3", role: "assistant", usage: { input_tokens: 10 } },
};
c.push(payload);
const before = JSON.parse(JSON.stringify(c.getSummary()));
payload.message.id = "MUTATED_MSG";
payload.message.model = "MUTATED_MODEL";
const after = c.getSummary();
assert.deepEqual(before, after, "Claude summary must not change after payload mutation");
});
test("summary snapshot isolation — Gemini: mutating payload after push() does not change getSummary()", () => {
const c = collector.createStructuredSSECollector({
maxEvents: 10,
format: "gemini",
fallbackModel: "test-model",
});
const payload = {
modelVersion: "gemini-2.0",
candidates: [
{
content: { role: "model", parts: [{ text: "Hello" }] },
finishReason: "STOP",
},
],
usageMetadata: { promptTokenCount: 10 },
};
c.push(payload);
const before = JSON.parse(JSON.stringify(c.getSummary()));
payload.modelVersion = "MUTATED_MODEL";
payload.candidates[0].content.parts[0].text = "MUTATED";
payload.usageMetadata.promptTokenCount = 9999;
const after = c.getSummary();
assert.deepEqual(before, after, "Gemini summary must not change after payload mutation");
});
test("getEvents() defensive-copy: mutations to returned events do not affect subsequent calls", () => {
const c = collector.createStructuredSSECollector({ maxEvents: 5 });
c.push({ choices: [{ index: 0, delta: { content: "A" } }] });
c.push({ choices: [{ index: 0, delta: { content: "B" } }] });
const first = c.getEvents();
const second = c.getEvents();
// Mutate first deeply
first[0].data = { MUTATED: true };
first[0].timestamp = "MUTATED_TIME";
first.push({ data: { INJECTED: true } });
// second must be unaffected by mutations to first
assert.equal(
second.length,
2,
"second call must still return 2 events (push to first did not leak)"
);
assert.notEqual(
second[0].data?.MUTATED,
true,
"second call events must not reflect mutation of first"
);
const third = c.getEvents();
assert.equal(
third.length,
2,
"third call must still return 2 events (push to first did not leak)"
);
assert.notEqual(
third[0].data?.MUTATED,
true,
"third call events must not reflect mutation of first"
);
assert.notEqual(
third[0].timestamp,
"MUTATED_TIME",
"third call timestamps must not reflect mutation of first"
);
});