Files
OmniRoute/tests/unit/lmarena-string-chunk-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

75 lines
2.3 KiB
TypeScript

/**
* TDD repro for #9237: Arena SSE stream emits string chunks (not Uint8Array),
* which causes TextDecoder.decode in the shared pipeline to throw
* TypeError ERR_INVALID_ARG_TYPE.
*/
import { describe, it } from "node:test";
import { ok, deepEqual, rejects } from "node:assert/strict";
import { createOpenAIArenaStream } from "../../open-sse/executors/lmarena/response.ts";
/**
* Build a fake upstream reader that yields SSE lines as Uint8Array,
* simulating what the Arena executor's upstream reader does.
*/
function fakeReader(lines: string[]): ReadableStreamDefaultReader<Uint8Array> {
let idx = 0;
const stream = new ReadableStream<Uint8Array>({
pull(controller) {
if (idx < lines.length) {
controller.enqueue(new TextEncoder().encode(lines[idx] + "\n"));
idx++;
} else {
controller.close();
}
},
});
return stream.getReader();
}
/**
* Drive the Arena stream through the real ensureStreamReadiness path
* to verify the contract: TextDecoder.decode must not throw on any chunk.
*/
async function collectArenaStream(
reader: ReadableStreamDefaultReader<Uint8Array>
): Promise<string> {
const decoder = new TextDecoder();
let result = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
// This is the exact call that throws ERR_INVALID_ARG_TYPE on string chunks
result += decoder.decode(value, { stream: true });
}
// flush
result += decoder.decode();
return result;
}
describe("Arena SSE stream — string vs Uint8Array contract (#9237)", () => {
it("should emit Uint8Array chunks that survive TextDecoder.decode without throwing", async () => {
const reader = fakeReader([
'data: a0:{"text":"Hello"}',
'data: ad:{}',
]);
const arenaStream = createOpenAIArenaStream({
reader,
model: "test-model",
});
// verify the stream type is Uint8Array, not string
const collected = await collectArenaStream(
arenaStream.getReader()
);
// Should contain the content text and the [DONE] marker
ok(
collected.includes("Hello"),
`Expected collected output to include "Hello", got: ${collected.slice(0, 200)}`
);
ok(
collected.includes("[DONE]"),
`Expected collected output to include "[DONE]", got: ${collected.slice(0, 200)}`
);
});
});