@runtypelabs/persona 3.37.0 → 4.1.0

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 (55) hide show
  1. package/README.md +4 -5
  2. package/dist/animations/glyph-cycle.d.cts +1 -1
  3. package/dist/animations/glyph-cycle.d.ts +1 -1
  4. package/dist/animations/{types-DgYsuwXL.d.cts → types-B_xbfvR0.d.cts} +263 -181
  5. package/dist/animations/{types-DgYsuwXL.d.ts → types-B_xbfvR0.d.ts} +263 -181
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/codegen.cjs +1 -1
  9. package/dist/codegen.js +1 -1
  10. package/dist/index.cjs +54 -52
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +328 -839
  13. package/dist/index.d.ts +328 -839
  14. package/dist/index.global.js +41 -39
  15. package/dist/index.global.js.map +1 -1
  16. package/dist/index.js +54 -52
  17. package/dist/index.js.map +1 -1
  18. package/dist/install.global.js +1 -1
  19. package/dist/install.global.js.map +1 -1
  20. package/dist/smart-dom-reader.d.cts +269 -192
  21. package/dist/smart-dom-reader.d.ts +269 -192
  22. package/dist/theme-editor-preview.cjs +55 -53
  23. package/dist/theme-editor-preview.d.cts +269 -192
  24. package/dist/theme-editor-preview.d.ts +269 -192
  25. package/dist/theme-editor-preview.js +57 -55
  26. package/dist/theme-editor.d.cts +269 -192
  27. package/dist/theme-editor.d.ts +269 -192
  28. package/dist/widget.css +14 -0
  29. package/package.json +1 -1
  30. package/src/client.test.ts +446 -1041
  31. package/src/client.ts +684 -967
  32. package/src/components/message-bubble.ts +7 -0
  33. package/src/components/tool-bubble.ts +46 -33
  34. package/src/generated/runtype-openapi-contract.ts +210 -714
  35. package/src/index-core.ts +2 -3
  36. package/src/install.test.ts +1 -34
  37. package/src/install.ts +1 -26
  38. package/src/runtime/init.test.ts +8 -67
  39. package/src/runtime/init.ts +2 -17
  40. package/src/session.test.ts +8 -8
  41. package/src/session.ts +1 -1
  42. package/src/styles/widget.css +14 -0
  43. package/src/types.ts +12 -13
  44. package/src/ui.postprocess.test.ts +107 -0
  45. package/src/ui.ts +45 -5
  46. package/src/utils/__fixtures__/unified-translator.oracle.ts +62 -14
  47. package/src/utils/copy-selection.test.ts +37 -0
  48. package/src/utils/copy-selection.ts +19 -0
  49. package/src/utils/event-stream-capture.test.ts +9 -64
  50. package/src/utils/streaming-table.test.ts +100 -0
  51. package/src/utils/streaming-table.ts +103 -0
  52. package/src/utils/sequence-buffer.test.ts +0 -256
  53. package/src/utils/sequence-buffer.ts +0 -130
  54. package/src/utils/unified-event-bridge.test.ts +0 -263
  55. package/src/utils/unified-event-bridge.ts +0 -431
