PluginProbe
ZIP AI – AI Website Builder & AI Agent (Beta) / 0.0.4
ZIP AI – AI Website Builder & AI Agent (Beta) v0.0.4
0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
zip-ai / src / utils / clientTerminalSnapshot.js

clientTerminalSnapshot.js in ZIP AI – AI Website Builder & AI Agent (Beta) 0.0.4, at src/utils/clientTerminalSnapshot.js

69 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * clientTerminalSnapshot — synthesizes a canonical TurnState on the client
3 * for transport-layer failures the brain never observed.
4 *
5 * Why this exists (Phase 4 polish):
6 * Pre-brain failures (DNS, CORS, Laravel 5xx, SSE abort, brain queue
7 * unavailable) used to surface as ad-hoc strings: a red `network error`
8 * banner bound to the free-form Axios `error.message`, plus a hardcoded
9 * system-role bubble `"Sorry, I encountered an error. Please try again."`.
10 * Neither path touched turnSnapshot, which re-introduced the same
11 * silence-as-success / prose-as-truth class this contract was built to
12 * eliminate.
13 *
14 * Contract:
15 * - The shape MUST match workers/agent-brain/src/types/contract.ts
16 * (TurnStateSchema). If brain-side Zod rejects this shape at the
17 * Laravel/React boundary in future, add a matching client synth here.
18 * - `status` collapses to 'unresolved' for transport_error (we don't
19 * know what happened server-side) and 'aborted' for client_abort
20 * (user intent).
21 * - `tool_calls` is always [] — the client has no authority to fabricate
22 * tool execution history.
23 * - `turn_id` is prefixed with `client_` so snapshots from this path are
24 * trivially distinguishable from brain-authored ones during triage.
25 */
26
27 export const TURN_STATE_SCHEMA_VERSION = 1;
28
29 /**
30 * @param {Object} params
31 * @param {'transport_error' | 'client_abort'} params.reason
32 * @param {string | null} params.sessionId
33 * @param {string | null} [params.turnId] - if the transport failure happened
34 * after Laravel assigned a turn_id,
35 * pass it through so reconciliation
36 * can align.
37 * @param {string | null} [params.detail] - raw error message, stored as the
38 * terminal.last_tool_error.message
39 * with a sentinel tool name for
40 * devtools/triage visibility.
41 */
42 export function buildClientTerminalSnapshot({ reason, sessionId, turnId = null, detail = null }) {
43 const now = new Date().toISOString();
44 const status = reason === 'client_abort' ? 'aborted' : 'unresolved';
45
46 return {
47 schema_version: TURN_STATE_SCHEMA_VERSION,
48 turn_id: turnId || `client_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
49 session_id: sessionId || '',
50 started_at: now,
51 ended_at: now,
52 status,
53 stage: 'unknown',
54 terminal: {
55 reason,
56 failure_class: null,
57 tool_error_count: 0,
58 unresolved_todo_count: 0,
59 last_stage: 'unknown',
60 last_tool_error: detail
61 ? { tool: '__transport__', call_id: 'client', message: String(detail) }
62 : null,
63 },
64 plan_state: null,
65 active_todos: [],
66 tool_calls: [],
67 };
68 }
69