@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.
- package/CHANGELOG.md +100 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/chunk-UFQQNUFE.js +1083 -0
- package/dist/chunk-UFQQNUFE.js.map +1 -0
- package/dist/fixtures.cjs +297 -0
- package/dist/fixtures.cjs.map +1 -0
- package/dist/fixtures.d.cts +81 -0
- package/dist/fixtures.d.ts +81 -0
- package/dist/fixtures.js +295 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/index.cjs +1783 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +937 -0
- package/dist/index.d.ts +937 -0
- package/dist/index.js +672 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/index.cjs +1109 -0
- package/dist/protocol/index.cjs.map +1 -0
- package/dist/protocol/index.d.cts +576 -0
- package/dist/protocol/index.d.ts +576 -0
- package/dist/protocol/index.js +3 -0
- package/dist/protocol/index.js.map +1 -0
- package/package.json +64 -0
|
@@ -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 };
|