@runtypelabs/persona 4.22.0 → 4.23.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 (95) 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.d.cts +148 -14
  10. package/dist/approval-ui.d.ts +148 -14
  11. package/dist/artifacts-ui.d.cts +148 -14
  12. package/dist/artifacts-ui.d.ts +148 -14
  13. package/dist/codegen.cjs +1 -1
  14. package/dist/codegen.js +1 -1
  15. package/dist/context-mentions.d.cts +148 -14
  16. package/dist/context-mentions.d.ts +148 -14
  17. package/dist/event-stream-view-GL3ADRY2.js +1 -0
  18. package/dist/event-stream-view.cjs +1 -1
  19. package/dist/event-stream-view.d.cts +148 -14
  20. package/dist/event-stream-view.d.ts +148 -14
  21. package/dist/event-stream-view.js +1 -1
  22. package/dist/forms-ui.d.cts +161 -23
  23. package/dist/forms-ui.d.ts +161 -23
  24. package/dist/history-view.d.cts +136 -6
  25. package/dist/history-view.d.ts +136 -6
  26. package/dist/index.cjs +67 -67
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +172 -27
  29. package/dist/index.d.ts +172 -27
  30. package/dist/index.global.js +51 -51
  31. package/dist/index.global.js.map +1 -1
  32. package/dist/index.js +67 -67
  33. package/dist/index.js.map +1 -1
  34. package/dist/launcher.global.js.map +1 -1
  35. package/dist/session-reconnect.d.cts +148 -14
  36. package/dist/session-reconnect.d.ts +148 -14
  37. package/dist/smart-dom-reader.d.cts +148 -14
  38. package/dist/smart-dom-reader.d.ts +148 -14
  39. package/dist/testing.cjs +3 -3
  40. package/dist/testing.d.cts +3 -4
  41. package/dist/testing.d.ts +3 -4
  42. package/dist/testing.js +3 -3
  43. package/dist/theme-editor-preview.cjs +71 -71
  44. package/dist/theme-editor-preview.d.cts +154 -14
  45. package/dist/theme-editor-preview.d.ts +154 -14
  46. package/dist/theme-editor-preview.js +48 -48
  47. package/dist/theme-editor.d.cts +148 -14
  48. package/dist/theme-editor.d.ts +148 -14
  49. package/dist/voice-runtime.d.cts +6 -2
  50. package/dist/voice-runtime.d.ts +6 -2
  51. package/package.json +1 -1
  52. package/src/ask-user-question-tool.ts +1 -1
  53. package/src/client-history-rest.test.ts +2 -1
  54. package/src/client-visitor-history.test.ts +106 -4
  55. package/src/client.composer-options.test.ts +1 -1
  56. package/src/client.interrupt.test.ts +2 -2
  57. package/src/client.test.ts +477 -915
  58. package/src/client.ts +134 -494
  59. package/src/client.unified-tools.test.ts +76 -0
  60. package/src/components/event-stream-badge-theming.test.ts +3 -0
  61. package/src/components/event-stream-view.test.ts +76 -76
  62. package/src/components/event-stream-view.ts +5 -0
  63. package/src/components/tool-bubble.test.ts +12 -0
  64. package/src/components/tool-bubble.ts +13 -2
  65. package/src/event-stream-view-bundle.test.ts +2 -2
  66. package/src/generated/runtype-openapi-contract.ts +129 -1
  67. package/src/internal/runtype-history-provider.test.ts +2 -2
  68. package/src/launcher-global.ts +1 -1
  69. package/src/session-history.test.ts +1 -1
  70. package/src/session.quote.test.ts +1 -1
  71. package/src/session.resubmit-from.test.ts +1 -1
  72. package/src/session.test.ts +5 -5
  73. package/src/session.ts +95 -36
  74. package/src/suggest-replies-tool.ts +1 -1
  75. package/src/testing/mock-stream.test.ts +37 -16
  76. package/src/testing/mock-stream.ts +14 -9
  77. package/src/types.ts +19 -14
  78. package/src/ui.ask-user-question-plugin.test.ts +7 -7
  79. package/src/ui.composer-defer-one.test.ts +6 -34
  80. package/src/ui.composer-draft-persistence.test.ts +1 -1
  81. package/src/ui.composer-quote.test.ts +1 -1
  82. package/src/ui.message-history-actions.test.ts +1 -1
  83. package/src/ui.streaming-coalescing.test.ts +10 -13
  84. package/src/ui.ts +80 -32
  85. package/src/ui.typing-indicator.test.ts +216 -0
  86. package/src/ui.voice-custom-provider.test.ts +211 -0
  87. package/src/utils/event-stream-buffer.test.ts +13 -13
  88. package/src/utils/event-stream-capture.test.ts +20 -20
  89. package/src/utils/throughput-tracker.test.ts +100 -142
  90. package/src/utils/throughput-tracker.ts +18 -132
  91. package/src/utils/voice-support.ts +18 -1
  92. package/src/voice/voice-turn-tracker.ts +18 -0
  93. package/src/webmcp-bridge.ts +1 -1
  94. package/dist/event-stream-view-FKWDY3UB.js +0 -1
  95. package/src/utils/__fixtures__/unified-translator.oracle.ts +0 -717
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/persona",
3
- "version": "4.22.0",
3
+ "version": "4.23.0",
4
4
  "description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -5,7 +5,7 @@
