@runtypelabs/persona 3.9.1 → 3.10.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/index.cjs +46 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.global.js +67 -65
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +46 -44
- package/dist/index.js.map +1 -1
- package/dist/theme-editor.cjs +828 -212
- package/dist/theme-editor.d.cts +128 -3
- package/dist/theme-editor.d.ts +128 -3
- package/dist/theme-editor.js +824 -212
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +8 -0
- package/dist/theme-reference.d.ts +8 -0
- package/dist/theme-reference.js +1 -1
- package/dist/widget.css +124 -0
- package/package.json +1 -1
- package/src/client.test.ts +312 -1
- package/src/client.ts +247 -24
- package/src/components/messages.ts +1 -1
- package/src/components/reasoning-bubble.ts +117 -28
- package/src/components/tool-bubble.ts +162 -28
- package/src/defaults.ts +13 -1
- package/src/styles/widget.css +124 -0
- package/src/theme-editor/index.ts +5 -0
- package/src/theme-editor/preview-utils.test.ts +58 -0
- package/src/theme-editor/preview-utils.ts +220 -4
- package/src/theme-editor/sections.test.ts +20 -0
- package/src/theme-editor/sections.ts +10 -0
- package/src/theme-reference.ts +8 -3
- package/src/tool-call-display-defaults.test.ts +23 -0
- package/src/types.ts +126 -0
- package/src/ui.scroll.test.ts +104 -0
- package/src/ui.tool-display.test.ts +204 -0
- package/src/ui.ts +103 -3
- package/src/utils/message-fingerprint.test.ts +17 -0
- package/src/utils/message-fingerprint.ts +13 -1
|
@@ -197,7 +197,195 @@ export function buildSrcdoc(
|
|
|
197
197
|
|
|
198
198
|
export type PreviewScene = 'home' | 'conversation' | 'minimized' | 'artifact';
|
|
199
199
|
|
|
200
|
-
export
|
|
200
|
+
export type PreviewTranscriptEntryPreset =
|
|
201
|
+
| 'user-message'
|
|
202
|
+
| 'assistant-message'
|
|
203
|
+
| 'reasoning-streaming'
|
|
204
|
+
| 'reasoning-complete'
|
|
205
|
+
| 'tool-running'
|
|
206
|
+
| 'tool-complete';
|
|
207
|
+
|
|
208
|
+
const PREVIEW_TRANSCRIPT_PRESET_LABELS: Record<PreviewTranscriptEntryPreset, string> = {
|
|
209
|
+
'user-message': 'User message',
|
|
210
|
+
'assistant-message': 'Assistant message',
|
|
211
|
+
'reasoning-streaming': 'Reasoning (streaming)',
|
|
212
|
+
'reasoning-complete': 'Reasoning (complete)',
|
|
213
|
+
'tool-running': 'Tool call (running)',
|
|
214
|
+
'tool-complete': 'Tool call (complete)',
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export function getPreviewTranscriptPresetLabel(preset: PreviewTranscriptEntryPreset): string {
|
|
218
|
+
return PREVIEW_TRANSCRIPT_PRESET_LABELS[preset];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function createPreviewTranscriptEntry(
|
|
222
|
+
preset: PreviewTranscriptEntryPreset,
|
|
223
|
+
index = 0
|
|
224
|
+
): AgentWidgetMessage {
|
|
225
|
+
const createdAt = new Date(Date.now() - Math.max(0, 60 - index) * 1000).toISOString();
|
|
226
|
+
const suffix = `${preset}-${index}`;
|
|
227
|
+
|
|
228
|
+
switch (preset) {
|
|
229
|
+
case 'user-message':
|
|
230
|
+
return {
|
|
231
|
+
id: `preview-seq-user-${suffix}`,
|
|
232
|
+
role: 'user',
|
|
233
|
+
content: 'Can you continue with the next step?',
|
|
234
|
+
createdAt,
|
|
235
|
+
};
|
|
236
|
+
case 'assistant-message':
|
|
237
|
+
return {
|
|
238
|
+
id: `preview-seq-assistant-${suffix}`,
|
|
239
|
+
role: 'assistant',
|
|
240
|
+
content: 'Absolutely. I can keep going and explain what happens next.',
|
|
241
|
+
createdAt,
|
|
242
|
+
};
|
|
243
|
+
case 'reasoning-streaming':
|
|
244
|
+
return {
|
|
245
|
+
id: `preview-seq-reasoning-stream-${suffix}`,
|
|
246
|
+
role: 'assistant',
|
|
247
|
+
content: '',
|
|
248
|
+
createdAt,
|
|
249
|
+
streaming: true,
|
|
250
|
+
variant: 'reasoning',
|
|
251
|
+
reasoning: {
|
|
252
|
+
id: `preview-reasoning-stream-${suffix}`,
|
|
253
|
+
status: 'streaming',
|
|
254
|
+
chunks: ['Thinking through the next step in the workflow...'],
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
case 'reasoning-complete':
|
|
258
|
+
return {
|
|
259
|
+
id: `preview-seq-reasoning-complete-${suffix}`,
|
|
260
|
+
role: 'assistant',
|
|
261
|
+
content: '',
|
|
262
|
+
createdAt,
|
|
263
|
+
streaming: false,
|
|
264
|
+
variant: 'reasoning',
|
|
265
|
+
reasoning: {
|
|
266
|
+
id: `preview-reasoning-complete-${suffix}`,
|
|
267
|
+
status: 'complete',
|
|
268
|
+
chunks: ['Reviewed the requirements and finalized the reasoning output.'],
|
|
269
|
+
durationMs: 1200,
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
case 'tool-complete':
|
|
273
|
+
return {
|
|
274
|
+
id: `preview-seq-tool-complete-${suffix}`,
|
|
275
|
+
role: 'assistant',
|
|
276
|
+
content: '',
|
|
277
|
+
createdAt,
|
|
278
|
+
streaming: false,
|
|
279
|
+
variant: 'tool',
|
|
280
|
+
toolCall: {
|
|
281
|
+
id: `preview-tool-complete-${suffix}`,
|
|
282
|
+
name: 'Create build instructions',
|
|
283
|
+
status: 'complete',
|
|
284
|
+
chunks: ['Prepared the build instructions and validated the inputs.'],
|
|
285
|
+
result: { ok: true },
|
|
286
|
+
duration: 420,
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
case 'tool-running':
|
|
290
|
+
default:
|
|
291
|
+
return {
|
|
292
|
+
id: `preview-seq-tool-running-${suffix}`,
|
|
293
|
+
role: 'assistant',
|
|
294
|
+
content: '',
|
|
295
|
+
createdAt,
|
|
296
|
+
streaming: true,
|
|
297
|
+
variant: 'tool',
|
|
298
|
+
toolCall: {
|
|
299
|
+
id: `preview-tool-running-${suffix}`,
|
|
300
|
+
name: 'Get platform documentation',
|
|
301
|
+
status: 'running',
|
|
302
|
+
chunks: ['Fetching the relevant platform documentation...'],
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function appendPreviewTranscriptEntry(
|
|
309
|
+
messages: AgentWidgetMessage[],
|
|
310
|
+
preset: PreviewTranscriptEntryPreset
|
|
311
|
+
): AgentWidgetMessage[] {
|
|
312
|
+
return [...messages, createPreviewTranscriptEntry(preset, messages.length)];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const createAdvancedTranscriptPreviewMessages = (): AgentWidgetMessage[] => [
|
|
316
|
+
{
|
|
317
|
+
id: "preview-adv-1",
|
|
318
|
+
role: "user",
|
|
319
|
+
content: "Can you create the product and gather the docs?",
|
|
320
|
+
createdAt: new Date(Date.now() - 180000).toISOString(),
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
id: "preview-adv-2",
|
|
324
|
+
role: "assistant",
|
|
325
|
+
content: "",
|
|
326
|
+
createdAt: new Date(Date.now() - 150000).toISOString(),
|
|
327
|
+
streaming: true,
|
|
328
|
+
variant: "reasoning",
|
|
329
|
+
reasoning: {
|
|
330
|
+
id: "preview-reasoning",
|
|
331
|
+
status: "streaming",
|
|
332
|
+
chunks: [
|
|
333
|
+
"Now let me get the Persona embed documentation and builtin tools catalog.",
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
id: "preview-adv-3",
|
|
339
|
+
role: "assistant",
|
|
340
|
+
content: "",
|
|
341
|
+
createdAt: new Date(Date.now() - 120000).toISOString(),
|
|
342
|
+
streaming: true,
|
|
343
|
+
variant: "tool",
|
|
344
|
+
toolCall: {
|
|
345
|
+
id: "preview-tool-1",
|
|
346
|
+
name: "Load tools",
|
|
347
|
+
status: "running",
|
|
348
|
+
chunks: ["Loaded tools, used Runtype integration"],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: "preview-adv-4",
|
|
353
|
+
role: "assistant",
|
|
354
|
+
content: "",
|
|
355
|
+
createdAt: new Date(Date.now() - 90000).toISOString(),
|
|
356
|
+
streaming: true,
|
|
357
|
+
variant: "tool",
|
|
358
|
+
toolCall: {
|
|
359
|
+
id: "preview-tool-2",
|
|
360
|
+
name: "Get platform documentation",
|
|
361
|
+
status: "running",
|
|
362
|
+
chunks: ["Get platform documentation"],
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
id: "preview-adv-5",
|
|
367
|
+
role: "assistant",
|
|
368
|
+
content: "I loaded the tools and fetched the docs. Next I can assemble the product details.",
|
|
369
|
+
createdAt: new Date(Date.now() - 30000).toISOString(),
|
|
370
|
+
},
|
|
371
|
+
];
|
|
372
|
+
|
|
373
|
+
const shouldSeedAdvancedTranscriptPreview = (
|
|
374
|
+
config?: Partial<AgentWidgetConfig>
|
|
375
|
+
): boolean =>
|
|
376
|
+
Boolean(
|
|
377
|
+
config?.features?.toolCallDisplay?.activePreview ||
|
|
378
|
+
config?.features?.toolCallDisplay?.grouped ||
|
|
379
|
+
(config?.features?.toolCallDisplay?.collapsedMode &&
|
|
380
|
+
config.features.toolCallDisplay.collapsedMode !== "tool-call") ||
|
|
381
|
+
config?.features?.reasoningDisplay?.activePreview
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
export function createPreviewMessages(
|
|
385
|
+
scene: PreviewScene,
|
|
386
|
+
config?: Partial<AgentWidgetConfig>,
|
|
387
|
+
appendedMessages: AgentWidgetMessage[] = []
|
|
388
|
+
): AgentWidgetMessage[] {
|
|
201
389
|
if (scene === 'home') {
|
|
202
390
|
return [{ id: 'preview-home-1', role: 'assistant', content: 'Hi there! How can we help today?', createdAt: new Date().toISOString() }];
|
|
203
391
|
}
|
|
@@ -210,22 +398,30 @@ export function createPreviewMessages(scene: PreviewScene): AgentWidgetMessage[]
|
|
|
210
398
|
{ id: 'preview-art-2', role: 'assistant', content: 'Here\u2019s a project overview document for you.', createdAt: new Date(Date.now() - 60000).toISOString() },
|
|
211
399
|
];
|
|
212
400
|
}
|
|
401
|
+
if (scene === 'conversation' && shouldSeedAdvancedTranscriptPreview(config)) {
|
|
402
|
+
return [...createAdvancedTranscriptPreviewMessages(), ...appendedMessages];
|
|
403
|
+
}
|
|
213
404
|
return [
|
|
214
405
|
{ id: 'preview-conv-1', role: 'assistant', content: 'Hello! How can I help you today?', createdAt: new Date(Date.now() - 180000).toISOString() },
|
|
215
406
|
{ id: 'preview-conv-2', role: 'user', content: 'I want to customize the theme editor preview.', createdAt: new Date(Date.now() - 120000).toISOString() },
|
|
216
407
|
{ id: 'preview-conv-3', role: 'assistant', content: 'Absolutely. Check out the [getting started guide](https://example.com) to see what\u2019s possible, then adjust colors and tokens to match your brand.', createdAt: new Date(Date.now() - 60000).toISOString() },
|
|
408
|
+
...appendedMessages,
|
|
217
409
|
];
|
|
218
410
|
}
|
|
219
411
|
|
|
220
412
|
// ─── Scene Config ───────────────────────────────────────────────
|
|
221
413
|
|
|
222
|
-
export function applySceneConfig(
|
|
414
|
+
export function applySceneConfig(
|
|
415
|
+
base: AgentWidgetConfig,
|
|
416
|
+
scene: PreviewScene,
|
|
417
|
+
appendedMessages: AgentWidgetMessage[] = []
|
|
418
|
+
): AgentWidgetConfig {
|
|
223
419
|
const launcher = { ...base.launcher, enabled: true, autoExpand: scene !== 'minimized' };
|
|
224
420
|
const config = {
|
|
225
421
|
...base,
|
|
226
422
|
launcher,
|
|
227
423
|
suggestionChips: scene === 'home' ? (base.suggestionChips?.length ? base.suggestionChips : HOME_SUGGESTION_CHIPS) : base.suggestionChips,
|
|
228
|
-
initialMessages: createPreviewMessages(scene),
|
|
424
|
+
initialMessages: createPreviewMessages(scene, base, appendedMessages),
|
|
229
425
|
storageAdapter: PREVIEW_STORAGE_ADAPTER,
|
|
230
426
|
} as AgentWidgetConfig;
|
|
231
427
|
|
|
@@ -244,6 +440,7 @@ export interface PreviewConfigOptions {
|
|
|
244
440
|
theme?: DeepPartial<PersonaTheme>;
|
|
245
441
|
darkTheme?: DeepPartial<PersonaTheme>;
|
|
246
442
|
scene?: PreviewScene;
|
|
443
|
+
appendedMessages?: AgentWidgetMessage[];
|
|
247
444
|
}
|
|
248
445
|
|
|
249
446
|
export function buildPreviewConfig(
|
|
@@ -261,5 +458,24 @@ export function buildPreviewConfig(
|
|
|
261
458
|
colorScheme: shellModeOverride ?? (options.config?.colorScheme as string) ?? 'light',
|
|
262
459
|
} as AgentWidgetConfig;
|
|
263
460
|
|
|
264
|
-
return applySceneConfig(base, scene);
|
|
461
|
+
return applySceneConfig(base, scene, options.appendedMessages ?? []);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function buildPreviewConfigWithMessages(
|
|
465
|
+
options: PreviewConfigOptions,
|
|
466
|
+
messages: AgentWidgetMessage[],
|
|
467
|
+
shellModeOverride?: 'light' | 'dark'
|
|
468
|
+
): AgentWidgetConfig {
|
|
469
|
+
const theme = options.theme ? createTheme(options.theme, { validate: false }) : createTheme();
|
|
470
|
+
const scene = options.scene ?? 'conversation';
|
|
471
|
+
|
|
472
|
+
const base = {
|
|
473
|
+
...DEFAULT_WIDGET_CONFIG,
|
|
474
|
+
...options.config,
|
|
475
|
+
theme,
|
|
476
|
+
darkTheme: options.darkTheme,
|
|
477
|
+
colorScheme: shellModeOverride ?? (options.config?.colorScheme as string) ?? 'light',
|
|
478
|
+
} as AgentWidgetConfig;
|
|
479
|
+
|
|
480
|
+
return applySceneConfig(base, scene, messages);
|
|
265
481
|
}
|
|
@@ -40,4 +40,24 @@ describe("theme editor scroll-to-bottom controls", () => {
|
|
|
40
40
|
);
|
|
41
41
|
expect(INTERFACE_ROLES_SECTION.fields.some((field) => field.id === "role-scroll-to-bottom")).toBe(true);
|
|
42
42
|
});
|
|
43
|
+
|
|
44
|
+
it("exposes grouped and collapsed tool call preview controls", () => {
|
|
45
|
+
const debugSection = CONFIGURE_SECTIONS.find((section) => section.id === "debug-inspection");
|
|
46
|
+
|
|
47
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.collapsedMode")).toBe(true);
|
|
48
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.activePreview")).toBe(true);
|
|
49
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.previewMaxLines")).toBe(true);
|
|
50
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.activeMinHeight")).toBe(true);
|
|
51
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.expandable")).toBe(true);
|
|
52
|
+
expect(debugSection?.fields.some((field) => field.path === "features.toolCallDisplay.grouped")).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("exposes collapsed reasoning preview controls", () => {
|
|
56
|
+
const debugSection = CONFIGURE_SECTIONS.find((section) => section.id === "debug-inspection");
|
|
57
|
+
|
|
58
|
+
expect(debugSection?.fields.some((field) => field.path === "features.reasoningDisplay.expandable")).toBe(true);
|
|
59
|
+
expect(debugSection?.fields.some((field) => field.path === "features.reasoningDisplay.activePreview")).toBe(true);
|
|
60
|
+
expect(debugSection?.fields.some((field) => field.path === "features.reasoningDisplay.previewMaxLines")).toBe(true);
|
|
61
|
+
expect(debugSection?.fields.some((field) => field.path === "features.reasoningDisplay.activeMinHeight")).toBe(true);
|
|
62
|
+
});
|
|
43
63
|
});
|
|
@@ -743,6 +743,16 @@ const debugSectionDef: SectionDef = {
|
|
|
743
743
|
fields: [
|
|
744
744
|
{ id: 'dev-reasoning', label: 'Show Reasoning', description: 'Display AI reasoning steps', type: 'toggle', path: 'features.showReasoning', defaultValue: false },
|
|
745
745
|
{ id: 'dev-tool-calls', label: 'Show Tool Calls', description: 'Display tool call details', type: 'toggle', path: 'features.showToolCalls', defaultValue: false },
|
|
746
|
+
{ id: 'dev-tool-collapsed-mode', label: 'Tool Call Summary', description: 'Choose what collapsed tool rows show by default', type: 'select', path: 'features.toolCallDisplay.collapsedMode', defaultValue: 'tool-call', options: [{ value: 'tool-call', label: 'Tool Call' }, { value: 'tool-name', label: 'Tool Name' }, { value: 'tool-preview', label: 'Tool Preview' }] },
|
|
747
|
+
{ id: 'dev-tool-active-preview', label: 'Tool Preview While Active', description: 'Show a lightweight preview in collapsed active tool rows', type: 'toggle', path: 'features.toolCallDisplay.activePreview', defaultValue: false },
|
|
748
|
+
{ id: 'dev-tool-preview-lines', label: 'Tool Preview Lines', type: 'select', path: 'features.toolCallDisplay.previewMaxLines', defaultValue: 3, options: [{ value: '1', label: '1' }, { value: '2', label: '2' }, { value: '3', label: '3' }, { value: '4', label: '4' }, { value: '5', label: '5' }], formatValue: (v: unknown) => String(v ?? 3), parseValue: (v: unknown) => Number(v) },
|
|
749
|
+
{ id: 'dev-tool-active-min-height', label: 'Tool Active Min Height', description: 'CSS min-height for collapsed active tool rows (e.g. 5rem)', type: 'text', path: 'features.toolCallDisplay.activeMinHeight', defaultValue: '' },
|
|
750
|
+
{ id: 'dev-tool-expandable', label: 'Tool Calls Expandable', description: 'Allow expanding tool call rows to see full details', type: 'toggle', path: 'features.toolCallDisplay.expandable', defaultValue: true },
|
|
751
|
+
{ id: 'dev-tool-grouped', label: 'Group Sequential Tool Calls', description: 'Render consecutive tool rows inside a grouped container', type: 'toggle', path: 'features.toolCallDisplay.grouped', defaultValue: false },
|
|
752
|
+
{ id: 'dev-reasoning-expandable', label: 'Reasoning Expandable', description: 'Allow expanding reasoning rows to see full details', type: 'toggle', path: 'features.reasoningDisplay.expandable', defaultValue: true },
|
|
753
|
+
{ id: 'dev-reasoning-active-preview', label: 'Reasoning Preview While Active', description: 'Show a lightweight preview in collapsed active reasoning rows', type: 'toggle', path: 'features.reasoningDisplay.activePreview', defaultValue: false },
|
|
754
|
+
{ id: 'dev-reasoning-preview-lines', label: 'Reasoning Preview Lines', type: 'select', path: 'features.reasoningDisplay.previewMaxLines', defaultValue: 3, options: [{ value: '1', label: '1' }, { value: '2', label: '2' }, { value: '3', label: '3' }, { value: '4', label: '4' }, { value: '5', label: '5' }], formatValue: (v: unknown) => String(v ?? 3), parseValue: (v: unknown) => Number(v) },
|
|
755
|
+
{ id: 'dev-reasoning-active-min-height', label: 'Reasoning Active Min Height', description: 'CSS min-height for collapsed active reasoning rows (e.g. 5rem)', type: 'text', path: 'features.reasoningDisplay.activeMinHeight', defaultValue: '' },
|
|
746
756
|
{ id: 'dev-debug', label: 'Debug Mode', description: 'Show debug information', type: 'toggle', path: 'debug', defaultValue: false },
|
|
747
757
|
],
|
|
748
758
|
};
|
package/src/theme-reference.ts
CHANGED
|
@@ -210,9 +210,14 @@ export const THEME_TOKEN_DOCS = {
|
|
|
210
210
|
'features.scrollToBottom.enabled, features.scrollToBottom.iconName, features.scrollToBottom.label (empty string renders icon-only). Defaults: enabled=true, iconName="arrow-down", label="".',
|
|
211
211
|
},
|
|
212
212
|
toolCall: {
|
|
213
|
-
description: 'Tool call display styling.',
|
|
213
|
+
description: 'Tool call display styling and collapsed/grouped rendering hooks.',
|
|
214
214
|
properties:
|
|
215
|
-
'shadow, backgroundColor, borderColor, borderWidth, borderRadius, headerBackgroundColor, headerTextColor, headerPaddingX, headerPaddingY, contentBackgroundColor, contentTextColor, contentPaddingX, contentPaddingY, codeBlockBackgroundColor, codeBlockBorderColor, codeBlockTextColor, toggleTextColor, labelTextColor.',
|
|
215
|
+
'shadow, backgroundColor, borderColor, borderWidth, borderRadius, headerBackgroundColor, headerTextColor, headerPaddingX, headerPaddingY, contentBackgroundColor, contentTextColor, contentPaddingX, contentPaddingY, codeBlockBackgroundColor, codeBlockBorderColor, codeBlockTextColor, toggleTextColor, labelTextColor, renderCollapsedSummary, renderCollapsedPreview, renderGroupedSummary.',
|
|
216
|
+
},
|
|
217
|
+
reasoning: {
|
|
218
|
+
description: 'Reasoning/thinking row rendering hooks.',
|
|
219
|
+
properties:
|
|
220
|
+
'renderCollapsedSummary, renderCollapsedPreview.',
|
|
216
221
|
},
|
|
217
222
|
approval: {
|
|
218
223
|
description:
|
|
@@ -277,7 +282,7 @@ export const THEME_TOKEN_DOCS = {
|
|
|
277
282
|
features: {
|
|
278
283
|
description: 'Feature flags.',
|
|
279
284
|
properties:
|
|
280
|
-
'showReasoning (AI thinking steps), showToolCalls (tool invocations), artifacts (sidebar config).',
|
|
285
|
+
'showReasoning (AI thinking steps), showToolCalls (tool invocations), toolCallDisplay (collapsedMode, activePreview, activeMinHeight, previewMaxLines, grouped), reasoningDisplay (activePreview, activeMinHeight, previewMaxLines), artifacts (sidebar config).',
|
|
281
286
|
},
|
|
282
287
|
},
|
|
283
288
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_WIDGET_CONFIG } from "./defaults";
|
|
4
|
+
|
|
5
|
+
describe("tool call display defaults", () => {
|
|
6
|
+
it("keeps advanced tool call transcript modes disabled by default", () => {
|
|
7
|
+
expect(DEFAULT_WIDGET_CONFIG.features?.toolCallDisplay).toEqual({
|
|
8
|
+
collapsedMode: "tool-call",
|
|
9
|
+
activePreview: false,
|
|
10
|
+
grouped: false,
|
|
11
|
+
previewMaxLines: 3,
|
|
12
|
+
expandable: true,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("keeps advanced reasoning transcript modes disabled by default", () => {
|
|
17
|
+
expect(DEFAULT_WIDGET_CONFIG.features?.reasoningDisplay).toEqual({
|
|
18
|
+
activePreview: false,
|
|
19
|
+
previewMaxLines: 3,
|
|
20
|
+
expandable: true,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -572,12 +572,77 @@ export type AgentWidgetScrollToBottomFeature = {
|
|
|
572
572
|
label?: string;
|
|
573
573
|
};
|
|
574
574
|
|
|
575
|
+
export type AgentWidgetToolCallCollapsedMode =
|
|
576
|
+
| "tool-call"
|
|
577
|
+
| "tool-name"
|
|
578
|
+
| "tool-preview";
|
|
579
|
+
|
|
580
|
+
export type AgentWidgetToolCallDisplayFeature = {
|
|
581
|
+
/**
|
|
582
|
+
* Controls what collapsed tool call rows show in their header/summary area.
|
|
583
|
+
* @default "tool-call"
|
|
584
|
+
*/
|
|
585
|
+
collapsedMode?: AgentWidgetToolCallCollapsedMode;
|
|
586
|
+
/**
|
|
587
|
+
* When true, active collapsed tool calls can render a lightweight preview block.
|
|
588
|
+
* @default false
|
|
589
|
+
*/
|
|
590
|
+
activePreview?: boolean;
|
|
591
|
+
/**
|
|
592
|
+
* Optional CSS min-height applied to active collapsed tool call rows.
|
|
593
|
+
*/
|
|
594
|
+
activeMinHeight?: string;
|
|
595
|
+
/**
|
|
596
|
+
* Maximum preview lines shown for collapsed active tool calls.
|
|
597
|
+
* @default 3
|
|
598
|
+
*/
|
|
599
|
+
previewMaxLines?: number;
|
|
600
|
+
/**
|
|
601
|
+
* When true, consecutive tool call rows can be visually grouped.
|
|
602
|
+
* @default false
|
|
603
|
+
*/
|
|
604
|
+
grouped?: boolean;
|
|
605
|
+
/**
|
|
606
|
+
* When false, tool call bubbles show only the collapsed summary with no
|
|
607
|
+
* expand/collapse toggle. Users see tool awareness without full details.
|
|
608
|
+
* @default true
|
|
609
|
+
*/
|
|
610
|
+
expandable?: boolean;
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
export type AgentWidgetReasoningDisplayFeature = {
|
|
614
|
+
/**
|
|
615
|
+
* When true, active collapsed reasoning rows can render a lightweight preview block.
|
|
616
|
+
* @default false
|
|
617
|
+
*/
|
|
618
|
+
activePreview?: boolean;
|
|
619
|
+
/**
|
|
620
|
+
* Optional CSS min-height applied to active collapsed reasoning rows.
|
|
621
|
+
*/
|
|
622
|
+
activeMinHeight?: string;
|
|
623
|
+
/**
|
|
624
|
+
* Maximum preview lines shown for collapsed active reasoning rows.
|
|
625
|
+
* @default 3
|
|
626
|
+
*/
|
|
627
|
+
previewMaxLines?: number;
|
|
628
|
+
/**
|
|
629
|
+
* When false, reasoning bubbles show only the collapsed summary with no
|
|
630
|
+
* expand/collapse toggle. Users see reasoning awareness without full details.
|
|
631
|
+
* @default true
|
|
632
|
+
*/
|
|
633
|
+
expandable?: boolean;
|
|
634
|
+
};
|
|
635
|
+
|
|
575
636
|
export type AgentWidgetFeatureFlags = {
|
|
576
637
|
showReasoning?: boolean;
|
|
577
638
|
showToolCalls?: boolean;
|
|
578
639
|
showEventStreamToggle?: boolean;
|
|
579
640
|
/** Shared transcript + event stream scroll-to-bottom affordance. */
|
|
580
641
|
scrollToBottom?: AgentWidgetScrollToBottomFeature;
|
|
642
|
+
/** Collapsed transcript behavior for tool call rows. */
|
|
643
|
+
toolCallDisplay?: AgentWidgetToolCallDisplayFeature;
|
|
644
|
+
/** Collapsed transcript behavior for reasoning rows. */
|
|
645
|
+
reasoningDisplay?: AgentWidgetReasoningDisplayFeature;
|
|
581
646
|
/** Configuration for the Event Stream inspector view */
|
|
582
647
|
eventStream?: EventStreamConfig;
|
|
583
648
|
/** Optional artifact sidebar (split pane / mobile drawer) */
|
|
@@ -1186,6 +1251,66 @@ export type AgentWidgetToolCallConfig = {
|
|
|
1186
1251
|
codeBlockTextColor?: string;
|
|
1187
1252
|
toggleTextColor?: string;
|
|
1188
1253
|
labelTextColor?: string;
|
|
1254
|
+
/**
|
|
1255
|
+
* Override the collapsed summary row content for a tool call bubble.
|
|
1256
|
+
* Return `null` to fall back to the built-in summary for the active display mode.
|
|
1257
|
+
*/
|
|
1258
|
+
renderCollapsedSummary?: (context: {
|
|
1259
|
+
message: AgentWidgetMessage;
|
|
1260
|
+
toolCall: AgentWidgetToolCall;
|
|
1261
|
+
defaultSummary: string;
|
|
1262
|
+
previewText: string;
|
|
1263
|
+
collapsedMode: AgentWidgetToolCallCollapsedMode;
|
|
1264
|
+
isActive: boolean;
|
|
1265
|
+
config: AgentWidgetConfig;
|
|
1266
|
+
}) => HTMLElement | string | null;
|
|
1267
|
+
/**
|
|
1268
|
+
* Override the lightweight collapsed preview content shown for active tool rows.
|
|
1269
|
+
* Return `null` to fall back to the built-in preview text.
|
|
1270
|
+
*/
|
|
1271
|
+
renderCollapsedPreview?: (context: {
|
|
1272
|
+
message: AgentWidgetMessage;
|
|
1273
|
+
toolCall: AgentWidgetToolCall;
|
|
1274
|
+
defaultPreview: string;
|
|
1275
|
+
isActive: boolean;
|
|
1276
|
+
config: AgentWidgetConfig;
|
|
1277
|
+
}) => HTMLElement | string | null;
|
|
1278
|
+
/**
|
|
1279
|
+
* Override the summary content for grouped consecutive tool-call containers.
|
|
1280
|
+
* Return `null` to fall back to the built-in `Called [x] tools` summary.
|
|
1281
|
+
*/
|
|
1282
|
+
renderGroupedSummary?: (context: {
|
|
1283
|
+
messages: AgentWidgetMessage[];
|
|
1284
|
+
toolCalls: AgentWidgetToolCall[];
|
|
1285
|
+
defaultSummary: string;
|
|
1286
|
+
config: AgentWidgetConfig;
|
|
1287
|
+
}) => HTMLElement | string | null;
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1290
|
+
export type AgentWidgetReasoningConfig = {
|
|
1291
|
+
/**
|
|
1292
|
+
* Override the collapsed summary row content for a reasoning bubble.
|
|
1293
|
+
* Return `null` to fall back to the built-in summary.
|
|
1294
|
+
*/
|
|
1295
|
+
renderCollapsedSummary?: (context: {
|
|
1296
|
+
message: AgentWidgetMessage;
|
|
1297
|
+
reasoning: AgentWidgetReasoning;
|
|
1298
|
+
defaultSummary: string;
|
|
1299
|
+
previewText: string;
|
|
1300
|
+
isActive: boolean;
|
|
1301
|
+
config: AgentWidgetConfig;
|
|
1302
|
+
}) => HTMLElement | string | null;
|
|
1303
|
+
/**
|
|
1304
|
+
* Override the lightweight collapsed preview content shown for active reasoning rows.
|
|
1305
|
+
* Return `null` to fall back to the built-in preview text.
|
|
1306
|
+
*/
|
|
1307
|
+
renderCollapsedPreview?: (context: {
|
|
1308
|
+
message: AgentWidgetMessage;
|
|
1309
|
+
reasoning: AgentWidgetReasoning;
|
|
1310
|
+
defaultPreview: string;
|
|
1311
|
+
isActive: boolean;
|
|
1312
|
+
config: AgentWidgetConfig;
|
|
1313
|
+
}) => HTMLElement | string | null;
|
|
1189
1314
|
};
|
|
1190
1315
|
|
|
1191
1316
|
export type AgentWidgetSuggestionChipsConfig = {
|
|
@@ -2358,6 +2483,7 @@ export type AgentWidgetConfig = {
|
|
|
2358
2483
|
*/
|
|
2359
2484
|
textToSpeech?: TextToSpeechConfig;
|
|
2360
2485
|
toolCall?: AgentWidgetToolCallConfig;
|
|
2486
|
+
reasoning?: AgentWidgetReasoningConfig;
|
|
2361
2487
|
/**
|
|
2362
2488
|
* Configuration for tool approval bubbles.
|
|
2363
2489
|
* Set to `false` to disable built-in approval handling entirely.
|
package/src/ui.scroll.test.ts
CHANGED
|
@@ -135,6 +135,36 @@ const emitReasoningMessage = (
|
|
|
135
135
|
});
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
+
const emitToolMessage = (
|
|
139
|
+
controller: ReturnType<typeof createAgentExperience>,
|
|
140
|
+
{
|
|
141
|
+
id = STREAM_MESSAGE_ID,
|
|
142
|
+
status = "running",
|
|
143
|
+
chunks,
|
|
144
|
+
}: {
|
|
145
|
+
id?: string;
|
|
146
|
+
status?: "pending" | "running" | "complete";
|
|
147
|
+
chunks: string[];
|
|
148
|
+
}
|
|
149
|
+
) => {
|
|
150
|
+
controller.injectTestMessage({
|
|
151
|
+
type: "message",
|
|
152
|
+
message: {
|
|
153
|
+
id,
|
|
154
|
+
role: "assistant",
|
|
155
|
+
content: "",
|
|
156
|
+
createdAt: STREAM_CREATED_AT,
|
|
157
|
+
streaming: status !== "complete",
|
|
158
|
+
variant: "tool",
|
|
159
|
+
toolCall: {
|
|
160
|
+
id,
|
|
161
|
+
status,
|
|
162
|
+
chunks,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
|
|
138
168
|
const createCustomComposer = () => {
|
|
139
169
|
const footer = document.createElement("div");
|
|
140
170
|
footer.className = "persona-widget-footer";
|
|
@@ -368,6 +398,80 @@ describe("createAgentExperience streaming scroll", () => {
|
|
|
368
398
|
controller.destroy();
|
|
369
399
|
});
|
|
370
400
|
|
|
401
|
+
it("keeps following collapsed tool preview updates while active", () => {
|
|
402
|
+
const raf = installRafMock();
|
|
403
|
+
const mount = createMount();
|
|
404
|
+
const controller = createAgentExperience(mount, {
|
|
405
|
+
apiUrl: "https://api.example.com/chat",
|
|
406
|
+
launcher: { enabled: false },
|
|
407
|
+
features: {
|
|
408
|
+
toolCallDisplay: {
|
|
409
|
+
activePreview: true,
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
} as any);
|
|
413
|
+
|
|
414
|
+
const scrollContainer = mount.querySelector<HTMLElement>("#persona-scroll-container");
|
|
415
|
+
expect(scrollContainer).not.toBeNull();
|
|
416
|
+
|
|
417
|
+
const metrics = installScrollMetrics(scrollContainer!, {
|
|
418
|
+
scrollHeight: 980,
|
|
419
|
+
clientHeight: 400
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
emitStreamingStatus(controller);
|
|
423
|
+
emitToolMessage(controller, { chunks: ["Loaded tools"] });
|
|
424
|
+
raf.flush();
|
|
425
|
+
|
|
426
|
+
expect(metrics.getScrollTop()).toBe(metrics.getBottomScrollTop());
|
|
427
|
+
|
|
428
|
+
metrics.setScrollHeight(1045);
|
|
429
|
+
emitToolMessage(controller, {
|
|
430
|
+
chunks: ["Loaded tools", "\nFetched platform documentation"]
|
|
431
|
+
});
|
|
432
|
+
raf.flush();
|
|
433
|
+
|
|
434
|
+
expect(metrics.getScrollTop()).toBe(metrics.getBottomScrollTop());
|
|
435
|
+
|
|
436
|
+
controller.destroy();
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("keeps following grouped tool sequences as new tool rows arrive", () => {
|
|
440
|
+
const raf = installRafMock();
|
|
441
|
+
const mount = createMount();
|
|
442
|
+
const controller = createAgentExperience(mount, {
|
|
443
|
+
apiUrl: "https://api.example.com/chat",
|
|
444
|
+
launcher: { enabled: false },
|
|
445
|
+
features: {
|
|
446
|
+
toolCallDisplay: {
|
|
447
|
+
grouped: true,
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
} as any);
|
|
451
|
+
|
|
452
|
+
const scrollContainer = mount.querySelector<HTMLElement>("#persona-scroll-container");
|
|
453
|
+
expect(scrollContainer).not.toBeNull();
|
|
454
|
+
|
|
455
|
+
const metrics = installScrollMetrics(scrollContainer!, {
|
|
456
|
+
scrollHeight: 960,
|
|
457
|
+
clientHeight: 400
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
emitStreamingStatus(controller);
|
|
461
|
+
emitToolMessage(controller, { id: "tool-1", chunks: ["Loaded tools"] });
|
|
462
|
+
raf.flush();
|
|
463
|
+
|
|
464
|
+
expect(metrics.getScrollTop()).toBe(metrics.getBottomScrollTop());
|
|
465
|
+
|
|
466
|
+
metrics.setScrollHeight(1030);
|
|
467
|
+
emitToolMessage(controller, { id: "tool-2", chunks: ["Fetched platform documentation"] });
|
|
468
|
+
raf.flush();
|
|
469
|
+
|
|
470
|
+
expect(metrics.getScrollTop()).toBe(metrics.getBottomScrollTop());
|
|
471
|
+
|
|
472
|
+
controller.destroy();
|
|
473
|
+
});
|
|
474
|
+
|
|
371
475
|
it("uses icon-only arrow-down defaults for the transcript affordance", () => {
|
|
372
476
|
const raf = installRafMock();
|
|
373
477
|
const mount = createMount();
|