@m8tes/sdk 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/fixtures.ts"],"names":[],"mappings":";;;AAuBO,IAAM,QAAA,GAAW;AAAA;AAAA;AAAA,EAGtB,UAAA,EAAY,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EA+BZ,gBAAA,EAAkB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA,EAoBlB,qBAAA,EAAuB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA,EA0BvB,oBAAA,EAAsB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAyBtB,iBAAA,EAAmB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA,EAqBnB,mBAAA,EAAqB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA,EAYrB,iBAAA,EAAmB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA,EAanB,SAAA,EAAW,CAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcX,kCAAA,EAAoC,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EA2BpC,iBAAA,EAAmB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA,EAgBnB,cAAA,EAAgB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA,EAkBhB,SAAA,EAAW,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBX,cAAA,EAAgB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgChB,sBAAA,EAAwB,CAAA;;AAAA;;AAAA;;AAAA;;AAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaxB,kBAAA,EAAoB,CAAA;;AAAA;;AAAA;;AAAA;AAOtB","file":"fixtures.cjs","sourcesContent":["/**\n * Recorded-style wire fixtures for the SSE parser + normalizer.\n *\n * PUBLIC, via `@m8tes/sdk/fixtures`. It is exported rather than kept private for\n * two reasons: it is the single test oracle for the wire protocol (both\n * `@m8tes/sdk` and `@m8tes/react` assert against THIS file, so there is no\n * second copy to drift), and anyone writing tests for their own protocol\n * consumer — a custom `ToolCall` renderer, a bespoke client — needs realistic\n * streams to feed it. It has its own bundle entry, so it never ships inside the\n * runtime bundles.\n *\n * Each value is the RAW SSE text the m8tes V2 backend sends — frames separated\n * by a blank line, including `: comment` keepalive lines. Derived from the\n * canonical streaming contract (workflow embed-stream-contract). These are the\n * test oracle; they match the documented flat Claude-native wire format.\n *\n * NOTE: a few scenarios encode reality the client must tolerate but that we\n * could not 100% confirm without a live stack (see the plan's \"open contracts\"\n * + the package TODOs): the exact `done-with-error` path, AskUserQuestion\n * rediscovery on rejoin, and concatenated-JSON prevalence. The normalizer is\n * built to handle all of them defensively regardless.\n */\n\nexport const FIXTURES = {\n /** Happy-path text run: preamble (comment + 2 metadata + json keepalive), one\n * streamed text block, terminal snapshot, run_metrics -> done. */\n \"text-run\": `: keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\", \"agent_name\": \"PPC Manager\", \"status\": \"running\"}\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_1\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 1840, \"input_tokens_used\": 100, \"output_tokens_used\": 5, \"claude_token_cost_usd\": 0.004, \"stop_reason\": \"end_turn\", \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"terminal_completion_seen\": true, \"sdk_total_cost_usd\": 0.0045, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"message_complete\", \"retry_count\": 0}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Computer-use screenshot: tool_result whose content is an array holding a\n * base64 image block (the desktop MCP server's `_png_to_image_block` shape).\n * Platform renders these inline (BubbleTimeline tool_result case). */\n \"screenshot-run\": `data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_s1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre1\", \"name\": \"bash\", \"input\": {\"command\": \"ls\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre1\", \"content\": \"ok\", \"result\": \"ok\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre2\", \"name\": \"bash\", \"input\": {\"command\": \"pwd\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre2\", \"content\": \"/\", \"result\": \"/\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_shot\", \"name\": \"computer\", \"input\": {\"action\": \"screenshot\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_shot\", \"content\": [{\"type\": \"image\", \"source\": {\"type\": \"base64\", \"media_type\": \"image/png\", \"data\": \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==\"}}]}\n\ndata: {\"type\": \"done\", \"message_count\": 2, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Full tool chain: block-start(tool_use) -> input_json_delta streaming ->\n * block-stop -> standalone tool_use (resolved input, SAME id) -> tool_result. */\n \"tool-call-lifecycle\": `data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_2\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_1\", \"block_type\": \"tool_use\", \"name\": \"get_weather\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\\\"location\\\\\": \\\\\"San\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \" Francisco\\\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_1\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_1\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_2\", \"role\": \"assistant\", \"content_blocks\": [{\"id\": \"toolu_1\", \"type\": \"tool_use\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 20}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_2\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\", \"result\": \"Sunny, 72°F\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_3\", \"role\": \"user\", \"content_blocks\": [{\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 3, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** HITL tool approval. Segment 1 ends on awaiting_approval (no done). Segment 2\n * (post-approve resume stream) delivers the tool_result -> done. */\n \"permission-approve\": `data: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_4\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 150, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_2\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_2\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\\\"command\\\\\": \\\\\"rm -rf build\\\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_2\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\n: resume after approval\n\ndata: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_2\", \"content\": \"\", \"result\": \"\"}\n\ndata: {\"type\": \"done\", \"message_count\": 5, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** AskUserQuestion HITL: awaiting_approval(tool_name=AskUserQuestion) must\n * normalize to a `question`, not `approval-request`. Resume delivers the\n * answer as a tool_result for the AskUserQuestion id. */\n \"question-answer\": `data: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_6\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 120, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_3\", \"block_type\": \"tool_use\", \"name\": \"AskUserQuestion\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_3\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"q1\", \"tool_name\": \"AskUserQuestion\", \"tool_input\": {\"questions\": [{\"question\": \"Which budget?\", \"options\": [{\"label\": \"$5k\", \"description\": \"Conservative start\"}, {\"label\": \"$10k\"}]}]}, \"timeout_seconds\": 0}\n\n: resume after answer\n\ndata: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_3\", \"content\": \"$10k\", \"result\": \"$10k\"}\n\ndata: {\"type\": \"done\", \"message_count\": 4, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Terminal error: partial text then `error` ends the stream with NO done. */\n \"error-before-done\": `data: {\"type\": \"metadata\", \"run_id\": 126, \"mode\": \"chat\", \"run_uuid\": \"run-jkl\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_2\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_2\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Working on it\"}}\n\ndata: {\"type\": \"error\", \"error\": \"Connection reset\", \"message\": \"Agent execution failed\"}\n\n`,\n\n /** Terminal-but-unsuccessful: `done` with completion_state !== complete and a\n * pending tool. run_metrics carries the diagnostics block. */\n \"done-with-error\": `data: {\"type\": \"metadata\", \"run_id\": 127, \"mode\": \"chat\", \"run_uuid\": \"run-mno\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_4\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_4\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 60000, \"input_tokens_used\": 90, \"output_tokens_used\": 12, \"claude_token_cost_usd\": 0.006, \"stop_reason\": null, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"terminal_completion_seen\": false, \"sdk_total_cost_usd\": 0.0065, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"content_block_stop\", \"retry_count\": 0, \"diagnostics\": {\"pending_tool_ids\": [\"toolu_4\"]}}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"stop_reason\": null, \"terminal_completion_seen\": false}\n\n`,\n\n /** Backend-injected cancellation: partial text then `cancelled` ends the stream. */\n cancelled: `data: {\"type\": \"metadata\", \"run_id\": 128, \"mode\": \"chat\", \"run_uuid\": \"run-pqr\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_3\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_3\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Analyzing\"}}\n\ndata: {\"type\": \"cancelled\", \"run_id\": 128}\n\n`,\n\n /** GET /stream rejoin of run 123: re-synthesized metadata + user_message (no id),\n * the SAME block_1 streamed again, a snapshot re-covering block_1 (duplicate),\n * and the SAME permission_request request_id TWICE. Client must render block_1\n * ONCE and show ONE approval. */\n \"reconnect-replay-with-duplicates\": `: keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"user_message\", \"content\": \"What is the weather?\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Parser robustness: a glued concatenated-JSON frame (two objects), an\n * invalid/unterminated JSON frame that must be dropped without crashing, then\n * valid frames so the stream recovers to done. */\n \"malformed-frame\": `data: {\"type\": \"metadata\", \"run_id\": 129, \"mode\": \"chat\", \"run_uuid\": \"run-stu\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_4\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \"ok\"}}{\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \" glued\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"broken\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_4\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Empty/whitespace payloads: an empty text_delta, a real delta, an empty\n * top-level message_delta. Final text must equal just the real content. */\n \"empty-deltas\": `data: {\"type\": \"metadata\", \"run_id\": 130, \"mode\": \"chat\", \"run_uuid\": \"run-vwx\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_5\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"real\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_5\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Keepalive/no-op handling via both layers: `: keep-alive` comment, JSON\n * keep-alive, `: ping` comment, JSON ping — all dropped — around a real text block. */\n keepalive: `: keep-alive\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\n: ping\n\ndata: {\"type\": \"ping\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 131, \"mode\": \"chat\", \"run_uuid\": \"run-yz\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_6\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_6\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hi\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_6\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n /** Extended thinking: thinking deltas carry `delta.thinking` (NOT `text`),\n * signature_delta is ignored, and the snapshot copy of the thinking block is\n * `{\"type\": \"thinking\", \"thinking\": ...}` with NO id (runtime accumulator\n * shape) — it must dedupe against the streamed content, not re-render. */\n \"thinking-run\": `data: {\"type\": \"metadata\", \"run_id\": 132, \"mode\": \"chat\", \"run_uuid\": \"run-think\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_7\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_7\", \"block_type\": \"thinking\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \"Let me check\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \" the budget\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"signature_delta\", \"signature\": \"sig_abc\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_7\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_8\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_8\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Done\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_8\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_7\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"thinking\", \"thinking\": \"Let me check the budget\", \"signature\": \"sig_abc\"}, {\"type\": \"text\", \"text\": \"Done\"}], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 9}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_7\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n\n /** Snapshot-only output: the CLI-handled-API-error path streams NO content\n * blocks — the synthetic final message_snapshot (id-less text block) is the\n * ONLY carrier of the assistant's output and must render. A replayed copy of\n * the same snapshot must dedupe. */\n \"snapshot-only-output\": `data: {\"type\": \"metadata\", \"run_id\": 133, \"mode\": \"chat\", \"run_uuid\": \"run-snap\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n`,\n /** Anthropic-side failure: the SDK ResultMessage arrives with is_error=true\n * but the wire STILL ends `done` + completion_state \"complete\" (the backend\n * marks the run failed from is_error). The client must surface the error and\n * suppress the misleading done. */\n \"sdk-error-result\": `data: {\"type\": \"metadata\", \"run_id\": 134, \"mode\": \"chat\", \"run_uuid\": \"run-sdkerr\"}\n\ndata: {\"type\": \"sdk_success\", \"subtype\": \"error_during_execution\", \"is_error\": true, \"result\": \"Credit balance is too low\", \"duration_ms\": 1200, \"num_turns\": 1}\n\ndata: {\"type\": \"done\", \"message_count\": 0, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": null, \"terminal_completion_seen\": true}\n\n`,\n} as const;\n\nexport type FixtureName = keyof typeof FIXTURES;\n"]}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Recorded-style wire fixtures for the SSE parser + normalizer.
3
+ *
4
+ * PUBLIC, via `@m8tes/sdk/fixtures`. It is exported rather than kept private for
5
+ * two reasons: it is the single test oracle for the wire protocol (both
6
+ * `@m8tes/sdk` and `@m8tes/react` assert against THIS file, so there is no
7
+ * second copy to drift), and anyone writing tests for their own protocol
8
+ * consumer — a custom `ToolCall` renderer, a bespoke client — needs realistic
9
+ * streams to feed it. It has its own bundle entry, so it never ships inside the
10
+ * runtime bundles.
11
+ *
12
+ * Each value is the RAW SSE text the m8tes V2 backend sends — frames separated
13
+ * by a blank line, including `: comment` keepalive lines. Derived from the
14
+ * canonical streaming contract (workflow embed-stream-contract). These are the
15
+ * test oracle; they match the documented flat Claude-native wire format.
16
+ *
17
+ * NOTE: a few scenarios encode reality the client must tolerate but that we
18
+ * could not 100% confirm without a live stack (see the plan's "open contracts"
19
+ * + the package TODOs): the exact `done-with-error` path, AskUserQuestion
20
+ * rediscovery on rejoin, and concatenated-JSON prevalence. The normalizer is
21
+ * built to handle all of them defensively regardless.
22
+ */
23
+ declare const FIXTURES: {
24
+ /** Happy-path text run: preamble (comment + 2 metadata + json keepalive), one
25
+ * streamed text block, terminal snapshot, run_metrics -> done. */
26
+ readonly "text-run": ": keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\", \"agent_name\": \"PPC Manager\", \"status\": \"running\"}\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_1\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 1840, \"input_tokens_used\": 100, \"output_tokens_used\": 5, \"claude_token_cost_usd\": 0.004, \"stop_reason\": \"end_turn\", \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"terminal_completion_seen\": true, \"sdk_total_cost_usd\": 0.0045, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"message_complete\", \"retry_count\": 0}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
27
+ /** Computer-use screenshot: tool_result whose content is an array holding a
28
+ * base64 image block (the desktop MCP server's `_png_to_image_block` shape).
29
+ * Platform renders these inline (BubbleTimeline tool_result case). */
30
+ readonly "screenshot-run": "data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_s1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre1\", \"name\": \"bash\", \"input\": {\"command\": \"ls\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre1\", \"content\": \"ok\", \"result\": \"ok\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre2\", \"name\": \"bash\", \"input\": {\"command\": \"pwd\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre2\", \"content\": \"/\", \"result\": \"/\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_shot\", \"name\": \"computer\", \"input\": {\"action\": \"screenshot\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_shot\", \"content\": [{\"type\": \"image\", \"source\": {\"type\": \"base64\", \"media_type\": \"image/png\", \"data\": \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==\"}}]}\n\ndata: {\"type\": \"done\", \"message_count\": 2, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
31
+ /** Full tool chain: block-start(tool_use) -> input_json_delta streaming ->
32
+ * block-stop -> standalone tool_use (resolved input, SAME id) -> tool_result. */
33
+ readonly "tool-call-lifecycle": "data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_2\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_1\", \"block_type\": \"tool_use\", \"name\": \"get_weather\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\"location\\\": \\\"San\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \" Francisco\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_1\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_1\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_2\", \"role\": \"assistant\", \"content_blocks\": [{\"id\": \"toolu_1\", \"type\": \"tool_use\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 20}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_2\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\", \"result\": \"Sunny, 72°F\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_3\", \"role\": \"user\", \"content_blocks\": [{\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 3, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
34
+ /** HITL tool approval. Segment 1 ends on awaiting_approval (no done). Segment 2
35
+ * (post-approve resume stream) delivers the tool_result -> done. */
36
+ readonly "permission-approve": "data: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_4\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 150, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_2\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_2\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\"command\\\": \\\"rm -rf build\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_2\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\n: resume after approval\n\ndata: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_2\", \"content\": \"\", \"result\": \"\"}\n\ndata: {\"type\": \"done\", \"message_count\": 5, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
37
+ /** AskUserQuestion HITL: awaiting_approval(tool_name=AskUserQuestion) must
38
+ * normalize to a `question`, not `approval-request`. Resume delivers the
39
+ * answer as a tool_result for the AskUserQuestion id. */
40
+ readonly "question-answer": "data: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_6\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 120, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_3\", \"block_type\": \"tool_use\", \"name\": \"AskUserQuestion\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_3\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"q1\", \"tool_name\": \"AskUserQuestion\", \"tool_input\": {\"questions\": [{\"question\": \"Which budget?\", \"options\": [{\"label\": \"$5k\", \"description\": \"Conservative start\"}, {\"label\": \"$10k\"}]}]}, \"timeout_seconds\": 0}\n\n: resume after answer\n\ndata: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_3\", \"content\": \"$10k\", \"result\": \"$10k\"}\n\ndata: {\"type\": \"done\", \"message_count\": 4, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
41
+ /** Terminal error: partial text then `error` ends the stream with NO done. */
42
+ readonly "error-before-done": "data: {\"type\": \"metadata\", \"run_id\": 126, \"mode\": \"chat\", \"run_uuid\": \"run-jkl\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_2\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_2\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Working on it\"}}\n\ndata: {\"type\": \"error\", \"error\": \"Connection reset\", \"message\": \"Agent execution failed\"}\n\n";
43
+ /** Terminal-but-unsuccessful: `done` with completion_state !== complete and a
44
+ * pending tool. run_metrics carries the diagnostics block. */
45
+ readonly "done-with-error": "data: {\"type\": \"metadata\", \"run_id\": 127, \"mode\": \"chat\", \"run_uuid\": \"run-mno\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_4\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_4\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 60000, \"input_tokens_used\": 90, \"output_tokens_used\": 12, \"claude_token_cost_usd\": 0.006, \"stop_reason\": null, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"terminal_completion_seen\": false, \"sdk_total_cost_usd\": 0.0065, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"content_block_stop\", \"retry_count\": 0, \"diagnostics\": {\"pending_tool_ids\": [\"toolu_4\"]}}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"stop_reason\": null, \"terminal_completion_seen\": false}\n\n";
46
+ /** Backend-injected cancellation: partial text then `cancelled` ends the stream. */
47
+ readonly cancelled: "data: {\"type\": \"metadata\", \"run_id\": 128, \"mode\": \"chat\", \"run_uuid\": \"run-pqr\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_3\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_3\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Analyzing\"}}\n\ndata: {\"type\": \"cancelled\", \"run_id\": 128}\n\n";
48
+ /** GET /stream rejoin of run 123: re-synthesized metadata + user_message (no id),
49
+ * the SAME block_1 streamed again, a snapshot re-covering block_1 (duplicate),
50
+ * and the SAME permission_request request_id TWICE. Client must render block_1
51
+ * ONCE and show ONE approval. */
52
+ readonly "reconnect-replay-with-duplicates": ": keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"user_message\", \"content\": \"What is the weather?\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
53
+ /** Parser robustness: a glued concatenated-JSON frame (two objects), an
54
+ * invalid/unterminated JSON frame that must be dropped without crashing, then
55
+ * valid frames so the stream recovers to done. */
56
+ readonly "malformed-frame": "data: {\"type\": \"metadata\", \"run_id\": 129, \"mode\": \"chat\", \"run_uuid\": \"run-stu\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_4\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \"ok\"}}{\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \" glued\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"broken\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_4\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
57
+ /** Empty/whitespace payloads: an empty text_delta, a real delta, an empty
58
+ * top-level message_delta. Final text must equal just the real content. */
59
+ readonly "empty-deltas": "data: {\"type\": \"metadata\", \"run_id\": 130, \"mode\": \"chat\", \"run_uuid\": \"run-vwx\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_5\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"real\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_5\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
60
+ /** Keepalive/no-op handling via both layers: `: keep-alive` comment, JSON
61
+ * keep-alive, `: ping` comment, JSON ping — all dropped — around a real text block. */
62
+ readonly keepalive: ": keep-alive\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\n: ping\n\ndata: {\"type\": \"ping\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 131, \"mode\": \"chat\", \"run_uuid\": \"run-yz\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_6\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_6\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hi\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_6\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
63
+ /** Extended thinking: thinking deltas carry `delta.thinking` (NOT `text`),
64
+ * signature_delta is ignored, and the snapshot copy of the thinking block is
65
+ * `{"type": "thinking", "thinking": ...}` with NO id (runtime accumulator
66
+ * shape) — it must dedupe against the streamed content, not re-render. */
67
+ readonly "thinking-run": "data: {\"type\": \"metadata\", \"run_id\": 132, \"mode\": \"chat\", \"run_uuid\": \"run-think\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_7\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_7\", \"block_type\": \"thinking\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \"Let me check\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \" the budget\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"signature_delta\", \"signature\": \"sig_abc\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_7\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_8\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_8\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Done\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_8\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_7\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"thinking\", \"thinking\": \"Let me check the budget\", \"signature\": \"sig_abc\"}, {\"type\": \"text\", \"text\": \"Done\"}], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 9}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_7\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
68
+ /** Snapshot-only output: the CLI-handled-API-error path streams NO content
69
+ * blocks — the synthetic final message_snapshot (id-less text block) is the
70
+ * ONLY carrier of the assistant's output and must render. A replayed copy of
71
+ * the same snapshot must dedupe. */
72
+ readonly "snapshot-only-output": "data: {\"type\": \"metadata\", \"run_id\": 133, \"mode\": \"chat\", \"run_uuid\": \"run-snap\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
73
+ /** Anthropic-side failure: the SDK ResultMessage arrives with is_error=true
74
+ * but the wire STILL ends `done` + completion_state "complete" (the backend
75
+ * marks the run failed from is_error). The client must surface the error and
76
+ * suppress the misleading done. */
77
+ readonly "sdk-error-result": "data: {\"type\": \"metadata\", \"run_id\": 134, \"mode\": \"chat\", \"run_uuid\": \"run-sdkerr\"}\n\ndata: {\"type\": \"sdk_success\", \"subtype\": \"error_during_execution\", \"is_error\": true, \"result\": \"Credit balance is too low\", \"duration_ms\": 1200, \"num_turns\": 1}\n\ndata: {\"type\": \"done\", \"message_count\": 0, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": null, \"terminal_completion_seen\": true}\n\n";
78
+ };
79
+ type FixtureName = keyof typeof FIXTURES;
80
+
81
+ export { FIXTURES, type FixtureName };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Recorded-style wire fixtures for the SSE parser + normalizer.
3
+ *
4
+ * PUBLIC, via `@m8tes/sdk/fixtures`. It is exported rather than kept private for
5
+ * two reasons: it is the single test oracle for the wire protocol (both
6
+ * `@m8tes/sdk` and `@m8tes/react` assert against THIS file, so there is no
7
+ * second copy to drift), and anyone writing tests for their own protocol
8
+ * consumer — a custom `ToolCall` renderer, a bespoke client — needs realistic
9
+ * streams to feed it. It has its own bundle entry, so it never ships inside the
10
+ * runtime bundles.
11
+ *
12
+ * Each value is the RAW SSE text the m8tes V2 backend sends — frames separated
13
+ * by a blank line, including `: comment` keepalive lines. Derived from the
14
+ * canonical streaming contract (workflow embed-stream-contract). These are the
15
+ * test oracle; they match the documented flat Claude-native wire format.
16
+ *
17
+ * NOTE: a few scenarios encode reality the client must tolerate but that we
18
+ * could not 100% confirm without a live stack (see the plan's "open contracts"
19
+ * + the package TODOs): the exact `done-with-error` path, AskUserQuestion
20
+ * rediscovery on rejoin, and concatenated-JSON prevalence. The normalizer is
21
+ * built to handle all of them defensively regardless.
22
+ */
23
+ declare const FIXTURES: {
24
+ /** Happy-path text run: preamble (comment + 2 metadata + json keepalive), one
25
+ * streamed text block, terminal snapshot, run_metrics -> done. */
26
+ readonly "text-run": ": keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\", \"agent_name\": \"PPC Manager\", \"status\": \"running\"}\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_1\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 1840, \"input_tokens_used\": 100, \"output_tokens_used\": 5, \"claude_token_cost_usd\": 0.004, \"stop_reason\": \"end_turn\", \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"terminal_completion_seen\": true, \"sdk_total_cost_usd\": 0.0045, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"message_complete\", \"retry_count\": 0}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
27
+ /** Computer-use screenshot: tool_result whose content is an array holding a
28
+ * base64 image block (the desktop MCP server's `_png_to_image_block` shape).
29
+ * Platform renders these inline (BubbleTimeline tool_result case). */
30
+ readonly "screenshot-run": "data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_s1\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre1\", \"name\": \"bash\", \"input\": {\"command\": \"ls\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre1\", \"content\": \"ok\", \"result\": \"ok\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_pre2\", \"name\": \"bash\", \"input\": {\"command\": \"pwd\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_pre2\", \"content\": \"/\", \"result\": \"/\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_shot\", \"name\": \"computer\", \"input\": {\"action\": \"screenshot\"}}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_shot\", \"content\": [{\"type\": \"image\", \"source\": {\"type\": \"base64\", \"media_type\": \"image/png\", \"data\": \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==\"}}]}\n\ndata: {\"type\": \"done\", \"message_count\": 2, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
31
+ /** Full tool chain: block-start(tool_use) -> input_json_delta streaming ->
32
+ * block-stop -> standalone tool_use (resolved input, SAME id) -> tool_result. */
33
+ readonly "tool-call-lifecycle": "data: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_2\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_1\", \"block_type\": \"tool_use\", \"name\": \"get_weather\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\"location\\\": \\\"San\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_1\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \" Francisco\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_1\"}\n\ndata: {\"type\": \"tool_use\", \"id\": \"toolu_1\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_2\", \"role\": \"assistant\", \"content_blocks\": [{\"id\": \"toolu_1\", \"type\": \"tool_use\", \"name\": \"get_weather\", \"input\": {\"location\": \"San Francisco\"}}], \"usage\": {\"input_tokens\": 200, \"output_tokens\": 20}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_2\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\", \"result\": \"Sunny, 72°F\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_3\", \"role\": \"user\", \"content_blocks\": [{\"type\": \"tool_result\", \"tool_use_id\": \"toolu_1\", \"content\": \"Sunny, 72°F\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 3, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
34
+ /** HITL tool approval. Segment 1 ends on awaiting_approval (no done). Segment 2
35
+ * (post-approve resume stream) delivers the tool_result -> done. */
36
+ readonly "permission-approve": "data: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_4\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 150, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_2\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"toolu_2\", \"delta\": {\"type\": \"input_json_delta\", \"partial_json\": \"{\\\"command\\\": \\\"rm -rf build\\\"}\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_2\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\n: resume after approval\n\ndata: {\"type\": \"metadata\", \"run_id\": 124, \"mode\": \"chat\", \"run_uuid\": \"run-def\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_2\", \"content\": \"\", \"result\": \"\"}\n\ndata: {\"type\": \"done\", \"message_count\": 5, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
37
+ /** AskUserQuestion HITL: awaiting_approval(tool_name=AskUserQuestion) must
38
+ * normalize to a `question`, not `approval-request`. Resume delivers the
39
+ * answer as a tool_result for the AskUserQuestion id. */
40
+ readonly "question-answer": "data: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_6\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 120, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_3\", \"block_type\": \"tool_use\", \"name\": \"AskUserQuestion\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_3\"}\n\ndata: {\"type\": \"awaiting_approval\", \"request_id\": \"q1\", \"tool_name\": \"AskUserQuestion\", \"tool_input\": {\"questions\": [{\"question\": \"Which budget?\", \"options\": [{\"label\": \"$5k\", \"description\": \"Conservative start\"}, {\"label\": \"$10k\"}]}]}, \"timeout_seconds\": 0}\n\n: resume after answer\n\ndata: {\"type\": \"metadata\", \"run_id\": 125, \"mode\": \"chat\", \"run_uuid\": \"run-ghi\"}\n\ndata: {\"type\": \"tool_result\", \"tool_use_id\": \"toolu_3\", \"content\": \"$10k\", \"result\": \"$10k\"}\n\ndata: {\"type\": \"done\", \"message_count\": 4, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
41
+ /** Terminal error: partial text then `error` ends the stream with NO done. */
42
+ readonly "error-before-done": "data: {\"type\": \"metadata\", \"run_id\": 126, \"mode\": \"chat\", \"run_uuid\": \"run-jkl\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_2\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_2\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Working on it\"}}\n\ndata: {\"type\": \"error\", \"error\": \"Connection reset\", \"message\": \"Agent execution failed\"}\n\n";
43
+ /** Terminal-but-unsuccessful: `done` with completion_state !== complete and a
44
+ * pending tool. run_metrics carries the diagnostics block. */
45
+ readonly "done-with-error": "data: {\"type\": \"metadata\", \"run_id\": 127, \"mode\": \"chat\", \"run_uuid\": \"run-mno\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"toolu_4\", \"block_type\": \"tool_use\", \"name\": \"Bash\"}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"toolu_4\"}\n\ndata: {\"type\": \"run_metrics\", \"model\": \"claude-opus-4-8\", \"execution_time_ms\": 60000, \"input_tokens_used\": 90, \"output_tokens_used\": 12, \"claude_token_cost_usd\": 0.006, \"stop_reason\": null, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"terminal_completion_seen\": false, \"sdk_total_cost_usd\": 0.0065, \"code_version\": \"v2-46\", \"message_count\": 1, \"last_event_type\": \"content_block_stop\", \"retry_count\": 0, \"diagnostics\": {\"pending_tool_ids\": [\"toolu_4\"]}}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"incomplete_tool_loop\", \"unresolved_tool_use_ids\": [\"toolu_4\"], \"stop_reason\": null, \"terminal_completion_seen\": false}\n\n";
46
+ /** Backend-injected cancellation: partial text then `cancelled` ends the stream. */
47
+ readonly cancelled: "data: {\"type\": \"metadata\", \"run_id\": 128, \"mode\": \"chat\", \"run_uuid\": \"run-pqr\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_3\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_3\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Analyzing\"}}\n\ndata: {\"type\": \"cancelled\", \"run_id\": 128}\n\n";
48
+ /** GET /stream rejoin of run 123: re-synthesized metadata + user_message (no id),
49
+ * the SAME block_1 streamed again, a snapshot re-covering block_1 (duplicate),
50
+ * and the SAME permission_request request_id TWICE. Client must render block_1
51
+ * ONCE and show ONE approval. */
52
+ readonly "reconnect-replay-with-duplicates": ": keep-alive\n\ndata: {\"type\": \"metadata\", \"run_id\": 123, \"mode\": \"chat\", \"run_uuid\": \"run-abc\"}\n\ndata: {\"type\": \"user_message\", \"content\": \"What is the weather?\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_1\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hello\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_1\", \"delta\": {\"type\": \"text_delta\", \"text\": \" world\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_1\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_1\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Hello world\"}], \"usage\": {\"input_tokens\": 100, \"output_tokens\": 5}}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"permission_request\", \"request_id\": \"r1\", \"tool_name\": \"Bash\", \"tool_input\": {\"command\": \"rm -rf build\"}, \"timeout_seconds\": 55}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
53
+ /** Parser robustness: a glued concatenated-JSON frame (two objects), an
54
+ * invalid/unterminated JSON frame that must be dropped without crashing, then
55
+ * valid frames so the stream recovers to done. */
56
+ readonly "malformed-frame": "data: {\"type\": \"metadata\", \"run_id\": 129, \"mode\": \"chat\", \"run_uuid\": \"run-stu\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_4\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \"ok\"}}{\"type\": \"content_block_delta\", \"id\": \"block_4\", \"delta\": {\"type\": \"text_delta\", \"text\": \" glued\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"broken\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_4\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
57
+ /** Empty/whitespace payloads: an empty text_delta, a real delta, an empty
58
+ * top-level message_delta. Final text must equal just the real content. */
59
+ readonly "empty-deltas": "data: {\"type\": \"metadata\", \"run_id\": 130, \"mode\": \"chat\", \"run_uuid\": \"run-vwx\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_5\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_5\", \"delta\": {\"type\": \"text_delta\", \"text\": \"real\"}}\n\ndata: {\"type\": \"message_delta\", \"delta\": {\"text\": \"\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_5\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
60
+ /** Keepalive/no-op handling via both layers: `: keep-alive` comment, JSON
61
+ * keep-alive, `: ping` comment, JSON ping — all dropped — around a real text block. */
62
+ readonly keepalive: ": keep-alive\n\ndata: {\"type\": \"keep-alive\", \"message\": \"Connection established\"}\n\n: ping\n\ndata: {\"type\": \"ping\"}\n\ndata: {\"type\": \"metadata\", \"run_id\": 131, \"mode\": \"chat\", \"run_uuid\": \"run-yz\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_6\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_6\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Hi\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_6\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
63
+ /** Extended thinking: thinking deltas carry `delta.thinking` (NOT `text`),
64
+ * signature_delta is ignored, and the snapshot copy of the thinking block is
65
+ * `{"type": "thinking", "thinking": ...}` with NO id (runtime accumulator
66
+ * shape) — it must dedupe against the streamed content, not re-render. */
67
+ readonly "thinking-run": "data: {\"type\": \"metadata\", \"run_id\": 132, \"mode\": \"chat\", \"run_uuid\": \"run-think\"}\n\ndata: {\"type\": \"message_start\", \"message\": {\"id\": \"msg_7\", \"role\": \"assistant\", \"content\": [], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 0}}}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_7\", \"block_type\": \"thinking\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \"Let me check\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"thinking_delta\", \"thinking\": \" the budget\"}}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_7\", \"delta\": {\"type\": \"signature_delta\", \"signature\": \"sig_abc\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_7\"}\n\ndata: {\"type\": \"content_block_start\", \"id\": \"block_8\", \"block_type\": \"text\"}\n\ndata: {\"type\": \"content_block_delta\", \"id\": \"block_8\", \"delta\": {\"type\": \"text_delta\", \"text\": \"Done\"}}\n\ndata: {\"type\": \"content_block_stop\", \"id\": \"block_8\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_7\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"thinking\", \"thinking\": \"Let me check the budget\", \"signature\": \"sig_abc\"}, {\"type\": \"text\", \"text\": \"Done\"}], \"usage\": {\"input_tokens\": 80, \"output_tokens\": 9}}\n\ndata: {\"type\": \"message_stop\", \"message_id\": \"msg_7\"}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
68
+ /** Snapshot-only output: the CLI-handled-API-error path streams NO content
69
+ * blocks — the synthetic final message_snapshot (id-less text block) is the
70
+ * ONLY carrier of the assistant's output and must render. A replayed copy of
71
+ * the same snapshot must dedupe. */
72
+ readonly "snapshot-only-output": "data: {\"type\": \"metadata\", \"run_id\": 133, \"mode\": \"chat\", \"run_uuid\": \"run-snap\"}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"message_snapshot\", \"message_id\": \"msg_8\", \"role\": \"assistant\", \"content_blocks\": [{\"type\": \"text\", \"text\": \"Final answer via snapshot\"}]}\n\ndata: {\"type\": \"done\", \"message_count\": 1, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": \"end_turn\", \"terminal_completion_seen\": true}\n\n";
73
+ /** Anthropic-side failure: the SDK ResultMessage arrives with is_error=true
74
+ * but the wire STILL ends `done` + completion_state "complete" (the backend
75
+ * marks the run failed from is_error). The client must surface the error and
76
+ * suppress the misleading done. */
77
+ readonly "sdk-error-result": "data: {\"type\": \"metadata\", \"run_id\": 134, \"mode\": \"chat\", \"run_uuid\": \"run-sdkerr\"}\n\ndata: {\"type\": \"sdk_success\", \"subtype\": \"error_during_execution\", \"is_error\": true, \"result\": \"Credit balance is too low\", \"duration_ms\": 1200, \"num_turns\": 1}\n\ndata: {\"type\": \"done\", \"message_count\": 0, \"completion_state\": \"complete\", \"unresolved_tool_use_ids\": [], \"stop_reason\": null, \"terminal_completion_seen\": true}\n\n";
78
+ };
79
+ type FixtureName = keyof typeof FIXTURES;
80
+
81
+ export { FIXTURES, type FixtureName };