5
5
  * `clientTools[]` (set `features.askUserQuestion.expose: true`): the same
6
6
  * wire surface WebMCP page tools ride. The server registers it as a LOCAL
7
7
  * tool under its bare name (`origin: 'sdk'` tools are not `webmcp:`-prefixed),
8
- * so when the model calls it the execution pauses with a `step_await`, the
8
+ * so when the model calls it the execution pauses with an `await`, the
9
9
  * widget's answer-pill sheet renders, and `session.resolveAskUserQuestion()`
10
10
  * resumes the execution with the structured answers. The public await frame
11
11
  * for a local-tool pause carries no `awaitReason`; that discriminator is
@@ -197,6 +197,7 @@ describe('history REST - request shape', () => {
197
197
  id: 'conv_1',
198
198
  title: 'Placeholder title',
199
199
  flowId: 'flow_1',
200
+ targetId: 'flow_1',
200
201
  messageCount: 4,
201
202
  createdAt: '2026-08-01T00:00:00.000Z',
202
203
  updatedAt: '2026-08-02T00:00:00.000Z',
@@ -222,7 +223,7 @@ describe('history REST - request shape', () => {
222
223
  expect(requests[1].method).toBe('GET');
223
224
  expect(requests[1].headers['X-Visitor-Token']).toBe('cvt_stored');
224
225
  expect(requests[1].headers['X-Persona-Version']).toBeTruthy();
225
- // Deprecated flowId is consumed at this boundary and never re-exposed.
226
+ // The deprecated flowId alias is not re-exposed.
226
227
  expect(page.data[0]).toEqual({
227
228
  id: 'conv_1',
228
229
  title: 'Placeholder title',
@@ -203,7 +203,7 @@ describe('client visitor history - init capability shape', () => {
203
203
  expect(requests[0].body).not.toHaveProperty('conversationId');
204
204
  });
205
205
 
206
- it('normalizes targetId, preferring the top-level field over flow.id', async () => {
206
+ it('uses canonical targetId without falling back to flow metadata', async () => {
207
207
  installFetch([
208
208
  ok({ targetId: 'agent_9' }),
209
209
  ok({ sessionId: 'sess_2', targetId: undefined, flow: { id: 'flow_7', name: 'F', description: null } }),
@@ -216,7 +216,23 @@ describe('client visitor history - init capability shape', () => {
216
216
 
217
217
  expect(a.targetId).toBe('agent_9');
218
218
  expect(a.flow.id).toBe('flow_1');
219
- expect(b.targetId).toBe('flow_7');
219
+ expect(b.targetId).toBeUndefined();
220
+ });
221
+
222
+ it('surfaces an init 400 without retrying a different payload', async () => {
223
+ installFetch([fail(400, { error: 'invalid_token' })]);
224
+ await expect(makeClient({}).client.initSession()).rejects.toThrow('invalid_token');
225
+ expect(requests).toHaveLength(1);
226
+ expect(requests[0].body.durableRecovery).toBe(true);
227
+ });
228
+
229
+ it('accepts a data-only init with no flow or target metadata', async () => {
230
+ installFetch([() => ({ ok: true, status: 200, json: async () => ({
231
+ ...initBody(), flow: undefined, targetId: undefined, app: { id: 'app_1' },
232
+ }) })]);
233
+ const session = await makeClient({}).client.initSession();
234
+ expect(session.targetId).toBeUndefined();
235
+ expect(session.conversationId).toBe('conv_1');
220
236
  });
221
237
 
222
238
  it('uses the exact visitor credential and durable cursor for reconnect', async () => {
@@ -235,14 +251,14 @@ describe('client visitor history - init capability shape', () => {
235
251
  const controller = new AbortController();
236
252
  const response = await h.client.reconnectClientTokenStream({
237
253
  executionId: 'exec_7',
238
- after: '12',
254
+ after: '12.3',
239
255
  signal: controller.signal,
240
256
  });
241
257
 
242
258
  expect(response).toBe(events);
243
259
  expect(fetchMock.mock.calls[1]?.[0]).toBe(
244
260
  `${API_URL}/v1/client/conversations/conv_1/executions/exec_7/events` +
245
- '?sessionId=sess_1&after=12'
261
+ '?sessionId=sess_1&after=12.3'
246
262
  );
247
263
  expect(fetchMock.mock.calls[1]?.[1]).toMatchObject({
248
264
  method: 'GET',
@@ -1064,3 +1080,89 @@ describe('client visitor history - dedupe', () => {
1064
1080
  expect(h.sessionInits).toHaveLength(1);
1065
1081
  });
1066
1082
  });
1083
+
1084
+ describe('voice integration visitor credential access', () => {
1085
+ const controllers: ReturnType<typeof createAgentExperience>[] = [];
1086
+ const mountWidget = (config: Partial<AgentWidgetConfig> = {}) => {
1087
+ const mount = document.createElement('div');
1088
+ document.body.appendChild(mount);
1089
+ const controller = createAgentExperience(mount, {
1090
+ apiUrl: API_URL,
1091
+ clientToken: CLIENT_TOKEN,
1092
+ launcher: { enabled: false },
1093
+ ...config,
1094
+ });
1095
+ controllers.push(controller);
1096
+ return controller;
1097
+ };
1098
+
1099
+ afterEach(() => {
1100
+ controllers.forEach((controller) => controller.destroy());
1101
+ controllers.length = 0;
1102
+ document.body.innerHTML = '';
1103
+ });
1104
+
1105
+ it('reads minted proof after the claim response omits it without enriching the callback', async () => {
1106
+ const minted = { id: 'vis_1', token: 'cvt_minted', expiresAt: futureIso(), endUserId: null };
1107
+ installFetch([
1108
+ ok({ sessionId: 'sess_first', visitor: minted }),
1109
+ ok({ sessionId: 'sess_claimed', visitor: { ...minted, token: undefined } }),
1110
+ ]);
1111
+ const onSessionInit = vi.fn();
1112
+ const controller = mountWidget({ persistState: false, onSessionInit });
1113
+ await vi.waitFor(() => expect(onSessionInit).toHaveBeenCalledOnce());
1114
+ expect(onSessionInit.mock.calls[0][0].visitor.token).toBeUndefined();
1115
+ await expect(controller.getVisitorToken()).resolves.toBe('cvt_minted');
1116
+ expect(JSON.stringify(controller.getState())).not.toContain('cvt_minted');
1117
+ expect(window.localStorage.getItem(await storageKeyFor())).toBeNull();
1118
+ });
1119
+
1120
+ it('reads the current persisted credential after reload and after rotation or removal', async () => {
1121
+ await seedToken('cvt_stored');
1122
+ installFetch([ok()]);
1123
+ const controller = mountWidget();
1124
+ await expect(controller.getVisitorToken()).resolves.toBe('cvt_stored');
1125
+ await seedToken('cvt_rotated');
1126
+ await expect(controller.getVisitorToken()).resolves.toBe('cvt_rotated');
1127
+ window.localStorage.removeItem(await storageKeyFor());
1128
+ await expect(controller.getVisitorToken()).resolves.toBeNull();
1129
+ });
1130
+
1131
+ it('does not return credentials from a replaced client-token scope', async () => {
1132
+ await seedToken('cvt_stored');
1133
+ installFetch([ok(), ok()]);
1134
+ const controller = mountWidget();
1135
+ await vi.waitFor(() => expect(requests).toHaveLength(1));
1136
+ const pending = controller.getVisitorToken();
1137
+ controller.update({ clientToken: 'ct_other' });
1138
+ await expect(pending).resolves.toBeNull();
1139
+ await expect(controller.getVisitorToken()).resolves.toBeNull();
1140
+ });
1141
+
1142
+ it('returns null after teardown, including a read already in flight', async () => {
1143
+ await seedToken('cvt_stored');
1144
+ installFetch([ok()]);
1145
+ const controller = mountWidget();
1146
+ await vi.waitFor(() => expect(requests).toHaveLength(1));
1147
+ const pending = controller.getVisitorToken();
1148
+ controller.destroy();
1149
+ controllers.length = 0;
1150
+ await expect(pending).resolves.toBeNull();
1151
+ await expect(controller.getVisitorToken()).resolves.toBeNull();
1152
+ });
1153
+
1154
+ it('returns null when no credential has been minted', async () => {
1155
+ installFetch([ok()]);
1156
+ const controller = mountWidget({ persistState: false });
1157
+ await expect(controller.getVisitorToken()).resolves.toBeNull();
1158
+ });
1159
+
1160
+ it('does not fetch or mint a visitor outside client-token mode', async () => {
1161
+ const fetch = vi.fn();
1162
+ vi.stubGlobal('fetch', fetch);
1163
+ const controller = mountWidget({ clientToken: undefined });
1164
+ await expect(controller.getVisitorToken()).resolves.toBeNull();
1165
+ expect(fetch).not.toHaveBeenCalled();
1166
+ vi.unstubAllGlobals();
1167
+ });
1168
+ });
@@ -22,7 +22,7 @@ const streamResponse = () => {
22
22
  body: new ReadableStream({
23
23
  start(controller) {
24
24
  controller.enqueue(
25
- encoder.encode('data: {"type":"flow_complete","success":true}\n\n')
25
+ encoder.encode('data: {"type":"execution_complete","success":true}\n\n')
26
26
  );
27
27
  controller.close();
28
28
  },
@@ -120,9 +120,9 @@ describe("client-token turn identity", () => {
120
120
  await vi.waitFor(() => expect(index).toBe(2));
121
121
 
122
122
  const beforeCount = firstEvents.length;
123
- first.push('data: {"type":"flow_complete","success":true}\n\n');
123
+ first.push('data: {"type":"execution_complete","success":true}\n\n');
124
124
  first.close();
125
- second.push('data: {"type":"flow_complete","success":true}\n\n');
125
+ second.push('data: {"type":"execution_complete","success":true}\n\n');
126
126
  second.close();
127
127
  await Promise.all([firstDispatch, secondDispatch]);
128
128