Compare commits

...

1 Commits

Author SHA1 Message Date
Markus Hartung
324011e969 fix(sse): set X-OmniRoute-Selected-Connection-Id on successful combo dispatches (#11810) 2026-08-29 05:16:30 -03:00
3 changed files with 150 additions and 2 deletions

View File

@@ -0,0 +1 @@
- fix(sse): set X-OmniRoute-Selected-Connection-Id on successful combo dispatches so downstream consumers stop falling back to an empty connection id (#11810)

View File

@@ -1913,11 +1913,15 @@ async function handleSingleModelChat(
}
if (telemetry) telemetry.startPhase("finalize");
if (telemetry) telemetry.endPhase();
const successResponse = withSelectedConnectionHeader(
result.response,
credentials?.connectionId
);
if (requestBody.stream === true) {
return wrapResponseWithOAuthSessionRelease(result.response, releaseOAuthSession);
return wrapResponseWithOAuthSessionRelease(successResponse, releaseOAuthSession);
}
releaseOAuthSession();
return result.response;
return successResponse;
}
// A final hard-lease fence rejection is authoritative. It must never mutate

View File

@@ -0,0 +1,143 @@
/**
* Regression test for #11810.
*
* On a successful provider dispatch, `handleSingleModelChat()`'s
* `result.success` branch in `src/sse/handlers/chat.ts` used to return
* `result.response` (non-streaming) or
* `wrapResponseWithOAuthSessionRelease(result.response, releaseOAuthSession)`
* (streaming) directly, without first calling `withSelectedConnectionHeader()`
* — unlike every failure exit in the same function, which does call it.
*
* As a result `X-OmniRoute-Selected-Connection-Id` was absent on every
* successful response for a dynamically-selected (unpinned) connection, so
* combo.ts's consumers (success-decay, provider cooldown recovery, webhook
* attribution, session stickiness, LKGP) fell back to the target's static
* `connectionId`, which is empty for provider-level combo targets like
* `openai/o3-mini`.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { createChatPipelineHarness } from "../integration/_chatPipelineHarness.ts";
const harness = await createChatPipelineHarness("combo-success-sel-conn-11810");
const { buildOpenAIResponse, buildRequest, combosDb, handleChat, resetStorage, seedConnection } =
harness;
const textEncoder = new TextEncoder();
function buildOpenAIStreamResponse(text = "hello streamed") {
return new Response(
new ReadableStream({
start(controller) {
controller.enqueue(
textEncoder.encode(
`data: ${JSON.stringify({
id: "chatcmpl_stream_11810",
object: "chat.completion.chunk",
created: 1,
model: "o3-mini",
choices: [{ index: 0, delta: { role: "assistant", content: text } }],
})}\n\n`
)
);
controller.enqueue(textEncoder.encode(`data: [DONE]\n\n`));
controller.close();
},
}),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
test.beforeEach(async () => {
await resetStorage();
});
test.afterEach(async () => {
await resetStorage();
});
test.after(async () => {
await harness.cleanup();
});
test("#11810 combo success response carries X-OmniRoute-Selected-Connection-Id for a dynamically selected connection", async () => {
const connection = await seedConnection("openai", {
apiKey: "sk-openai-11810",
});
await combosDb.createCombo({
name: "combo-11810-priority",
strategy: "priority",
config: { maxRetries: 0, retryDelayMs: 0 },
// Provider-level target, no pinned connectionId — the connection is selected
// dynamically at dispatch time.
models: ["openai/o3-mini"],
});
globalThis.fetch = async () => buildOpenAIResponse("hello from o3-mini", "o3-mini");
const response = await handleChat(
buildRequest({
body: {
model: "combo-11810-priority",
stream: false,
messages: [{ role: "user", content: "hi" }],
},
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { choices: Array<{ message: { content: string } }> };
assert.equal(body.choices[0].message.content, "hello from o3-mini");
const selectedConnectionId = response.headers.get("X-OmniRoute-Selected-Connection-Id");
assert.equal(
selectedConnectionId,
connection.id,
`expected the response to carry the dynamically selected connection id (${connection.id}), got ${selectedConnectionId}`
);
});
test("#11810 combo streaming success response carries X-OmniRoute-Selected-Connection-Id for a dynamically selected connection", async () => {
const connection = await seedConnection("openai", {
apiKey: "sk-openai-11810-stream",
});
await combosDb.createCombo({
name: "combo-11810-priority-stream",
strategy: "priority",
config: { maxRetries: 0, retryDelayMs: 0 },
// Provider-level target, no pinned connectionId — the connection is selected
// dynamically at dispatch time.
models: ["openai/o3-mini"],
});
globalThis.fetch = async () => buildOpenAIStreamResponse("hello streamed from o3-mini");
const response = await handleChat(
buildRequest({
body: {
model: "combo-11810-priority-stream",
stream: true,
messages: [{ role: "user", content: "hi" }],
},
})
);
assert.equal(response.status, 200);
const selectedConnectionId = response.headers.get("X-OmniRoute-Selected-Connection-Id");
assert.equal(
selectedConnectionId,
connection.id,
`expected the streaming response to carry the dynamically selected connection id (${connection.id}), got ${selectedConnectionId}`
);
// Drain the stream so the harness's fetch mock/db handles are released cleanly.
await response.text();
});