@@ -1,431 +0,0 @@
1
- /**
2
- * Unified → legacy SSE event bridge (widget consumer side).
3
- *
4
- * The mirror image of the runtype-core `createUnifiedEventWrite` translator: it
5
- * takes frames in the neutral 33-event UNIFIED vocabulary (emitted by the API
6
- * when a caller requests `?events=unified`) and maps each back onto the LEGACY
7
- * `agent_*` / `flow_*` / `step_*` / `artifact_*` events the widget's existing
8
- * dispatch chain (`client.ts`) already renders. The dispatch chain is untouched.
9
- *
10
- * Opt-in: only engaged when `events: 'unified'` is set (or auto-detected from a
11
- * leading `execution_start` frame). Default `'legacy'` bypasses this module.
12
- *
13
- * Stateful: the unified vocabulary collapses agent/flow distinctions and
14
- * decouples text/reasoning block ids from turns, so the bridge tracks `kind`,
15
- * the open turn/step, and buffers the media triad — exactly inverting the api
16
- * translator's state. See `docs/specs/widget-unified-event-bridge.md` for the
17
- * full mapping table (every field rename is pinned to the handler that reads it).
18
- */
19
-
20
- /** Canonical WebMCP wire prefix — mirrors `webmcp-bridge.ts` (WEBMCP_TOOL_PREFIX
21
- * / isWebMcpToolName). Inlined to keep this pure mapper dependency-free. */
22
- const WEBMCP_PREFIX = "webmcp:";
23
-
24
- export type LegacyEvent = { payloadType: string; payload: Record<string, unknown> };
25
-
26
- /** True when a frame's `type` identifies the unified vocabulary unambiguously.
27
- * `execution_start` is unified-exclusive; `agent_start` / `flow_start` are
28
- * legacy-exclusive. Used by `client.ts` to auto-detect the wire mode from the
29
- * first lifecycle frame (so the `events` flag is a request, not a commitment). */
30
- export function isUnifiedLifecycleStart(type: string): boolean {
31
- return type === "execution_start";
32
- }
33
-
34
- export class UnifiedToLegacyBridge {
35
- private kind: "agent" | "flow" = "agent";
36
- private executionId: string;
37
- private iteration = 1;
38
- /** current agent turn id (from `turn_start`) — the `turnId` agent deltas need */
39
- private openTurnId: string | null = null;
40
- /** current flow step id (from `step_start`) — the `id` flow text attaches to */
41
- private openStepId: string | null = null;
42
- private openTextBlockId: string | null = null;
43
- private openReasoningId: string | null = null;
44
- private readonly mediaBuffers = new Map<
45
- string,
46
- { mediaType?: string; role?: string; toolCallId?: unknown; parts: string[] }
47
- >();
48
-
49
- constructor(opts?: { executionId?: string }) {
50
- this.executionId = opts?.executionId ?? "";
51
- }
52
-
53
- /** Translate ONE decoded unified frame into 0..N legacy events, in order. */
54
- push(type: string, payload: Record<string, unknown>): LegacyEvent[] {
55
- // Every unified frame carries the envelope executionId/seq; iteration rides
56
- // on turn/tool frames. Capture them so legacy `agent_*` payloads can be stamped.
57
- if (typeof payload.executionId === "string" && payload.executionId) {
58
- this.executionId = payload.executionId;
59
- }
60
- if (typeof payload.iteration === "number") this.iteration = payload.iteration;
61
-
62
- switch (type) {
63
- // ===== lifecycle =====
64
- case "execution_start": {
65
- this.kind = payload.kind === "flow" ? "flow" : "agent";
66
- if (this.kind !== "agent") return []; // no flow_start handler; state only
67
- return [
68
- this.out("agent_start", {
69
- executionId: this.executionId,
70
- agentId: payload.agentId,
71
- agentName: payload.agentName,
72
- maxTurns: payload.maxTurns,
73
- startedAt: payload.startedAt,
74
- }),
75
- ];
76
- }
77
- case "turn_start": {
78
- this.openTurnId = typeof payload.id === "string" ? payload.id : null;
79
- if (this.kind !== "agent") return [];
80
- return [this.out("agent_turn_start", { turnId: payload.id, iteration: payload.iteration })];
81
- }
82
- case "turn_complete": {
83
- const out =
84
- this.kind === "agent"
85
- ? [
86
- this.out("agent_turn_complete", {
87
- turnId: payload.id,
88
- iteration: payload.iteration,
89
- stopReason: payload.stopReason,
90
- completedAt: payload.completedAt,
91
- }),
92
- ]
93
- : [];
94
- if (this.openTurnId === payload.id) this.openTurnId = null;
95
- return out;
96
- }
97
- case "execution_complete": {
98
- if ((payload.kind ?? this.kind) === "agent") {
99
- return [
100
- this.out("agent_complete", {
101
- executionId: this.executionId,
102
- success: payload.success,
103
- completedAt: payload.completedAt,
104
- stopReason: payload.stopReason,
105
- }),
106
- ];
107
- }
108
- return [
109
- this.out("flow_complete", {
110
- success: payload.success,
111
- completedAt: payload.completedAt,
112
- duration: payload.durationMs,
113
- finalOutput: payload.finalOutput,
114
- totalSteps: payload.totalSteps,
115
- successfulSteps: payload.successfulSteps,
116
- failedSteps: payload.failedSteps,
117
- }),
118
- ];
119
- }
120
- case "execution_error": {
121
- if ((payload.kind ?? this.kind) === "agent") {
122
- // API emits no execution_complete on agent failure; surface as a
123
- // terminal agent_error (recoverable:false → onEvent error in client.ts).
124
- return [this.out("agent_error", { recoverable: false, error: payload.error })];
125
- }
126
- return [
127
- this.out("flow_error", {
128
- error: payload.error,
129
- code: payload.code,
130
- upgradeUrl: payload.upgradeUrl,
131
- }),
132
- ];
133
- }
134
- case "error":
135
- // Unified `error` is the NON-terminal one. Route to agent_error
136
- // (recoverable → warn only), NOT legacy `error` (that branch is terminal).
137
- return [this.out("agent_error", { recoverable: true, error: payload.error })];
138
- case "ping":
139
- return [this.out("agent_ping", { timestamp: payload.timestamp })];
140
-
141
- // ===== text channel =====
142
- case "text_start":
143
- this.openTextBlockId = typeof payload.id === "string" ? payload.id : null;
144
- return []; // agent bubble created lazily by the first delta
145
- case "text_delta": {
146
- const delta = String(payload.delta ?? "");
147
- if (this.kind === "agent") {
148
- return [
149
- this.out("agent_turn_delta", {
150
- contentType: "text",
151
- delta,
152
- turnId: this.openTurnId ?? payload.id,
153
- iteration: this.iteration,
154
- executionId: this.executionId,
155
- }),
156
- ];
157
- }
158
- return [this.out("step_delta", { id: this.openStepId ?? payload.id, text: delta, stepType: "prompt" })];
159
- }
160
- case "text_complete":
161
- if (this.openTextBlockId === payload.id) this.openTextBlockId = null;
162
- return [];
163
-
164
- // ===== reasoning channel =====
165
- case "reasoning_start":
166
- this.openReasoningId = typeof payload.id === "string" ? payload.id : null;
167
- if (this.kind === "flow") return [this.out("reason_start", { id: payload.id })];
168
- return [];
169
- case "reasoning_delta": {
170
- const delta = String(payload.delta ?? "");
171
- if (this.kind === "agent") {
172
- return [
173
- this.out("agent_turn_delta", {
174
- contentType: "thinking",
175
- delta,
176
- turnId: this.openTurnId ?? payload.id,
177
- iteration: this.iteration,
178
- executionId: this.executionId,
179
- }),
180
- ];
181
- }
182
- return [this.out("reason_delta", { id: payload.id, delta })];
183
- }
184
- case "reasoning_complete": {
185
- const hasText = typeof payload.text === "string" && payload.text.length > 0;
186
- if (this.kind === "agent") {
187
- // E3: scope:'loop' (or a text-carrying close) is a reflection fold.
188
- if (payload.scope === "loop" || hasText) {
189
- return [
190
- this.out("agent_reflection", {
191
- reflection: payload.text ?? "",
192
- executionId: this.executionId,
193
- iteration: this.iteration,
194
- }),
195
- ];
196
- }
197
- return []; // turn-scoped thinking: closed by turn_complete
198
- }
199
- const out: LegacyEvent[] = [];
200
- if (hasText) out.push(this.out("reason_delta", { id: payload.id, delta: payload.text }));
201
- out.push(this.out("reason_complete", { id: payload.id }));
202
- return out;
203
- }
204
-
205
- // ===== tool channel =====
206
- case "tool_start": {
207
- if (this.kind === "agent") {
208
- return [
209
- this.out("agent_tool_start", {
210
- toolCallId: payload.toolCallId,
211
- toolName: payload.toolName,
212
- parameters: payload.parameters,
213
- executionId: this.executionId,
214
- iteration: payload.iteration ?? this.iteration,
215
- startedAt: payload.startedAt,
216
- }),
217
- ];
218
- }
219
- return [
220
- this.out("tool_start", {
221
- toolId: payload.toolCallId,
222
- toolName: payload.toolName,
223
- parameters: payload.parameters,
224
- executionId: this.executionId,
225
- iteration: payload.iteration ?? this.iteration,
226
- startedAt: payload.startedAt,
227
- }),
228
- ];
229
- }
230
- case "tool_input_delta": {
231
- if (this.kind === "agent") {
232
- return [
233
- this.out("agent_turn_delta", {
234
- contentType: "tool_input",
235
- delta: String(payload.delta ?? ""),
236
- toolCallId: payload.toolCallId,
237
- }),
238
- ];
239
- }
240
- return []; // flow tool-input isn't surfaced to the UI
241
- }
242
- case "tool_input_complete":
243
- return []; // args already set at tool_start; no handler
244
- case "tool_output_delta": {
245
- const delta = String(payload.delta ?? "");
246
- if (this.kind === "agent") {
247
- return [this.out("agent_tool_delta", { toolCallId: payload.toolCallId, delta })];
248
- }
249
- return [this.out("tool_delta", { toolId: payload.toolCallId, delta })];
250
- }
251
- case "tool_complete": {
252
- if (this.kind === "agent") {
253
- return [
254
- this.out("agent_tool_complete", {
255
- toolCallId: payload.toolCallId,
256
- result: payload.result,
257
- executionTime: payload.executionTime,
258
- completedAt: payload.completedAt,
259
- }),
260
- ];
261
- }
262
- return [
263
- this.out("tool_complete", {
264
- toolId: payload.toolCallId,
265
- result: payload.result,
266
- duration: payload.executionTime,
267
- completedAt: payload.completedAt,
268
- }),
269
- ];
270
- }
271
-
272
- // ===== media channel (triad → one agent_media) =====
273
- case "media_start": {
274
- const id = String(payload.id);
275
- this.mediaBuffers.set(id, {
276
- mediaType: typeof payload.mediaType === "string" ? payload.mediaType : undefined,
277
- role: typeof payload.role === "string" ? payload.role : undefined,
278
- toolCallId: payload.toolCallId,
279
- parts: [],
280
- });
281
- return [];
282
- }
283
- case "media_delta": {
284
- const buf = this.mediaBuffers.get(String(payload.id));
285
- if (buf && typeof payload.delta === "string") buf.parts.push(payload.delta);
286
- return [];
287
- }
288
- case "media_complete": {
289
- const id = String(payload.id);
290
- const buf = this.mediaBuffers.get(id);
291
- this.mediaBuffers.delete(id);
292
- const mediaType =
293
- (typeof payload.mediaType === "string" ? payload.mediaType : undefined) ??
294
- buf?.mediaType ??
295
- "application/octet-stream";
296
- const data = typeof payload.data === "string" ? payload.data : undefined;
297
- const url =
298
- typeof payload.url === "string"
299
- ? payload.url
300
- : buf && buf.parts.length > 0
301
- ? buf.parts.join("")
302
- : undefined;
303
- let part: Record<string, unknown> | null = null;
304
- if (data) {
305
- part = { type: "media", data, mediaType };
306
- } else if (url) {
307
- part = { type: mediaType.startsWith("image/") ? "image-url" : "file-url", url, mediaType };
308
- }
309
- if (!part) return [];
310
- return [
311
- this.out("agent_media", {
312
- media: [part],
313
- executionId: this.executionId,
314
- iteration: this.iteration,
315
- toolCallId: payload.toolCallId ?? buf?.toolCallId,
316
- }),
317
- ];
318
- }
319
-
320
- // ===== approvals =====
321
- case "approval_start":
322
- return [
323
- this.out("agent_approval_start", {
324
- approvalId: payload.approvalId,
325
- toolName: payload.toolName,
326
- toolType: payload.toolType,
327
- description: payload.description,
328
- reason: payload.reason,
329
- parameters: payload.parameters,
330
- executionId: this.executionId,
331
- }),
332
- ];
333
- case "approval_complete":
334
- return [
335
- this.out("agent_approval_complete", {
336
- approvalId: payload.approvalId,
337
- decision: payload.decision,
338
- executionId: this.executionId,
339
- toolName: payload.toolName,
340
- description: payload.description,
341
- }),
342
- ];
343
-
344
- // ===== await (local-tool / WebMCP pause) — onto the 3.35.0 step_await path =====
345
- case "await": {
346
- const raw = typeof payload.toolName === "string" ? payload.toolName : "";
347
- const toolName =
348
- payload.origin === "webmcp" && !raw.startsWith(WEBMCP_PREFIX) ? `${WEBMCP_PREFIX}${raw}` : raw;
349
- return [
350
- this.out("step_await", {
351
- awaitReason: "local_tool_required",
352
- toolName,
353
- parameters: payload.parameters,
354
- toolCallId: payload.toolCallId,
355
- toolId: payload.toolId,
356
- executionId: this.executionId,
357
- awaitedAt: payload.awaitedAt,
358
- }),
359
- ];
360
- }
361
-
362
- // ===== steps (flow) =====
363
- case "step_start":
364
- this.openStepId = typeof payload.id === "string" ? payload.id : null;
365
- return [
366
- this.out("step_start", {
367
- id: payload.id,
368
- name: payload.name,
369
- stepType: payload.stepType,
370
- index: payload.index,
371
- totalSteps: payload.totalSteps,
372
- startedAt: payload.startedAt,
373
- outputVariable: payload.outputVariable,
374
- }),
375
- ];
376
- case "step_complete": {
377
- const out = this.out("step_complete", {
378
- id: payload.id,
379
- name: payload.name,
380
- stepType: payload.stepType,
381
- success: payload.success,
382
- duration: payload.durationMs,
383
- result: payload.result,
384
- stopReason: payload.stopReason,
385
- completedAt: payload.completedAt,
386
- unresolvedVariables: payload.unresolvedVariables,
387
- });
388
- if (this.openStepId === payload.id) this.openStepId = null;
389
- return [out];
390
- }
391
- case "step_skip":
392
- return []; // no step_skip handler
393
-
394
- // ===== artifacts (1:1) =====
395
- case "artifact_start":
396
- return [
397
- this.out("artifact_start", {
398
- id: payload.id,
399
- artifactType: payload.artifactType,
400
- title: payload.title,
401
- component: payload.component,
402
- }),
403
- ];
404
- case "artifact_delta":
405
- return [this.out("artifact_delta", { id: payload.id, delta: payload.delta })];
406
- case "artifact_update":
407
- return [
408
- this.out("artifact_update", { id: payload.id, component: payload.component, props: payload.props }),
409
- ];
410
- case "artifact_complete":
411
- return [this.out("artifact_complete", { id: payload.id })];
412
-
413
- // ===== dropped (no legacy renderer) =====
414
- case "source":
415
- case "custom":
416
- return [];
417
-
418
- default:
419
- return [];
420
- }
421
- }
422
-
423
- /** Build a legacy event, dropping undefined fields so the payload is clean. */
424
- private out(payloadType: string, payload: Record<string, unknown>): LegacyEvent {
425
- const pruned: Record<string, unknown> = {};
426
- for (const [k, v] of Object.entries(payload)) {
427
- if (v !== undefined) pruned[k] = v;
428
- }
429
- return { payloadType, payload: pruned };
430
- }
431
- }