Files
OmniRoute/tests/unit/zai-web-silent-empty-repro.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

158 lines
6.5 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const { buildZaiStreamingBody, parseZaiFrame, collectZaiNonStreaming } = await import(
"../../open-sse/executors/zai-web/stream.ts"
);
/**
* Hard Rule #6 — "never silently swallow errors in SSE streams".
*
* HTTP-level failures are already handled: `fetchUpstream` turns any `!ok`
* response into a `makeErrorResult` with the sanitized body. The gap is a
* **200 whose SSE body carries an error payload** — `parseZaiFrame` returns
* null for it, `drainSseDeltas` drops it, and the stream closes with an empty
* assistant message + stop + [DONE]. The caller sees a successful empty
* completion: HTTP 200, `out=0`, "complete". That is the shape reported on
* #8451, and it makes a rejected signature, an expired captcha and a stale
* token all look identical.
*
* Scope note: returning null for a *contentless* frame is deliberate and
* live-validated — z.ai sends phase frames with no `delta_content`, and
* `executor-zai-web.test.ts` pins that ("returns null for frames with no usable
* delta"). So this only adds recognition of affirmatively error-shaped frames;
* "nothing parseable arrived" is left alone, because on this protocol that is
* not by itself evidence of failure.
*/
function sseStream(...frames: string[]): ReadableStream<Uint8Array> {
const enc = new TextEncoder();
return new ReadableStream({
start(c) {
for (const f of frames) c.enqueue(enc.encode(`data: ${f}\n\n`));
c.close();
},
});
}
async function readAll(stream: ReadableStream): Promise<string> {
const reader = stream.getReader();
const dec = new TextDecoder();
let out = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
out += dec.decode(value as Uint8Array, { stream: true });
}
return out;
}
const emitChunk = (
controller: ReadableStreamDefaultController,
delta: Record<string, unknown>,
finish?: string
) => {
const payload = JSON.stringify({
choices: [{ index: 0, delta, finish_reason: finish ?? null }],
});
controller.enqueue(new TextEncoder().encode(`data: ${payload}\n\n`));
};
const contentOf = (sse: string) =>
[...sse.matchAll(/"content":"([^"]*)"/g)].map((m) => m[1]).join("");
test("parseZaiFrame classifies an error-shaped frame instead of discarding it", () => {
assert.equal(parseZaiFrame({ error: "captcha expired" })?.error, "captcha expired");
assert.equal(
parseZaiFrame({ error: { detail: "signature invalid" } })?.error,
"signature invalid"
);
assert.equal(
parseZaiFrame({ data: { error: { message: "token expired" } } })?.error,
"token expired"
);
});
test("an error frame is terminal", () => {
assert.equal(parseZaiFrame({ error: "nope" })?.done, true);
});
test("REGRESSION GUARD: contentless frames are still skipped, not reported as errors", () => {
// Live-validated behaviour — z.ai emits phase frames with no delta_content.
// Pinned by executor-zai-web.test.ts; re-asserted here because the error path
// added below runs in the same function.
assert.equal(parseZaiFrame({ data: { phase: "answer" } }), null);
assert.equal(parseZaiFrame({ type: "chat:completion", data: { phase: "thinking" } }), null);
assert.equal(parseZaiFrame({}), null);
assert.equal(parseZaiFrame(null), null);
assert.equal(parseZaiFrame("not-an-object"), null);
});
test("a 200 stream carrying an error frame surfaces it instead of finishing empty", async () => {
const upstream = sseStream(JSON.stringify({ error: { detail: "signature invalid" } }));
const out = await readAll(buildZaiStreamingBody(upstream, emitChunk, null));
assert.match(contentOf(out), /signature invalid/, "the upstream's diagnosis must reach the caller");
assert.match(contentOf(out), /\[Z\.ai error\]/, "tagged like the other web executors");
assert.ok(out.includes('"finish_reason":"stop"'));
assert.ok(out.includes("[DONE]"), "the stream still terminates cleanly for the client");
});
test("an error frame after partial content still surfaces, keeping what was streamed", async () => {
const upstream = sseStream(
JSON.stringify({ type: "chat:completion", data: { delta_content: "partial", phase: "answer" } }),
JSON.stringify({ error: "stream aborted upstream" })
);
const out = await readAll(buildZaiStreamingBody(upstream, emitChunk, null));
assert.match(contentOf(out), /partial/, "already-streamed content is preserved");
assert.match(contentOf(out), /stream aborted upstream/, "and the failure is appended, not dropped");
});
test("control: a well-formed stream is untouched", async () => {
const upstream = sseStream(
JSON.stringify({ type: "chat:completion", data: { delta_content: "hello", phase: "answer" } }),
JSON.stringify({ type: "chat:completion", data: { phase: "done", done: true } })
);
const out = await readAll(buildZaiStreamingBody(upstream, emitChunk, null));
assert.equal(contentOf(out), "hello");
assert.ok(!out.includes("[Z.ai error]"), "the happy path must stay clean");
});
test("control: a phase-only stream is not turned into an error", async () => {
// The exact case the deliberate-null design exists for.
const upstream = sseStream(
JSON.stringify({ type: "chat:completion", data: { phase: "answer" } }),
JSON.stringify({ type: "chat:completion", data: { delta_content: "hi", phase: "answer" } }),
JSON.stringify({ type: "chat:completion", data: { phase: "done", done: true } })
);
const out = await readAll(buildZaiStreamingBody(upstream, emitChunk, null));
assert.equal(contentOf(out), "hi");
assert.ok(!out.includes("[Z.ai error]"));
});
// ── Non-streaming path (collectZaiNonStreaming) ───────────────────────────────
test("collectZaiNonStreaming rejects on an error frame instead of returning empty", async () => {
const upstream = sseStream(JSON.stringify({ error: { detail: "captcha expired" } }));
await assert.rejects(
() => collectZaiNonStreaming(upstream),
(err: Error) => {
assert.match(err.message, /captcha expired/);
return true;
}
);
});
test("collectZaiNonStreaming returns content when no error frame is present", async () => {
const upstream = sseStream(
JSON.stringify({ type: "chat:completion", data: { delta_content: "hello", phase: "answer" } }),
JSON.stringify({ type: "chat:completion", data: { phase: "done", done: true } })
);
const result = await collectZaiNonStreaming(upstream);
assert.equal(result.answer, "hello");
assert.equal(result.reasoning, "");
});