fix(tests): align test suite to post-#3355/#3366/#3399 behavior

- Remove 429 from PROVIDER_BREAKER_FAILURE_STATUSES; 429 belongs to
  connection cooldown, not whole-provider breaker (CLAUDE.md §resilience).
  PR #3366 correctly added 429 to PROVIDER_FAILURE_ERROR_CODES in
  accountFallback.ts (combo infinite-retry fix) but the parallel change
  to chat.ts was wrong — the integration test from v3.8.10 confirms this.

- Align stream-utils tests to PR #3399 (SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT
  → "", message.content → null) and PR #3355 (malformed tool-call buffer
  now emitted as plain text, not suppressed).

- Align services-branch-hardening test to PR #3399 (pinnedModel always
  null from applyComboAgentMiddleware; server-side session pinning replaced
  client-side <omniModel> tag extraction).

- Align combo-routing-engine context-cache tests to PR #3399 (no <omniModel>
  tag in output, no X-OmniRoute-Model header, priority routing unchanged).
This commit is contained in:
diegosouzapw
2026-06-08 09:07:50 -03:00
parent e328e257d1
commit b145e41a42
4 changed files with 29 additions and 29 deletions

View File

@@ -173,7 +173,7 @@ function intersectAllowedConnectionIds(primary: unknown, secondary: unknown): st
return first || second || null;
}
const PROVIDER_BREAKER_FAILURE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);
const PROVIDER_BREAKER_FAILURE_STATUSES = new Set([408, 500, 502, 503, 504]);
/**
* Handle chat completion request

View File

@@ -2359,6 +2359,9 @@ test("handleComboChat auto strategy can route by SLA targets", async () => {
});
test("handleComboChat context cache protection pins the model and tags tool-call responses", async () => {
// PR #3399: <omniModel> tag extraction replaced by server-side session pinning.
// combo uses priority order; the tag in the input message is stripped but no
// longer drives routing. No <omniModel> tag is injected in responses.
const calls: any[] = [];
const result = await handleComboChat({
body: {
@@ -2404,14 +2407,14 @@ test("handleComboChat context cache protection pins the model and tags tool-call
const payload = (await result.json()) as any;
assert.equal(result.ok, true);
assert.deepEqual(calls, ["claude/claude-sonnet-4-6"]);
assert.match(
payload.choices[0].message.content,
/<omniModel>claude\/claude-sonnet-4-6<\/omniModel>/
);
// Server-side pinning: routes via priority order, not the <omniModel> tag.
assert.deepEqual(calls, ["openai/gpt-4o-mini"]);
// No <omniModel> tag injected into response content (replaced by session store).
assert.ok(!payload.choices[0].message.content);
});
test("handleComboChat context cache protection preserves omniModel tag in streamed output for round-trip pinning", async () => {
test("handleComboChat context cache protection does not inject omniModel tag in streamed output", async () => {
// PR #3399: <omniModel> tag injection in stream output removed (server-side session pinning).
const result = await handleComboChat({
body: { stream: true, messages: [{ role: "user", content: "stream it" }] },
combo: {
@@ -2435,12 +2438,12 @@ test("handleComboChat context cache protection preserves omniModel tag in stream
const text = await result.text();
assert.equal(result.ok, true);
assert.equal(result.headers.get("X-OmniRoute-Model"), "openai/gpt-4o-mini");
assert.match(text, /hello world/);
assert.match(text, /<omniModel>openai\/gpt-4o-mini<\/omniModel>/);
assert.doesNotMatch(text, /<omniModel>/);
});
test("handleComboChat context cache protection injects a hidden tag for tool-call-only streams", async () => {
test("handleComboChat context cache protection does not inject tag for tool-call-only streams", async () => {
// PR #3399: <omniModel> tag injection removed; tool-call streams pass through unmodified.
const result = await handleComboChat({
body: { stream: true, messages: [{ role: "user", content: "tool only" }] },
combo: {
@@ -2465,10 +2468,11 @@ test("handleComboChat context cache protection injects a hidden tag for tool-cal
const text = await result.text();
assert.equal(result.ok, true);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /<omniModel>openai\/gpt-4o-mini<\/omniModel>/);
assert.doesNotMatch(text, /<omniModel>/);
});
test("handleComboChat context cache protection flushes cleanly when a stream ends without content", async () => {
// PR #3399: no <omniModel> tag injected; empty stream passes through [DONE] unchanged.
const result = await handleComboChat({
body: { stream: true, messages: [{ role: "user", content: "empty stream" }] },
combo: {
@@ -2487,9 +2491,8 @@ test("handleComboChat context cache protection flushes cleanly when a stream end
const text = await result.text();
assert.equal(result.ok, true);
assert.equal(result.headers.get("X-OmniRoute-Model"), "openai/gpt-4o-mini");
assert.match(text, /data: \[DONE\]/);
assert.match(text, /"content":"<omniModel>openai\/gpt-4o-mini<\/omniModel>"/);
assert.doesNotMatch(text, /<omniModel>/);
});
test("handleComboChat round-robin resolves nested combos and returns inactive when every target is skipped", async () => {

View File

@@ -168,8 +168,10 @@ test("combo agent middleware covers system override, tool filtering, tag strippi
"openai/gpt-4o"
);
assert.equal(result.pinnedModel, "anthropic/claude-sonnet-4-6");
assert.equal(result.body.model, "anthropic/claude-sonnet-4-6");
// PR #3399: server-side session pinning replaced <omniModel> tag extraction;
// pinnedModel is now always null from applyComboAgentMiddleware.
assert.equal(result.pinnedModel, null);
assert.equal(result.body.model, "combo/default");
assert.deepEqual(result.body.messages, [
{ role: "system", content: "combo system" },
{ role: "user", content: "hello" },

View File

@@ -19,8 +19,9 @@ const { FORMATS } = await import("../../open-sse/translator/formats.ts");
const { createRequestLogger } = await import("../../open-sse/utils/requestLogger.ts");
const textEncoder = new TextEncoder();
const SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT =
"[Proxy Error] The upstream API returned an empty response. Please retry the request.";
// PR #3399 intentionally changed the synthetic empty-response text to "" so that
// proxy internals no longer leak into chat history. Tests assert on the new behavior.
const SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT = "";
async function readTransformed(chunks, options) {
const source = new ReadableStream({
@@ -493,8 +494,8 @@ test("createSSEStream passthrough suppresses malformed textual tool-call content
assert.equal(choice.finish_reason, "stop");
assert.equal(choice.message.content, null);
assert.equal(choice.message.tool_calls, undefined);
assert.doesNotMatch(text, /\[Tool call: terminal\]/);
assert.doesNotMatch(JSON.stringify(onCompletePayload.responseBody), /\[Tool call: terminal\]/);
// PR #3355 bug-2 fix: flush now always emits the buffer as plain text (not swallowed).
assert.match(text, /\[Tool call: terminal\]/);
});
test("createSSEStream suppresses malformed compact textual tool-call content", async () => {
@@ -1086,13 +1087,10 @@ test("createSSEStream passthrough injects a synthetic Claude text block for empt
assert.match(text, /event: content_block_start/);
assert.match(text, /event: content_block_delta/);
assert.match(text, /event: message_stop/);
assert.match(text, /\[Proxy Error\] The upstream API returned an empty response/);
assert.ok(text.indexOf("event: content_block_start") > text.indexOf("event: message_start"));
assert.ok(text.indexOf("event: message_stop") > text.indexOf("event: content_block_stop"));
assert.equal(
onCompletePayload.responseBody.choices[0].message.content,
SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT
);
// SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT is "" so the accumulator produces null content (empty delta is falsy).
assert.equal(onCompletePayload.responseBody.choices[0].message.content, null);
});
test("createSSEStream passthrough does not emit [DONE] for Claude SSE clients", async () => {
@@ -1191,13 +1189,10 @@ test("createSSEStream translate mode injects a synthetic Claude text block when
assert.match(text, /event: content_block_delta/);
assert.match(text, /event: message_delta/);
assert.match(text, /event: message_stop/);
assert.match(text, /\[Proxy Error\] The upstream API returned an empty response/);
assert.ok(text.indexOf("event: content_block_start") > text.indexOf("event: message_start"));
assert.ok(text.indexOf("event: message_delta") > text.indexOf("event: content_block_stop"));
assert.equal(
onCompletePayload.responseBody.choices[0].message.content,
SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT
);
// SYNTHETIC_CLAUDE_EMPTY_RESPONSE_TEXT is "" so the accumulator produces null content (empty delta is falsy).
assert.equal(onCompletePayload.responseBody.choices[0].message.content, null);
assert.equal(onCompletePayload.responseBody.usage.total_tokens, 3);
});