fix(e2e): don't crash the mock LLM on a non-array tools field

The malformed-body guard only rejects non-object top-level payloads, so a body like
{"tools":5} passed it and reached `(payload.tools ?? []).map(...)` — `.map` on a
number throws outside the try/catch and kills the process, dropping any in-flight SSE
streams and violating the guard's stated contract. Guards on Array.isArray before
mapping. Proven: the old expression throws on {"tools":5}, the new one yields "" and
still maps a real tools array.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Sergey Kozyrenko
2026-07-24 02:41:58 +07:00
co-authored by Claude Opus 4.8
parent ecfb2029ce
commit 3e4316e53c
+5 -1
View File
@@ -137,7 +137,11 @@ createServer(async (request, response) => {
}
const rule = pickAnswer(payload);
const toolNames = (payload.tools ?? []).map((tool) => tool.function?.name ?? tool.type).join(',');
// Array.isArray, not ?? []: the top-level guard only rejects non-object bodies, so a payload
// like {"tools":5} reaches here and `.map` on a non-array would throw outside the try/catch
// and kill the process — violating the guard's own contract.
const toolList = Array.isArray(payload.tools) ? payload.tools : [];
const toolNames = toolList.map((tool) => tool.function?.name ?? tool.type).join(',');
console.log(`[mock-llm] ${rule.label}: ${payload.stream ? 'stream' : 'plain'} tools=[${toolNames}]`);
respondCompletion(response, payload, rule);