@runtypelabs/persona 4.21.1 → 4.22.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.
Files changed (129) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-B_JdVK9o.d.cts → types-9Vxm-PPz.d.cts} +136 -6
  4. package/dist/animations/{types-B_JdVK9o.d.ts → types-9Vxm-PPz.d.ts} +136 -6
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +136 -6
  8. package/dist/animations-extra.d.ts +136 -6
  9. package/dist/{approval-ui-RNNBR5R3.js → approval-ui-K7R5Q5OC.js} +1 -1
  10. package/dist/approval-ui.cjs +2 -2
  11. package/dist/approval-ui.d.cts +221 -16
  12. package/dist/approval-ui.d.ts +221 -16
  13. package/dist/approval-ui.js +2 -2
  14. package/dist/artifacts-ui-F4N6VMKF.js +7 -0
  15. package/dist/artifacts-ui.cjs +1 -1
  16. package/dist/artifacts-ui.d.cts +221 -16
  17. package/dist/artifacts-ui.d.ts +221 -16
  18. package/dist/artifacts-ui.js +1 -1
  19. package/dist/chunk-NQLDCJAP.js +4 -0
  20. package/dist/codegen.cjs +1 -1
  21. package/dist/codegen.js +1 -1
  22. package/dist/context-mentions.d.cts +221 -16
  23. package/dist/context-mentions.d.ts +221 -16
  24. package/dist/event-stream-view-GL3ADRY2.js +1 -0
  25. package/dist/event-stream-view.cjs +1 -1
  26. package/dist/event-stream-view.d.cts +221 -16
  27. package/dist/event-stream-view.d.ts +221 -16
  28. package/dist/event-stream-view.js +1 -1
  29. package/dist/forms-ui.d.cts +234 -25
  30. package/dist/forms-ui.d.ts +234 -25
  31. package/dist/history-view.d.cts +136 -6
  32. package/dist/history-view.d.ts +136 -6
  33. package/dist/index.cjs +70 -70
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +302 -32
  36. package/dist/index.d.ts +302 -32
  37. package/dist/index.global.js +54 -54
  38. package/dist/index.global.js.map +1 -1
  39. package/dist/index.js +69 -69
  40. package/dist/index.js.map +1 -1
  41. package/dist/launcher.global.js +2 -2
  42. package/dist/launcher.global.js.map +1 -1
  43. package/dist/session-reconnect.d.cts +221 -16
  44. package/dist/session-reconnect.d.ts +221 -16
  45. package/dist/smart-dom-reader.d.cts +221 -16
  46. package/dist/smart-dom-reader.d.ts +221 -16
  47. package/dist/testing.cjs +3 -3
  48. package/dist/testing.d.cts +3 -4
  49. package/dist/testing.d.ts +3 -4
  50. package/dist/testing.js +3 -3
  51. package/dist/theme-editor-preview.cjs +73 -73
  52. package/dist/theme-editor-preview.d.cts +221 -16
  53. package/dist/theme-editor-preview.d.ts +221 -16
  54. package/dist/theme-editor-preview.js +51 -51
  55. package/dist/theme-editor.cjs +4 -4
  56. package/dist/theme-editor.d.cts +221 -16
  57. package/dist/theme-editor.d.ts +221 -16
  58. package/dist/theme-editor.js +2 -2
  59. package/dist/theme-reference.cjs +1 -1
  60. package/dist/theme-reference.d.cts +65 -1
  61. package/dist/theme-reference.d.ts +65 -1
  62. package/dist/theme-reference.js +1 -1
  63. package/dist/voice-runtime.d.cts +6 -2
  64. package/dist/voice-runtime.d.ts +6 -2
  65. package/dist/webmcp-polyfill.js +1 -4
  66. package/dist/webmcp-runtime-JI7T4QYF.js +6 -0
  67. package/dist/webmcp-runtime.cjs +2 -2
  68. package/dist/webmcp-runtime.d.cts +34 -2
  69. package/dist/webmcp-runtime.d.ts +34 -2
  70. package/dist/webmcp-runtime.js +2 -2
  71. package/package.json +2 -2
  72. package/src/ask-user-question-tool.ts +1 -1
  73. package/src/client-history-rest.test.ts +2 -1
  74. package/src/client-visitor-history.test.ts +20 -4
  75. package/src/client.composer-options.test.ts +1 -1
  76. package/src/client.interrupt.test.ts +2 -2
  77. package/src/client.test.ts +477 -915
  78. package/src/client.ts +134 -494
  79. package/src/client.unified-tools.test.ts +76 -0
  80. package/src/components/artifact-preview.ts +5 -0
  81. package/src/components/event-stream-badge-theming.test.ts +162 -0
  82. package/src/components/event-stream-view.test.ts +76 -76
  83. package/src/components/event-stream-view.ts +55 -20
  84. package/src/components/tool-bubble.test.ts +12 -0
  85. package/src/components/tool-bubble.ts +13 -2
  86. package/src/event-stream-view-bundle.test.ts +2 -2
  87. package/src/generated/runtype-openapi-contract.ts +137 -1
  88. package/src/index-core.ts +2 -0
  89. package/src/internal/runtype-history-provider.test.ts +2 -2
  90. package/src/runtime/init.registry.test.ts +56 -0
  91. package/src/runtime/init.ts +17 -0
  92. package/src/session-history.test.ts +1 -1
  93. package/src/session.quote.test.ts +1 -1
  94. package/src/session.resubmit-from.test.ts +1 -1
  95. package/src/session.test.ts +5 -5
  96. package/src/session.ts +95 -36
  97. package/src/suggest-replies-tool.ts +1 -1
  98. package/src/testing/mock-stream.test.ts +37 -16
  99. package/src/testing/mock-stream.ts +14 -9
  100. package/src/types/theme.ts +41 -1
  101. package/src/types.ts +57 -15
  102. package/src/ui.ask-user-question-plugin.test.ts +7 -7
  103. package/src/ui.composer-defer-one.test.ts +6 -34
  104. package/src/ui.composer-draft-persistence.test.ts +1 -1
  105. package/src/ui.composer-quote.test.ts +1 -1
  106. package/src/ui.message-history-actions.test.ts +1 -1
  107. package/src/ui.reasoning-display.test.ts +136 -2
  108. package/src/ui.streaming-coalescing.test.ts +10 -13
  109. package/src/ui.ts +101 -35
  110. package/src/ui.typing-indicator.test.ts +216 -0
  111. package/src/ui.voice-custom-provider.test.ts +211 -0
  112. package/src/utils/__snapshots__/tokens-parity.test.ts.snap +1740 -0
  113. package/src/utils/event-stream-buffer.test.ts +13 -13
  114. package/src/utils/event-stream-capture.test.ts +20 -20
  115. package/src/utils/formatting.ts +22 -0
  116. package/src/utils/theme.ts +16 -0
  117. package/src/utils/throughput-tracker.test.ts +100 -142
  118. package/src/utils/throughput-tracker.ts +18 -132
  119. package/src/utils/tokens.ts +59 -0
  120. package/src/utils/voice-support.ts +18 -1
  121. package/src/voice/voice-turn-tracker.ts +18 -0
  122. package/src/webmcp-bridge.test.ts +132 -23
  123. package/src/webmcp-bridge.ts +27 -3
  124. package/src/webmcp-runtime-entry.ts +71 -11
  125. package/dist/artifacts-ui-J6AKUGTS.js +0 -7
  126. package/dist/chunk-HBE7LFNT.js +0 -4
  127. package/dist/event-stream-view-73NWKWVQ.js +0 -1
  128. package/dist/webmcp-runtime-P3CHZRHF.js +0 -6
  129. package/src/utils/__fixtures__/unified-translator.oracle.ts +0 -717
