@miiflow/assistant-ui 0.10.0 → 0.15.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 +209 -46
- package/dist/{WelcomeScreen-Cbipi2rK.d.ts → WelcomeScreen-CSzlU0Yx.d.ts} +54 -14
- package/dist/{avatar-CD685KQV.d.ts → avatar-B_AvYfE8.d.ts} +4 -1
- package/dist/chunk-7QNDCHY7.js +2 -0
- package/dist/chunk-7QNDCHY7.js.map +1 -0
- package/dist/chunk-BINTGT2Q.js +5 -0
- package/dist/chunk-BINTGT2Q.js.map +1 -0
- package/dist/chunk-HNHLLH6W.js +2 -0
- package/dist/chunk-HNHLLH6W.js.map +1 -0
- package/dist/{chunk-WG77GQR3.js → chunk-ISMTV5BU.js} +2 -2
- package/dist/{chunk-WG77GQR3.js.map → chunk-ISMTV5BU.js.map} +1 -1
- package/dist/chunk-LDTAZ4GT.js +2 -0
- package/dist/chunk-LDTAZ4GT.js.map +1 -0
- package/dist/chunk-OU5ITGKX.js +2 -0
- package/dist/chunk-OU5ITGKX.js.map +1 -0
- package/dist/chunk-W7HQXA2Z.js +146 -0
- package/dist/chunk-W7HQXA2Z.js.map +1 -0
- package/dist/client/index.d.ts +66 -5
- package/dist/client/index.js +6 -6
- package/dist/client/index.js.map +1 -1
- package/dist/composer/index.d.ts +37 -3
- package/dist/composer/index.js +1 -1
- package/dist/context/index.d.ts +10 -3
- package/dist/context/index.js +1 -1
- package/dist/hooks/index.d.ts +11 -141
- package/dist/hooks/index.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{message-D0oMw3tR.d.ts → message-DTNTKSQr.d.ts} +1 -1
- package/dist/primitives/index.d.ts +3 -3
- package/dist/primitives/index.js +1 -1
- package/dist/{streaming-CmQo_OOA.d.ts → streaming-BfLEgW5u.d.ts} +81 -3
- package/dist/styled/index.d.ts +410 -11
- package/dist/styled/index.js +1 -1
- package/dist/styles-no-preflight.css +1 -1
- package/dist/styles.css +3 -1
- package/dist/use-branding-css-vars-CR2tjSV8.d.ts +155 -0
- package/package.json +5 -3
- package/dist/chunk-4WWJTYYA.js +0 -2
- package/dist/chunk-4WWJTYYA.js.map +0 -1
- package/dist/chunk-6RN7SUWT.js +0 -2
- package/dist/chunk-6RN7SUWT.js.map +0 -1
- package/dist/chunk-D2PFIJNZ.js +0 -2
- package/dist/chunk-D2PFIJNZ.js.map +0 -1
- package/dist/chunk-NKLA5PPB.js +0 -2
- package/dist/chunk-NKLA5PPB.js.map +0 -1
- package/dist/chunk-UZ2Z7C43.js +0 -133
- package/dist/chunk-UZ2Z7C43.js.map +0 -1
- package/dist/chunk-ZP4FGAAH.js +0 -2
- package/dist/chunk-ZP4FGAAH.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ React components and hooks for building custom Miiflow chat interfaces. Install
|
|
|
8
8
|
npm install @miiflow/assistant-ui
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
**Peer dependencies:** `react >=
|
|
11
|
+
**Peer dependencies:** `react >= 19`, `react-dom >= 19`, `zod >= 3`. Optionally `lexical >= 0.20` and `@lexical/react >= 0.20` — required only if you use the Lexical-based `MessageComposer` / `WelcomeScreen` input or the `/composer` entry. React 18 projects must stay on `0.10.x`.
|
|
12
12
|
|
|
13
13
|
The styled components use [TailwindCSS](https://tailwindcss.com/). If your project doesn't use Tailwind, import the pre-built CSS instead:
|
|
14
14
|
|
|
@@ -44,6 +44,7 @@ function Chat() {
|
|
|
44
44
|
streamingMessageId,
|
|
45
45
|
sendMessage,
|
|
46
46
|
uploadFile,
|
|
47
|
+
stopStreaming,
|
|
47
48
|
startNewThread,
|
|
48
49
|
branding,
|
|
49
50
|
brandingCSSVars,
|
|
@@ -63,7 +64,8 @@ function Chat() {
|
|
|
63
64
|
messages={messages}
|
|
64
65
|
isStreaming={isStreaming}
|
|
65
66
|
streamingMessageId={streamingMessageId}
|
|
66
|
-
onSendMessage={sendMessage}
|
|
67
|
+
onSendMessage={(content) => sendMessage(content)}
|
|
68
|
+
onStopStreaming={stopStreaming}
|
|
67
69
|
>
|
|
68
70
|
<div style={{ height: "100vh", ...brandingCSSVars }}>
|
|
69
71
|
<ChatLayout
|
|
@@ -82,8 +84,9 @@ function Chat() {
|
|
|
82
84
|
welcomeText={branding?.welcomeMessage}
|
|
83
85
|
placeholders={branding?.rotatingPlaceholders}
|
|
84
86
|
suggestions={branding?.presetQuestions}
|
|
85
|
-
onSubmit={sendMessage}
|
|
86
|
-
onSuggestionClick={sendMessage}
|
|
87
|
+
onSubmit={(message) => sendMessage(message)}
|
|
88
|
+
onSuggestionClick={(s) => sendMessage(s)}
|
|
89
|
+
disabled={isStreaming}
|
|
87
90
|
/>
|
|
88
91
|
}
|
|
89
92
|
messageList={
|
|
@@ -101,9 +104,12 @@ function Chat() {
|
|
|
101
104
|
}
|
|
102
105
|
composer={
|
|
103
106
|
<MessageComposer
|
|
104
|
-
onSubmit={
|
|
107
|
+
onSubmit={(content, _files, attachmentIds) =>
|
|
108
|
+
sendMessage(content, attachmentIds)
|
|
109
|
+
}
|
|
105
110
|
onUploadFile={uploadFile}
|
|
106
|
-
|
|
111
|
+
isStreaming={isStreaming}
|
|
112
|
+
onStopStreaming={stopStreaming}
|
|
107
113
|
placeholder={branding?.chatboxPlaceholder}
|
|
108
114
|
/>
|
|
109
115
|
}
|
|
@@ -114,6 +120,8 @@ function Chat() {
|
|
|
114
120
|
}
|
|
115
121
|
```
|
|
116
122
|
|
|
123
|
+
Note the small signature adapters: the hook's `sendMessage` takes `(content, attachmentIds?)`, while `ChatProvider.onSendMessage` passes `(content, attachments?: File[])` and `MessageComposer.onSubmit` passes `(content, attachments?, attachmentIds?)` — wrap them as shown rather than passing `sendMessage` directly.
|
|
124
|
+
|
|
117
125
|
## Configuration Reference
|
|
118
126
|
|
|
119
127
|
Pass a `MiiflowChatConfig` object to `useMiiflowChat`:
|
|
@@ -126,11 +134,70 @@ Pass a `MiiflowChatConfig` object to `useMiiflowChat`:
|
|
|
126
134
|
| `userName` | `string` | No | User display name |
|
|
127
135
|
| `userEmail` | `string` | No | User email |
|
|
128
136
|
| `userMetadata` | `string` | No | JSON string of custom user metadata |
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
137
|
+
| `userData` | `string` | No | The exact JSON string your server signed, sent verbatim. See [Verified identity](#verified-identity-hmac) |
|
|
138
|
+
| `hmac` | `string` | No | Signature over `userData` + `timestamp`. See [Verified identity](#verified-identity-hmac) |
|
|
139
|
+
| `timestamp` | `string` | No | Unix seconds (string) used in the signature |
|
|
140
|
+
| `baseUrl` | `string` | No | API origin override (default: `https://api.miiflow.ai`). A trailing `/api` is stripped; the client appends `/api/...` per request |
|
|
132
141
|
| `webSocketUrl` | `string` | No | WebSocket URL for tool invocations (auto-derived from `baseUrl` if not set) |
|
|
133
|
-
| `
|
|
142
|
+
| `initialBranding` | `BrandingData` | No | Branding rendered before session init so the shell paints instantly (SSR-safe). Server branding overrides it once init resolves |
|
|
143
|
+
| `tools` | `ClientToolDefinition[]` | No | Client tools folded into the init round-trip instead of a separate `registerTools()` call |
|
|
144
|
+
| `onToolInvocationFallback` | `(invocation: ToolInvocationRequest) => Promise<boolean>` | No | Handles tool invocations with no local handler (multi-widget routing); return `true` if handled |
|
|
145
|
+
| `onUserMessageCreated` | `(message: { id: string; content: string }) => void` | No | Fired when a user message is created |
|
|
146
|
+
| `onAssistantMessageComplete` | `(message: { id: string; content: string }) => void` | No | Fired when an assistant stream completes |
|
|
147
|
+
|
|
148
|
+
## Verified identity (HMAC)
|
|
149
|
+
|
|
150
|
+
By default a session is anonymous: the widget keys it on a random id in
|
|
151
|
+
`localStorage`, and `userId`/`userName`/`userEmail` are untrusted hints the
|
|
152
|
+
browser could set to anything. That is fine for a public help widget.
|
|
153
|
+
|
|
154
|
+
If the assistant should act **as a signed-in person** — see their data, or use
|
|
155
|
+
a connected integration on their behalf — the browser cannot be the one making
|
|
156
|
+
that claim. Sign the identity on your server instead:
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
// SERVER-SIDE ONLY. The private key must never reach the browser: anyone
|
|
160
|
+
// holding it can impersonate any of your users to the assistant.
|
|
161
|
+
import crypto from "node:crypto";
|
|
162
|
+
|
|
163
|
+
const userData = JSON.stringify({
|
|
164
|
+
user_id: "your-internal-user-id", // required — the session is keyed on this
|
|
165
|
+
name: "Ada Lovelace", // optional
|
|
166
|
+
email: "ada@example.com", // optional
|
|
167
|
+
tenant_scope: "acme-hvac", // optional — see below
|
|
168
|
+
});
|
|
169
|
+
const timestamp = String(Math.floor(Date.now() / 1000));
|
|
170
|
+
const hmac = crypto
|
|
171
|
+
.createHmac("sha256", process.env.MIIFLOW_EMBED_PRIVATE_KEY)
|
|
172
|
+
.update(`${userData}|${timestamp}`)
|
|
173
|
+
.digest("hex");
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Pass all three to the hook and send nothing else:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
useMiiflowChat({ publicKey, assistantId, userData, hmac, timestamp });
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Details that matter:
|
|
183
|
+
|
|
184
|
+
- **The signature covers the exact bytes of `userData`.** Pass the same string
|
|
185
|
+
you signed — re-serializing it, even to equivalent JSON, invalidates the
|
|
186
|
+
signature. This is why `userData` is a string you supply rather than
|
|
187
|
+
something the SDK assembles for you.
|
|
188
|
+
- **All three fields travel together.** Send a partial set and the session
|
|
189
|
+
falls back to anonymous rather than failing loudly.
|
|
190
|
+
- **`timestamp` must be within 5 minutes** of server time. Sign per page load,
|
|
191
|
+
not once at build time.
|
|
192
|
+
- **`user_id` is the session identity.** Two different signed-in users on the
|
|
193
|
+
same browser get separate sessions and separate chat histories, and neither
|
|
194
|
+
can reach the other's — an unsigned request cannot claim a signed identity.
|
|
195
|
+
- **`tenant_scope`** names which of *your* tenants (workspace, shop, account)
|
|
196
|
+
the session is acting for, when one deployment serves many. It scopes the
|
|
197
|
+
credentials the assistant uses, so a session can only reach the tenant it was
|
|
198
|
+
signed for. Omit it if your users belong to exactly one.
|
|
199
|
+
|
|
200
|
+
Rotate the private key from the Miiflow dashboard if it is ever exposed.
|
|
134
201
|
|
|
135
202
|
## Connecting to a Custom Backend
|
|
136
203
|
|
|
@@ -140,13 +207,13 @@ By default, the hook connects to `https://api.miiflow.ai`. To point to your own
|
|
|
140
207
|
useMiiflowChat({
|
|
141
208
|
publicKey: "pk_live_...",
|
|
142
209
|
assistantId: "ast_...",
|
|
143
|
-
baseUrl: "https://your-server.example.com
|
|
210
|
+
baseUrl: "https://your-server.example.com",
|
|
144
211
|
// webSocketUrl is auto-derived from baseUrl; override if needed:
|
|
145
212
|
// webSocketUrl: "wss://your-server.example.com/ws",
|
|
146
213
|
});
|
|
147
214
|
```
|
|
148
215
|
|
|
149
|
-
Your backend must implement the same API contract as the Miiflow platform (session init, SSE streaming, file upload, and tool-result endpoints).
|
|
216
|
+
Pass the bare origin — the client appends `/api/...` to each request itself (a trailing `/api` on `baseUrl` is stripped). Your backend must implement the same API contract as the Miiflow platform (session init, SSE streaming, file upload, and tool-result endpoints).
|
|
150
217
|
|
|
151
218
|
## Hook API — `useMiiflowChat`
|
|
152
219
|
|
|
@@ -173,12 +240,17 @@ const result = useMiiflowChat(config);
|
|
|
173
240
|
|
|
174
241
|
| Method | Signature | Description |
|
|
175
242
|
|--------|-----------|-------------|
|
|
176
|
-
| `sendMessage` | `(content: string, attachmentIds?: string[]) => Promise<void>` | Send a message
|
|
243
|
+
| `sendMessage` | `(content: string, attachmentIds?: string[]) => Promise<void>` | Send a message; queued if init hasn't resolved yet |
|
|
177
244
|
| `uploadFile` | `(file: File) => Promise<string>` | Upload a file and get an attachment ID |
|
|
178
|
-
| `
|
|
245
|
+
| `removeUploadedAttachment` | `(attachmentId: string) => void` | Drop uploaded-attachment metadata when the user removes it pre-send |
|
|
246
|
+
| `stopStreaming` | `() => void` | Abort the in-flight stream, preserving partial content |
|
|
247
|
+
| `startNewThread` | `() => Promise<string>` | Start a new conversation thread; re-registers client tools |
|
|
179
248
|
| `registerTool` | `(tool: ClientToolDefinition) => Promise<void>` | Register a client-side tool |
|
|
180
249
|
| `registerTools` | `(tools: ClientToolDefinition[]) => Promise<void>` | Register multiple tools |
|
|
181
|
-
| `sendSystemEvent` | `(event: SystemEvent) => Promise<void>` | Send an invisible system event |
|
|
250
|
+
| `sendSystemEvent` | `(event: SystemEvent) => Promise<void>` | Send an invisible system event (triggers a reply) |
|
|
251
|
+
| `sendPageContext` | `(context: PageContext) => Promise<void>` | Append hidden page context to the thread (no reply) |
|
|
252
|
+
| `handleToolInvocation` | `(invocation: ToolInvocationRequest) => Promise<boolean>` | Execute a tool invocation; `true` if handled locally |
|
|
253
|
+
| `updateSession` | `(session: EmbedSession) => void` | Replace the session externally (e.g. after token refresh) |
|
|
182
254
|
|
|
183
255
|
## Components Reference
|
|
184
256
|
|
|
@@ -188,14 +260,18 @@ Wraps children and provides chat context via React context.
|
|
|
188
260
|
|
|
189
261
|
| Prop | Type | Default | Description |
|
|
190
262
|
|------|------|---------|-------------|
|
|
191
|
-
| `
|
|
263
|
+
| `children` | `ReactNode` | — | **Required.** Subtree |
|
|
264
|
+
| `messages` | `ChatMessage[]` | — | **Required.** Messages to display |
|
|
265
|
+
| `onSendMessage` | `(content: string, attachments?: File[]) => Promise<void>` | — | **Required.** Message send handler |
|
|
192
266
|
| `isStreaming` | `boolean` | `false` | Whether a response is streaming |
|
|
193
267
|
| `streamingMessageId` | `string \| null` | `null` | ID of the streaming message |
|
|
194
268
|
| `viewerRole` | `ParticipantRole` | `"user"` | Viewer's role (determines message alignment) |
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `onVisualizationAction` | `(event: VisualizationActionEvent) => void` | — | Callback for form/card interactions |
|
|
269
|
+
| `onStopStreaming` | `() => void` | — | Stop streaming handler (wire to the hook's `stopStreaming`) |
|
|
270
|
+
| `onRetryLastMessage` | `() => Promise<void>` | — | Retry last message handler (host-implemented) |
|
|
271
|
+
| `customData` | `Record<string, unknown>` | — | Arbitrary data passed through context |
|
|
272
|
+
| `onVisualizationAction` | `(event: VisualizationActionEvent) => void` | — | Callback for form/card/auth interactions |
|
|
273
|
+
| `resolveCommandToken` | `(id: string, kind: string) => { label?: string; tag?: ReactNode } \| undefined` | — | Customize inline command-token chip rendering |
|
|
274
|
+
| `isDarkSurface` | `boolean` | `false` | Tells the package the host surface is dark — drives choices CSS variables can't express, currently the code-block syntax theme |
|
|
199
275
|
|
|
200
276
|
### `ChatLayout`
|
|
201
277
|
|
|
@@ -203,13 +279,12 @@ Handles the empty-to-active state transition with crossfade animation. Accepts r
|
|
|
203
279
|
|
|
204
280
|
| Prop | Type | Default | Description |
|
|
205
281
|
|------|------|---------|-------------|
|
|
206
|
-
| `isEmpty` | `boolean` | — | Whether the chat has no messages |
|
|
282
|
+
| `isEmpty` | `boolean` | — | **Required.** Whether the chat has no messages |
|
|
207
283
|
| `header` | `ReactNode` | — | Header slot (rendered in both states) |
|
|
208
284
|
| `welcomeScreen` | `ReactNode` | — | Content for empty state |
|
|
209
285
|
| `messageList` | `ReactNode` | — | Message list for active state |
|
|
210
286
|
| `composer` | `ReactNode` | — | Composer for active state |
|
|
211
287
|
| `footer` | `ReactNode` | — | Extra content between list and composer |
|
|
212
|
-
| `variant` | `"standalone" \| "embedded" \| "widget"` | `"standalone"` | Layout variant |
|
|
213
288
|
| `className` | `string` | — | Additional CSS classes |
|
|
214
289
|
|
|
215
290
|
### `WelcomeScreen`
|
|
@@ -220,38 +295,64 @@ Empty state with rotating placeholder text and suggestion cards.
|
|
|
220
295
|
|------|------|---------|-------------|
|
|
221
296
|
| `placeholders` | `string[]` | `[]` | Rotating placeholder strings |
|
|
222
297
|
| `suggestions` | `string[]` | `[]` | Preset suggestion cards |
|
|
223
|
-
| `onSubmit` | `(message: string) => void` | — | Submit handler for built-in input |
|
|
298
|
+
| `onSubmit` | `(message: string, files?: File[]) => void` | — | Submit handler for built-in input |
|
|
224
299
|
| `onSuggestionClick` | `(suggestion: string) => void` | — | Suggestion card click handler |
|
|
225
300
|
| `welcomeText` | `string` | `"How can I help you today?"` | Heading text |
|
|
301
|
+
| `supportsAttachments` | `boolean` | — | Show the attach button on the built-in input |
|
|
302
|
+
| `disabled` | `boolean` | — | Block the built-in input (e.g. while streaming). Ignored when `composerSlot` is set |
|
|
226
303
|
| `composerSlot` | `ReactNode` | — | Override default input with custom composer |
|
|
304
|
+
| `commandProvider` | `CommandProvider \| null` | — | Slash-command typeahead provider |
|
|
305
|
+
| `commandProviders` | `CommandProvider[]` | — | Multiple trigger providers; takes precedence over `commandProvider` |
|
|
306
|
+
| `assistantAvatar` | `string` | — | Avatar URL; when set, welcome text renders in message format |
|
|
307
|
+
| `assistantName` | `string` | — | Name shown alongside the avatar |
|
|
227
308
|
| `className` | `string` | — | Additional CSS classes |
|
|
228
309
|
|
|
229
310
|
### `MessageList`
|
|
230
311
|
|
|
231
|
-
Scrollable message
|
|
312
|
+
Scrollable message transcript built on a scroll engine that follows streamed output only while the reader is pinned to the live edge, and preserves the reader's position when earlier content changes height. Each direct child is wrapped in a scroll-anchored item.
|
|
232
313
|
|
|
233
314
|
| Prop | Type | Default | Description |
|
|
234
315
|
|------|------|---------|-------------|
|
|
235
|
-
| `children` | `ReactNode` | — | Message elements |
|
|
236
|
-
| `autoScroll` | `boolean` | `true` |
|
|
237
|
-
| `
|
|
316
|
+
| `children` | `ReactNode` | — | **Required.** Message elements |
|
|
317
|
+
| `autoScroll` | `boolean` | `true` | Follow streamed output while at the live edge (not "always jump to bottom") |
|
|
318
|
+
| `showScrollToBottom` | `boolean` | `true` | Render the floating scroll-to-bottom button |
|
|
319
|
+
| `className` | `string` | — | Classes applied to the inner transcript content container |
|
|
238
320
|
|
|
239
321
|
### `Message`
|
|
240
322
|
|
|
241
|
-
Individual message with markdown rendering, reasoning panel, citations, and
|
|
323
|
+
Individual message with markdown rendering, reasoning panel, citations, visualizations, media, artifacts, and interactive panels (clarification, tool approval).
|
|
242
324
|
|
|
243
325
|
| Prop | Type | Default | Description |
|
|
244
326
|
|------|------|---------|-------------|
|
|
245
|
-
| `message` | `MessageData` | — | Message data object |
|
|
327
|
+
| `message` | `MessageData` | — | **Required.** Message data object |
|
|
246
328
|
| `viewerRole` | `ParticipantRole` | `"user"` | Viewer's role (determines alignment) |
|
|
247
329
|
| `showAvatar` | `boolean` | `true` | Show participant avatar |
|
|
248
330
|
| `showTimestamp` | `boolean` | `true` | Show message timestamp |
|
|
249
331
|
| `renderMarkdown` | `boolean` | `true` | Render content as markdown |
|
|
250
332
|
| `reasoning` | `StreamingChunk[]` | — | Reasoning/thinking chunks for collapsible panel |
|
|
333
|
+
| `reasoningExpanded` | `boolean` | — | Controlled expansion of the reasoning panel |
|
|
334
|
+
| `onReasoningExpandedChange` | `(expanded: boolean) => void` | — | Reasoning panel expansion callback |
|
|
335
|
+
| `executionPlan` | `unknown` | — | Execution plan for completed agent messages |
|
|
336
|
+
| `executionTimeline` | `unknown[]` | — | Execution timeline for completed messages |
|
|
337
|
+
| `executionTime` | `number` | — | Total execution time in seconds (persisted) |
|
|
338
|
+
| `streamStartedAt` | `number` | — | Epoch ms the in-progress run started, so the live elapsed counter survives remounts |
|
|
251
339
|
| `suggestedActions` | `SuggestedAction[]` | — | Suggested follow-up actions |
|
|
252
340
|
| `onSuggestedAction` | `(action: SuggestedAction) => void` | — | Suggested action click handler |
|
|
341
|
+
| `renderInlineSuggestedAction` | `(id: string) => ReactNode` | — | Renderer for inline `[SA:id]` markers |
|
|
253
342
|
| `citations` | `SourceReference[]` | — | Citation sources to display |
|
|
254
|
-
| `visualizations` | `VisualizationChunkData[]` | — | Inline visualizations |
|
|
343
|
+
| `visualizations` | `VisualizationChunkData[]` | — | Inline visualizations (`[VIZ:id]` markers) |
|
|
344
|
+
| `medias` | `MediaChunkData[]` | — | Inline images/videos |
|
|
345
|
+
| `artifacts` | `ArtifactChunkData[]` | — | Inline downloadable artifacts (PDF, HTML, …) |
|
|
346
|
+
| `onArtifactOpen` | `(artifact: ArtifactChunkData) => void` | — | Artifact inline-card click handler |
|
|
347
|
+
| `baselineFontSize` | `number` | — | Base font size multiplier for markdown |
|
|
348
|
+
| `pendingClarification` | `ClarificationData` | — | Agent needs user input |
|
|
349
|
+
| `onClarificationSubmit` | `(response: string) => void` | — | Clarification response handler |
|
|
350
|
+
| `pendingToolApproval` | `ToolApprovalData` | — | Tool awaiting approval |
|
|
351
|
+
| `onToolApprove` | `(modifiedInputs: Record<string, unknown>) => void` | — | Tool approval handler |
|
|
352
|
+
| `onToolReject` | `(reason?: string) => void` | — | Tool rejection handler |
|
|
353
|
+
| `onReportIncorrect` | `(reason?: string) => void` | — | Report the response as incorrect |
|
|
354
|
+
| `onConfirmCorrect` | `() => void` | — | Confirm the response was helpful |
|
|
355
|
+
| `onEditSubmit` | `(newText: string) => void` | — | Edit-and-resubmit for the viewer's own messages; enables the edit action in the hover bar |
|
|
255
356
|
| `className` | `string` | — | Additional CSS classes |
|
|
256
357
|
|
|
257
358
|
### `MessageComposer`
|
|
@@ -260,15 +361,35 @@ Rich text editor (Lexical) with file upload, drag-and-drop, and Enter-to-send.
|
|
|
260
361
|
|
|
261
362
|
| Prop | Type | Default | Description |
|
|
262
363
|
|------|------|---------|-------------|
|
|
263
|
-
| `onSubmit` | `(content: string, attachments?: File[]) => Promise<void>` | — | Submit handler |
|
|
364
|
+
| `onSubmit` | `(content: string, attachments?: File[], attachmentIds?: string[]) => Promise<void>` | — | **Required.** Submit handler; `attachmentIds` carries server-uploaded IDs |
|
|
264
365
|
| `onUploadFile` | `(file: File) => Promise<string>` | — | File upload handler (returns attachment ID) |
|
|
265
366
|
| `onAttach` | `(files: File[]) => void` | — | Called when files are attached |
|
|
266
|
-
| `
|
|
367
|
+
| `onRemoveUploadedAttachment` | `(attachmentId: string) => void` | — | Called when an uploaded attachment is removed pre-send |
|
|
368
|
+
| `disabled` | `boolean` | `false` | Disable the composer entirely |
|
|
267
369
|
| `supportsAttachments` | `boolean` | `true` | Enable file attachments |
|
|
268
370
|
| `allowedFileTypes` | `string[]` | images, docs, videos | Allowed MIME types |
|
|
269
371
|
| `maxFileSize` | `number` | `104857600` (100MB) | Max file size in bytes |
|
|
270
372
|
| `placeholder` | `string` | `"Type a message..."` | Placeholder text |
|
|
271
|
-
| `isSubmitting` | `boolean` | `false` |
|
|
373
|
+
| `isSubmitting` | `boolean` | `false` | Guards the submit handshake only (loading state on send) |
|
|
374
|
+
| `isStreaming` | `boolean` | `false` | Per-conversation gate while a response streams: blocks Enter and swaps Send for Stop |
|
|
375
|
+
| `onStopStreaming` | `() => void` | — | Stop-button handler |
|
|
376
|
+
| `centered` | `boolean` | `false` | Welcome-screen mode: bigger radius, more padding, larger shadow |
|
|
377
|
+
| `commandProvider` | `CommandProvider \| null` | — | Slash-command typeahead provider |
|
|
378
|
+
| `commandProviders` | `CommandProvider[]` | — | Multiple trigger providers; takes precedence |
|
|
379
|
+
| `className` | `string` | — | Additional CSS classes |
|
|
380
|
+
|
|
381
|
+
Use `isStreaming` (not `disabled`) while a response is streaming — it keeps the composer editable, blocks submission, and shows the Stop button.
|
|
382
|
+
|
|
383
|
+
### `MessageAttachments`
|
|
384
|
+
|
|
385
|
+
Attachment strip rendered inside messages. Image attachments render as inline thumbnails that open a shared lightbox (Esc to close, arrow-key paging, body scroll-lock); non-image files render as downloadable chips. Images whose URL fails to load fall back to the file chip.
|
|
386
|
+
|
|
387
|
+
| Prop | Type | Default | Description |
|
|
388
|
+
|------|------|---------|-------------|
|
|
389
|
+
| `attachments` | `Attachment[]` | — | **Required.** Attachments to display |
|
|
390
|
+
| `onDownload` | `(attachment: Attachment) => void` | — | Custom download handler |
|
|
391
|
+
| `onPreview` | `(attachment: Attachment) => void` | — | Custom preview handler |
|
|
392
|
+
| `align` | `"start" \| "end"` | `"start"` | Edge to align against; use `"end"` for right-aligned viewer messages |
|
|
272
393
|
| `className` | `string` | — | Additional CSS classes |
|
|
273
394
|
|
|
274
395
|
### `ChatHeader`
|
|
@@ -307,14 +428,31 @@ The `brandingCSSVars` object from `useMiiflowChat` contains CSS custom propertie
|
|
|
307
428
|
</div>
|
|
308
429
|
```
|
|
309
430
|
|
|
310
|
-
|
|
431
|
+
Variables emitted by `brandingCSSVars`:
|
|
311
432
|
|
|
312
433
|
| Variable | Source | Description |
|
|
313
434
|
|----------|--------|-------------|
|
|
314
435
|
| `--chat-primary` | `backgroundBubbleColor` | Primary accent color |
|
|
315
436
|
| `--chat-user-message-bg` | `backgroundBubbleColor` | User message bubble background |
|
|
437
|
+
| `--chat-user-message-text` | derived | Auto-computed contrast color for user bubbles |
|
|
316
438
|
| `--chat-header-bg` | `headerBackgroundColor` | Header background color |
|
|
317
439
|
| `--chat-message-font-size` | `messageFontSize` | Base message font size |
|
|
440
|
+
| `--chat-font-family` | `fontFamily` | Base font stack |
|
|
441
|
+
| `--chat-approval-accent` / `--chat-approval-accent-soft` | `approvalAccentColor` | Tool-approval panel accent |
|
|
442
|
+
| `--chat-approve-bg` / `--chat-approve-bg-hover` | `approveButtonColor` | Approve button colors |
|
|
443
|
+
| `--chat-reject-bg-hover` | `rejectButtonHoverColor` | Reject button hover |
|
|
444
|
+
| `--chat-clarification-accent` / `--chat-clarification-accent-soft` | `clarificationAccentColor` | Clarification panel accent |
|
|
445
|
+
| `--chat-activity` | `activityAccentColor` | In-progress indicators (falls back to `--chat-primary`) |
|
|
446
|
+
|
|
447
|
+
Beyond these, the stylesheet declares many more host-overridable `--chat-*` tokens (surfaces, borders, text, radii, composer chrome, `--chat-font-mono` for code, and more) — see `styles.css` for the full set. Set them on any ancestor element to theme the components.
|
|
448
|
+
|
|
449
|
+
### Dark surfaces
|
|
450
|
+
|
|
451
|
+
CSS variables handle colors, but some choices can't be expressed in CSS — currently the syntax-highlighting theme for code blocks. If your app renders the chat on a dark surface, pass `isDarkSurface` to `ChatProvider` (the package does not infer dark mode from the OS `prefers-color-scheme`):
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
<ChatProvider isDarkSurface {...rest}>
|
|
455
|
+
```
|
|
318
456
|
|
|
319
457
|
### TailwindCSS Customization
|
|
320
458
|
|
|
@@ -332,13 +470,13 @@ Pass `onUploadFile={uploadFile}` to `MessageComposer` to enable server-side file
|
|
|
332
470
|
const { sendMessage, uploadFile } = useMiiflowChat(config);
|
|
333
471
|
|
|
334
472
|
<MessageComposer
|
|
335
|
-
onSubmit={sendMessage}
|
|
473
|
+
onSubmit={(content, _files, attachmentIds) => sendMessage(content, attachmentIds)}
|
|
336
474
|
onUploadFile={uploadFile}
|
|
337
475
|
supportsAttachments={true}
|
|
338
476
|
/>
|
|
339
477
|
```
|
|
340
478
|
|
|
341
|
-
The composer handles file picking, validation, drag-and-drop, and preview thumbnails. Files are uploaded via `uploadFile()` which returns an attachment ID
|
|
479
|
+
The composer handles file picking, validation, drag-and-drop, and preview thumbnails. Files are uploaded via `uploadFile()` which returns an attachment ID; the IDs arrive as `onSubmit`'s third argument. A message with attachments and no text is valid — the composer allows attachment-only sends.
|
|
342
480
|
|
|
343
481
|
## Client-Side Tools
|
|
344
482
|
|
|
@@ -364,9 +502,9 @@ await registerTool({
|
|
|
364
502
|
});
|
|
365
503
|
```
|
|
366
504
|
|
|
367
|
-
Tools are automatically re-registered when starting a new thread via `startNewThread()`.
|
|
505
|
+
Tools known at mount time can instead be passed via `config.tools` — they're folded into the session-init round-trip, saving a registration call. Tools are automatically re-registered when starting a new thread via `startNewThread()`.
|
|
368
506
|
|
|
369
|
-
The `handler` function receives the parameters as a `Record<string, unknown>` and must return a `Promise`. Results are sent back to the assistant automatically. A 30-second timeout is enforced per invocation.
|
|
507
|
+
The `handler` function receives the parameters as a `Record<string, unknown>` and must return a `Promise`. Results are sent back to the assistant automatically. A 30-second timeout is enforced per invocation. Invocations with no locally registered handler are offered to `config.onToolInvocationFallback` (useful when several widgets share one session).
|
|
370
508
|
|
|
371
509
|
## System Events
|
|
372
510
|
|
|
@@ -389,6 +527,8 @@ await sendSystemEvent({
|
|
|
389
527
|
| `followUpInstruction` | `string` | Yes | Instruction for the assistant |
|
|
390
528
|
| `metadata` | `Record<string, unknown>` | No | Additional structured data |
|
|
391
529
|
|
|
530
|
+
A system event triggers an assistant reply. To attach silent context that the assistant only uses on the *next* user message, use `sendPageContext(context)` instead — it appends hidden context to the thread without generating a response.
|
|
531
|
+
|
|
392
532
|
## Identity Verification (HMAC)
|
|
393
533
|
|
|
394
534
|
For secure identity verification, compute an HMAC on your server and pass it to the config:
|
|
@@ -421,6 +561,7 @@ Assistant messages can contain rich visualizations (charts, tables, forms, etc.)
|
|
|
421
561
|
| `kpi` | `KpiVisualization` | Key performance indicator metrics with trends |
|
|
422
562
|
| `code_preview` | `CodePreviewVisualization` | Syntax-highlighted code blocks |
|
|
423
563
|
| `form` | `FormVisualization` | Interactive forms with validation |
|
|
564
|
+
| `auth_prompt` | `AuthPromptVisualization` | "Connect this integration" card shown when the assistant needs an authorized provider; emits an `auth_connect` action via `onAction` (no button renders without it) |
|
|
424
565
|
|
|
425
566
|
### Visualization Registry
|
|
426
567
|
|
|
@@ -441,7 +582,7 @@ registerVisualization("my_widget", {
|
|
|
441
582
|
|
|
442
583
|
// Check what's registered
|
|
443
584
|
console.log(getRegisteredTypes());
|
|
444
|
-
// ["chart", "table", "card", "kpi", "code_preview", "form", "my_widget"]
|
|
585
|
+
// ["chart", "table", "card", "kpi", "code_preview", "form", "auth_prompt", "my_widget"]
|
|
445
586
|
```
|
|
446
587
|
|
|
447
588
|
Your component receives these props:
|
|
@@ -452,6 +593,7 @@ interface VisualizationComponentProps {
|
|
|
452
593
|
config?: VisualizationConfig;
|
|
453
594
|
isStreaming?: boolean;
|
|
454
595
|
onAction?: (event: VisualizationActionEvent) => void;
|
|
596
|
+
medias?: MediaChunkData[]; // for resolving media_ref:<id> values
|
|
455
597
|
}
|
|
456
598
|
```
|
|
457
599
|
|
|
@@ -471,6 +613,7 @@ import {
|
|
|
471
613
|
kpiVisualizationSchema,
|
|
472
614
|
codePreviewVisualizationSchema,
|
|
473
615
|
formVisualizationSchema,
|
|
616
|
+
authPromptVisualizationSchema,
|
|
474
617
|
} from "@miiflow/assistant-ui/styled";
|
|
475
618
|
|
|
476
619
|
const result = chartVisualizationSchema.safeParse(data);
|
|
@@ -499,7 +642,7 @@ registerVisualization("my_widget", {
|
|
|
499
642
|
|
|
500
643
|
### Interaction Callbacks
|
|
501
644
|
|
|
502
|
-
Forms and
|
|
645
|
+
Forms, cards, and auth prompts can trigger user interactions. Instead of listening for global `CustomEvent`s, pass a callback through `ChatProvider`:
|
|
503
646
|
|
|
504
647
|
```tsx
|
|
505
648
|
function handleVisualizationAction(event: VisualizationActionEvent) {
|
|
@@ -514,12 +657,16 @@ function handleVisualizationAction(event: VisualizationActionEvent) {
|
|
|
514
657
|
case "card_action":
|
|
515
658
|
console.log("Card action clicked:", event.action);
|
|
516
659
|
break;
|
|
660
|
+
case "auth_connect":
|
|
661
|
+
// Kick off your OAuth/connect flow for event.providerName
|
|
662
|
+
console.log("Connect requested:", event.providerName);
|
|
663
|
+
break;
|
|
517
664
|
}
|
|
518
665
|
}
|
|
519
666
|
|
|
520
667
|
<ChatProvider
|
|
521
668
|
messages={messages}
|
|
522
|
-
onSendMessage={sendMessage}
|
|
669
|
+
onSendMessage={(content) => sendMessage(content)}
|
|
523
670
|
onVisualizationAction={handleVisualizationAction}
|
|
524
671
|
>
|
|
525
672
|
...
|
|
@@ -532,9 +679,17 @@ The `VisualizationActionEvent` type is a discriminated union:
|
|
|
532
679
|
type VisualizationActionEvent =
|
|
533
680
|
| { type: "form_submit"; action: string; data: Record<string, unknown> }
|
|
534
681
|
| { type: "form_cancel"; action: string }
|
|
535
|
-
| { type: "card_action"; action: string }
|
|
682
|
+
| { type: "card_action"; action: string }
|
|
683
|
+
| {
|
|
684
|
+
type: "auth_connect";
|
|
685
|
+
providerName: string;
|
|
686
|
+
mcpServerId?: string;
|
|
687
|
+
serviceProviderId?: string;
|
|
688
|
+
};
|
|
536
689
|
```
|
|
537
690
|
|
|
691
|
+
Note the `auth_connect` variant has no `action` field — narrow on `event.type` before reading variant-specific fields.
|
|
692
|
+
|
|
538
693
|
**Backward compatibility:** If no `onVisualizationAction` callback is provided, components fall back to dispatching `CustomEvent`s on `window` (`visualization-form-submit`, `visualization-form-cancel`, `visualization-action`).
|
|
539
694
|
|
|
540
695
|
### Using `VisualizationRenderer` Standalone
|
|
@@ -562,10 +717,11 @@ import { VisualizationRenderer } from "@miiflow/assistant-ui/styled";
|
|
|
562
717
|
|
|
563
718
|
| Import | Description |
|
|
564
719
|
|--------|-------------|
|
|
565
|
-
| `@miiflow/assistant-ui` | Core types, context, hooks, primitives |
|
|
566
|
-
| `@miiflow/assistant-ui/styled` | TailwindCSS-styled components, visualization
|
|
567
|
-
| `@miiflow/assistant-ui/client` | `useMiiflowChat` hook, session utilities, types |
|
|
720
|
+
| `@miiflow/assistant-ui` | Core types, context, hooks, primitives — plus re-exports of the styled components and shared utils (`cn`, format/color helpers, `chatTokens`) |
|
|
721
|
+
| `@miiflow/assistant-ui/styled` | TailwindCSS-styled components, visualization + artifact registries, schemas |
|
|
722
|
+
| `@miiflow/assistant-ui/client` | `useMiiflowChat` hook, session utilities, tool validation, SSE helpers, types |
|
|
568
723
|
| `@miiflow/assistant-ui/primitives` | Headless unstyled component primitives |
|
|
724
|
+
| `@miiflow/assistant-ui/composer` | Lexical composer internals: `LexicalChatInput`, command-token node/plugin/view, `CommandProvider` types |
|
|
569
725
|
| `@miiflow/assistant-ui/styles.css` | Full CSS (includes Tailwind preflight) |
|
|
570
726
|
| `@miiflow/assistant-ui/styles-no-preflight.css` | CSS without preflight (for embedding in existing pages) |
|
|
571
727
|
|
|
@@ -575,7 +731,14 @@ import { VisualizationRenderer } from "@miiflow/assistant-ui/styled";
|
|
|
575
731
|
`registerVisualization`, `getVisualization`, `getRegisteredTypes`, `VisualizationEntry`
|
|
576
732
|
|
|
577
733
|
**Visualization Schemas:**
|
|
578
|
-
`chartVisualizationSchema`, `tableVisualizationSchema`, `cardVisualizationSchema`, `kpiVisualizationSchema`, `codePreviewVisualizationSchema`, `formVisualizationSchema`
|
|
734
|
+
`chartVisualizationSchema`, `tableVisualizationSchema`, `cardVisualizationSchema`, `kpiVisualizationSchema`, `codePreviewVisualizationSchema`, `formVisualizationSchema`, `authPromptVisualizationSchema`
|
|
735
|
+
|
|
736
|
+
**Artifact Registry:**
|
|
737
|
+
`registerArtifact`, `getArtifact`, `getRegisteredArtifactTypes`, `ArtifactInlineCard`, `ArtifactList`
|
|
579
738
|
|
|
580
739
|
**Types:**
|
|
581
740
|
`VisualizationActionEvent`, `VisualizationChunkData`, `VisualizationConfig`, `VisualizationType`
|
|
741
|
+
|
|
742
|
+
### Key Exports from `@miiflow/assistant-ui/client`
|
|
743
|
+
|
|
744
|
+
Beyond `useMiiflowChat`: session helpers (`initSession`, `createThread`, `uploadFile`, `sendSystemEvent`, `sendPageContext`, `sendToolResult`, `getBackendBaseUrl`), tool validation (`validateToolDefinition`, `serializeToolDefinition`, `ToolValidationError`), and SSE-reducer helpers for hosts with their own stream parsing (`findToolChunkIndex`, `MatchableToolChunk`, `ToolFrame`).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
-
import { A as Attachment, M as MessageData, P as ParticipantRole, d as SuggestedAction, S as SourceReference } from './message-
|
|
4
|
-
import { h as AvatarProps$1 } from './avatar-
|
|
5
|
-
import { S as StreamingChunk, V as VisualizationChunkData, M as MediaChunkData, A as ArtifactChunkData, C as ClarificationData, T as ToolApprovalData } from './streaming-
|
|
3
|
+
import { A as Attachment, M as MessageData, P as ParticipantRole, d as SuggestedAction, S as SourceReference } from './message-DTNTKSQr.js';
|
|
4
|
+
import { h as AvatarProps$1 } from './avatar-B_AvYfE8.js';
|
|
5
|
+
import { S as StreamingChunk, V as VisualizationChunkData, M as MediaChunkData, A as ArtifactChunkData, C as ClarificationData, T as ToolApprovalData } from './streaming-BfLEgW5u.js';
|
|
6
6
|
import { C as CommandProvider } from './types-Du00UBst.js';
|
|
7
7
|
|
|
8
8
|
interface AttachmentPreviewProps {
|
|
@@ -46,12 +46,19 @@ interface MarkdownContentProps {
|
|
|
46
46
|
className?: string;
|
|
47
47
|
/** Base font size multiplier for responsive scaling */
|
|
48
48
|
baselineFontSize?: number;
|
|
49
|
-
/** Use dark theme for code blocks
|
|
49
|
+
/** Use dark theme for code blocks. Falls back to the host surface's
|
|
50
|
+
* `isDarkSurface` from ChatProvider. */
|
|
50
51
|
darkCodeTheme?: boolean;
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
54
|
+
* Markdown renderer for chat messages.
|
|
55
|
+
*
|
|
56
|
+
* Appearance lives entirely in the `.chat-prose` rules in
|
|
57
|
+
* `src/styles/prose.css`; the overrides below carry only behaviour (heading
|
|
58
|
+
* anchors, the code-block copy button, inline command-token chips, and the
|
|
59
|
+
* image-URL swap). Keep it that way — the two used to be duplicated, and
|
|
60
|
+
* because react-markdown v9 dropped the `className` prop the CSS half was
|
|
61
|
+
* silently dead for the entire time both existed.
|
|
55
62
|
*/
|
|
56
63
|
declare function MarkdownContent({ children, className, baselineFontSize, darkCodeTheme, }: MarkdownContentProps): react.JSX.Element;
|
|
57
64
|
|
|
@@ -70,9 +77,14 @@ interface MessageProps {
|
|
|
70
77
|
renderMarkdown?: boolean;
|
|
71
78
|
/** Streaming chunks for reasoning panel */
|
|
72
79
|
reasoning?: StreamingChunk[];
|
|
73
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated No longer read. Host adapters already reconstruct these into
|
|
82
|
+
* `reasoning` chunks, so passing them separately made the same run
|
|
83
|
+
* describable two ways. Kept on the interface so existing callers compile;
|
|
84
|
+
* remove in the next major.
|
|
85
|
+
*/
|
|
74
86
|
executionPlan?: unknown;
|
|
75
|
-
/**
|
|
87
|
+
/** @deprecated No longer read — see `executionPlan`. */
|
|
76
88
|
executionTimeline?: unknown[];
|
|
77
89
|
/** Suggested actions */
|
|
78
90
|
suggestedActions?: SuggestedAction[];
|
|
@@ -96,6 +108,15 @@ interface MessageProps {
|
|
|
96
108
|
baselineFontSize?: number;
|
|
97
109
|
/** Total execution time in seconds (persisted from streaming wall-clock) */
|
|
98
110
|
executionTime?: number;
|
|
111
|
+
/** Epoch ms the in-progress run started. Supply the run's durable start
|
|
112
|
+
* (e.g. from a server snapshot) so the streaming elapsed figure stays
|
|
113
|
+
* correct across remounts; omit to time from when this component mounted. */
|
|
114
|
+
streamStartedAt?: number;
|
|
115
|
+
/** This turn finished moments ago. The streaming message and the completed
|
|
116
|
+
* message are different elements, so this component cannot see that edge
|
|
117
|
+
* itself — the host reports it, and it is what animates the reasoning
|
|
118
|
+
* steps folding into the "Thought for …" line instead of snapping shut. */
|
|
119
|
+
justCompleted?: boolean;
|
|
99
120
|
/** Pending clarification data (agent needs user input) */
|
|
100
121
|
pendingClarification?: ClarificationData;
|
|
101
122
|
/** Callback when user responds to a clarification */
|
|
@@ -113,6 +134,10 @@ interface MessageProps {
|
|
|
113
134
|
onReportIncorrect?: (reason?: string) => void;
|
|
114
135
|
/** Confirm this assistant response was correct/helpful */
|
|
115
136
|
onConfirmCorrect?: () => void;
|
|
137
|
+
/** Edit-and-resubmit for the viewer's own messages (ChatGPT-style). When
|
|
138
|
+
* provided, a pencil appears in the hover action bar; submitting replaces
|
|
139
|
+
* this message and everything after it with a fresh agent turn. */
|
|
140
|
+
onEditSubmit?: (newText: string) => void;
|
|
116
141
|
}
|
|
117
142
|
/**
|
|
118
143
|
* Styled Message component with grid layout matching the main app.
|
|
@@ -165,17 +190,21 @@ declare const MessageComposer: react.ForwardRefExoticComponent<MessageComposerPr
|
|
|
165
190
|
interface MessageListProps {
|
|
166
191
|
/** Messages to render */
|
|
167
192
|
children: ReactNode;
|
|
168
|
-
/** Whether to auto-scroll to bottom */
|
|
193
|
+
/** Whether to auto-scroll to bottom while streaming (follows only when at the live edge) */
|
|
169
194
|
autoScroll?: boolean;
|
|
170
195
|
/** Whether to show the scroll-to-bottom button */
|
|
171
196
|
showScrollToBottom?: boolean;
|
|
172
|
-
/** Additional CSS classes */
|
|
197
|
+
/** Additional CSS classes applied to the transcript container (e.g. horizontal padding) */
|
|
173
198
|
className?: string;
|
|
174
199
|
}
|
|
175
200
|
/**
|
|
176
|
-
* Styled MessageList
|
|
177
|
-
*
|
|
178
|
-
*
|
|
201
|
+
* Styled MessageList — scroll container for a chat transcript.
|
|
202
|
+
*
|
|
203
|
+
* Scroll behavior is provided by shadcn's `@shadcn/react` message-scroller
|
|
204
|
+
* engine (auto-follow while at the live edge, position preservation, scroll
|
|
205
|
+
* anchoring) rather than the legacy `useAutoScroll` hook. The public API is
|
|
206
|
+
* unchanged: pass message rows as `children`; each direct child is wrapped in a
|
|
207
|
+
* `MessageScroller.Item` for measurement and anchoring.
|
|
179
208
|
*/
|
|
180
209
|
declare const MessageList: react.ForwardRefExoticComponent<MessageListProps & react.RefAttributes<HTMLDivElement>>;
|
|
181
210
|
|
|
@@ -221,9 +250,17 @@ declare const SuggestedActions: react.ForwardRefExoticComponent<SuggestedActions
|
|
|
221
250
|
interface TypingIndicatorProps {
|
|
222
251
|
/** Additional CSS classes */
|
|
223
252
|
className?: string;
|
|
253
|
+
/** Optional status line rendered beside the mark (e.g. "Getting started…") */
|
|
254
|
+
label?: string | null;
|
|
255
|
+
/** Brand mark for the waiting state, supplied by the host. */
|
|
256
|
+
mark?: ReactNode;
|
|
224
257
|
}
|
|
225
258
|
/**
|
|
226
|
-
*
|
|
259
|
+
* The pre-first-token waiting state.
|
|
260
|
+
*
|
|
261
|
+
* Kept as a thin wrapper over `ThinkingIndicator` so the primitive's semantics
|
|
262
|
+
* (and every existing `<TypingIndicator label=… />` call site) survive the
|
|
263
|
+
* change from three bouncing dots to a decoding line.
|
|
227
264
|
*/
|
|
228
265
|
declare const TypingIndicator: react.ForwardRefExoticComponent<TypingIndicatorProps & react.RefAttributes<HTMLDivElement>>;
|
|
229
266
|
|
|
@@ -320,6 +357,9 @@ interface WelcomeScreenProps {
|
|
|
320
357
|
welcomeText?: string;
|
|
321
358
|
/** Whether to show the attachment (paperclip) button */
|
|
322
359
|
supportsAttachments?: boolean;
|
|
360
|
+
/** Blocks the built-in input (e.g. while a response is already streaming).
|
|
361
|
+
* Ignored when `composerSlot` is provided — that composer owns its own gating. */
|
|
362
|
+
disabled?: boolean;
|
|
323
363
|
/** Override the default plain-text input with a custom composer (e.g. chat-ui MessageComposer) */
|
|
324
364
|
composerSlot?: ReactNode;
|
|
325
365
|
/** Optional slash-command typeahead provider (e.g. for skill picker). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode, TextareaHTMLAttributes, ButtonHTMLAttributes } from 'react';
|
|
3
|
-
import { M as MessageData, P as ParticipantRole } from './message-
|
|
3
|
+
import { M as MessageData, P as ParticipantRole } from './message-DTNTKSQr.js';
|
|
4
4
|
|
|
5
5
|
interface MessageContextValue {
|
|
6
6
|
message: MessageData;
|
|
@@ -65,6 +65,9 @@ interface MessageComposerProps {
|
|
|
65
65
|
onSubmit: (content: string, attachments?: File[]) => Promise<void>;
|
|
66
66
|
/** Whether the composer is disabled */
|
|
67
67
|
disabled?: boolean;
|
|
68
|
+
/** Whether the current conversation is mid-response. Blocks submitting a
|
|
69
|
+
* second, concurrent turn into the same conversation. */
|
|
70
|
+
isStreaming?: boolean;
|
|
68
71
|
/** Children to render inside the composer */
|
|
69
72
|
children: ReactNode;
|
|
70
73
|
/** Additional CSS classes */
|