@runtypelabs/persona 3.34.1 → 3.35.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/README.md +11 -11
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-CthJFfNx.d.cts → types-DgYsuwXL.d.cts} +15 -14
- package/dist/animations/{types-CthJFfNx.d.ts → types-DgYsuwXL.d.ts} +15 -14
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/codegen.cjs +11 -11
- package/dist/codegen.js +10 -10
- package/dist/index.cjs +46 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +514 -158
- package/dist/index.d.ts +514 -158
- package/dist/index.global.js +41 -89
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +46 -44
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +2 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/markdown-parsers.js +53 -0
- package/dist/plugin-kit.d.cts +4 -4
- package/dist/plugin-kit.d.ts +4 -4
- package/dist/runtype-tts.js +1 -0
- package/dist/smart-dom-reader.cjs +1 -1
- package/dist/smart-dom-reader.d.cts +352 -103
- package/dist/smart-dom-reader.d.ts +352 -103
- package/dist/smart-dom-reader.js +1 -1
- package/dist/theme-editor-preview.cjs +203 -0
- package/dist/theme-editor-preview.d.cts +5748 -0
- package/dist/theme-editor-preview.d.ts +5748 -0
- package/dist/theme-editor-preview.js +203 -0
- package/dist/theme-editor.cjs +14 -131
- package/dist/theme-editor.d.cts +362 -574
- package/dist/theme-editor.d.ts +362 -574
- package/dist/theme-editor.js +14 -131
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +1 -1
- package/dist/theme-reference.d.ts +1 -1
- package/dist/theme-reference.js +1 -1
- package/dist/voice-worklet-player.cjs +80 -0
- package/dist/voice-worklet-player.d.cts +215 -0
- package/dist/voice-worklet-player.d.ts +215 -0
- package/dist/voice-worklet-player.js +80 -0
- package/dist/widget.css +54 -36
- package/package.json +16 -2
- package/src/animations/glyph-cycle.ts +11 -14
- package/src/animations/wipe.ts +1 -1
- package/src/ask-user-question-tool.test.ts +1 -1
- package/src/ask-user-question-tool.ts +6 -8
- package/src/client.test.ts +12 -12
- package/src/client.ts +30 -31
- package/src/codegen.test.ts +1 -1
- package/src/codegen.ts +1 -1
- package/src/components/approval-bubble.test.ts +1 -1
- package/src/components/approval-bubble.ts +3 -3
- package/src/components/artifact-pane.ts +3 -3
- package/src/components/ask-user-question-bubble.test.ts +14 -14
- package/src/components/ask-user-question-bubble.ts +10 -10
- package/src/components/composer-builder.ts +17 -16
- package/src/components/composer-parts.test.ts +54 -0
- package/src/components/composer-parts.ts +95 -126
- package/src/components/demo-carousel.ts +1 -1
- package/src/components/event-stream-view.test.ts +7 -7
- package/src/components/event-stream-view.ts +5 -5
- package/src/components/header-builder.ts +33 -27
- package/src/components/header-layouts.ts +1 -1
- package/src/components/header-parts.test.ts +90 -0
- package/src/components/header-parts.ts +62 -93
- package/src/components/launcher.test.ts +11 -0
- package/src/components/launcher.ts +1 -1
- package/src/components/message-bubble.test.ts +74 -2
- package/src/components/message-bubble.ts +25 -11
- package/src/components/messages.ts +2 -2
- package/src/components/panel.test.ts +1 -1
- package/src/components/panel.ts +92 -97
- package/src/components/pill-composer-builder.ts +28 -24
- package/src/components/reasoning-bubble.ts +2 -2
- package/src/components/suggestions.ts +1 -1
- package/src/components/tool-bubble.ts +1 -1
- package/src/components/widget-view.test.ts +181 -0
- package/src/components/widget-view.ts +234 -0
- package/src/defaults.ts +54 -51
- package/src/generated/runtype-openapi-contract.ts +5 -0
- package/src/index-core.ts +30 -4
- package/src/index-global.ts +73 -6
- package/src/index.ts +7 -1
- package/src/install.test.ts +11 -11
- package/src/install.ts +28 -18
- package/src/launcher-global.ts +25 -14
- package/src/markdown-parsers-eager.ts +20 -0
- package/src/markdown-parsers-entry.ts +4 -0
- package/src/markdown-parsers-loader.ts +49 -0
- package/src/plugin-kit.test.ts +1 -1
- package/src/plugin-kit.ts +7 -7
- package/src/plugins/types.ts +5 -5
- package/src/postprocessors.ts +27 -14
- package/src/runtime/host-layout.test.ts +1 -1
- package/src/runtime/host-layout.ts +4 -5
- package/src/runtime/init.ts +2 -2
- package/src/session.test.ts +5 -6
- package/src/session.ts +333 -227
- package/src/session.voice.test.ts +146 -0
- package/src/session.webmcp.test.ts +24 -25
- package/src/smart-dom-reader.ts +3 -4
- package/src/styles/widget.css +54 -36
- package/src/suggest-replies-tool.test.ts +3 -3
- package/src/suggest-replies-tool.ts +5 -5
- package/src/testing/index.ts +1 -1
- package/src/theme-editor/color-utils.ts +2 -2
- package/src/theme-editor/index.ts +4 -13
- package/src/theme-editor/presets.ts +1 -1
- package/src/theme-editor/preview-utils.ts +22 -20
- package/src/theme-editor/preview.ts +4 -1
- package/src/theme-editor/role-mappings.ts +3 -3
- package/src/theme-editor/sections.ts +21 -20
- package/src/theme-editor/types.ts +1 -1
- package/src/theme-editor/webmcp/index.ts +1 -1
- package/src/theme-editor/webmcp/summary.ts +1 -2
- package/src/theme-editor/webmcp/tools.ts +30 -30
- package/src/theme-editor/webmcp/types.ts +2 -2
- package/src/theme-editor-preview.ts +10 -0
- package/src/theme-reference.ts +26 -26
- package/src/types.ts +368 -99
- package/src/ui.approval-plugin.test.ts +3 -3
- package/src/ui.ask-user-question-plugin.test.ts +9 -9
- package/src/ui.component-directive.test.ts +4 -4
- package/src/ui.composer-bar.test.ts +10 -11
- package/src/ui.composer-keyboard.test.ts +5 -5
- package/src/ui.header-icon-color.test.ts +59 -0
- package/src/ui.scroll.test.ts +5 -6
- package/src/ui.stop-button.test.ts +3 -4
- package/src/ui.suggest-replies.test.ts +2 -2
- package/src/ui.ts +292 -131
- package/src/utils/buttons.ts +1 -1
- package/src/utils/code-generators.ts +1 -1
- package/src/utils/composer-history.ts +3 -3
- package/src/utils/dom-context.test.ts +2 -2
- package/src/utils/dom-context.ts +7 -7
- package/src/utils/dom.test.ts +67 -0
- package/src/utils/dom.ts +75 -0
- package/src/utils/dropdown.ts +2 -2
- package/src/utils/event-stream-buffer.test.ts +2 -2
- package/src/utils/message-fingerprint.test.ts +9 -0
- package/src/utils/message-fingerprint.ts +5 -0
- package/src/utils/morph.ts +1 -1
- package/src/utils/sanitize.ts +32 -16
- package/src/utils/sequence-buffer.test.ts +8 -8
- package/src/utils/sequence-buffer.ts +4 -4
- package/src/utils/smart-dom-adapter.test.ts +1 -1
- package/src/utils/smart-dom-adapter.ts +4 -5
- package/src/utils/speech-text.test.ts +122 -0
- package/src/utils/speech-text.ts +101 -0
- package/src/utils/stream-animation.test.ts +3 -3
- package/src/utils/stream-animation.ts +6 -6
- package/src/utils/theme.test.ts +1 -1
- package/src/utils/throughput-tracker.test.ts +11 -11
- package/src/utils/throughput-tracker.ts +9 -9
- package/src/utils/tokens.ts +13 -13
- package/src/utils/virtual-scroller.ts +1 -1
- package/src/vendor/smart-dom-reader/README.md +4 -4
- package/src/vendor/smart-dom-reader/index.d.ts +1 -1
- package/src/vendor/smart-dom-reader/index.js +2 -2
- package/src/version.ts +1 -1
- package/src/voice/audio-playback-manager.test.ts +159 -0
- package/src/voice/audio-playback-manager.ts +145 -30
- package/src/voice/browser-speech-engine.ts +130 -0
- package/src/voice/fallback-speech-engine.ts +89 -0
- package/src/voice/index.ts +21 -0
- package/src/voice/read-aloud-controller.test.ts +143 -0
- package/src/voice/read-aloud-controller.ts +136 -0
- package/src/voice/runtype-speech-engine.test.ts +280 -0
- package/src/voice/runtype-speech-engine.ts +211 -0
- package/src/voice/runtype-tts-entry.ts +10 -0
- package/src/voice/runtype-tts-loader.test.ts +47 -0
- package/src/voice/runtype-tts-loader.ts +42 -0
- package/src/voice/runtype-voice-provider.ts +332 -537
- package/src/voice/voice-factory.ts +26 -4
- package/src/voice/voice.test.ts +321 -7
- package/src/voice/worklet-playback-engine.ts +272 -0
- package/src/voice-worklet-player.ts +39 -0
- package/src/webmcp-bridge.test.ts +6 -6
- package/src/webmcp-bridge.ts +24 -25
- package/src/webmcp-polyfill.ts +1 -1
- package/src/voice/voice-activity-detector.ts +0 -90
package/src/types.ts
CHANGED
|
@@ -206,7 +206,7 @@ export type AgentConfig = {
|
|
|
206
206
|
temperature?: number;
|
|
207
207
|
/** Tool configuration for the agent */
|
|
208
208
|
tools?: AgentToolsConfig;
|
|
209
|
-
/** Persona artifacts
|
|
209
|
+
/** Persona artifacts: sibling of tools (virtual agent / API parity) */
|
|
210
210
|
artifacts?: ArtifactConfigPayload;
|
|
211
211
|
/** Loop configuration for multi-turn execution */
|
|
212
212
|
loopConfig?: AgentLoopConfig;
|
|
@@ -236,7 +236,7 @@ export type AgentWidgetAgentRequestPayload = {
|
|
|
236
236
|
context?: Record<string, unknown>;
|
|
237
237
|
metadata?: Record<string, unknown>;
|
|
238
238
|
/**
|
|
239
|
-
* Per-turn page-discovered tools (WebMCP)
|
|
239
|
+
* Per-turn page-discovered tools (WebMCP): same shape as
|
|
240
240
|
* `AgentWidgetRequestPayload.clientTools`.
|
|
241
241
|
*/
|
|
242
242
|
clientTools?: ClientToolDefinition[];
|
|
@@ -250,7 +250,7 @@ export type AgentWidgetAgentRequestPayload = {
|
|
|
250
250
|
* Wire shape for a single client-discovered tool sent on `dispatch.clientTools[]`.
|
|
251
251
|
*
|
|
252
252
|
* Mirrors the SDK's `ClientToolDefinition` in `@runtypelabs/sdk`. Only the
|
|
253
|
-
* JSON-serializable surface of a WebMCP tool
|
|
253
|
+
* JSON-serializable surface of a WebMCP tool: the `execute` function stays
|
|
254
254
|
* client-side; the server merges these into the agent's tool catalog under
|
|
255
255
|
* the `webmcp:` namespace.
|
|
256
256
|
*/
|
|
@@ -258,16 +258,16 @@ export type ClientToolDefinition = {
|
|
|
258
258
|
/** Bare tool name; the server prepends `webmcp:` on the wire. */
|
|
259
259
|
name: string;
|
|
260
260
|
description: string;
|
|
261
|
-
/** JSON Schema (per WebMCP spec)
|
|
261
|
+
/** JSON Schema (per WebMCP spec): passed through as-is. */
|
|
262
262
|
parametersSchema?: object;
|
|
263
263
|
/**
|
|
264
264
|
* `'webmcp'` for tools discovered via the polyfill (server prepends the
|
|
265
265
|
* `webmcp:` wire prefix); `'sdk'` for widget/SDK-provided tools (name stays
|
|
266
|
-
* bare on the wire). Matches the server's accepted enum
|
|
266
|
+
* bare on the wire). Matches the server's accepted enum: any other value
|
|
267
267
|
* fails dispatch validation.
|
|
268
268
|
*/
|
|
269
269
|
origin?: 'webmcp' | 'sdk';
|
|
270
|
-
/** Origin of the page that registered the tool
|
|
270
|
+
/** Origin of the page that registered the tool: for server-side audit. */
|
|
271
271
|
pageOrigin?: string;
|
|
272
272
|
/**
|
|
273
273
|
* WebMCP `Tool.annotations` (spec). Not used for gating server-side; the
|
|
@@ -300,7 +300,7 @@ export type WebMcpConfirmInfo = {
|
|
|
300
300
|
untrustedContentHint?: boolean;
|
|
301
301
|
};
|
|
302
302
|
/**
|
|
303
|
-
* Why the confirm was requested. Currently always `'gate'
|
|
303
|
+
* Why the confirm was requested. Currently always `'gate'`: the default
|
|
304
304
|
* confirm-by-default gate that fires before every `webmcp:*` call. (The
|
|
305
305
|
* `@mcp-b/webmcp-polyfill` owns the spec's `requestUserInteraction` callback
|
|
306
306
|
* internally, so Persona no longer surfaces a nested in-tool confirm.)
|
|
@@ -333,7 +333,7 @@ export type WebMcpToolResult = {
|
|
|
333
333
|
/**
|
|
334
334
|
* Widget-level WebMCP configuration. Set `enabled: true` to opt in. The
|
|
335
335
|
* surface's server-side `webmcp` policy is the source of truth for which
|
|
336
|
-
* tools are accepted
|
|
336
|
+
* tools are accepted: these client-side options are convenience filters.
|
|
337
337
|
*/
|
|
338
338
|
export type AgentWidgetWebMcpConfig = {
|
|
339
339
|
/** Master switch. Default: `false` (widget never installs the polyfill). */
|
|
@@ -349,7 +349,7 @@ export type AgentWidgetWebMcpConfig = {
|
|
|
349
349
|
* `webmcp:*` call; return `true` to approve immediately and skip the
|
|
350
350
|
* confirmation UI entirely. Use this to auto-allow read-only tools (e.g.
|
|
351
351
|
* a catalog search) while still gating mutating ones. Only consulted on
|
|
352
|
-
* the default-UI path
|
|
352
|
+
* the default-UI path: a custom `onConfirm` takes full control instead.
|
|
353
353
|
*/
|
|
354
354
|
autoApprove?: (info: WebMcpConfirmInfo) => boolean;
|
|
355
355
|
/**
|
|
@@ -408,7 +408,7 @@ export type AgentMessageMetadata = {
|
|
|
408
408
|
* `flow_await` events for a LOCAL tool (core#3878). Present only when the
|
|
409
409
|
* server emits it. Two PARALLEL calls to the same tool in one turn share a
|
|
410
410
|
* `toolName` (and a collapsed `toolId`) but get DISTINCT `webMcpToolCallId`s,
|
|
411
|
-
* so this is the key the widget batches a single `/resume` on
|
|
411
|
+
* so this is the key the widget batches a single `/resume` on: preferred
|
|
412
412
|
* over tool name, which collides for same-tool parallel calls. Absent →
|
|
413
413
|
* fall back to the legacy name-keyed resume contract.
|
|
414
414
|
*/
|
|
@@ -522,11 +522,38 @@ export type AgentWidgetVoiceStateEvent = {
|
|
|
522
522
|
timestamp: number;
|
|
523
523
|
};
|
|
524
524
|
|
|
525
|
+
/**
|
|
526
|
+
* Fired on every voice `VoiceStatus` transition (listening / processing /
|
|
527
|
+
* speaking / idle / …). Unlike `voice:state` (a coarse active on/off), this
|
|
528
|
+
* exposes the granular status so consumers can render their own per-state UI
|
|
529
|
+
* (e.g. a listening/speaking status dock).
|
|
530
|
+
*/
|
|
531
|
+
export type AgentWidgetVoiceStatusEvent = {
|
|
532
|
+
status: VoiceStatus;
|
|
533
|
+
timestamp: number;
|
|
534
|
+
};
|
|
535
|
+
|
|
525
536
|
export type AgentWidgetActionEventPayload = {
|
|
526
537
|
action: AgentWidgetParsedAction;
|
|
527
538
|
message: AgentWidgetMessage;
|
|
528
539
|
};
|
|
529
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Fired on every "Read aloud" (text-to-speech) state transition for a message:
|
|
543
|
+
* `loading` (press) → `playing` → `paused`/`playing` → `idle` (finished or
|
|
544
|
+
* stopped). On the terminal `idle` transition, `messageId`/`message` still
|
|
545
|
+
* identify the message that just stopped.
|
|
546
|
+
*/
|
|
547
|
+
export type AgentWidgetReadAloudEvent = {
|
|
548
|
+
/** The message being read aloud (or that just finished/stopped), if known. */
|
|
549
|
+
messageId: string | null;
|
|
550
|
+
/** The message object, when still present in the thread. */
|
|
551
|
+
message: AgentWidgetMessage | null;
|
|
552
|
+
/** The new playback state for this message. */
|
|
553
|
+
state: ReadAloudState;
|
|
554
|
+
timestamp: number;
|
|
555
|
+
};
|
|
556
|
+
|
|
530
557
|
/**
|
|
531
558
|
* Feedback event payload for upvote/downvote actions on messages
|
|
532
559
|
*/
|
|
@@ -579,6 +606,14 @@ export type AgentWidgetMessageActionsConfig = {
|
|
|
579
606
|
* @default false
|
|
580
607
|
*/
|
|
581
608
|
showDownvote?: boolean;
|
|
609
|
+
/**
|
|
610
|
+
* Show a "Read aloud" button that speaks the assistant message via
|
|
611
|
+
* text-to-speech (play / pause / resume). Uses the browser Web Speech API by
|
|
612
|
+
* default, or a hosted engine supplied via `textToSpeech.createEngine`.
|
|
613
|
+
* Voice, rate and pitch are read from the `textToSpeech` config.
|
|
614
|
+
* @default false
|
|
615
|
+
*/
|
|
616
|
+
showReadAloud?: boolean;
|
|
582
617
|
/**
|
|
583
618
|
* Visibility mode: 'always' shows buttons always, 'hover' shows on hover only
|
|
584
619
|
* @default 'hover'
|
|
@@ -632,6 +667,7 @@ export type AgentWidgetControllerEventMap = {
|
|
|
632
667
|
"assistant:message": AgentWidgetMessage;
|
|
633
668
|
"assistant:complete": AgentWidgetMessage;
|
|
634
669
|
"voice:state": AgentWidgetVoiceStateEvent;
|
|
670
|
+
"voice:status": AgentWidgetVoiceStatusEvent;
|
|
635
671
|
"action:detected": AgentWidgetActionEventPayload;
|
|
636
672
|
"action:resubmit": AgentWidgetActionEventPayload;
|
|
637
673
|
"widget:opened": AgentWidgetStateEvent;
|
|
@@ -639,6 +675,7 @@ export type AgentWidgetControllerEventMap = {
|
|
|
639
675
|
"widget:state": AgentWidgetStateSnapshot;
|
|
640
676
|
"message:feedback": AgentWidgetMessageFeedback;
|
|
641
677
|
"message:copy": AgentWidgetMessage;
|
|
678
|
+
"message:read-aloud": AgentWidgetReadAloudEvent;
|
|
642
679
|
"eventStream:opened": { timestamp: number };
|
|
643
680
|
"eventStream:closed": { timestamp: number };
|
|
644
681
|
"approval:requested": { approval: AgentWidgetApproval; message: AgentWidgetMessage };
|
|
@@ -685,8 +722,8 @@ export type AgentWidgetArtifactsLayoutConfig = {
|
|
|
685
722
|
resizableMaxWidth?: string;
|
|
686
723
|
/**
|
|
687
724
|
* Visual treatment for the artifact column in split mode.
|
|
688
|
-
* - `'panel'
|
|
689
|
-
* - `'seamless'
|
|
725
|
+
* - `'panel'`: bordered sidebar with left border, gap, and shadow (default).
|
|
726
|
+
* - `'seamless'`: flush with chat: no border or shadow, container background, zero gap.
|
|
690
727
|
* @default 'panel'
|
|
691
728
|
*/
|
|
692
729
|
paneAppearance?: "panel" | "seamless";
|
|
@@ -700,7 +737,7 @@ export type AgentWidgetArtifactsLayoutConfig = {
|
|
|
700
737
|
*/
|
|
701
738
|
paneBorder?: string;
|
|
702
739
|
/**
|
|
703
|
-
* `border-left` shorthand only
|
|
740
|
+
* `border-left` shorthand only: typical for split view next to chat (with or without resizer).
|
|
704
741
|
* Ignored if `paneBorder` is set. Example: `"1px solid #cccccc"`.
|
|
705
742
|
*/
|
|
706
743
|
paneBorderLeft?: string;
|
|
@@ -727,8 +764,8 @@ export type AgentWidgetArtifactsLayoutConfig = {
|
|
|
727
764
|
panePadding?: string;
|
|
728
765
|
/**
|
|
729
766
|
* Toolbar layout preset.
|
|
730
|
-
* - `default
|
|
731
|
-
* - `document
|
|
767
|
+
* - `default`: "Artifacts" title, horizontal tabs, text close.
|
|
768
|
+
* - `document`: view/source toggle, document title, copy / refresh / close; tab strip hidden when only one artifact.
|
|
732
769
|
* @default 'default'
|
|
733
770
|
*/
|
|
734
771
|
toolbarPreset?: "default" | "document";
|
|
@@ -740,7 +777,7 @@ export type AgentWidgetArtifactsLayoutConfig = {
|
|
|
740
777
|
* When `toolbarPreset` is `document`, show a small chevron after the copy control (e.g. menu affordance).
|
|
741
778
|
*/
|
|
742
779
|
documentToolbarShowCopyChevron?: boolean;
|
|
743
|
-
/** Document toolbar icon buttons (view, code, copy, refresh, close)
|
|
780
|
+
/** Document toolbar icon buttons (view, code, copy, refresh, close): CSS color. Sets `--persona-artifact-doc-toolbar-icon-color` on the widget root. */
|
|
744
781
|
documentToolbarIconColor?: string;
|
|
745
782
|
/** Active view/source toggle background. Sets `--persona-artifact-doc-toggle-active-bg`. */
|
|
746
783
|
documentToolbarToggleActiveBackground?: string;
|
|
@@ -896,11 +933,11 @@ export type AgentWidgetToolCallDisplayFeature = {
|
|
|
896
933
|
expandable?: boolean;
|
|
897
934
|
/**
|
|
898
935
|
* Animation mode applied to the tool call header text while the tool is active.
|
|
899
|
-
* - "none"
|
|
900
|
-
* - "pulse"
|
|
901
|
-
* - "shimmer"
|
|
902
|
-
* - "shimmer-color"
|
|
903
|
-
* - "rainbow"
|
|
936
|
+
* - "none": static text, no animation
|
|
937
|
+
* - "pulse": opacity pulse on the entire header text
|
|
938
|
+
* - "shimmer": monochrome opacity sweep per character
|
|
939
|
+
* - "shimmer-color": color gradient sweep per character
|
|
940
|
+
* - "rainbow": rainbow color cycle per character
|
|
904
941
|
* @default "none"
|
|
905
942
|
*/
|
|
906
943
|
loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
|
|
@@ -930,11 +967,11 @@ export type AgentWidgetReasoningDisplayFeature = {
|
|
|
930
967
|
/**
|
|
931
968
|
* Animation mode applied to the reasoning header text while reasoning is active.
|
|
932
969
|
* Reuses the same modes as tool call animations.
|
|
933
|
-
* - "none"
|
|
934
|
-
* - "pulse"
|
|
935
|
-
* - "shimmer"
|
|
936
|
-
* - "shimmer-color"
|
|
937
|
-
* - "rainbow"
|
|
970
|
+
* - "none": static text, no animation
|
|
971
|
+
* - "pulse": opacity pulse on the entire header text
|
|
972
|
+
* - "shimmer": monochrome opacity sweep per character
|
|
973
|
+
* - "shimmer-color": color gradient sweep per character
|
|
974
|
+
* - "rainbow": rainbow color cycle per character
|
|
938
975
|
* @default "none"
|
|
939
976
|
*/
|
|
940
977
|
loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
|
|
@@ -944,16 +981,16 @@ export type AgentWidgetReasoningDisplayFeature = {
|
|
|
944
981
|
* Reveal animation applied to assistant message text while it is streaming.
|
|
945
982
|
*
|
|
946
983
|
* Built-in types always available:
|
|
947
|
-
* - `none
|
|
948
|
-
* - `typewriter
|
|
949
|
-
* - `pop-bubble
|
|
950
|
-
* - `letter-rise
|
|
951
|
-
* - `word-fade
|
|
984
|
+
* - `none`: text appears as tokens arrive (default).
|
|
985
|
+
* - `typewriter`: characters fade in with a blinking caret.
|
|
986
|
+
* - `pop-bubble`: the bubble scales in; text streams normally afterward.
|
|
987
|
+
* - `letter-rise`: per-char translateY + fade reveal.
|
|
988
|
+
* - `word-fade`: per-word blur + translateY fade-in.
|
|
952
989
|
*
|
|
953
990
|
* Subpath plugins (import from `@runtypelabs/persona/animations/*` to register):
|
|
954
991
|
* - `wipe`, `glyph-cycle`.
|
|
955
992
|
*
|
|
956
|
-
* Custom types are allowed
|
|
993
|
+
* Custom types are allowed: register a plugin with any string name and
|
|
957
994
|
* reference it by that name in `type`.
|
|
958
995
|
*/
|
|
959
996
|
export type AgentWidgetStreamAnimationBuiltinType =
|
|
@@ -971,19 +1008,19 @@ export type AgentWidgetStreamAnimationType =
|
|
|
971
1008
|
|
|
972
1009
|
/**
|
|
973
1010
|
* Placeholder shown inside a streaming assistant bubble before the first token arrives.
|
|
974
|
-
* - `none
|
|
975
|
-
* - `skeleton
|
|
1011
|
+
* - `none`: use the default typing-dots indicator (existing behavior).
|
|
1012
|
+
* - `skeleton`: shimmer bars, replaced by streaming content once it starts.
|
|
976
1013
|
*/
|
|
977
1014
|
export type AgentWidgetStreamAnimationPlaceholder = "none" | "skeleton";
|
|
978
1015
|
|
|
979
1016
|
/**
|
|
980
1017
|
* How much of the accumulated streaming content to display while tokens are
|
|
981
1018
|
* still arriving. Trimming to a boundary means in-progress words or lines
|
|
982
|
-
* stay hidden until they complete
|
|
1019
|
+
* stay hidden until they complete: useful for animations that benefit from
|
|
983
1020
|
* unit-complete reveals (e.g. wipe, glyph-cycle).
|
|
984
|
-
* - `none
|
|
985
|
-
* - `word
|
|
986
|
-
* - `line
|
|
1021
|
+
* - `none`: show every character as it arrives (default).
|
|
1022
|
+
* - `word`: trim to the last whitespace boundary.
|
|
1023
|
+
* - `line`: trim to the last newline boundary.
|
|
987
1024
|
*/
|
|
988
1025
|
export type AgentWidgetStreamAnimationBuffer = "none" | "word" | "line";
|
|
989
1026
|
|
|
@@ -1016,7 +1053,7 @@ export type StreamAnimationContext = {
|
|
|
1016
1053
|
* widget's style host.
|
|
1017
1054
|
* - For each streaming assistant message whose `type` matches `name`, the
|
|
1018
1055
|
* widget applies `containerClass` / `bubbleClass`, wraps text per `wrap`,
|
|
1019
|
-
* and
|
|
1056
|
+
* and, if `useCaret` is true, appends a blinking caret.
|
|
1020
1057
|
* - Hooks fire after the live DOM is morphed; plugins use stable element IDs
|
|
1021
1058
|
* and `data-preserve-animation` to safely mutate per-char or per-word spans
|
|
1022
1059
|
* without idiomorph clobbering in-flight work.
|
|
@@ -1032,7 +1069,7 @@ export type StreamAnimationPlugin = {
|
|
|
1032
1069
|
wrap?: "none" | "char" | "word";
|
|
1033
1070
|
/**
|
|
1034
1071
|
* HTML tags whose descendant text is skipped during wrapping. Defaults to
|
|
1035
|
-
* `["pre", "code", "a", "script", "style"]
|
|
1072
|
+
* `["pre", "code", "a", "script", "style"]`: useful for keeping code
|
|
1036
1073
|
* blocks legible and link click-targets intact. Plugins that want to
|
|
1037
1074
|
* animate characters inside inline code (e.g. `glyph-cycle`) can narrow
|
|
1038
1075
|
* the list.
|
|
@@ -1061,8 +1098,7 @@ export type StreamAnimationPlugin = {
|
|
|
1061
1098
|
/**
|
|
1062
1099
|
* Report whether the plugin still has in-flight animation work for a
|
|
1063
1100
|
* message. When `true`, the widget keeps rendering the message in its
|
|
1064
|
-
* "streaming-animated" mode even after `message.streaming` flips false
|
|
1065
|
-
* preventing the final non-animated render from yanking the rug out from
|
|
1101
|
+
* "streaming-animated" mode even after `message.streaming` flips false: * preventing the final non-animated render from yanking the rug out from
|
|
1066
1102
|
* under unfinished per-char cycles or reveals.
|
|
1067
1103
|
*/
|
|
1068
1104
|
isAnimating?: (message: AgentWidgetMessage) => boolean;
|
|
@@ -1076,7 +1112,7 @@ export type AgentWidgetStreamAnimationFeature = {
|
|
|
1076
1112
|
/**
|
|
1077
1113
|
* Per-unit animation duration (ms) for `typewriter`, `letter-rise`, `word-fade`,
|
|
1078
1114
|
* and per-unit plugin animations. Each arriving character/word animates from
|
|
1079
|
-
* invisible to visible over this duration, independent of its position
|
|
1115
|
+
* invisible to visible over this duration, independent of its position: the
|
|
1080
1116
|
* streaming cadence itself provides the visible stagger.
|
|
1081
1117
|
* @default 120
|
|
1082
1118
|
*/
|
|
@@ -1137,7 +1173,7 @@ export type AgentWidgetFeatureFlags = {
|
|
|
1137
1173
|
* Built-in `suggest_replies` quick-reply chips. When the assistant invokes
|
|
1138
1174
|
* the tool, the widget shows the suggestions as tappable chips above the
|
|
1139
1175
|
* composer (reusing the suggestion-chips surface) and immediately resumes
|
|
1140
|
-
* the execution
|
|
1176
|
+
* the execution: fire-and-forget, no user input awaited.
|
|
1141
1177
|
*/
|
|
1142
1178
|
suggestReplies?: AgentWidgetSuggestRepliesFeature;
|
|
1143
1179
|
};
|
|
@@ -1152,14 +1188,14 @@ export type AgentWidgetFeatureFlags = {
|
|
|
1152
1188
|
export type AgentWidgetSuggestRepliesFeature = {
|
|
1153
1189
|
/**
|
|
1154
1190
|
* Enable the feature. Defaults to true. When false, `suggest_replies`
|
|
1155
|
-
* renders as a regular tool bubble and is NOT auto-resumed
|
|
1191
|
+
* renders as a regular tool bubble and is NOT auto-resumed: only set this
|
|
1156
1192
|
* with no server-side `suggest_replies` declaration, or the execution
|
|
1157
1193
|
* parks awaiting a resume that never comes.
|
|
1158
1194
|
*/
|
|
1159
1195
|
enabled?: boolean;
|
|
1160
1196
|
/**
|
|
1161
1197
|
* Advertise the built-in `suggest_replies` tool to the agent on every
|
|
1162
|
-
* dispatch via `clientTools[]
|
|
1198
|
+
* dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
|
|
1163
1199
|
* needed. Defaults to `false`: flows that already declare the tool via
|
|
1164
1200
|
* `runtimeTools` would otherwise present it to the model twice. Ignored
|
|
1165
1201
|
* when `enabled` is `false`.
|
|
@@ -1176,7 +1212,7 @@ export type AskUserQuestionOption = {
|
|
|
1176
1212
|
label: string;
|
|
1177
1213
|
/** Optional long-form description (shown as a subtitle on tap-hover). */
|
|
1178
1214
|
description?: string;
|
|
1179
|
-
/** Optional rich preview
|
|
1215
|
+
/** Optional rich preview: reserved for future rendering; ignored in v1. */
|
|
1180
1216
|
preview?: string;
|
|
1181
1217
|
};
|
|
1182
1218
|
|
|
@@ -1232,14 +1268,14 @@ export type AgentWidgetAskUserQuestionFeature = {
|
|
|
1232
1268
|
enabled?: boolean;
|
|
1233
1269
|
/**
|
|
1234
1270
|
* Advertise the built-in `ask_user_question` tool to the agent on every
|
|
1235
|
-
* dispatch via `clientTools[]
|
|
1271
|
+
* dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
|
|
1236
1272
|
* needed. The tool ships with a model-facing description and JSON schema
|
|
1237
1273
|
* matching {@link AskUserQuestionPayload}; when the model calls it, the
|
|
1238
1274
|
* existing answer-pill sheet renders and the answer resumes the execution.
|
|
1239
1275
|
*
|
|
1240
1276
|
* Defaults to `false`: flows that already declare `ask_user_question` via
|
|
1241
1277
|
* `runtimeTools` would otherwise present the tool to the model twice.
|
|
1242
|
-
* Ignored when `enabled` is `false
|
|
1278
|
+
* Ignored when `enabled` is `false`: never offer the agent a question
|
|
1243
1279
|
* tool the widget can't render an answer UI for.
|
|
1244
1280
|
*/
|
|
1245
1281
|
expose?: boolean;
|
|
@@ -1260,17 +1296,17 @@ export type AgentWidgetAskUserQuestionFeature = {
|
|
|
1260
1296
|
/**
|
|
1261
1297
|
* In grouped (multi-question) mode, auto-advance to the next page after a
|
|
1262
1298
|
* single-select pill pick or free-text submit on intermediate pages.
|
|
1263
|
-
* Defaults to `true`. The final page never auto-submits
|
|
1299
|
+
* Defaults to `true`. The final page never auto-submits: users always
|
|
1264
1300
|
* confirm with an explicit "Submit all" click. Multi-select pages always
|
|
1265
1301
|
* require an explicit Next regardless of this setting.
|
|
1266
1302
|
*/
|
|
1267
1303
|
groupedAutoAdvance?: boolean;
|
|
1268
1304
|
/**
|
|
1269
1305
|
* Visual layout for the option list.
|
|
1270
|
-
* - `"rows"` (default)
|
|
1306
|
+
* - `"rows"` (default): full-width stacked rows with always-visible
|
|
1271
1307
|
* descriptions, right-edge number badges (single-select) or checkboxes
|
|
1272
1308
|
* (multi-select), and an always-visible inline "Other" input.
|
|
1273
|
-
* - `"pills"
|
|
1309
|
+
* - `"pills"`: legacy compact pill list with horizontal wrap; description
|
|
1274
1310
|
* surfaces as a tooltip and the "Other…" pill expands on click.
|
|
1275
1311
|
*/
|
|
1276
1312
|
layout?: "rows" | "pills";
|
|
@@ -1450,7 +1486,7 @@ export type AgentWidgetDockConfig = {
|
|
|
1450
1486
|
*
|
|
1451
1487
|
* - Set a CSS length (e.g. `"600px"`, `"80vh"`) to override the cap.
|
|
1452
1488
|
* - Set `false` to disable the guard entirely (the panel then sizes purely
|
|
1453
|
-
* from the surrounding layout
|
|
1489
|
+
* from the surrounding layout: make sure your page provides a definite
|
|
1454
1490
|
* height all the way down to the dock target's parent).
|
|
1455
1491
|
*
|
|
1456
1492
|
* @default "100dvh"
|
|
@@ -1525,7 +1561,7 @@ export type AgentWidgetComposerBarConfig = {
|
|
|
1525
1561
|
*/
|
|
1526
1562
|
modalMaxHeight?: string;
|
|
1527
1563
|
/**
|
|
1528
|
-
* Configuration for the "peek" banner
|
|
1564
|
+
* Configuration for the "peek" banner: the chrome-less row above the
|
|
1529
1565
|
* collapsed pill that previews the most recent assistant message.
|
|
1530
1566
|
*/
|
|
1531
1567
|
peek?: AgentWidgetComposerBarPeekConfig;
|
|
@@ -1541,7 +1577,7 @@ export type AgentWidgetComposerBarConfig = {
|
|
|
1541
1577
|
* - Otherwise the peek inherits from `features.streamAnimation`.
|
|
1542
1578
|
*
|
|
1543
1579
|
* Per-surface carve-outs:
|
|
1544
|
-
* - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored
|
|
1580
|
+
* - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored: the peek
|
|
1545
1581
|
* has no bubble analog.
|
|
1546
1582
|
* - `containerClass`, `wrap` ("char" | "word"), `useCaret`, `placeholder`
|
|
1547
1583
|
* ("skeleton"), `buffer` ("word" | "line"), `speed`, `duration`, and
|
|
@@ -1794,7 +1830,13 @@ export type AgentWidgetVoiceRecognitionConfig = {
|
|
|
1794
1830
|
/** Button border color while speaking. Inherits idle borderColor if not set */
|
|
1795
1831
|
speakingBorderColor?: string;
|
|
1796
1832
|
autoResume?: boolean | "assistant";
|
|
1797
|
-
|
|
1833
|
+
|
|
1834
|
+
/**
|
|
1835
|
+
* Called with per-turn latency metrics on the realtime (`runtype`) voice path.
|
|
1836
|
+
* Fires once per turn after the reply completes.
|
|
1837
|
+
*/
|
|
1838
|
+
onMetrics?: (metrics: VoiceMetrics) => void;
|
|
1839
|
+
|
|
1798
1840
|
// Voice provider configuration
|
|
1799
1841
|
provider?: {
|
|
1800
1842
|
type: 'browser' | 'runtype' | 'custom';
|
|
@@ -1804,15 +1846,31 @@ export type AgentWidgetVoiceRecognitionConfig = {
|
|
|
1804
1846
|
};
|
|
1805
1847
|
runtype?: {
|
|
1806
1848
|
agentId: string;
|
|
1807
|
-
clientToken
|
|
1849
|
+
/** Defaults to the widget's `clientToken` when omitted. */
|
|
1850
|
+
clientToken?: string;
|
|
1851
|
+
/** Defaults to the widget's `apiUrl` when omitted. */
|
|
1808
1852
|
host?: string;
|
|
1809
1853
|
voiceId?: string;
|
|
1810
|
-
/**
|
|
1854
|
+
/**
|
|
1855
|
+
* Optional custom streaming playback engine. Defaults to the built-in
|
|
1856
|
+
* `AudioPlaybackManager`. Import `createWorkletPlaybackEngine` from
|
|
1857
|
+
* `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
|
|
1858
|
+
*/
|
|
1859
|
+
createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
|
|
1860
|
+
/** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
|
|
1811
1861
|
pauseDuration?: number;
|
|
1812
|
-
/**
|
|
1862
|
+
/** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
|
|
1813
1863
|
silenceThreshold?: number;
|
|
1814
1864
|
};
|
|
1815
|
-
|
|
1865
|
+
/**
|
|
1866
|
+
* Bring-your-own voice provider. Set `type: 'custom'` and pass either a
|
|
1867
|
+
* ready {@link VoiceProvider} instance or a `() => VoiceProvider` factory
|
|
1868
|
+
* (the factory defers construction until voice is set up). STT-style
|
|
1869
|
+
* providers deliver a final transcript via `onResult` (sent as a user
|
|
1870
|
+
* message); full-duplex providers can drive `onTranscript`/`onMetrics` like
|
|
1871
|
+
* the realtime `runtype` provider.
|
|
1872
|
+
*/
|
|
1873
|
+
custom?: VoiceProvider | (() => VoiceProvider);
|
|
1816
1874
|
};
|
|
1817
1875
|
};
|
|
1818
1876
|
|
|
@@ -1836,18 +1894,68 @@ export type TextToSpeechConfig = {
|
|
|
1836
1894
|
enabled: boolean;
|
|
1837
1895
|
/**
|
|
1838
1896
|
* TTS provider.
|
|
1839
|
-
* - `'browser'
|
|
1840
|
-
* - `'runtype'
|
|
1841
|
-
*
|
|
1897
|
+
* - `'browser'`: Use the Web Speech API for all assistant messages (default).
|
|
1898
|
+
* - `'runtype'`: Use Runtype-hosted TTS. The realtime voice path speaks
|
|
1899
|
+
* replies during a voice call, and the per-message "Read aloud" button (and
|
|
1900
|
+
* auto-speak of text-typed replies) stream from Runtype's
|
|
1901
|
+
* `POST {host}/v1/agents/:agentId/speak` endpoint via the built-in
|
|
1902
|
+
* {@link SpeechEngine}. `host`/`agentId`/`clientToken` are derived from the
|
|
1903
|
+
* widget config (see `agentId`/`host` below); unless `browserFallback` is
|
|
1904
|
+
* `false`, a missing endpoint or transient failure falls back to the browser
|
|
1905
|
+
* voice so the button is never broken.
|
|
1842
1906
|
*/
|
|
1843
1907
|
provider?: 'browser' | 'runtype';
|
|
1844
1908
|
/**
|
|
1845
|
-
* When `provider` is `'runtype'
|
|
1846
|
-
*
|
|
1909
|
+
* When `provider` is `'runtype'`:
|
|
1910
|
+
* - Read-aloud / auto-speak: acts as a safety net — if Runtype TTS is
|
|
1911
|
+
* unreachable (no endpoint yet, network/auth failure) or the Runtype config
|
|
1912
|
+
* is incomplete, speech falls back to the browser Web Speech API instead of
|
|
1913
|
+
* erroring. Set to `false` to surface Runtype errors instead. **Defaults to
|
|
1914
|
+
* on for this path.**
|
|
1915
|
+
* - Auto-speak of text-typed replies also requires this to be truthy (the
|
|
1916
|
+
* realtime voice path already speaks voice-call replies).
|
|
1917
|
+
*
|
|
1847
1918
|
* Has no effect when provider is `'browser'` (browser TTS is always used).
|
|
1848
|
-
* @default false
|
|
1849
1919
|
*/
|
|
1850
1920
|
browserFallback?: boolean;
|
|
1921
|
+
/**
|
|
1922
|
+
* When `provider` is `'runtype'`, the agent whose configured voice synthesizes
|
|
1923
|
+
* read-aloud / auto-speak audio. Falls back to
|
|
1924
|
+
* `voiceRecognition.provider.runtype.agentId` when omitted. Required (here or
|
|
1925
|
+
* there) for Runtype TTS to activate; without it the browser voice is used.
|
|
1926
|
+
*/
|
|
1927
|
+
agentId?: string;
|
|
1928
|
+
/**
|
|
1929
|
+
* When `provider` is `'runtype'`, the Runtype API host (e.g.
|
|
1930
|
+
* `https://api.runtype.com`). Defaults to the widget's `apiUrl`.
|
|
1931
|
+
*/
|
|
1932
|
+
host?: string;
|
|
1933
|
+
/**
|
|
1934
|
+
* When `provider` is `'runtype'`, audio (ms) the streaming player buffers
|
|
1935
|
+
* before the first sample and after an underrun. Lower = snappier start;
|
|
1936
|
+
* higher = rides out delivery hiccups. Default 200. Applies to the default
|
|
1937
|
+
* in-bundle player; a custom `createPlaybackEngine` manages its own prebuffer.
|
|
1938
|
+
*/
|
|
1939
|
+
prebufferMs?: number;
|
|
1940
|
+
/**
|
|
1941
|
+
* When `provider` is `'runtype'`, an optional factory for the streaming PCM
|
|
1942
|
+
* player that synthesizes read-aloud / auto-speak audio. Defaults to the
|
|
1943
|
+
* in-bundle, main-thread `AudioPlaybackManager` (smooth for steady Runtype
|
|
1944
|
+
* streams, no AudioWorklet — keeps the widget bundle lean).
|
|
1945
|
+
*
|
|
1946
|
+
* For the higher-quality, jitter-buffered AudioWorklet player, import
|
|
1947
|
+
* `createPcmStreamPlayer` from `@runtypelabs/persona/voice-worklet-player` and
|
|
1948
|
+
* pass it here — it then ships in your bundle, not Persona's:
|
|
1949
|
+
*
|
|
1950
|
+
* @example
|
|
1951
|
+
* import { createPcmStreamPlayer } from '@runtypelabs/persona/voice-worklet-player'
|
|
1952
|
+
* textToSpeech: {
|
|
1953
|
+
* enabled: true,
|
|
1954
|
+
* provider: 'runtype',
|
|
1955
|
+
* createPlaybackEngine: () => createPcmStreamPlayer({ prebufferMs: 400 }),
|
|
1956
|
+
* }
|
|
1957
|
+
*/
|
|
1958
|
+
createPlaybackEngine?: () => PcmStreamPlayer | Promise<PcmStreamPlayer>;
|
|
1851
1959
|
/** Voice name to use for browser TTS (e.g., 'Google US English'). If not found, uses auto-detect. */
|
|
1852
1960
|
voice?: string;
|
|
1853
1961
|
/**
|
|
@@ -1866,8 +1974,78 @@ export type TextToSpeechConfig = {
|
|
|
1866
1974
|
rate?: number;
|
|
1867
1975
|
/** Speech pitch (0 - 2). Default: 1 */
|
|
1868
1976
|
pitch?: number;
|
|
1977
|
+
/**
|
|
1978
|
+
* Factory for a custom {@link SpeechEngine}, used by both the auto-speak path
|
|
1979
|
+
* and the per-message "Read aloud" action. When omitted, the browser Web
|
|
1980
|
+
* Speech API engine is used. Return a hosted engine here to use server-side
|
|
1981
|
+
* TTS (e.g. Runtype) — such an engine can stream audio through the realtime
|
|
1982
|
+
* voice {@link VoicePlaybackEngine}. May be async (it is resolved on first
|
|
1983
|
+
* playback, inside the user gesture).
|
|
1984
|
+
*/
|
|
1985
|
+
createEngine?: () => SpeechEngine | Promise<SpeechEngine>;
|
|
1869
1986
|
};
|
|
1870
1987
|
|
|
1988
|
+
/**
|
|
1989
|
+
* Playback state of the per-message "Read aloud" action.
|
|
1990
|
+
* - `idle`: not reading this message.
|
|
1991
|
+
* - `loading`: the engine is preparing audio (e.g. a hosted TTS fetch). Browser
|
|
1992
|
+
* engines pass through this state almost instantly.
|
|
1993
|
+
* - `playing`: audio is playing.
|
|
1994
|
+
* - `paused`: playback is paused and resumable.
|
|
1995
|
+
*/
|
|
1996
|
+
export type ReadAloudState = "idle" | "loading" | "playing" | "paused";
|
|
1997
|
+
|
|
1998
|
+
/** A unit of speech handed to a {@link SpeechEngine}. */
|
|
1999
|
+
export interface SpeechRequest {
|
|
2000
|
+
/** Plain text to speak. The widget strips Markdown before calling the engine. */
|
|
2001
|
+
text: string;
|
|
2002
|
+
/** Preferred voice identifier (engine-specific; browser = voice name). */
|
|
2003
|
+
voice?: string;
|
|
2004
|
+
/** Speech rate (engine-specific range; browser: 0.1–10, default 1). */
|
|
2005
|
+
rate?: number;
|
|
2006
|
+
/** Speech pitch (engine-specific range; browser: 0–2, default 1). */
|
|
2007
|
+
pitch?: number;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
/** Lifecycle callbacks a {@link SpeechEngine} invokes during playback. */
|
|
2011
|
+
export interface SpeechCallbacks {
|
|
2012
|
+
/** Audio has started playing. */
|
|
2013
|
+
onStart?: () => void;
|
|
2014
|
+
/** Playback finished naturally (or was canceled). */
|
|
2015
|
+
onEnd?: () => void;
|
|
2016
|
+
/** Playback failed. */
|
|
2017
|
+
onError?: (error: Error) => void;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
/**
|
|
2021
|
+
* Pluggable text-to-speech engine behind the "Read aloud" message action.
|
|
2022
|
+
*
|
|
2023
|
+
* The widget ships a browser Web Speech API engine by default. Provide a hosted
|
|
2024
|
+
* engine (Runtype TTS, ElevenLabs, a server proxy, …) by implementing this
|
|
2025
|
+
* interface and returning it from {@link TextToSpeechConfig.createEngine}; a
|
|
2026
|
+
* server engine can stream audio into the realtime voice
|
|
2027
|
+
* {@link VoicePlaybackEngine}.
|
|
2028
|
+
*/
|
|
2029
|
+
export interface SpeechEngine {
|
|
2030
|
+
/** Stable identifier, e.g. `"browser"`, `"runtype"`, or a custom id. */
|
|
2031
|
+
readonly id: string;
|
|
2032
|
+
/**
|
|
2033
|
+
* Whether {@link pause}/{@link resume} are supported. When `false`, the UI
|
|
2034
|
+
* offers play/stop only (tapping a playing message stops it).
|
|
2035
|
+
*/
|
|
2036
|
+
readonly supportsPause: boolean;
|
|
2037
|
+
/** Begin speaking. Drives the lifecycle through `callbacks`. */
|
|
2038
|
+
speak(request: SpeechRequest, callbacks: SpeechCallbacks): void;
|
|
2039
|
+
/** Pause playback (no-op if unsupported). */
|
|
2040
|
+
pause(): void;
|
|
2041
|
+
/** Resume paused playback (no-op if unsupported). */
|
|
2042
|
+
resume(): void;
|
|
2043
|
+
/** Stop playback and discard any queued audio. */
|
|
2044
|
+
stop(): void;
|
|
2045
|
+
/** Optional teardown of engine resources. */
|
|
2046
|
+
destroy?(): void;
|
|
2047
|
+
}
|
|
2048
|
+
|
|
1871
2049
|
// ============================================================================
|
|
1872
2050
|
// Voice Provider Types
|
|
1873
2051
|
// ============================================================================
|
|
@@ -1900,6 +2078,69 @@ export type VoiceStatus =
|
|
|
1900
2078
|
| 'error'
|
|
1901
2079
|
| 'idle';
|
|
1902
2080
|
|
|
2081
|
+
/**
|
|
2082
|
+
* Per-turn latency metrics emitted by the realtime voice path.
|
|
2083
|
+
* The wire frame is snake_case (`metrics`); decoded to camelCase at the
|
|
2084
|
+
* provider boundary before being surfaced through `onMetrics`.
|
|
2085
|
+
*/
|
|
2086
|
+
export type VoiceMetrics = {
|
|
2087
|
+
/** LLM generation time (ms). */
|
|
2088
|
+
llmMs?: number;
|
|
2089
|
+
/** Text-to-speech synthesis time (ms). */
|
|
2090
|
+
ttsMs?: number;
|
|
2091
|
+
/** Time to first audio frame (ms). */
|
|
2092
|
+
firstAudioMs?: number;
|
|
2093
|
+
/** Total turn time (ms). */
|
|
2094
|
+
totalMs?: number;
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2097
|
+
/**
|
|
2098
|
+
* Streaming PCM playback engine used by the realtime voice provider.
|
|
2099
|
+
*
|
|
2100
|
+
* The provider feeds raw PCM16 LE mono @ 24kHz (WAV header already stripped)
|
|
2101
|
+
* via `enqueue`, signals end-of-reply with `markStreamEnd`, and learns when
|
|
2102
|
+
* playback has fully drained via `onFinished`. The default implementation is
|
|
2103
|
+
* `AudioPlaybackManager`; an optional jitter-buffered AudioWorklet engine ships
|
|
2104
|
+
* from `@runtypelabs/persona/voice-worklet-player` and can be injected via the
|
|
2105
|
+
* `runtype.createPlaybackEngine` config hook.
|
|
2106
|
+
*/
|
|
2107
|
+
export interface VoicePlaybackEngine {
|
|
2108
|
+
/** Enqueue a raw PCM16 LE mono @ 24kHz chunk (no WAV header). */
|
|
2109
|
+
enqueue(pcm: Uint8Array): void;
|
|
2110
|
+
/** Signal that no more chunks will arrive for the current reply. */
|
|
2111
|
+
markStreamEnd(): void;
|
|
2112
|
+
/** Immediately stop playback and discard queued audio. */
|
|
2113
|
+
flush(): void;
|
|
2114
|
+
/** Register a callback fired once all queued audio has finished playing. */
|
|
2115
|
+
onFinished(callback: () => void): void;
|
|
2116
|
+
/** Release all audio resources. */
|
|
2117
|
+
destroy(): Promise<void> | void;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
/**
|
|
2121
|
+
* A {@link VoicePlaybackEngine} that also supports pause/resume. Returned by
|
|
2122
|
+
* `createPcmStreamPlayer` (`@runtypelabs/persona/voice-worklet-player`): a
|
|
2123
|
+
* jitter-buffered AudioWorklet player for raw PCM16 / 24 kHz / mono streams.
|
|
2124
|
+
* Reuse it inside a hosted {@link SpeechEngine} to get gapless playback with a
|
|
2125
|
+
* configurable prebuffer and graceful underrun handling — feed each streamed
|
|
2126
|
+
* chunk to {@link VoicePlaybackEngine.enqueue} and the worklet does the rest.
|
|
2127
|
+
*/
|
|
2128
|
+
export interface PcmStreamPlayer extends VoicePlaybackEngine {
|
|
2129
|
+
/** Pause playback; the audio clock suspends and {@link resume} continues in place. */
|
|
2130
|
+
pause(): void;
|
|
2131
|
+
/** Resume playback after {@link pause}. */
|
|
2132
|
+
resume(): void;
|
|
2133
|
+
/**
|
|
2134
|
+
* Register a callback fired once audible playback actually begins — i.e. the
|
|
2135
|
+
* prebuffer waterline filled and the first sample reached the output. Use this
|
|
2136
|
+
* (rather than "first chunk enqueued") to flip a UI from loading to playing, so
|
|
2137
|
+
* the spinner holds through the prebuffer. Fires once per playback session
|
|
2138
|
+
* (cleared by {@link VoicePlaybackEngine.flush}); a mid-reply underrun re-buffer
|
|
2139
|
+
* does not re-fire it.
|
|
2140
|
+
*/
|
|
2141
|
+
onStarted(callback: () => void): void;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
1903
2144
|
/**
|
|
1904
2145
|
* Voice provider configuration
|
|
1905
2146
|
* Determines which voice provider to use and its specific settings
|
|
@@ -1912,15 +2153,29 @@ export type VoiceConfig = {
|
|
|
1912
2153
|
};
|
|
1913
2154
|
runtype?: {
|
|
1914
2155
|
agentId: string;
|
|
1915
|
-
clientToken
|
|
2156
|
+
/** Defaults to the widget's `clientToken` when omitted. */
|
|
2157
|
+
clientToken?: string;
|
|
2158
|
+
/** Defaults to the widget's `apiUrl` (as a ws(s):// base) when omitted. */
|
|
1916
2159
|
host?: string;
|
|
1917
2160
|
voiceId?: string;
|
|
1918
|
-
/**
|
|
2161
|
+
/**
|
|
2162
|
+
* Optional custom streaming playback engine. Defaults to the built-in
|
|
2163
|
+
* `AudioPlaybackManager`. Import `createWorkletPlaybackEngine` from
|
|
2164
|
+
* `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
|
|
2165
|
+
*/
|
|
2166
|
+
createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
|
|
2167
|
+
/** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
|
|
1919
2168
|
pauseDuration?: number;
|
|
1920
|
-
/**
|
|
2169
|
+
/** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
|
|
1921
2170
|
silenceThreshold?: number;
|
|
1922
2171
|
};
|
|
1923
|
-
|
|
2172
|
+
/**
|
|
2173
|
+
* Bring-your-own voice provider for `type: 'custom'`: either a ready
|
|
2174
|
+
* {@link VoiceProvider} instance or a `() => VoiceProvider` factory. The
|
|
2175
|
+
* factory form defers construction (WebSocket/AudioContext/etc.) until
|
|
2176
|
+
* `createVoiceProvider` runs.
|
|
2177
|
+
*/
|
|
2178
|
+
custom?: VoiceProvider | (() => VoiceProvider);
|
|
1924
2179
|
};
|
|
1925
2180
|
|
|
1926
2181
|
/**
|
|
@@ -1942,13 +2197,27 @@ export interface VoiceProvider {
|
|
|
1942
2197
|
/** Register a callback fired when recording stops and audio is about to be sent */
|
|
1943
2198
|
onProcessingStart?(callback: () => void): void;
|
|
1944
2199
|
|
|
2200
|
+
/**
|
|
2201
|
+
* Register a callback for incremental transcript updates during a voice turn.
|
|
2202
|
+
* `isFinal=false` is a live interim update (user partials, or assistant deltas
|
|
2203
|
+
* on providers that stream them); `isFinal=true` finalizes that role's text.
|
|
2204
|
+
* On the realtime `runtype` path, interim updates fire for the `user` only and
|
|
2205
|
+
* the `assistant` arrives as a single final.
|
|
2206
|
+
*/
|
|
2207
|
+
onTranscript?(
|
|
2208
|
+
callback: (role: 'user' | 'assistant', text: string, isFinal: boolean) => void,
|
|
2209
|
+
): void;
|
|
2210
|
+
|
|
2211
|
+
/** Register a callback for per-turn latency metrics (realtime path). */
|
|
2212
|
+
onMetrics?(callback: (metrics: VoiceMetrics) => void): void;
|
|
2213
|
+
|
|
1945
2214
|
/** Returns the current interruption mode (only meaningful for Runtype provider) */
|
|
1946
2215
|
getInterruptionMode?(): "none" | "cancel" | "barge-in";
|
|
1947
2216
|
|
|
1948
2217
|
/** Returns true if the barge-in mic stream is alive (hot mic between turns) */
|
|
1949
2218
|
isBargeInActive?(): boolean;
|
|
1950
2219
|
|
|
1951
|
-
/** Tear down the barge-in mic pipeline
|
|
2220
|
+
/** Tear down the barge-in mic pipeline: "hang up" the always-on mic */
|
|
1952
2221
|
deactivateBargeIn?(): Promise<void>;
|
|
1953
2222
|
|
|
1954
2223
|
/** Stop playback / cancel in-flight request without starting recording */
|
|
@@ -1963,7 +2232,7 @@ export type AgentWidgetApprovalDecisionOptions = {
|
|
|
1963
2232
|
/**
|
|
1964
2233
|
* The user chose a "remember this" affordance (e.g. an "Always allow"
|
|
1965
2234
|
* button) rather than a one-time decision. The widget resolves the *current*
|
|
1966
|
-
* approval identically whether or not this is set
|
|
2235
|
+
* approval identically whether or not this is set: an approval bubble is a
|
|
1967
2236
|
* single binary gate (`approved`/`denied`). Persisting a don't-ask-again
|
|
1968
2237
|
* policy for *future* approvals (auto-resolving them, or not surfacing them)
|
|
1969
2238
|
* is the integrator's responsibility, typically inside `onDecision`.
|
|
@@ -2018,9 +2287,9 @@ export type AgentWidgetApprovalConfig = {
|
|
|
2018
2287
|
/**
|
|
2019
2288
|
* How the technical details (the tool's agent-facing description and the
|
|
2020
2289
|
* raw parameters JSON) are presented:
|
|
2021
|
-
* - `"collapsed"` (default)
|
|
2022
|
-
* - `"expanded"
|
|
2023
|
-
* - `"hidden"
|
|
2290
|
+
* - `"collapsed"` (default): hidden behind a "Show details" toggle
|
|
2291
|
+
* - `"expanded"`: visible, with the toggle available to hide them
|
|
2292
|
+
* - `"hidden"`: never rendered
|
|
2024
2293
|
*/
|
|
2025
2294
|
detailsDisplay?: "collapsed" | "expanded" | "hidden";
|
|
2026
2295
|
/** Label for the toggle that reveals the technical details */
|
|
@@ -2042,7 +2311,7 @@ export type AgentWidgetApprovalConfig = {
|
|
|
2042
2311
|
displayTitle?: string;
|
|
2043
2312
|
/**
|
|
2044
2313
|
* Agent-authored justification for this specific call, when the agent
|
|
2045
|
-
* provided one. It is the agent's own claim
|
|
2314
|
+
* provided one. It is the agent's own claim: if you fold it into the
|
|
2046
2315
|
* summary, keep it attributed to the agent.
|
|
2047
2316
|
*/
|
|
2048
2317
|
reason?: string;
|
|
@@ -2148,7 +2417,7 @@ export type AgentWidgetToolCallConfig = {
|
|
|
2148
2417
|
*
|
|
2149
2418
|
* **Placeholders:** `{toolName}` (tool name), `{duration}` (live-updating elapsed time).
|
|
2150
2419
|
*
|
|
2151
|
-
* **Inline formatting:** `~dim~`, `*italic*`, `**bold
|
|
2420
|
+
* **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: parsed at render time and
|
|
2152
2421
|
* applied as styled `<span>` elements. Works with all animation modes.
|
|
2153
2422
|
*
|
|
2154
2423
|
* When not set, falls back to the current `collapsedMode` behavior.
|
|
@@ -2161,7 +2430,7 @@ export type AgentWidgetToolCallConfig = {
|
|
|
2161
2430
|
*
|
|
2162
2431
|
* **Placeholders:** `{toolName}` (tool name), `{duration}` (final elapsed time).
|
|
2163
2432
|
*
|
|
2164
|
-
* **Inline formatting:** `~dim~`, `*italic*`, `**bold
|
|
2433
|
+
* **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: same syntax as `activeTextTemplate`.
|
|
2165
2434
|
*
|
|
2166
2435
|
* When not set, falls back to the existing "Used tool for X seconds" text.
|
|
2167
2436
|
* @example "Finished {toolName} ~{duration}~"
|
|
@@ -2223,7 +2492,7 @@ export type AgentWidgetReasoningConfig = {
|
|
|
2223
2492
|
*
|
|
2224
2493
|
* **Placeholders:** `{duration}` (live-updating elapsed time).
|
|
2225
2494
|
*
|
|
2226
|
-
* **Inline formatting:** `~dim~`, `*italic*`, `**bold
|
|
2495
|
+
* **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: parsed at render time.
|
|
2227
2496
|
*
|
|
2228
2497
|
* When not set, falls back to the default "Thinking..." text.
|
|
2229
2498
|
* @example "Thinking... ~{duration}~"
|
|
@@ -2234,7 +2503,7 @@ export type AgentWidgetReasoningConfig = {
|
|
|
2234
2503
|
*
|
|
2235
2504
|
* **Placeholders:** `{duration}` (final elapsed time).
|
|
2236
2505
|
*
|
|
2237
|
-
* **Inline formatting:** `~dim~`, `*italic*`, `**bold
|
|
2506
|
+
* **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: same syntax as `activeTextTemplate`.
|
|
2238
2507
|
*
|
|
2239
2508
|
* When not set, falls back to the default "Thought for X seconds" text.
|
|
2240
2509
|
* @example "Thought for ~{duration}~"
|
|
@@ -2345,7 +2614,7 @@ export type AgentWidgetSSEEventResult = {
|
|
|
2345
2614
|
done?: boolean;
|
|
2346
2615
|
/** Error message if an error occurred */
|
|
2347
2616
|
error?: string;
|
|
2348
|
-
/** Text segment identity
|
|
2617
|
+
/** Text segment identity: when this changes, a new assistant message bubble is created */
|
|
2349
2618
|
partId?: string;
|
|
2350
2619
|
} | null;
|
|
2351
2620
|
|
|
@@ -2433,7 +2702,7 @@ export type ClientChatRequest = {
|
|
|
2433
2702
|
/** Per-turn inputs for Runtype prompt templates (e.g. {{page_url}}). */
|
|
2434
2703
|
inputs?: Record<string, unknown>;
|
|
2435
2704
|
context?: Record<string, unknown>;
|
|
2436
|
-
/** WebMCP page-discovered tools
|
|
2705
|
+
/** WebMCP page-discovered tools: same shape as `dispatch.clientTools[]`. */
|
|
2437
2706
|
clientTools?: ClientToolDefinition[];
|
|
2438
2707
|
/**
|
|
2439
2708
|
* Diff-only / send-once: order-independent fingerprint of the client tool set.
|
|
@@ -3453,7 +3722,7 @@ export type AgentWidgetConfig = {
|
|
|
3453
3722
|
* Per-stop-reason copy for the inline notice rendered on assistant
|
|
3454
3723
|
* bubbles when the runtime reports a non-natural stop (e.g. the agent
|
|
3455
3724
|
* loop hit `max_tool_calls` and was cut off mid-loop). Each key is
|
|
3456
|
-
* optional
|
|
3725
|
+
* optional: keys you omit fall back to the built-in defaults. Set a
|
|
3457
3726
|
* key to an empty string to suppress the notice for that reason.
|
|
3458
3727
|
*/
|
|
3459
3728
|
stopReasonNotice?: Partial<Record<StopReasonKind, string>>;
|
|
@@ -3546,12 +3815,12 @@ export type AgentWidgetConfig = {
|
|
|
3546
3815
|
*/
|
|
3547
3816
|
approval?: AgentWidgetApprovalConfig | false;
|
|
3548
3817
|
/**
|
|
3549
|
-
* WebMCP
|
|
3818
|
+
* WebMCP: consume page-registered tools (`document.modelContext.registerTool`).
|
|
3550
3819
|
* When `enabled`, the widget installs `@mcp-b/webmcp-polyfill`, snapshots the
|
|
3551
3820
|
* registry on every dispatch, ships it as `clientTools[]`, and executes
|
|
3552
3821
|
* returned `webmcp:*` tool calls with confirm-by-default gating.
|
|
3553
3822
|
*
|
|
3554
|
-
* Server-side policy on the chat surface is the source of truth
|
|
3823
|
+
* Server-side policy on the chat surface is the source of truth: these
|
|
3555
3824
|
* fields layer on top.
|
|
3556
3825
|
*
|
|
3557
3826
|
* @example
|
|
@@ -3585,7 +3854,7 @@ export type AgentWidgetConfig = {
|
|
|
3585
3854
|
* This hook runs synchronously and must return the (potentially modified) state.
|
|
3586
3855
|
*
|
|
3587
3856
|
* Returning `{ state, open: true }` also signals that the widget panel should
|
|
3588
|
-
* open after initialization
|
|
3857
|
+
* open after initialization: useful when injecting a post-navigation message
|
|
3589
3858
|
* that the user should immediately see.
|
|
3590
3859
|
*
|
|
3591
3860
|
* @example
|
|
@@ -3908,7 +4177,7 @@ export type AgentWidgetConfig = {
|
|
|
3908
4177
|
* Setting this to `false` is the explicit kill-switch: it disables UI-state
|
|
3909
4178
|
* persistence **and** message-history persistence. When `false`, any
|
|
3910
4179
|
* `storageAdapter` you configure is ignored and the default localStorage
|
|
3911
|
-
* adapter is not created
|
|
4180
|
+
* adapter is not created: no chat history is read or written. Pass `true`
|
|
3912
4181
|
* (or omit) to keep the default behavior of persisting messages via the
|
|
3913
4182
|
* configured `storageAdapter` (or the built-in localStorage adapter).
|
|
3914
4183
|
*
|
|
@@ -3937,7 +4206,7 @@ export type AgentWidgetConfig = {
|
|
|
3937
4206
|
*
|
|
3938
4207
|
* @example
|
|
3939
4208
|
* ```typescript
|
|
3940
|
-
* // Ephemeral widget
|
|
4209
|
+
* // Ephemeral widget: no message history written anywhere
|
|
3941
4210
|
* config: {
|
|
3942
4211
|
* persistState: false
|
|
3943
4212
|
* }
|
|
@@ -4009,7 +4278,7 @@ export type AgentWidgetApproval = {
|
|
|
4009
4278
|
* Agent-authored justification for this specific call (the agent's own
|
|
4010
4279
|
* claim about its intent, extracted server-side from the reserved
|
|
4011
4280
|
* `_approvalReason` parameter). Render it attributed to the agent and as
|
|
4012
|
-
* plain text
|
|
4281
|
+
* plain text: it is approver context, not a system statement.
|
|
4013
4282
|
*/
|
|
4014
4283
|
reason?: string;
|
|
4015
4284
|
parameters?: unknown;
|
|
@@ -4021,16 +4290,16 @@ export type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "ap
|
|
|
4021
4290
|
/**
|
|
4022
4291
|
* Per-turn / per-step stop reason emitted by the runtime on
|
|
4023
4292
|
* `agent_turn_complete` and `step_complete` SSE events. The vocabulary is
|
|
4024
|
-
* owned by the upstream Runtype API
|
|
4293
|
+
* owned by the upstream Runtype API: do not extend without coordination.
|
|
4025
4294
|
*
|
|
4026
|
-
* - `end_turn
|
|
4027
|
-
* - `max_tool_calls
|
|
4028
|
-
* - `length
|
|
4029
|
-
* - `content_filter
|
|
4030
|
-
* - `error
|
|
4031
|
-
* - `unknown
|
|
4295
|
+
* - `end_turn`: natural completion (no affordance needed)
|
|
4296
|
+
* - `max_tool_calls`: agent loop tripped the configured tool-call ceiling
|
|
4297
|
+
* - `length`: provider hit max output tokens
|
|
4298
|
+
* - `content_filter`: provider content filter intervened
|
|
4299
|
+
* - `error`: provider/runtime error (prefer existing error rendering)
|
|
4300
|
+
* - `unknown`: explicitly reported but uninformative
|
|
4032
4301
|
*
|
|
4033
|
-
* Absent (`undefined`) means "not reported"
|
|
4302
|
+
* Absent (`undefined`) means "not reported": distinct from `'unknown'`.
|
|
4034
4303
|
*/
|
|
4035
4304
|
export type StopReasonKind = RuntypeStopReasonKind;
|
|
4036
4305
|
|
|
@@ -4215,7 +4484,7 @@ export type InjectMessageOptions = {
|
|
|
4215
4484
|
|
|
4216
4485
|
/**
|
|
4217
4486
|
* Raw structured payload (typically a JSON string) representing the
|
|
4218
|
-
* full directive that produced this message
|
|
4487
|
+
* full directive that produced this message: e.g. `{ "text": "...",
|
|
4219
4488
|
* "component": "Foo", "props": {...} }`.
|
|
4220
4489
|
*
|
|
4221
4490
|
* Mirrors the field populated by stream parsers during normal LLM
|
|
@@ -4251,7 +4520,7 @@ export type InjectSystemMessageOptions = Omit<InjectMessageOptions, "role">;
|
|
|
4251
4520
|
|
|
4252
4521
|
/**
|
|
4253
4522
|
* Options for injecting an assistant message that renders as a component
|
|
4254
|
-
* directive
|
|
4523
|
+
* directive: sugar over `injectAssistantMessage` for the common case of
|
|
4255
4524
|
* "render this registered component, same as if the LLM had emitted it".
|
|
4256
4525
|
*
|
|
4257
4526
|
* Equivalent to calling `injectAssistantMessage({ content: text, rawContent:
|