@@ -1,717 +0,0 @@
1
- /**
2
- * TEST ORACLE — vendored copy of the runtype-core `createUnifiedEventWrite`
3
- * translator (the api-side legacy → wire 33-event encoder).
4
- *
5
- * NOT shipped. Used only by legacy-wire handler tests as the inverse
6
- * reference: `legacy frames → THIS oracle → wire frames → client handlers
7
- * → legacy frames'` must be semantically equal to the original. Keeping a real
8
- * copy here means the round-trip test fails loudly if the api mapping and the
9
- * widget bridge ever drift.
10
- *
11
- * The only edit vs the api source is the removed `getLogger` import (the
12
- * per-frame error log is a no-op here).
13
- */
14
-
15
- type Json = Record<string, unknown>;
16
-
17
- type ExecutionKind = "agent" | "flow";
18
-
19
- interface UnifiedEventWriteOptions {
20
- executionId?: string;
21
- }
22
-
23
- const ENVELOPE_KEYS = new Set(["type", "executionId", "seq"]);
24
-
25
- function omitEnvelope(data: Json): Json {
26
- const out: Json = {};
27
- for (const [k, v] of Object.entries(data)) {
28
- if (!ENVELOPE_KEYS.has(k)) out[k] = v;
29
- }
30
- return out;
31
- }
32
-
33
- class UnifiedEventTranslator {
34
- private executionId: string;
35
- private seq = 0;
36
- private kind: ExecutionKind = "flow";
37
- private blockCounter = 0;
38
- private openText: string | null = null;
39
- private openTextBuffer = "";
40
- private openReasoning: string | null = null;
41
- private openReasoningBuffer = "";
42
-
43
- constructor(
44
- private readonly sink: (chunk: string) => void,
45
- options?: UnifiedEventWriteOptions
46
- ) {
47
- this.executionId = options?.executionId ?? "";
48
- }
49
-
50
- private mint(prefix: string): string {
51
- this.blockCounter += 1;
52
- return `${prefix}_${this.blockCounter}`;
53
- }
54
-
55
- private out(type: string, payload: Json): void {
56
- const frame: Json = { type, executionId: this.executionId, seq: this.seq, ...payload };
57
- this.seq += 1;
58
- this.sink(`event: ${type}\ndata: ${JSON.stringify(frame)}\n\n`);
59
- }
60
-
61
- /**
62
- * Parent model tool-call id stamped by the `tool_nested` FilteredStream as
63
- * `toolContext.toolId` (a flow running as a tool enriches its frames this way).
64
- * Surfaced on the text/reasoning channel as `parentToolCallId` so consumers can
65
- * route nested streamed output into the parent tool's row (PR #4602). Undefined
66
- * for top-level output.
67
- */
68
- private parentToolCallId(data: Json): string | undefined {
69
- const toolContext = data.toolContext;
70
- if (toolContext && typeof toolContext === "object") {
71
- const toolId = (toolContext as Json).toolId;
72
- if (typeof toolId === "string" && toolId) return toolId;
73
- }
74
- return undefined;
75
- }
76
-
77
- private emitTextDelta(delta: unknown, parentToolCallId?: string): void {
78
- if (delta == null || delta === "") return;
79
- if (!this.openText) {
80
- this.openText = this.mint("text");
81
- this.openTextBuffer = "";
82
- this.out("text_start", {
83
- id: this.openText,
84
- ...(this.kind === "agent" ? { role: "assistant" } : {}),
85
- ...(parentToolCallId ? { parentToolCallId } : {}),
86
- });
87
- }
88
- const text = String(delta);
89
- this.openTextBuffer += text;
90
- this.out("text_delta", { id: this.openText, delta: text });
91
- }
92
-
93
- private closeText(): void {
94
- if (!this.openText) return;
95
- // U2: carry the assembled text so a non-streaming consumer can read the
96
- // finished message off `text_complete` instead of re-concatenating deltas.
97
- this.out("text_complete", {
98
- id: this.openText,
99
- ...(this.openTextBuffer ? { text: this.openTextBuffer } : {}),
100
- });
101
- this.openText = null;
102
- this.openTextBuffer = "";
103
- }
104
-
105
- private ensureReasoningOpen(scope?: "turn" | "loop", parentToolCallId?: string): void {
106
- if (this.openReasoning) return;
107
- this.openReasoning = this.mint("reason");
108
- this.openReasoningBuffer = "";
109
- this.out("reasoning_start", {
110
- id: this.openReasoning,
111
- ...(scope ? { scope } : {}),
112
- ...(parentToolCallId ? { parentToolCallId } : {}),
113
- });
114
- }
115
-
116
- private emitReasoningDelta(delta: unknown, parentToolCallId?: string): void {
117
- if (delta == null || delta === "") return;
118
- this.ensureReasoningOpen(undefined, parentToolCallId);
119
- const text = String(delta);
120
- this.openReasoningBuffer += text;
121
- this.out("reasoning_delta", { id: this.openReasoning, delta: text });
122
- }
123
-
124
- private closeReasoning(): void {
125
- if (!this.openReasoning) return;
126
- // U2: carry the assembled reasoning text (parity with text_complete).
127
- this.out("reasoning_complete", {
128
- id: this.openReasoning,
129
- ...(this.openReasoningBuffer ? { text: this.openReasoningBuffer } : {}),
130
- });
131
- this.openReasoning = null;
132
- this.openReasoningBuffer = "";
133
- }
134
-
135
- private closeChannels(): void {
136
- this.closeText();
137
- this.closeReasoning();
138
- }
139
-
140
- private fallbackInfo(data: Json): Json | undefined {
141
- const used = data.usedFallback === true;
142
- const executions = Array.isArray(data.fallbackExecutions) ? data.fallbackExecutions : [];
143
- if (!used && executions.length === 0) return undefined;
144
- const attempts = executions.map((entry: unknown, index: number) => {
145
- const e = (entry ?? {}) as Json;
146
- return {
147
- attempt: typeof e.attempt === "number" ? e.attempt : index + 1,
148
- type: typeof e.fallbackType === "string" ? e.fallbackType : "model",
149
- ...(e.fallbackModel != null ? { model: e.fallbackModel } : {}),
150
- success: true,
151
- };
152
- });
153
- return {
154
- fallback: {
155
- used,
156
- ...(data.modelUsed != null
157
- ? { model: data.modelUsed }
158
- : data.fallbackModel != null
159
- ? { model: data.fallbackModel }
160
- : {}),
161
- attempts,
162
- exhausted: false,
163
- },
164
- };
165
- }
166
-
167
- private handle(type: string, data: Json): void {
168
- switch (type) {
169
- case "agent_start":
170
- this.kind = "agent";
171
- if (typeof data.executionId === "string") this.executionId = data.executionId;
172
- this.out("execution_start", {
173
- kind: "agent",
174
- startedAt: data.startedAt ?? new Date().toISOString(),
175
- agentId: data.agentId,
176
- agentName: data.agentName,
177
- maxTurns: data.maxTurns,
178
- config: data.config,
179
- });
180
- break;
181
- case "agent_iteration_start":
182
- case "agent_iteration_complete":
183
- break;
184
- case "agent_turn_start":
185
- this.closeChannels();
186
- this.out("turn_start", {
187
- id: data.turnId,
188
- iteration: data.iteration,
189
- turnIndex: data.turnIndex,
190
- role: data.role ?? "assistant",
191
- });
192
- break;
193
- case "agent_turn_delta": {
194
- const contentType = data.contentType;
195
- if (contentType === "thinking") this.emitReasoningDelta(data.delta);
196
- else if (contentType === "tool_input")
197
- this.out("tool_input_delta", {
198
- toolCallId: data.turnId ?? this.mint("toolinput"),
199
- delta: String(data.delta ?? ""),
200
- });
201
- else this.emitTextDelta(data.delta);
202
- break;
203
- }
204
- case "agent_turn_complete":
205
- this.closeChannels();
206
- this.out("turn_complete", {
207
- id: data.turnId,
208
- iteration: data.iteration,
209
- role: data.role ?? "assistant",
210
- content: data.content,
211
- tokens: data.tokens,
212
- cost: data.cost,
213
- stopReason: data.stopReason,
214
- completedAt: data.completedAt,
215
- });
216
- break;
217
- case "agent_tool_start":
218
- this.out("tool_start", {
219
- toolCallId: data.toolCallId,
220
- toolName: data.toolName,
221
- toolType: data.toolType ?? "builtin",
222
- iteration: data.iteration,
223
- parameters: data.parameters,
224
- hiddenParameterNames: data.hiddenParameterNames,
225
- origin: data.origin,
226
- pageOrigin: data.pageOrigin,
227
- });
228
- break;
229
- case "agent_tool_delta":
230
- this.out("tool_output_delta", {
231
- toolCallId: data.toolCallId,
232
- delta: String(data.delta ?? ""),
233
- });
234
- break;
235
- case "agent_tool_input_delta":
236
- this.out("tool_input_delta", {
237
- toolCallId: data.toolCallId,
238
- delta: String(data.delta ?? ""),
239
- });
240
- break;
241
- case "agent_tool_input_complete":
242
- this.out("tool_input_complete", {
243
- toolCallId: data.toolCallId,
244
- toolName: data.toolName,
245
- parameters: (data.parameters as Json) ?? {},
246
- hiddenParameterNames: data.hiddenParameterNames,
247
- });
248
- break;
249
- case "agent_tool_complete":
250
- this.out("tool_complete", {
251
- toolCallId: data.toolCallId,
252
- toolName: data.toolName,
253
- success: data.success ?? true,
254
- result: data.result,
255
- executionTime: data.executionTime,
256
- iteration: data.iteration,
257
- });
258
- break;
259
- case "agent_media":
260
- this.emitMedia(data);
261
- break;
262
- case "agent_approval_start":
263
- this.out("approval_start", {
264
- approvalId: data.approvalId,
265
- toolCallId: data.toolCallId,
266
- toolName: data.toolName,
267
- toolType: data.toolType,
268
- description: data.description,
269
- reason: data.reason,
270
- parameters: data.parameters,
271
- timeout: data.timeout,
272
- startedAt: data.startedAt,
273
- iteration: data.iteration,
274
- });
275
- break;
276
- case "agent_approval_complete":
277
- this.out("approval_complete", {
278
- approvalId: data.approvalId,
279
- decision: data.decision,
280
- completedAt: data.completedAt,
281
- resolvedBy: data.resolvedBy,
282
- });
283
- break;
284
- case "agent_await":
285
- this.out("await", {
286
- toolId: data.toolId,
287
- toolCallId: data.toolCallId,
288
- toolName: data.toolName,
289
- parameters: data.parameters,
290
- awaitedAt: data.awaitedAt,
291
- origin: data.origin,
292
- pageOrigin: data.pageOrigin,
293
- });
294
- break;
295
- case "agent_reflection": {
296
- const id = this.mint("reason");
297
- this.out("reasoning_start", { id, scope: "loop" });
298
- this.out("reasoning_complete", { id, text: data.reflection, scope: "loop" });
299
- break;
300
- }
301
- case "agent_skill_loaded": {
302
- const toolCallId = (data.toolCallId as string) ?? this.mint("skill");
303
- const toolName = `skill:${String(data.skill ?? "unknown")}`;
304
- this.out("tool_start", {
305
- toolCallId,
306
- toolName,
307
- toolType: "builtin",
308
- iteration: data.iteration,
309
- });
310
- this.out("tool_complete", {
311
- toolCallId,
312
- toolName,
313
- success: true,
314
- result: {
315
- kind: "skill_loaded",
316
- skill: data.skill,
317
- activatedCapabilities: data.activatedCapabilities ?? [],
318
- },
319
- iteration: data.iteration,
320
- });
321
- break;
322
- }
323
- case "agent_skill_proposed": {
324
- const toolCallId = (data.toolCallId as string) ?? this.mint("propose");
325
- this.out("tool_start", {
326
- toolCallId,
327
- toolName: "propose_skill",
328
- toolType: "builtin",
329
- iteration: data.iteration,
330
- });
331
- this.out("tool_complete", {
332
- toolCallId,
333
- toolName: "propose_skill",
334
- success: true,
335
- result: {
336
- kind: "skill_proposed",
337
- skill: data.skill,
338
- outcome: data.outcome,
339
- proposalId: data.proposalId,
340
- },
341
- iteration: data.iteration,
342
- });
343
- break;
344
- }
345
- case "agent_complete":
346
- this.closeChannels();
347
- if (data.success === false || data.stopReason === "error") {
348
- this.out("execution_error", {
349
- kind: "agent",
350
- error: this.toErrorPayload(data.error ?? "Agent execution failed"),
351
- completedAt: data.completedAt,
352
- });
353
- } else {
354
- this.out("execution_complete", {
355
- kind: "agent",
356
- success: data.success ?? true,
357
- iterations: data.iterations,
358
- stopReason: data.stopReason,
359
- completedAt: data.completedAt,
360
- durationMs: data.duration,
361
- finalOutput: data.finalOutput,
362
- totalCost: data.totalCost,
363
- totalTokens: data.totalTokens,
364
- });
365
- }
366
- break;
367
- case "agent_error":
368
- if (data.recoverable)
369
- this.out("error", { error: this.toErrorPayload(data.error), recoverable: true });
370
- else this.out("execution_error", { kind: this.kind, error: this.toErrorPayload(data.error) });
371
- break;
372
- case "agent_ping":
373
- this.out("ping", { timestamp: data.timestamp ?? new Date().toISOString() });
374
- break;
375
-
376
- case "flow_start":
377
- this.kind = "flow";
378
- if (typeof data.executionId === "string") this.executionId = data.executionId;
379
- this.out("execution_start", {
380
- kind: "flow",
381
- startedAt: data.startedAt ?? new Date().toISOString(),
382
- flowId: data.flowId,
383
- flowName: data.flowName,
384
- totalSteps: data.totalSteps,
385
- source: data.source,
386
- });
387
- break;
388
- case "flow_complete":
389
- this.closeChannels();
390
- this.out("execution_complete", {
391
- kind: "flow",
392
- success: data.success ?? true,
393
- completedAt: data.completedAt,
394
- durationMs: data.duration ?? data.executionTime,
395
- finalOutput: data.finalOutput,
396
- totalSteps: data.totalSteps,
397
- successfulSteps: data.successfulSteps,
398
- failedSteps: data.failedSteps,
399
- });
400
- break;
401
- case "flow_error":
402
- this.closeChannels();
403
- this.out("execution_error", {
404
- kind: "flow",
405
- error: this.toErrorPayload(data.error),
406
- code: data.code,
407
- upgradeUrl: data.upgradeUrl,
408
- });
409
- break;
410
- case "flow_await":
411
- this.out("await", {
412
- toolId: data.toolId,
413
- toolCallId: data.toolCallId,
414
- toolName: data.toolName,
415
- parameters: data.parameters,
416
- awaitedAt: data.awaitedAt,
417
- origin: data.origin,
418
- pageOrigin: data.pageOrigin,
419
- });
420
- break;
421
- case "step_start":
422
- this.closeChannels();
423
- this.out("step_start", {
424
- id: data.id ?? data.stepId,
425
- name: data.name ?? data.stepName,
426
- stepType: data.stepType,
427
- index: data.index,
428
- totalSteps: data.totalSteps,
429
- startedAt: data.startedAt,
430
- outputVariable: data.outputVariable,
431
- });
432
- break;
433
- case "step_delta":
434
- this.emitTextDelta(data.text ?? data.delta, this.parentToolCallId(data));
435
- break;
436
- case "step_complete":
437
- this.closeChannels();
438
- this.out("step_complete", {
439
- id: data.id ?? data.stepId,
440
- name: data.name ?? data.stepName,
441
- stepType: data.stepType,
442
- success: data.success ?? true,
443
- durationMs: data.duration ?? data.durationMs ?? data.executionTime,
444
- result: data.result ?? data.output,
445
- stopReason: data.stopReason,
446
- completedAt: data.completedAt,
447
- unresolvedVariables: data.unresolvedVariables,
448
- ...(this.fallbackInfo(data) ?? {}),
449
- });
450
- break;
451
- case "step_error":
452
- this.closeChannels();
453
- this.out("step_complete", {
454
- id: data.id ?? data.stepId,
455
- name: data.name,
456
- stepType: data.stepType,
457
- success: false,
458
- error: data.error,
459
- durationMs: data.executionTime,
460
- });
461
- break;
462
- case "step_skip":
463
- this.out("step_skip", {
464
- id: data.id,
465
- name: data.name,
466
- stepType: data.stepType,
467
- index: data.index,
468
- totalSteps: data.totalSteps,
469
- when: data.when,
470
- skippedAt: data.skippedAt,
471
- });
472
- break;
473
- case "step_await":
474
- this.out("await", {
475
- toolId: data.toolId,
476
- toolCallId: data.toolCallId,
477
- toolName: data.toolName,
478
- parameters: data.parameters,
479
- awaitedAt: data.awaitedAt,
480
- });
481
- break;
482
-
483
- case "tool_start":
484
- this.out("tool_start", {
485
- toolCallId: data.toolCallId ?? data.toolId,
486
- toolName: data.toolName ?? data.name,
487
- toolType: data.toolType ?? "builtin",
488
- stepId: data.stepId,
489
- parameters: data.parameters,
490
- hiddenParameterNames: data.hiddenParameterNames,
491
- startedAt: data.startedAt,
492
- });
493
- break;
494
- case "tool_delta":
495
- this.out("tool_output_delta", {
496
- toolCallId: data.toolId ?? data.toolCallId,
497
- delta: String(data.delta ?? ""),
498
- });
499
- break;
500
- case "tool_input_delta":
501
- this.out("tool_input_delta", {
502
- toolCallId: data.toolCallId ?? data.toolId,
503
- delta: String(data.delta ?? ""),
504
- });
505
- break;
506
- case "tool_input_complete":
507
- this.out("tool_input_complete", {
508
- toolCallId: data.toolCallId ?? data.toolId,
509
- toolName: data.toolName,
510
- parameters: (data.parameters as Json) ?? {},
511
- hiddenParameterNames: data.hiddenParameterNames,
512
- });
513
- break;
514
- case "tool_complete":
515
- this.out("tool_complete", {
516
- toolCallId: data.toolCallId ?? data.toolId,
517
- toolName: data.toolName ?? data.name,
518
- success: data.success ?? true,
519
- result: data.result,
520
- error: data.error,
521
- executionTime: data.executionTime,
522
- stepId: data.stepId,
523
- });
524
- break;
525
- case "tool_error":
526
- this.out("tool_complete", {
527
- toolCallId: data.toolId ?? data.toolCallId,
528
- toolName: data.name,
529
- success: false,
530
- error: data.error,
531
- executionTime: data.executionTime,
532
- });
533
- break;
534
- case "chunk":
535
- this.emitTextDelta(data.text, this.parentToolCallId(data));
536
- break;
537
-
538
- case "text_start":
539
- if (!this.openText) {
540
- this.openText = (data.id as string) ?? this.mint("text");
541
- this.openTextBuffer = "";
542
- const parentToolCallId = this.parentToolCallId(data);
543
- this.out("text_start", {
544
- id: this.openText,
545
- ...(parentToolCallId ? { parentToolCallId } : {}),
546
- });
547
- }
548
- break;
549
- case "text_end":
550
- this.closeText();
551
- break;
552
- case "reason_start":
553
- this.ensureReasoningOpen(undefined, this.parentToolCallId(data));
554
- break;
555
- case "reason_delta":
556
- this.emitReasoningDelta(
557
- data.reasoningText ?? data.delta ?? data.text,
558
- this.parentToolCallId(data)
559
- );
560
- break;
561
- case "reason_complete":
562
- this.closeReasoning();
563
- break;
564
- case "source":
565
- this.out("source", omitEnvelope(data));
566
- break;
567
-
568
- case "fallback_start":
569
- this.out("custom", {
570
- name: "runtype.fallback",
571
- value: { phase: "start", ...omitEnvelope(data) },
572
- });
573
- break;
574
- case "fallback_complete":
575
- this.out("custom", {
576
- name: "runtype.fallback",
577
- value: { phase: "complete", ...omitEnvelope(data) },
578
- });
579
- break;
580
- case "fallback_exhausted":
581
- this.out("custom", {
582
- name: "runtype.fallback",
583
- value: { phase: "exhausted", ...omitEnvelope(data) },
584
- });
585
- break;
586
-
587
- case "artifact_start":
588
- this.out("artifact_start", {
589
- id: data.id,
590
- artifactType: data.artifactType,
591
- title: data.title,
592
- component: data.component,
593
- });
594
- break;
595
- case "artifact_delta":
596
- this.out("artifact_delta", { id: data.id, delta: data.delta });
597
- break;
598
- case "artifact_update":
599
- this.out("artifact_update", { id: data.id, component: data.component, props: data.props });
600
- break;
601
- case "artifact_complete":
602
- this.out("artifact_complete", { id: data.id });
603
- break;
604
- case "artifact":
605
- this.out("artifact_start", {
606
- id: data.id,
607
- artifactType: data.artifactType ?? "markdown",
608
- title: data.title,
609
- component: data.component,
610
- });
611
- this.out("artifact_complete", { id: data.id });
612
- break;
613
-
614
- case "dispatch_error":
615
- this.closeChannels();
616
- this.out("execution_error", {
617
- kind: this.kind,
618
- error: this.toErrorPayload(data),
619
- code: data.code,
620
- upgradeUrl: data.upgradeUrl,
621
- });
622
- break;
623
-
624
- default:
625
- break;
626
- }
627
- }
628
-
629
- private emitMedia(data: Json): void {
630
- const media = Array.isArray(data.media) ? data.media : [];
631
- for (const raw of media) {
632
- const item = (raw ?? {}) as Json;
633
- const id = this.mint("media");
634
- const mediaType =
635
- typeof item.mediaType === "string"
636
- ? item.mediaType
637
- : item.type === "image-url"
638
- ? "image"
639
- : "application/octet-stream";
640
- this.out("media_start", {
641
- id,
642
- mediaType,
643
- role: "assistant",
644
- toolCallId: data.toolCallId,
645
- });
646
- const fragment =
647
- typeof item.url === "string" ? item.url : typeof item.data === "string" ? item.data : "";
648
- if (fragment) this.out("media_delta", { id, delta: fragment });
649
- this.out("media_complete", {
650
- id,
651
- mediaType,
652
- url: item.url,
653
- data: item.data,
654
- toolCallId: data.toolCallId,
655
- });
656
- }
657
- }
658
-
659
- private toErrorPayload(error: unknown): Json | string {
660
- if (typeof error === "string") return error;
661
- if (error && typeof error === "object") {
662
- const e = error as Json;
663
- if (typeof e.code === "string" && typeof e.message === "string") {
664
- return {
665
- code: e.code,
666
- message: e.message,
667
- ...(e.details ? { details: e.details } : {}),
668
- };
669
- }
670
- if (typeof e.error === "string") return e.error;
671
- if (typeof e.message === "string")
672
- return { code: typeof e.code === "string" ? e.code : "error", message: e.message };
673
- }
674
- return { code: "error", message: "Execution failed" };
675
- }
676
-
677
- write(chunk: string): void {
678
- const parts = chunk.split("\n\n");
679
- for (const part of parts) {
680
- if (!part.trim()) continue;
681
- let dataStr: string | null = null;
682
- for (const line of part.split("\n")) {
683
- if (line.startsWith("data: ")) dataStr = line.slice(6);
684
- }
685
- if (dataStr === null) {
686
- this.sink(`${part}\n\n`);
687
- continue;
688
- }
689
- if (dataStr.trim() === "[DONE]") {
690
- this.sink("data: [DONE]\n\n");
691
- continue;
692
- }
693
- let data: Json;
694
- try {
695
- data = JSON.parse(dataStr) as Json;
696
- } catch {
697
- this.sink(`${part}\n\n`);
698
- continue;
699
- }
700
- const type = data?.type;
701
- if (typeof type !== "string") continue;
702
- try {
703
- this.handle(type, data);
704
- } catch {
705
- // oracle fixture: swallow per-frame translation errors (prod logs via getLogger)
706
- }
707
- }
708
- }
709
- }
710
-
711
- export function createUnifiedEventWrite(
712
- sink: (chunk: string) => void,
713
- options?: UnifiedEventWriteOptions
714
- ): (chunk: string) => void {
715
- const translator = new UnifiedEventTranslator(sink, options);
716
- return (chunk: string) => translator.write(chunk);
717
- }