@runtypelabs/persona 3.15.1 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animations/glyph-cycle.cjs +279 -0
- package/dist/animations/glyph-cycle.d.cts +5 -0
- package/dist/animations/glyph-cycle.d.ts +5 -0
- package/dist/animations/glyph-cycle.js +252 -0
- package/dist/animations/types-HPZY7oAI.d.cts +282 -0
- package/dist/animations/types-HPZY7oAI.d.ts +282 -0
- package/dist/animations/wipe.cjs +107 -0
- package/dist/animations/wipe.d.cts +5 -0
- package/dist/animations/wipe.d.ts +5 -0
- package/dist/animations/wipe.js +80 -0
- package/dist/index.cjs +49 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +216 -1
- package/dist/index.d.ts +216 -1
- package/dist/index.global.js +137 -82
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +49 -48
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +85 -0
- package/dist/testing.d.cts +39 -0
- package/dist/testing.d.ts +39 -0
- package/dist/testing.js +56 -0
- package/dist/theme-editor.cjs +847 -127
- package/dist/theme-editor.d.cts +225 -2
- package/dist/theme-editor.d.ts +225 -2
- package/dist/theme-editor.js +845 -127
- package/dist/widget.css +133 -0
- package/package.json +20 -3
- package/src/animations/glyph-cycle.ts +332 -0
- package/src/animations/wipe.ts +66 -0
- package/src/client.test.ts +141 -0
- package/src/client.ts +197 -2
- package/src/components/composer-builder.ts +61 -10
- package/src/components/header-builder.ts +18 -7
- package/src/components/header-layouts.ts +3 -1
- package/src/components/message-bubble.test.ts +181 -2
- package/src/components/message-bubble.ts +209 -14
- package/src/components/panel.ts +4 -1
- package/src/defaults.ts +22 -0
- package/src/index-global.ts +31 -0
- package/src/index.ts +18 -0
- package/src/session.test.ts +93 -1
- package/src/session.ts +5 -0
- package/src/styles/widget.css +133 -0
- package/src/testing/index.ts +11 -0
- package/src/testing/mock-stream.test.ts +80 -0
- package/src/testing/mock-stream.ts +94 -0
- package/src/testing.ts +2 -0
- package/src/theme-editor/index.ts +4 -0
- package/src/theme-editor/preview-utils.test.ts +60 -0
- package/src/theme-editor/preview-utils.ts +129 -0
- package/src/theme-editor/sections.test.ts +19 -0
- package/src/theme-editor/sections.ts +84 -1
- package/src/types.ts +221 -0
- package/src/ui.stop-button.test.ts +165 -0
- package/src/ui.ts +79 -8
- package/src/utils/message-fingerprint.ts +2 -0
- package/src/utils/morph.ts +7 -0
- package/src/utils/stream-animation.test.ts +417 -0
- package/src/utils/stream-animation.ts +449 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text content part for multi-modal messages
|
|
3
|
+
*/
|
|
4
|
+
type TextContentPart = {
|
|
5
|
+
type: 'text';
|
|
6
|
+
text: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Image content part for multi-modal messages
|
|
10
|
+
* Supports base64 data URIs or URLs
|
|
11
|
+
*/
|
|
12
|
+
type ImageContentPart = {
|
|
13
|
+
type: 'image';
|
|
14
|
+
image: string;
|
|
15
|
+
mimeType?: string;
|
|
16
|
+
alt?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* File content part for multi-modal messages
|
|
20
|
+
* Supports PDF, TXT, DOCX, and other document types
|
|
21
|
+
*/
|
|
22
|
+
type FileContentPart = {
|
|
23
|
+
type: 'file';
|
|
24
|
+
data: string;
|
|
25
|
+
mimeType: string;
|
|
26
|
+
filename: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Union type for all content part types
|
|
30
|
+
*/
|
|
31
|
+
type ContentPart = TextContentPart | ImageContentPart | FileContentPart;
|
|
32
|
+
/**
|
|
33
|
+
* Metadata attached to messages created during agent execution.
|
|
34
|
+
*/
|
|
35
|
+
type AgentMessageMetadata = {
|
|
36
|
+
executionId?: string;
|
|
37
|
+
iteration?: number;
|
|
38
|
+
turnId?: string;
|
|
39
|
+
agentName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* When this message was produced by a step inside a nested flow executed
|
|
42
|
+
* as a tool, identifies the parent tool call id. Enables renderers to
|
|
43
|
+
* visually group or indent nested-flow output under its parent tool.
|
|
44
|
+
*/
|
|
45
|
+
parentToolId?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Nested flow step id that produced this message (e.g. a `send-stream`
|
|
48
|
+
* or `prompt` step inside the nested flow). Stable key for that step.
|
|
49
|
+
*/
|
|
50
|
+
parentStepId?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Context passed to plugin lifecycle hooks. Carries the live DOM references
|
|
54
|
+
* and resolved animation settings for the currently-streaming message.
|
|
55
|
+
*/
|
|
56
|
+
type StreamAnimationContext = {
|
|
57
|
+
/** The `.persona-message-content` element owning the streamed text. */
|
|
58
|
+
container: HTMLElement;
|
|
59
|
+
/** The outer message bubble element. */
|
|
60
|
+
bubble: HTMLElement;
|
|
61
|
+
/** ID of the streaming message. */
|
|
62
|
+
messageId: string;
|
|
63
|
+
/** Read-only reference to the message being streamed. */
|
|
64
|
+
message: AgentWidgetMessage;
|
|
65
|
+
/** Effective `speed` from `streamAnimation.speed`. */
|
|
66
|
+
speed: number;
|
|
67
|
+
/** Effective `duration` from `streamAnimation.duration`. */
|
|
68
|
+
duration: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Pluggable stream animation. Third-party packages and inline registrations
|
|
72
|
+
* implement this interface to add custom reveal effects.
|
|
73
|
+
*
|
|
74
|
+
* Lifecycle:
|
|
75
|
+
* - When the widget mounts and detects a plugin (either passed via config or
|
|
76
|
+
* auto-registered in the IIFE bundle), it injects `styles` once into the
|
|
77
|
+
* widget's style host.
|
|
78
|
+
* - For each streaming assistant message whose `type` matches `name`, the
|
|
79
|
+
* widget applies `containerClass` / `bubbleClass`, wraps text per `wrap`,
|
|
80
|
+
* and — if `useCaret` is true — appends a blinking caret.
|
|
81
|
+
* - Hooks fire after the live DOM is morphed; plugins use stable element IDs
|
|
82
|
+
* and `data-preserve-animation` to safely mutate per-char or per-word spans
|
|
83
|
+
* without idiomorph clobbering in-flight work.
|
|
84
|
+
*/
|
|
85
|
+
type StreamAnimationPlugin = {
|
|
86
|
+
/** Plugin identifier. Matches the `type` field in `streamAnimation`. */
|
|
87
|
+
name: string;
|
|
88
|
+
/** Class added to `.persona-message-content` while streaming. */
|
|
89
|
+
containerClass?: string;
|
|
90
|
+
/** Class added to the bubble element (e.g. a one-shot scale animation). */
|
|
91
|
+
bubbleClass?: string;
|
|
92
|
+
/** Wrap mode applied to text nodes during streaming. @default "none" */
|
|
93
|
+
wrap?: "none" | "char" | "word";
|
|
94
|
+
/**
|
|
95
|
+
* HTML tags whose descendant text is skipped during wrapping. Defaults to
|
|
96
|
+
* `["pre", "code", "a", "script", "style"]` — useful for keeping code
|
|
97
|
+
* blocks legible and link click-targets intact. Plugins that want to
|
|
98
|
+
* animate characters inside inline code (e.g. `glyph-cycle`) can narrow
|
|
99
|
+
* the list.
|
|
100
|
+
*/
|
|
101
|
+
skipTags?: string[];
|
|
102
|
+
/** Append a blinking caret after the last rendered char/word. */
|
|
103
|
+
useCaret?: boolean;
|
|
104
|
+
/** CSS string injected into the widget style host on first activation. */
|
|
105
|
+
styles?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Optional custom buffering strategy. Returns the portion of `content`
|
|
108
|
+
* that should be rendered during streaming. Use this for buffering
|
|
109
|
+
* schemes beyond the built-in `word` / `line` strategies.
|
|
110
|
+
*/
|
|
111
|
+
bufferContent?: (content: string, message: AgentWidgetMessage) => string;
|
|
112
|
+
/**
|
|
113
|
+
* Fires once when the plugin is first activated inside a widget instance.
|
|
114
|
+
* Use this to set up MutationObservers or other long-lived listeners.
|
|
115
|
+
* Return an optional cleanup function that runs on widget destroy.
|
|
116
|
+
*/
|
|
117
|
+
onAttach?: (root: HTMLElement | ShadowRoot) => (() => void) | void;
|
|
118
|
+
/** Fires after each render that reaches the live DOM. */
|
|
119
|
+
onAfterRender?: (ctx: StreamAnimationContext) => void;
|
|
120
|
+
/** Fires when a streamed message's `streaming` flag flips to false. */
|
|
121
|
+
onStreamComplete?: (ctx: StreamAnimationContext) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Report whether the plugin still has in-flight animation work for a
|
|
124
|
+
* message. When `true`, the widget keeps rendering the message in its
|
|
125
|
+
* "streaming-animated" mode even after `message.streaming` flips false —
|
|
126
|
+
* preventing the final non-animated render from yanking the rug out from
|
|
127
|
+
* under unfinished per-char cycles or reveals.
|
|
128
|
+
*/
|
|
129
|
+
isAnimating?: (message: AgentWidgetMessage) => boolean;
|
|
130
|
+
};
|
|
131
|
+
type AgentWidgetMessageRole = "user" | "assistant" | "system";
|
|
132
|
+
type AgentWidgetReasoning = {
|
|
133
|
+
id: string;
|
|
134
|
+
status: "pending" | "streaming" | "complete";
|
|
135
|
+
chunks: string[];
|
|
136
|
+
startedAt?: number;
|
|
137
|
+
completedAt?: number;
|
|
138
|
+
durationMs?: number;
|
|
139
|
+
};
|
|
140
|
+
type AgentWidgetToolCall = {
|
|
141
|
+
id: string;
|
|
142
|
+
name?: string;
|
|
143
|
+
status: "pending" | "running" | "complete";
|
|
144
|
+
args?: unknown;
|
|
145
|
+
chunks?: string[];
|
|
146
|
+
result?: unknown;
|
|
147
|
+
duration?: number;
|
|
148
|
+
startedAt?: number;
|
|
149
|
+
completedAt?: number;
|
|
150
|
+
durationMs?: number;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Represents a tool approval request in the chat conversation.
|
|
154
|
+
* Created when the agent requires human approval before executing a tool.
|
|
155
|
+
*/
|
|
156
|
+
type AgentWidgetApproval = {
|
|
157
|
+
id: string;
|
|
158
|
+
status: "pending" | "approved" | "denied" | "timeout";
|
|
159
|
+
agentId: string;
|
|
160
|
+
executionId: string;
|
|
161
|
+
toolName: string;
|
|
162
|
+
toolType?: string;
|
|
163
|
+
description: string;
|
|
164
|
+
parameters?: unknown;
|
|
165
|
+
resolvedAt?: number;
|
|
166
|
+
};
|
|
167
|
+
type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval";
|
|
168
|
+
/**
|
|
169
|
+
* Per-turn / per-step stop reason emitted by the runtime on
|
|
170
|
+
* `agent_turn_complete` and `step_complete` SSE events. The vocabulary is
|
|
171
|
+
* owned by the upstream Runtype API — do not extend without coordination.
|
|
172
|
+
*
|
|
173
|
+
* - `end_turn` — natural completion (no affordance needed)
|
|
174
|
+
* - `max_tool_calls` — agent loop tripped the configured tool-call ceiling
|
|
175
|
+
* - `length` — provider hit max output tokens
|
|
176
|
+
* - `content_filter` — provider content filter intervened
|
|
177
|
+
* - `error` — provider/runtime error (prefer existing error rendering)
|
|
178
|
+
* - `unknown` — explicitly reported but uninformative
|
|
179
|
+
*
|
|
180
|
+
* Absent (`undefined`) means "not reported" — distinct from `'unknown'`.
|
|
181
|
+
*/
|
|
182
|
+
type StopReasonKind = 'end_turn' | 'max_tool_calls' | 'length' | 'content_filter' | 'error' | 'unknown';
|
|
183
|
+
/**
|
|
184
|
+
* Represents a message in the chat conversation.
|
|
185
|
+
*
|
|
186
|
+
* @property id - Unique message identifier
|
|
187
|
+
* @property role - Message role: "user", "assistant", or "system"
|
|
188
|
+
* @property content - Message text content (for display)
|
|
189
|
+
* @property contentParts - Original multi-modal content parts (for API requests)
|
|
190
|
+
* @property createdAt - ISO timestamp when message was created
|
|
191
|
+
* @property streaming - Whether message is still streaming (for assistant messages)
|
|
192
|
+
* @property variant - Message variant for assistant messages: "assistant", "reasoning", or "tool"
|
|
193
|
+
* @property sequence - Message ordering number
|
|
194
|
+
* @property reasoning - Reasoning data for assistant reasoning messages
|
|
195
|
+
* @property toolCall - Tool call data for assistant tool messages
|
|
196
|
+
* @property tools - Array of tool calls
|
|
197
|
+
* @property viaVoice - Set to `true` when a user message is sent via voice recognition.
|
|
198
|
+
* Useful for implementing voice-specific behaviors like auto-reactivation.
|
|
199
|
+
*/
|
|
200
|
+
type AgentWidgetMessage = {
|
|
201
|
+
id: string;
|
|
202
|
+
role: AgentWidgetMessageRole;
|
|
203
|
+
content: string;
|
|
204
|
+
createdAt: string;
|
|
205
|
+
/**
|
|
206
|
+
* Original multi-modal content parts for this message.
|
|
207
|
+
* When present, this is sent to the API instead of `content`.
|
|
208
|
+
* The `content` field contains the text-only representation for display.
|
|
209
|
+
*/
|
|
210
|
+
contentParts?: ContentPart[];
|
|
211
|
+
streaming?: boolean;
|
|
212
|
+
variant?: AgentWidgetMessageVariant;
|
|
213
|
+
sequence?: number;
|
|
214
|
+
reasoning?: AgentWidgetReasoning;
|
|
215
|
+
toolCall?: AgentWidgetToolCall;
|
|
216
|
+
tools?: AgentWidgetToolCall[];
|
|
217
|
+
/** Approval data for messages with variant "approval" */
|
|
218
|
+
approval?: AgentWidgetApproval;
|
|
219
|
+
viaVoice?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Set to `true` on placeholder messages injected during Runtype voice processing.
|
|
222
|
+
* Use this in `messageTransform` to detect and customize voice processing placeholders.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* messageTransform: ({ text, message }) => {
|
|
226
|
+
* if (message.voiceProcessing && message.role === 'user') {
|
|
227
|
+
* return '<div class="my-voice-spinner">Transcribing...</div>';
|
|
228
|
+
* }
|
|
229
|
+
* return text;
|
|
230
|
+
* }
|
|
231
|
+
*/
|
|
232
|
+
voiceProcessing?: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Raw structured payload for this message (e.g., JSON action response).
|
|
235
|
+
* Populated automatically when structured parsers run.
|
|
236
|
+
*/
|
|
237
|
+
rawContent?: string;
|
|
238
|
+
/**
|
|
239
|
+
* LLM-specific content for API requests.
|
|
240
|
+
* When present, this is sent to the LLM instead of `content`.
|
|
241
|
+
*
|
|
242
|
+
* Priority for API payload:
|
|
243
|
+
* 1. `contentParts` (if present, used as-is for multi-modal)
|
|
244
|
+
* 2. `llmContent` (if present, sent as string)
|
|
245
|
+
* 3. `rawContent` (backward compatibility with structured parsers)
|
|
246
|
+
* 4. `content` (fallback - display content)
|
|
247
|
+
*
|
|
248
|
+
* The `content` field is always used for UI display.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* // Show full details to user, send summary to LLM
|
|
252
|
+
* {
|
|
253
|
+
* content: "**Product:** iPhone 15 Pro\n**Price:** $1,199\n**SKU:** IP15P-256",
|
|
254
|
+
* llmContent: "[Product search: iPhone 15 Pro, $1199]"
|
|
255
|
+
* }
|
|
256
|
+
*/
|
|
257
|
+
llmContent?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Text segment identity for chronological ordering.
|
|
260
|
+
* When present, identifies which text segment this message represents
|
|
261
|
+
* (e.g., "text_0", "text_1") for messages split at tool boundaries.
|
|
262
|
+
*/
|
|
263
|
+
partId?: string;
|
|
264
|
+
/**
|
|
265
|
+
* Metadata for messages created during agent loop execution.
|
|
266
|
+
* Contains execution context like iteration number and turn ID.
|
|
267
|
+
*/
|
|
268
|
+
agentMetadata?: AgentMessageMetadata;
|
|
269
|
+
/**
|
|
270
|
+
* Per-turn stop reason reported by the runtime on `agent_turn_complete`
|
|
271
|
+
* (agent-loop path) or the last `step_complete` for a prompt step
|
|
272
|
+
* (dispatch / flow path). Absent when the API did not report a value.
|
|
273
|
+
*
|
|
274
|
+
* When set to a non-natural value (`max_tool_calls`, `length`,
|
|
275
|
+
* `content_filter`, `error`), the widget renders an inline notice on
|
|
276
|
+
* the assistant bubble. See `config.copy.stopReasonNotice` to override
|
|
277
|
+
* the default copy.
|
|
278
|
+
*/
|
|
279
|
+
stopReason?: StopReasonKind;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export type { StreamAnimationPlugin as S };
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text content part for multi-modal messages
|
|
3
|
+
*/
|
|
4
|
+
type TextContentPart = {
|
|
5
|
+
type: 'text';
|
|
6
|
+
text: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Image content part for multi-modal messages
|
|
10
|
+
* Supports base64 data URIs or URLs
|
|
11
|
+
*/
|
|
12
|
+
type ImageContentPart = {
|
|
13
|
+
type: 'image';
|
|
14
|
+
image: string;
|
|
15
|
+
mimeType?: string;
|
|
16
|
+
alt?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* File content part for multi-modal messages
|
|
20
|
+
* Supports PDF, TXT, DOCX, and other document types
|
|
21
|
+
*/
|
|
22
|
+
type FileContentPart = {
|
|
23
|
+
type: 'file';
|
|
24
|
+
data: string;
|
|
25
|
+
mimeType: string;
|
|
26
|
+
filename: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Union type for all content part types
|
|
30
|
+
*/
|
|
31
|
+
type ContentPart = TextContentPart | ImageContentPart | FileContentPart;
|
|
32
|
+
/**
|
|
33
|
+
* Metadata attached to messages created during agent execution.
|
|
34
|
+
*/
|
|
35
|
+
type AgentMessageMetadata = {
|
|
36
|
+
executionId?: string;
|
|
37
|
+
iteration?: number;
|
|
38
|
+
turnId?: string;
|
|
39
|
+
agentName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* When this message was produced by a step inside a nested flow executed
|
|
42
|
+
* as a tool, identifies the parent tool call id. Enables renderers to
|
|
43
|
+
* visually group or indent nested-flow output under its parent tool.
|
|
44
|
+
*/
|
|
45
|
+
parentToolId?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Nested flow step id that produced this message (e.g. a `send-stream`
|
|
48
|
+
* or `prompt` step inside the nested flow). Stable key for that step.
|
|
49
|
+
*/
|
|
50
|
+
parentStepId?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Context passed to plugin lifecycle hooks. Carries the live DOM references
|
|
54
|
+
* and resolved animation settings for the currently-streaming message.
|
|
55
|
+
*/
|
|
56
|
+
type StreamAnimationContext = {
|
|
57
|
+
/** The `.persona-message-content` element owning the streamed text. */
|
|
58
|
+
container: HTMLElement;
|
|
59
|
+
/** The outer message bubble element. */
|
|
60
|
+
bubble: HTMLElement;
|
|
61
|
+
/** ID of the streaming message. */
|
|
62
|
+
messageId: string;
|
|
63
|
+
/** Read-only reference to the message being streamed. */
|
|
64
|
+
message: AgentWidgetMessage;
|
|
65
|
+
/** Effective `speed` from `streamAnimation.speed`. */
|
|
66
|
+
speed: number;
|
|
67
|
+
/** Effective `duration` from `streamAnimation.duration`. */
|
|
68
|
+
duration: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Pluggable stream animation. Third-party packages and inline registrations
|
|
72
|
+
* implement this interface to add custom reveal effects.
|
|
73
|
+
*
|
|
74
|
+
* Lifecycle:
|
|
75
|
+
* - When the widget mounts and detects a plugin (either passed via config or
|
|
76
|
+
* auto-registered in the IIFE bundle), it injects `styles` once into the
|
|
77
|
+
* widget's style host.
|
|
78
|
+
* - For each streaming assistant message whose `type` matches `name`, the
|
|
79
|
+
* widget applies `containerClass` / `bubbleClass`, wraps text per `wrap`,
|
|
80
|
+
* and — if `useCaret` is true — appends a blinking caret.
|
|
81
|
+
* - Hooks fire after the live DOM is morphed; plugins use stable element IDs
|
|
82
|
+
* and `data-preserve-animation` to safely mutate per-char or per-word spans
|
|
83
|
+
* without idiomorph clobbering in-flight work.
|
|
84
|
+
*/
|
|
85
|
+
type StreamAnimationPlugin = {
|
|
86
|
+
/** Plugin identifier. Matches the `type` field in `streamAnimation`. */
|
|
87
|
+
name: string;
|
|
88
|
+
/** Class added to `.persona-message-content` while streaming. */
|
|
89
|
+
containerClass?: string;
|
|
90
|
+
/** Class added to the bubble element (e.g. a one-shot scale animation). */
|
|
91
|
+
bubbleClass?: string;
|
|
92
|
+
/** Wrap mode applied to text nodes during streaming. @default "none" */
|
|
93
|
+
wrap?: "none" | "char" | "word";
|
|
94
|
+
/**
|
|
95
|
+
* HTML tags whose descendant text is skipped during wrapping. Defaults to
|
|
96
|
+
* `["pre", "code", "a", "script", "style"]` — useful for keeping code
|
|
97
|
+
* blocks legible and link click-targets intact. Plugins that want to
|
|
98
|
+
* animate characters inside inline code (e.g. `glyph-cycle`) can narrow
|
|
99
|
+
* the list.
|
|
100
|
+
*/
|
|
101
|
+
skipTags?: string[];
|
|
102
|
+
/** Append a blinking caret after the last rendered char/word. */
|
|
103
|
+
useCaret?: boolean;
|
|
104
|
+
/** CSS string injected into the widget style host on first activation. */
|
|
105
|
+
styles?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Optional custom buffering strategy. Returns the portion of `content`
|
|
108
|
+
* that should be rendered during streaming. Use this for buffering
|
|
109
|
+
* schemes beyond the built-in `word` / `line` strategies.
|
|
110
|
+
*/
|
|
111
|
+
bufferContent?: (content: string, message: AgentWidgetMessage) => string;
|
|
112
|
+
/**
|
|
113
|
+
* Fires once when the plugin is first activated inside a widget instance.
|
|
114
|
+
* Use this to set up MutationObservers or other long-lived listeners.
|
|
115
|
+
* Return an optional cleanup function that runs on widget destroy.
|
|
116
|
+
*/
|
|
117
|
+
onAttach?: (root: HTMLElement | ShadowRoot) => (() => void) | void;
|
|
118
|
+
/** Fires after each render that reaches the live DOM. */
|
|
119
|
+
onAfterRender?: (ctx: StreamAnimationContext) => void;
|
|
120
|
+
/** Fires when a streamed message's `streaming` flag flips to false. */
|
|
121
|
+
onStreamComplete?: (ctx: StreamAnimationContext) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Report whether the plugin still has in-flight animation work for a
|
|
124
|
+
* message. When `true`, the widget keeps rendering the message in its
|
|
125
|
+
* "streaming-animated" mode even after `message.streaming` flips false —
|
|
126
|
+
* preventing the final non-animated render from yanking the rug out from
|
|
127
|
+
* under unfinished per-char cycles or reveals.
|
|
128
|
+
*/
|
|
129
|
+
isAnimating?: (message: AgentWidgetMessage) => boolean;
|
|
130
|
+
};
|
|
131
|
+
type AgentWidgetMessageRole = "user" | "assistant" | "system";
|
|
132
|
+
type AgentWidgetReasoning = {
|
|
133
|
+
id: string;
|
|
134
|
+
status: "pending" | "streaming" | "complete";
|
|
135
|
+
chunks: string[];
|
|
136
|
+
startedAt?: number;
|
|
137
|
+
completedAt?: number;
|
|
138
|
+
durationMs?: number;
|
|
139
|
+
};
|
|
140
|
+
type AgentWidgetToolCall = {
|
|
141
|
+
id: string;
|
|
142
|
+
name?: string;
|
|
143
|
+
status: "pending" | "running" | "complete";
|
|
144
|
+
args?: unknown;
|
|
145
|
+
chunks?: string[];
|
|
146
|
+
result?: unknown;
|
|
147
|
+
duration?: number;
|
|
148
|
+
startedAt?: number;
|
|
149
|
+
completedAt?: number;
|
|
150
|
+
durationMs?: number;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Represents a tool approval request in the chat conversation.
|
|
154
|
+
* Created when the agent requires human approval before executing a tool.
|
|
155
|
+
*/
|
|
156
|
+
type AgentWidgetApproval = {
|
|
157
|
+
id: string;
|
|
158
|
+
status: "pending" | "approved" | "denied" | "timeout";
|
|
159
|
+
agentId: string;
|
|
160
|
+
executionId: string;
|
|
161
|
+
toolName: string;
|
|
162
|
+
toolType?: string;
|
|
163
|
+
description: string;
|
|
164
|
+
parameters?: unknown;
|
|
165
|
+
resolvedAt?: number;
|
|
166
|
+
};
|
|
167
|
+
type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval";
|
|
168
|
+
/**
|
|
169
|
+
* Per-turn / per-step stop reason emitted by the runtime on
|
|
170
|
+
* `agent_turn_complete` and `step_complete` SSE events. The vocabulary is
|
|
171
|
+
* owned by the upstream Runtype API — do not extend without coordination.
|
|
172
|
+
*
|
|
173
|
+
* - `end_turn` — natural completion (no affordance needed)
|
|
174
|
+
* - `max_tool_calls` — agent loop tripped the configured tool-call ceiling
|
|
175
|
+
* - `length` — provider hit max output tokens
|
|
176
|
+
* - `content_filter` — provider content filter intervened
|
|
177
|
+
* - `error` — provider/runtime error (prefer existing error rendering)
|
|
178
|
+
* - `unknown` — explicitly reported but uninformative
|
|
179
|
+
*
|
|
180
|
+
* Absent (`undefined`) means "not reported" — distinct from `'unknown'`.
|
|
181
|
+
*/
|
|
182
|
+
type StopReasonKind = 'end_turn' | 'max_tool_calls' | 'length' | 'content_filter' | 'error' | 'unknown';
|
|
183
|
+
/**
|
|
184
|
+
* Represents a message in the chat conversation.
|
|
185
|
+
*
|
|
186
|
+
* @property id - Unique message identifier
|
|
187
|
+
* @property role - Message role: "user", "assistant", or "system"
|
|
188
|
+
* @property content - Message text content (for display)
|
|
189
|
+
* @property contentParts - Original multi-modal content parts (for API requests)
|
|
190
|
+
* @property createdAt - ISO timestamp when message was created
|
|
191
|
+
* @property streaming - Whether message is still streaming (for assistant messages)
|
|
192
|
+
* @property variant - Message variant for assistant messages: "assistant", "reasoning", or "tool"
|
|
193
|
+
* @property sequence - Message ordering number
|
|
194
|
+
* @property reasoning - Reasoning data for assistant reasoning messages
|
|
195
|
+
* @property toolCall - Tool call data for assistant tool messages
|
|
196
|
+
* @property tools - Array of tool calls
|
|
197
|
+
* @property viaVoice - Set to `true` when a user message is sent via voice recognition.
|
|
198
|
+
* Useful for implementing voice-specific behaviors like auto-reactivation.
|
|
199
|
+
*/
|
|
200
|
+
type AgentWidgetMessage = {
|
|
201
|
+
id: string;
|
|
202
|
+
role: AgentWidgetMessageRole;
|
|
203
|
+
content: string;
|
|
204
|
+
createdAt: string;
|
|
205
|
+
/**
|
|
206
|
+
* Original multi-modal content parts for this message.
|
|
207
|
+
* When present, this is sent to the API instead of `content`.
|
|
208
|
+
* The `content` field contains the text-only representation for display.
|
|
209
|
+
*/
|
|
210
|
+
contentParts?: ContentPart[];
|
|
211
|
+
streaming?: boolean;
|
|
212
|
+
variant?: AgentWidgetMessageVariant;
|
|
213
|
+
sequence?: number;
|
|
214
|
+
reasoning?: AgentWidgetReasoning;
|
|
215
|
+
toolCall?: AgentWidgetToolCall;
|
|
216
|
+
tools?: AgentWidgetToolCall[];
|
|
217
|
+
/** Approval data for messages with variant "approval" */
|
|
218
|
+
approval?: AgentWidgetApproval;
|
|
219
|
+
viaVoice?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Set to `true` on placeholder messages injected during Runtype voice processing.
|
|
222
|
+
* Use this in `messageTransform` to detect and customize voice processing placeholders.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* messageTransform: ({ text, message }) => {
|
|
226
|
+
* if (message.voiceProcessing && message.role === 'user') {
|
|
227
|
+
* return '<div class="my-voice-spinner">Transcribing...</div>';
|
|
228
|
+
* }
|
|
229
|
+
* return text;
|
|
230
|
+
* }
|
|
231
|
+
*/
|
|
232
|
+
voiceProcessing?: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Raw structured payload for this message (e.g., JSON action response).
|
|
235
|
+
* Populated automatically when structured parsers run.
|
|
236
|
+
*/
|
|
237
|
+
rawContent?: string;
|
|
238
|
+
/**
|
|
239
|
+
* LLM-specific content for API requests.
|
|
240
|
+
* When present, this is sent to the LLM instead of `content`.
|
|
241
|
+
*
|
|
242
|
+
* Priority for API payload:
|
|
243
|
+
* 1. `contentParts` (if present, used as-is for multi-modal)
|
|
244
|
+
* 2. `llmContent` (if present, sent as string)
|
|
245
|
+
* 3. `rawContent` (backward compatibility with structured parsers)
|
|
246
|
+
* 4. `content` (fallback - display content)
|
|
247
|
+
*
|
|
248
|
+
* The `content` field is always used for UI display.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* // Show full details to user, send summary to LLM
|
|
252
|
+
* {
|
|
253
|
+
* content: "**Product:** iPhone 15 Pro\n**Price:** $1,199\n**SKU:** IP15P-256",
|
|
254
|
+
* llmContent: "[Product search: iPhone 15 Pro, $1199]"
|
|
255
|
+
* }
|
|
256
|
+
*/
|
|
257
|
+
llmContent?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Text segment identity for chronological ordering.
|
|
260
|
+
* When present, identifies which text segment this message represents
|
|
261
|
+
* (e.g., "text_0", "text_1") for messages split at tool boundaries.
|
|
262
|
+
*/
|
|
263
|
+
partId?: string;
|
|
264
|
+
/**
|
|
265
|
+
* Metadata for messages created during agent loop execution.
|
|
266
|
+
* Contains execution context like iteration number and turn ID.
|
|
267
|
+
*/
|
|
268
|
+
agentMetadata?: AgentMessageMetadata;
|
|
269
|
+
/**
|
|
270
|
+
* Per-turn stop reason reported by the runtime on `agent_turn_complete`
|
|
271
|
+
* (agent-loop path) or the last `step_complete` for a prompt step
|
|
272
|
+
* (dispatch / flow path). Absent when the API did not report a value.
|
|
273
|
+
*
|
|
274
|
+
* When set to a non-natural value (`max_tool_calls`, `length`,
|
|
275
|
+
* `content_filter`, `error`), the widget renders an inline notice on
|
|
276
|
+
* the assistant bubble. See `config.copy.stopReasonNotice` to override
|
|
277
|
+
* the default copy.
|
|
278
|
+
*/
|
|
279
|
+
stopReason?: StopReasonKind;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export type { StreamAnimationPlugin as S };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/animations/wipe.ts
|
|
21
|
+
var wipe_exports = {};
|
|
22
|
+
__export(wipe_exports, {
|
|
23
|
+
default: () => wipe_default,
|
|
24
|
+
wipe: () => wipe
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(wipe_exports);
|
|
27
|
+
|
|
28
|
+
// src/utils/stream-animation.ts
|
|
29
|
+
var BUILTIN_PLUGINS = [
|
|
30
|
+
{
|
|
31
|
+
name: "typewriter",
|
|
32
|
+
containerClass: "persona-stream-typewriter",
|
|
33
|
+
wrap: "char",
|
|
34
|
+
useCaret: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "pop-bubble",
|
|
38
|
+
bubbleClass: "persona-stream-pop",
|
|
39
|
+
wrap: "none"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "letter-rise",
|
|
43
|
+
containerClass: "persona-stream-letter-rise",
|
|
44
|
+
wrap: "char"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "word-fade",
|
|
48
|
+
containerClass: "persona-stream-word-fade",
|
|
49
|
+
wrap: "word"
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
var globalRegistry = /* @__PURE__ */ new Map();
|
|
53
|
+
for (const plugin of BUILTIN_PLUGINS) globalRegistry.set(plugin.name, plugin);
|
|
54
|
+
var registerStreamAnimationPlugin = (plugin) => {
|
|
55
|
+
globalRegistry.set(plugin.name, plugin);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/animations/wipe.ts
|
|
59
|
+
var STYLES = `
|
|
60
|
+
@keyframes persona-stream-wipe {
|
|
61
|
+
from { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
|
|
62
|
+
to { -webkit-mask-position: 0% 0; mask-position: 0% 0; }
|
|
63
|
+
}
|
|
64
|
+
[data-persona-root] .persona-stream-wipe .persona-stream-word {
|
|
65
|
+
-webkit-mask-image: linear-gradient(
|
|
66
|
+
90deg,
|
|
67
|
+
black 0%,
|
|
68
|
+
black 45%,
|
|
69
|
+
transparent 55%,
|
|
70
|
+
transparent 100%
|
|
71
|
+
);
|
|
72
|
+
mask-image: linear-gradient(
|
|
73
|
+
90deg,
|
|
74
|
+
black 0%,
|
|
75
|
+
black 45%,
|
|
76
|
+
transparent 55%,
|
|
77
|
+
transparent 100%
|
|
78
|
+
);
|
|
79
|
+
-webkit-mask-size: 200% 100%;
|
|
80
|
+
mask-size: 200% 100%;
|
|
81
|
+
-webkit-mask-position: 100% 0;
|
|
82
|
+
mask-position: 100% 0;
|
|
83
|
+
-webkit-mask-repeat: no-repeat;
|
|
84
|
+
mask-repeat: no-repeat;
|
|
85
|
+
animation: persona-stream-wipe calc(var(--persona-stream-step, 120ms) * 3)
|
|
86
|
+
ease-out forwards;
|
|
87
|
+
}
|
|
88
|
+
@media (prefers-reduced-motion: reduce) {
|
|
89
|
+
[data-persona-root] .persona-stream-wipe .persona-stream-word {
|
|
90
|
+
animation: none !important;
|
|
91
|
+
-webkit-mask-image: none !important;
|
|
92
|
+
mask-image: none !important;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`.trim();
|
|
96
|
+
var wipe = {
|
|
97
|
+
name: "wipe",
|
|
98
|
+
containerClass: "persona-stream-wipe",
|
|
99
|
+
wrap: "word",
|
|
100
|
+
styles: STYLES
|
|
101
|
+
};
|
|
102
|
+
registerStreamAnimationPlugin(wipe);
|
|
103
|
+
var wipe_default = wipe;
|
|
104
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
105
|
+
0 && (module.exports = {
|
|
106
|
+
wipe
|
|
107
|
+
});
|