@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.
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-B_JdVK9o.d.cts → types-9Vxm-PPz.d.cts} +136 -6
- package/dist/animations/{types-B_JdVK9o.d.ts → types-9Vxm-PPz.d.ts} +136 -6
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/animations-extra.d.cts +136 -6
- package/dist/animations-extra.d.ts +136 -6
- package/dist/approval-ui.d.cts +148 -14
- package/dist/approval-ui.d.ts +148 -14
- package/dist/artifacts-ui.d.cts +148 -14
- package/dist/artifacts-ui.d.ts +148 -14
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions.d.cts +148 -14
- package/dist/context-mentions.d.ts +148 -14
- package/dist/event-stream-view-GL3ADRY2.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +148 -14
- package/dist/event-stream-view.d.ts +148 -14
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +161 -23
- package/dist/forms-ui.d.ts +161 -23
- package/dist/history-view.d.cts +136 -6
- package/dist/history-view.d.ts +136 -6
- package/dist/index.cjs +67 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +172 -27
- package/dist/index.d.ts +172 -27
- package/dist/index.global.js +51 -51
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +67 -67
- package/dist/index.js.map +1 -1
- package/dist/launcher.global.js.map +1 -1
- package/dist/session-reconnect.d.cts +148 -14
- package/dist/session-reconnect.d.ts +148 -14
- package/dist/smart-dom-reader.d.cts +148 -14
- package/dist/smart-dom-reader.d.ts +148 -14
- package/dist/testing.cjs +3 -3
- package/dist/testing.d.cts +3 -4
- package/dist/testing.d.ts +3 -4
- package/dist/testing.js +3 -3
- package/dist/theme-editor-preview.cjs +71 -71
- package/dist/theme-editor-preview.d.cts +154 -14
- package/dist/theme-editor-preview.d.ts +154 -14
- package/dist/theme-editor-preview.js +48 -48
- package/dist/theme-editor.d.cts +148 -14
- package/dist/theme-editor.d.ts +148 -14
- package/dist/voice-runtime.d.cts +6 -2
- package/dist/voice-runtime.d.ts +6 -2
- package/package.json +1 -1
- package/src/ask-user-question-tool.ts +1 -1
- package/src/client-history-rest.test.ts +2 -1
- package/src/client-visitor-history.test.ts +106 -4
- package/src/client.composer-options.test.ts +1 -1
- package/src/client.interrupt.test.ts +2 -2
- package/src/client.test.ts +477 -915
- package/src/client.ts +134 -494
- package/src/client.unified-tools.test.ts +76 -0
- package/src/components/event-stream-badge-theming.test.ts +3 -0
- package/src/components/event-stream-view.test.ts +76 -76
- package/src/components/event-stream-view.ts +5 -0
- package/src/components/tool-bubble.test.ts +12 -0
- package/src/components/tool-bubble.ts +13 -2
- package/src/event-stream-view-bundle.test.ts +2 -2
- package/src/generated/runtype-openapi-contract.ts +129 -1
- package/src/internal/runtype-history-provider.test.ts +2 -2
- package/src/launcher-global.ts +1 -1
- package/src/session-history.test.ts +1 -1
- package/src/session.quote.test.ts +1 -1
- package/src/session.resubmit-from.test.ts +1 -1
- package/src/session.test.ts +5 -5
- package/src/session.ts +95 -36
- package/src/suggest-replies-tool.ts +1 -1
- package/src/testing/mock-stream.test.ts +37 -16
- package/src/testing/mock-stream.ts +14 -9
- package/src/types.ts +19 -14
- package/src/ui.ask-user-question-plugin.test.ts +7 -7
- package/src/ui.composer-defer-one.test.ts +6 -34
- package/src/ui.composer-draft-persistence.test.ts +1 -1
- package/src/ui.composer-quote.test.ts +1 -1
- package/src/ui.message-history-actions.test.ts +1 -1
- package/src/ui.streaming-coalescing.test.ts +10 -13
- package/src/ui.ts +80 -32
- package/src/ui.typing-indicator.test.ts +216 -0
- package/src/ui.voice-custom-provider.test.ts +211 -0
- package/src/utils/event-stream-buffer.test.ts +13 -13
- package/src/utils/event-stream-capture.test.ts +20 -20
- package/src/utils/throughput-tracker.test.ts +100 -142
- package/src/utils/throughput-tracker.ts +18 -132
- package/src/utils/voice-support.ts +18 -1
- package/src/voice/voice-turn-tracker.ts +18 -0
- package/src/webmcp-bridge.ts +1 -1
- package/dist/event-stream-view-FKWDY3UB.js +0 -1
- 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.
|
|
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
|
|
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
|
-
//
|
|
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('
|
|
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).
|
|
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":"
|
|
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":"
|
|
123
|
+
first.push('data: {"type":"execution_complete","success":true}\n\n');
|
|
124
124
|
first.close();
|
|
125
|
-
second.push('data: {"type":"
|
|
125
|
+
second.push('data: {"type":"execution_complete","success":true}\n\n');
|
|
126
126
|
second.close();
|
|
127
127
|
await Promise.all([firstDispatch, secondDispatch]);
|
|
128
128
|
|