@x12i/ai 0.0.0-stage → 1.1.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.
@@ -0,0 +1,906 @@
1
+ import * as react from 'react';
2
+ import { ComponentPropsWithRef, ReactNode, Ref, RefObject, MouseEvent, JSX } from 'react';
3
+ import { MessageRole, ToolState, ErrorKind, Message as Message$1, TextPart, ReasoningPart, ToolPart, SourcePart, FilePart, DataPart, ThreadStatus, ThreadError, BranchInfo, StreamEvent, ThreadState, ThreadAction } from './index.js';
4
+
5
+ /**
6
+ * Every word the chat components show. The kit's components contain no
7
+ * user-facing text of their own: they read it from this catalog. English ships
8
+ * as `defaultMessages`. To translate, pass a partial override as the
9
+ * `messages` prop of a component (`strings` on `ChatThread`), or provide one
10
+ * for a whole subtree with `AiMessagesProvider`.
11
+ *
12
+ * Values that are functions take the dynamic parts (a tool name, a count, a
13
+ * duration) so a translation can put them anywhere in the sentence. Counts
14
+ * should use `Intl.PluralRules` in your translation when the language needs it.
15
+ * Values that are data, such as a tool name or a source title, are shown as
16
+ * they are.
17
+ */
18
+ interface AiMessages {
19
+ /** Accessible name of the whole chat region. */
20
+ chat: string;
21
+ /** Accessible name of the scrolling message log. */
22
+ conversation: string;
23
+ jumpToLatest: string;
24
+ emptyTitle: string;
25
+ emptyDescription: string;
26
+ /** Shown under the prompt: never hide that content is AI-generated. */
27
+ disclaimer: string;
28
+ /** Accessible name of the follow-up suggestions list. */
29
+ suggestions: string;
30
+ roles: Record<MessageRole, string>;
31
+ /** The visible badge on assistant messages. */
32
+ aiGenerated: string;
33
+ /** The badge's accessible name. */
34
+ aiGeneratedLabel: string;
35
+ edited: string;
36
+ stopped: string;
37
+ failed: string;
38
+ /** Visually hidden while a message is being written. */
39
+ responding: string;
40
+ /** For example `1.2K tokens`. */
41
+ tokens: (count: string) => string;
42
+ /** `Message from {role}` for the message's accessible name. */
43
+ messageFrom: (role: string) => string;
44
+ promptLabel: string;
45
+ promptPlaceholder: string;
46
+ send: string;
47
+ stop: string;
48
+ attach: string;
49
+ attachments: string;
50
+ removeAttachment: (name: string) => string;
51
+ attachmentUploading: string;
52
+ attachmentFailed: string;
53
+ dropFiles: string;
54
+ /** For example `12 / 500`. */
55
+ characterCount: (count: number, max: number) => string;
56
+ characterLimitReached: string;
57
+ commands: string;
58
+ commandsAvailable: (count: number) => string;
59
+ reasoning: string;
60
+ thinking: string;
61
+ thought: string;
62
+ /** `duration` is already formatted, for example `4s`. */
63
+ thoughtFor: (duration: string) => string;
64
+ toolStates: Record<ToolState, string>;
65
+ toolCall: (name: string) => string;
66
+ toolInput: string;
67
+ toolOutput: string;
68
+ toolError: string;
69
+ /** Shown when the user stopped the run before the tool finished. */
70
+ toolAborted: string;
71
+ noInput: string;
72
+ noOutput: string;
73
+ approvalTitle: (toolName: string) => string;
74
+ approvalDescription: string;
75
+ approvalAction: string;
76
+ approve: string;
77
+ deny: string;
78
+ approveLabel: (toolName: string) => string;
79
+ denyLabel: (toolName: string) => string;
80
+ reasonLabel: string;
81
+ reasonPlaceholder: string;
82
+ sources: string;
83
+ sourcesCount: (count: number) => string;
84
+ /** The accessible name of an inline citation chip. */
85
+ citationLabel: (number: number, title: string) => string;
86
+ opensInNewTab: string;
87
+ noLink: string;
88
+ actions: string;
89
+ copy: string;
90
+ copied: string;
91
+ copyFailed: string;
92
+ regenerate: string;
93
+ edit: string;
94
+ goodResponse: string;
95
+ badResponse: string;
96
+ /** `Version 2 of 3`. */
97
+ versionLabel: (index: number, count: number) => string;
98
+ previousVersion: string;
99
+ nextVersion: string;
100
+ saveEdit: string;
101
+ cancelEdit: string;
102
+ editLabel: string;
103
+ attachmentsList: string;
104
+ download: (name: string) => string;
105
+ thinkingIndicator: string;
106
+ errorKinds: Record<ErrorKind, {
107
+ title: string;
108
+ description: string;
109
+ }>;
110
+ retry: string;
111
+ dismiss: string;
112
+ editInstead: string;
113
+ announceReply: (text: string) => string;
114
+ announceStopped: string;
115
+ announceApproval: (toolName: string) => string;
116
+ copyCode: string;
117
+ codeCopied: string;
118
+ /** Accessible name of a code block. `language` is empty when unknown. */
119
+ codeBlock: (language: string) => string;
120
+ plainText: string;
121
+ table: string;
122
+ taskDone: string;
123
+ taskTodo: string;
124
+ footnotes: string;
125
+ footnoteBack: string;
126
+ /** Shown instead of an image that is blocked. */
127
+ imageBlocked: string;
128
+ copyJson: string;
129
+ showMore: (hidden: number) => string;
130
+ showLess: string;
131
+ }
132
+ /** A partial catalog. The nested records may be partial too. */
133
+ interface AiMessagesOverride extends Partial<Omit<AiMessages, "roles" | "toolStates" | "errorKinds">> {
134
+ roles?: Partial<AiMessages["roles"]>;
135
+ toolStates?: Partial<AiMessages["toolStates"]>;
136
+ errorKinds?: {
137
+ [K in ErrorKind]?: Partial<AiMessages["errorKinds"][K]>;
138
+ };
139
+ }
140
+ declare const defaultMessages: AiMessages;
141
+ /**
142
+ * Merges catalogs, later ones winning. The record-valued entries (`roles`,
143
+ * `toolStates`, `errorKinds`) merge key by key, so you can translate a single
144
+ * tool state or error title.
145
+ */
146
+ declare function mergeMessages(base: AiMessages, ...overrides: Array<AiMessagesOverride | undefined>): AiMessages;
147
+
148
+ interface ConversationHandle {
149
+ /** Scrolls to the newest message and resumes following. */
150
+ scrollToBottom: (behavior?: ScrollBehavior) => void;
151
+ }
152
+ interface ConversationProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
153
+ children?: ReactNode;
154
+ /** Pixels from the end that still count as "at the bottom". Default 48. */
155
+ stickThreshold?: number | undefined;
156
+ /** Called when the user scrolls away from, or back to, the end. */
157
+ onAtBottomChange?: ((atBottom: boolean) => void) | undefined;
158
+ /** Accessible name of the log. Defaults to `messages.conversation`. */
159
+ label?: string | undefined;
160
+ /** Imperative handle: `scrollToBottom()`. */
161
+ handleRef?: Ref<ConversationHandle> | undefined;
162
+ messages?: AiMessagesOverride | undefined;
163
+ }
164
+ /**
165
+ * The scrolling list of messages.
166
+ *
167
+ * - It follows new content (a streaming reply) while you are at the bottom,
168
+ * and lets go the moment you scroll up. A "Jump to latest" button appears
169
+ * while you are away from the end.
170
+ * - The scroller is `role="log"` with polite, additions-only live updates, and is
171
+ * focusable so the keyboard can scroll it. A streaming message turns its
172
+ * own text off (`aria-live="off"`), so a screen reader hears messages, not tokens.
173
+ */
174
+ declare function Conversation({ children, stickThreshold, onAtBottomChange, label, handleRef, messages: override, className, ref, ...props }: ConversationProps): react.JSX.Element;
175
+
176
+ interface PartRenderContext {
177
+ message: Message$1;
178
+ /** The part's position in `message.parts` (the first one, for grouped parts). */
179
+ index: number;
180
+ /** True while the message is still being written. */
181
+ streaming: boolean;
182
+ /** Renders the built-in view, so a custom renderer can wrap it. */
183
+ defaultRender: () => ReactNode;
184
+ }
185
+ /**
186
+ * Renders one part (or, for `sources` and `files`, all of them at once).
187
+ * Return `undefined` to use the built-in view and `null` to show nothing.
188
+ */
189
+ type PartRenderer<P> = (part: P, context: PartRenderContext) => ReactNode | undefined;
190
+ /**
191
+ * Overrides how parts render. Keys: `text`, `reasoning`, `tool`, `sources`,
192
+ * `files`, `data` (every data part) and `data:<kind>` for one kind, such as
193
+ * `data:chart`. A `data:<kind>` renderer wins over `data`.
194
+ */
195
+ interface PartRenderers {
196
+ text?: PartRenderer<TextPart>;
197
+ reasoning?: PartRenderer<ReasoningPart>;
198
+ tool?: PartRenderer<ToolPart>;
199
+ sources?: PartRenderer<SourcePart[]>;
200
+ files?: PartRenderer<FilePart[]>;
201
+ data?: PartRenderer<DataPart>;
202
+ [key: `data:${string}`]: PartRenderer<DataPart> | undefined;
203
+ }
204
+ interface MessageProps extends Omit<ComponentPropsWithRef<"article">, "children"> {
205
+ message: Message$1;
206
+ /** Defaults to `message.status === "streaming"`. */
207
+ streaming?: boolean | undefined;
208
+ /** A decorative avatar. Give it `aria-hidden` if it has no text alternative. */
209
+ avatar?: ReactNode;
210
+ /** Display name. Defaults to the role's name from `messages.roles`. */
211
+ name?: string | undefined;
212
+ /** Show `createdAt` as a time. Default false. */
213
+ showTimestamp?: boolean | undefined;
214
+ /** Formats `createdAt`. Defaults to a short localized time. */
215
+ formatTimestamp?: ((iso: string, locale: string | undefined) => string) | undefined;
216
+ /** Show the token count of a finished reply. Default false. */
217
+ showUsage?: boolean | undefined;
218
+ locale?: string | undefined;
219
+ renderPart?: PartRenderers | undefined;
220
+ /** Called when the user decides on a tool call that needs approval. */
221
+ onToolDecision?: ((callId: string, decision: "approve" | "deny", reason?: string) => void) | undefined;
222
+ /** Retry button of the error banner, for a failed reply. */
223
+ onRetry?: (() => void) | undefined;
224
+ /** Edit mode for a user message: shows a text box with Save and Cancel. */
225
+ editing?: boolean | undefined;
226
+ onEditSubmit?: ((text: string) => void) | undefined;
227
+ onEditCancel?: (() => void) | undefined;
228
+ /** Rendered under the content, usually `MessageActions`. */
229
+ actions?: ReactNode;
230
+ /** Passed to `Markdown`: how images in replies are shown. */
231
+ images?: "inline" | "link" | "none" | undefined;
232
+ messages?: AiMessagesOverride | undefined;
233
+ }
234
+ /**
235
+ * One message: author, an "AI" label on assistant messages, an optional
236
+ * time, and its parts.
237
+ *
238
+ * - Assistant text is rendered as safe Markdown; user and system text stays plain.
239
+ * - Source parts become the numbered source list; `[1]` in the text links to it.
240
+ * - While streaming, the content is `aria-live="off"` and the article is
241
+ * `aria-busy`, so assistive technology reads the finished reply once.
242
+ * - `renderPart` replaces any part's view, for example to draw a chart for a `data:chart` part.
243
+ */
244
+ declare function Message({ message, streaming: streamingProp, avatar, name, showTimestamp, formatTimestamp, showUsage, locale, renderPart, onToolDecision, onRetry, editing, onEditSubmit, onEditCancel, actions, images, messages: override, className, ref, ...props }: MessageProps): react.JSX.Element;
245
+ /** Alias of `Message`, for code that also imports the `Message` data type from `@x12i/ai`. */
246
+ declare const ChatMessage: typeof Message;
247
+ type ChatMessageProps = MessageProps;
248
+
249
+ type Feedback = "up" | "down";
250
+ interface MessageBranchControl {
251
+ /** The shown version, from 0. */
252
+ index: number;
253
+ /** How many versions exist. The control is hidden when there is only one. */
254
+ count: number;
255
+ onSelect: (index: number) => void;
256
+ }
257
+ interface MessageActionsProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
258
+ /** The text the copy button copies. Without it there is no copy button. */
259
+ text?: string | undefined;
260
+ onCopied?: ((text: string) => void) | undefined;
261
+ /** Shows a regenerate button. */
262
+ onRegenerate?: (() => void) | undefined;
263
+ /** Shows an edit button (for user messages). */
264
+ onEdit?: (() => void) | undefined;
265
+ /** The current rating. `null` or omitted means none. */
266
+ feedback?: Feedback | null | undefined;
267
+ /** Shows thumbs buttons. Called with the new rating, or `null` when it is withdrawn. */
268
+ onFeedback?: ((feedback: Feedback | null) => void) | undefined;
269
+ /** Previous / next version controls for an edited or regenerated message. */
270
+ branch?: MessageBranchControl | undefined;
271
+ /** Disables regenerate, edit and branch changes, for example while a reply is streaming. */
272
+ disabled?: boolean | undefined;
273
+ /** Your own actions, after the built-in ones. */
274
+ children?: ReactNode;
275
+ messages?: AiMessagesOverride | undefined;
276
+ }
277
+ /**
278
+ * The actions under a message: copy, regenerate, edit, thumbs up and down,
279
+ * and version navigation. Every control is a labelled button; the thumbs are
280
+ * toggle buttons (`aria-pressed`). The copy result is announced politely.
281
+ */
282
+ declare function MessageActions({ text, onCopied, onRegenerate, onEdit, feedback, onFeedback, branch, disabled, children, messages: override, className, ref, ...props }: MessageActionsProps): react.JSX.Element;
283
+
284
+ /** A file waiting to be sent with the next message. */
285
+ interface PromptAttachment {
286
+ id: string;
287
+ name: string;
288
+ size?: number | undefined;
289
+ mediaType?: string | undefined;
290
+ /** `uploading` blocks sending; `error` shows a failure on the chip. Default `ready`. */
291
+ status?: "ready" | "uploading" | "error" | undefined;
292
+ /** The file itself, set when `PromptInput` collected it (uncontrolled attachments). */
293
+ file?: File | undefined;
294
+ }
295
+ /** A command the user can pick by typing `/` in the prompt. */
296
+ interface SlashCommand {
297
+ id?: string;
298
+ /** The text after the slash, such as `summarize` for `/summarize`. */
299
+ name: string;
300
+ description?: string | undefined;
301
+ }
302
+ interface PromptInputProps extends Omit<ComponentPropsWithRef<"form">, "onSubmit" | "children" | "onChange"> {
303
+ /** Called with the trimmed text and the attachments when the user sends. */
304
+ onSubmit: (text: string, attachments: readonly PromptAttachment[]) => void;
305
+ /** Controlled text. Clear it yourself in `onSubmit`. */
306
+ value?: string | undefined;
307
+ defaultValue?: string | undefined;
308
+ onValueChange?: ((value: string) => void) | undefined;
309
+ /**
310
+ * The conversation's state. While `submitted` or `streaming` the send button
311
+ * becomes a stop button and Enter does nothing.
312
+ */
313
+ status?: ThreadStatus | undefined;
314
+ /** Called by the stop button, and by Escape when `stopOnEscape` is true. */
315
+ onStop?: (() => void) | undefined;
316
+ disabled?: boolean | undefined;
317
+ placeholder?: string | undefined;
318
+ /** Hard limit; the counter shows `n / max`. */
319
+ maxLength?: number | undefined;
320
+ /** Smallest height in lines. Default 1. */
321
+ minRows?: number | undefined;
322
+ /** The height at which the box stops growing and scrolls. Default 8 lines. */
323
+ maxRows?: number | undefined;
324
+ /** Enter sends and Shift+Enter adds a line. When false, Ctrl or Cmd+Enter sends. Default true. */
325
+ submitOnEnter?: boolean | undefined;
326
+ /** Escape stops a running reply. Default true. */
327
+ stopOnEscape?: boolean | undefined;
328
+ autoFocus?: boolean | undefined;
329
+ /** Attachments, controlled. Leave it out and `PromptInput` keeps the files itself. */
330
+ attachments?: readonly PromptAttachment[] | undefined;
331
+ onRemoveAttachment?: ((id: string) => void) | undefined;
332
+ /** Called with files from the attach button, a paste or a drop. Providing it turns on all three. */
333
+ onFiles?: ((files: File[]) => void) | undefined;
334
+ /**
335
+ * Show the attach button and accept pasted and dropped files. Defaults to true
336
+ * when `onFiles` or `attachments` is given. With `allowFiles` alone, `PromptInput`
337
+ * keeps the chosen files itself and hands them to `onSubmit` as `attachments[].file`.
338
+ */
339
+ allowFiles?: boolean | undefined;
340
+ /** The `accept` list of the file picker, for example `image/*,.pdf`. */
341
+ accept?: string | undefined;
342
+ /** Most files per message. */
343
+ maxFiles?: number | undefined;
344
+ /** Commands offered after typing `/` at the start. */
345
+ slashCommands?: readonly SlashCommand[] | undefined;
346
+ /** Called when a command is picked. By default, it inserts `/name ` into the text. */
347
+ onCommandSelect?: ((command: SlashCommand) => void) | undefined;
348
+ /** Content under the box, such as a disclaimer. */
349
+ footer?: ReactNode;
350
+ /** A ref to the textarea. */
351
+ textareaRef?: Ref<HTMLTextAreaElement> | undefined;
352
+ locale?: string | undefined;
353
+ messages?: AiMessagesOverride | undefined;
354
+ }
355
+ /**
356
+ * The message box. It grows with the text up to `maxRows`, sends on Enter
357
+ * (Shift+Enter adds a line, and Enter during IME composition never sends),
358
+ * turns the send button into a stop button while a reply runs, and supports
359
+ * attachments (button, paste, drop), a character counter and `/` commands.
360
+ *
361
+ * Accessibility: the textarea has an accessible name; the button's name says
362
+ * what it does now ("Send message" or "Stop generating"); nothing steals focus;
363
+ * the command list is announced and navigated with the arrow keys, with focus
364
+ * staying in the textarea.
365
+ */
366
+ declare function PromptInput({ onSubmit, value: valueProp, defaultValue, onValueChange, status, onStop, disabled, placeholder, maxLength, minRows, maxRows, submitOnEnter, stopOnEscape, autoFocus, attachments: attachmentsProp, onRemoveAttachment, onFiles, allowFiles, accept, maxFiles, slashCommands, onCommandSelect, footer, textareaRef: textareaRefProp, locale, messages: override, className, style, ref, ...props }: PromptInputProps): react.JSX.Element;
367
+
368
+ /** A suggestion is a string (shown and sent as it is), or a short label with a longer prompt behind it. */
369
+ type Suggestion = string | {
370
+ id?: string;
371
+ label: string;
372
+ prompt?: string;
373
+ };
374
+ interface SuggestionsProps extends Omit<ComponentPropsWithRef<"div">, "children" | "onSelect"> {
375
+ suggestions: readonly Suggestion[];
376
+ /** Called with the text to send (the suggestion's `prompt`, or its label). */
377
+ onSelect: (prompt: string, suggestion: Suggestion) => void;
378
+ disabled?: boolean | undefined;
379
+ messages?: AiMessagesOverride | undefined;
380
+ }
381
+ /** A row of follow-up or starter prompts. Each is a button; picking one is the same as sending that text. */
382
+ declare function Suggestions({ suggestions, onSelect, disabled, messages: override, className, ref, ...props }: SuggestionsProps): react.JSX.Element | null;
383
+
384
+ /**
385
+ * When the thread speaks a reply to a screen reader:
386
+ * - `complete`: once, when the reply is finished (default).
387
+ * - `sentences`: each finished sentence while it streams, then the rest.
388
+ * - `off`: never. The messages are still in the `role="log"`.
389
+ */
390
+ type AnnounceMode = "complete" | "sentences" | "off";
391
+ interface ChatThreadProps extends Omit<ComponentPropsWithRef<"section">, "children" | "onSubmit"> {
392
+ messages: readonly Message$1[];
393
+ /** The conversation's state. Defaults to `streaming` if the last message is streaming, otherwise `idle`. */
394
+ status?: ThreadStatus | undefined;
395
+ /** A failure that is not tied to a message. */
396
+ error?: ThreadError | null | undefined;
397
+ /** Called with the text and attachments when the user sends. */
398
+ onSend: (text: string, attachments?: readonly PromptAttachment[]) => void;
399
+ onStop?: (() => void) | undefined;
400
+ /** Shows a regenerate button on the last reply, and the retry button of an error. */
401
+ onRegenerate?: (() => void) | undefined;
402
+ /** Called when the user approves or denies a tool call. Without it the approval buttons are not shown. */
403
+ onToolDecision?: ((callId: string, decision: "approve" | "deny", reason?: string) => void) | undefined;
404
+ /** Shows an edit button on user messages. */
405
+ onEdit?: ((messageId: string, text: string) => void) | undefined;
406
+ /** Version navigation for edited messages, from `useThread().chatProps.branches`. */
407
+ branches?: Record<string, BranchInfo> | undefined;
408
+ onSwitchBranch?: ((parentId: string, index: number) => void) | undefined;
409
+ onDismissError?: (() => void) | undefined;
410
+ /** Shows thumbs buttons on replies. */
411
+ onFeedback?: ((messageId: string, feedback: Feedback | null) => void) | undefined;
412
+ /** Current ratings by message id. Omit to let the thread remember them. */
413
+ feedback?: Record<string, Feedback | null | undefined> | undefined;
414
+ /** Starter prompts, shown while the thread is empty. */
415
+ suggestions?: readonly Suggestion[] | undefined;
416
+ /** Follow-up prompts, shown under the last reply when nothing is running. */
417
+ followUps?: readonly Suggestion[] | undefined;
418
+ /** Replaces how parts render, for example to draw a chart for `data:chart`. Memoize it. */
419
+ renderPart?: PartRenderers | undefined;
420
+ /** Replaces the empty state. */
421
+ emptyState?: ReactNode;
422
+ /** Content above the conversation, such as a title bar. */
423
+ header?: ReactNode;
424
+ /** Text under the prompt. Defaults to the AI-generated notice. Pass `false` to hide it. */
425
+ disclaimer?: ReactNode | false | undefined;
426
+ /** Avatars by role (decorative). */
427
+ avatars?: {
428
+ user?: ReactNode;
429
+ assistant?: ReactNode;
430
+ } | undefined;
431
+ /** Display names by role. Defaults to `strings.roles`. */
432
+ names?: {
433
+ user?: string;
434
+ assistant?: string;
435
+ } | undefined;
436
+ showTimestamps?: boolean | undefined;
437
+ showUsage?: boolean | undefined;
438
+ /** How images in replies are shown. Default `"link"`. See `Markdown`. */
439
+ images?: "inline" | "link" | "none" | undefined;
440
+ announce?: AnnounceMode | undefined;
441
+ /** Disables the prompt. */
442
+ disabled?: boolean | undefined;
443
+ /** More props for the prompt box: `maxLength`, `slashCommands`, `onFiles`, `accept`, `placeholder`... */
444
+ promptProps?: Partial<Omit<PromptInputProps, "onSubmit" | "status" | "onStop" | "disabled">> | undefined;
445
+ locale?: string | undefined;
446
+ /** The words the thread shows. A partial catalog, merged over `defaultMessages`. (Named `strings` because `messages` is the list.) */
447
+ strings?: AiMessagesOverride | undefined;
448
+ /** Imperative handle of the conversation: `scrollToBottom()`. */
449
+ conversationRef?: Ref<ConversationHandle> | undefined;
450
+ }
451
+ /**
452
+ * The whole chat: message list, composer, errors, suggestions and live
453
+ * announcements, driven by props. Pair it with `useThread`:
454
+ *
455
+ * ```tsx
456
+ * const thread = useThread({ onSend });
457
+ * return <ChatThread {...thread.chatProps} suggestions={["Hello"]} />;
458
+ * ```
459
+ *
460
+ * It owns no conversation state: pass `messages` and `status` from anywhere.
461
+ */
462
+ declare function ChatThread({ messages: threadMessages, status: statusProp, error, onSend, onStop, onRegenerate, onToolDecision, onEdit, branches, onSwitchBranch, onDismissError, onFeedback, feedback: feedbackProp, suggestions, followUps, renderPart, emptyState, header, disclaimer, avatars, names, showTimestamps, showUsage, images, announce, disabled, promptProps, locale, strings, conversationRef, className, ref, ...props }: ChatThreadProps): react.JSX.Element;
463
+
464
+ type Awaitable<T> = T | Promise<T>;
465
+ /** What a handler returns to stream a reply: any async iterable of stream events, such as an async generator. Return nothing to stream nothing. */
466
+ type ThreadStreamResult = AsyncIterable<StreamEvent> | void | undefined;
467
+ /** A file to send with a message. `PromptInput`'s attachments fit this shape. */
468
+ interface SendAttachment {
469
+ id?: string | undefined;
470
+ name: string;
471
+ mediaType?: string | undefined;
472
+ size?: number | undefined;
473
+ /** Where the file can be read. Without it, a `file` is shown through a `blob:` URL. */
474
+ url?: string | undefined;
475
+ file?: File | undefined;
476
+ }
477
+ type ThreadTrigger = "send" | "regenerate" | "edit";
478
+ interface ThreadRequest {
479
+ trigger: ThreadTrigger;
480
+ /** The user message this turn answers (the newest one). */
481
+ message: Message$1 | undefined;
482
+ /** Its text. */
483
+ text: string;
484
+ /** Its files. */
485
+ attachments: FilePart[];
486
+ /** Every message of the thread, including the new user message. A snapshot: it does not change. */
487
+ messages: readonly Message$1[];
488
+ /** Aborted by `stop()`. Pass it to `fetch` so the request is cancelled too. */
489
+ signal: AbortSignal;
490
+ }
491
+ interface ToolDecisionRequest {
492
+ callId: string;
493
+ toolName: string;
494
+ decision: "approve" | "deny";
495
+ reason: string | undefined;
496
+ /** Tool calls still waiting for a decision after this one. Resume the model only when it is 0. */
497
+ pending: number;
498
+ messages: readonly Message$1[];
499
+ signal: AbortSignal;
500
+ }
501
+ interface UseThreadOptions {
502
+ /** Messages to start with, for example loaded from your store. Read once. */
503
+ initialMessages?: readonly Message$1[] | undefined;
504
+ /** Called to answer a new user message. Return (or yield) stream events to write the reply. */
505
+ onSend?: ((request: ThreadRequest) => Awaitable<ThreadStreamResult>) | undefined;
506
+ /** Called to answer the last user message again. Defaults to `onSend` with `trigger: "regenerate"`. */
507
+ onRegenerate?: ((request: ThreadRequest) => Awaitable<ThreadStreamResult>) | undefined;
508
+ /**
509
+ * Called after the user approves or denies a tool call. Return a stream to
510
+ * continue the reply (it is written into the same message), or nothing.
511
+ * If the stream of the original reply is still open (because it is waiting
512
+ * for this decision), it is left running and not aborted.
513
+ */
514
+ onToolDecision?: ((request: ToolDecisionRequest) => Awaitable<ThreadStreamResult>) | undefined;
515
+ /** Called after the user stops a reply. The run's `signal` has already been aborted. */
516
+ onStop?: ((info: {
517
+ messages: readonly Message$1[];
518
+ }) => void) | undefined;
519
+ /** Called when a reply finishes normally. */
520
+ onFinish?: ((message: Message$1 | undefined) => void) | undefined;
521
+ /** Called when a reply fails. */
522
+ onError?: ((error: ThreadError) => void) | undefined;
523
+ /**
524
+ * Group stream events into one render per animation frame, so a fast stream
525
+ * does not render once per token. Default true. Turn it off in tests.
526
+ */
527
+ batch?: boolean | undefined;
528
+ /** Makes ids for user messages. Defaults to `crypto.randomUUID`. */
529
+ generateId?: (() => string) | undefined;
530
+ /** The clock, in epoch milliseconds. For tests. */
531
+ now?: (() => number) | undefined;
532
+ }
533
+ interface EditOptions {
534
+ /** `truncate` (default) replaces the message and drops what followed; `branch` keeps the old version. */
535
+ mode?: "truncate" | "branch" | undefined;
536
+ }
537
+ /** Props that `ChatThread` understands, so `<ChatThread {...thread.chatProps} />` just works. */
538
+ interface ThreadChatProps {
539
+ messages: Message$1[];
540
+ status: ThreadStatus;
541
+ error: ThreadError | null;
542
+ branches: Record<string, BranchInfo>;
543
+ onSend: (text: string, attachments?: readonly SendAttachment[]) => void;
544
+ onStop: () => void;
545
+ onRegenerate: () => void;
546
+ onToolDecision: (callId: string, decision: "approve" | "deny", reason?: string) => void;
547
+ onEdit: (messageId: string, text: string) => void;
548
+ onSwitchBranch: (parentId: string, index: number) => void;
549
+ onDismissError: () => void;
550
+ }
551
+ interface UseThreadResult {
552
+ messages: Message$1[];
553
+ status: ThreadStatus;
554
+ error: ThreadError | null;
555
+ /** The whole state, including branches. */
556
+ state: ThreadState;
557
+ /** Adds a user message and asks `onSend` for the reply. Ignored while a reply is running. */
558
+ send: (text: string, attachments?: readonly SendAttachment[]) => Promise<void>;
559
+ /** Stops the running reply and keeps what was written. */
560
+ stop: () => void;
561
+ /** Answers the last user message again. */
562
+ regenerate: () => Promise<void>;
563
+ /** Approves a tool call that needs approval. */
564
+ approve: (callId: string, reason?: string) => Promise<void>;
565
+ /** Denies a tool call that needs approval. */
566
+ deny: (callId: string, reason?: string) => Promise<void>;
567
+ decide: (callId: string, decision: "approve" | "deny", reason?: string) => Promise<void>;
568
+ /** Edits a user message and asks for a new reply. */
569
+ edit: (messageId: string, text: string, options?: EditOptions) => Promise<void>;
570
+ /** Shows another version of an edited message. */
571
+ switchBranch: (parentId: string, index: number) => void;
572
+ dismissError: () => void;
573
+ /** Empties the thread and stops any reply. */
574
+ clear: () => void;
575
+ /** Replaces the thread. Stops any reply. */
576
+ setMessages: (messages: readonly Message$1[]) => void;
577
+ /** Applies a reducer action, for example to add a system note. */
578
+ dispatch: (action: ThreadAction) => void;
579
+ /** Applies one stream event yourself, for events that arrive outside `onSend`, such as from a WebSocket. */
580
+ applyEvent: (event: StreamEvent) => void;
581
+ /** Spread into `ChatThread`. */
582
+ chatProps: ThreadChatProps;
583
+ }
584
+ /**
585
+ * Chat state for any provider. It keeps the thread with `threadReducer`, runs
586
+ * your `onSend` (an async generator of stream events works), and gives you
587
+ * `send`, `stop`, `regenerate`, `approve` and `deny`.
588
+ *
589
+ * - Events are applied to the thread as they arrive but rendered once per
590
+ * animation frame (`batch: false` to render each one).
591
+ * - `stop()` aborts the signal your handler received, ends the stream, and
592
+ * keeps the text written so far.
593
+ * - A failure becomes `status: "error"` with a typed `error`; `regenerate()` retries.
594
+ * - Nothing is ever approved on its own: a tool call that needs approval waits
595
+ * until `approve` or `deny` is called.
596
+ */
597
+ declare function useThread(options?: UseThreadOptions): UseThreadResult;
598
+
599
+ interface UseStickToBottomOptions {
600
+ /** How close to the end (in pixels) still counts as "at the bottom". Default 48. */
601
+ threshold?: number | undefined;
602
+ /** Called when the user moves away from, or returns to, the bottom. */
603
+ onAtBottomChange?: ((atBottom: boolean) => void) | undefined;
604
+ }
605
+ interface StickToBottom {
606
+ /** Put on the scrolling element. */
607
+ scrollerRef: RefObject<HTMLDivElement | null>;
608
+ /** Put on the element that holds the content, so growth is noticed. */
609
+ contentRef: RefObject<HTMLDivElement | null>;
610
+ /** True while the view is at (or near) the end, or following it. */
611
+ atBottom: boolean;
612
+ /** Scrolls to the end and resumes following. */
613
+ scrollToBottom: (behavior?: ScrollBehavior) => void;
614
+ }
615
+ /**
616
+ * Keeps a scroller pinned to its end while content grows (a streaming reply),
617
+ * and stops as soon as the user scrolls up, so they can read in peace. It
618
+ * resumes when they scroll back to the bottom, or call `scrollToBottom`.
619
+ *
620
+ * A scroll the hook caused itself is told apart from the user's, so a long
621
+ * smooth scroll or a growing reply does not make it let go by mistake.
622
+ */
623
+ declare function useStickToBottom({ threshold, onAtBottomChange }?: UseStickToBottomOptions): StickToBottom;
624
+
625
+ /** How `![alt](url)` is shown. */
626
+ type MarkdownImageMode = "inline" | "link" | "none";
627
+ interface MarkdownProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
628
+ /** The Markdown text. Raw HTML in it is dropped, never rendered. */
629
+ children: string;
630
+ /** True while the text is still arriving. Sets `data-streaming`; finished blocks are not re-rendered either way. */
631
+ streaming?: boolean | undefined;
632
+ /**
633
+ * Added to heading levels so a `#` in a reply does not compete with the
634
+ * page's own headings: with the default 2, `#` renders as `<h3>`. Capped at `<h6>`.
635
+ */
636
+ headingOffset?: number | undefined;
637
+ /**
638
+ * What to do with images. `"link"` (default) shows a link to the image, `"inline"`
639
+ * renders it, `"none"` shows only the alt text. A model can leak data in an
640
+ * image URL, so inline images are opt-in. Unsafe URLs are never rendered.
641
+ */
642
+ images?: MarkdownImageMode | undefined;
643
+ /** Allow raster `data:image/...;base64` images when `images="inline"`. Default false. */
644
+ allowDataImages?: boolean | undefined;
645
+ /**
646
+ * Rewrites an image URL before it is rendered, for example to send it through
647
+ * your own proxy. Return `null` to block the image. The result is checked again.
648
+ */
649
+ transformImageUrl?: ((url: string) => string | null | undefined) | undefined;
650
+ /**
651
+ * Turn `[1]`, `[1, 2]` and `[1-3]` into citation chips. Defaults to true when
652
+ * `sources` is given or a surrounding `SourcesProvider` has sources. A number
653
+ * with no matching source stays as plain text.
654
+ */
655
+ citations?: boolean | undefined;
656
+ /** The sources the citations point at. Defaults to the surrounding `SourcesProvider`'s. */
657
+ sources?: readonly SourcePart[] | undefined;
658
+ /** Called when a link is clicked. Call `preventDefault` to handle navigation yourself. */
659
+ onLinkClick?: ((event: MouseEvent<HTMLAnchorElement>, url: string) => void) | undefined;
660
+ /** Called after a code block was copied. */
661
+ onCopyCode?: ((code: string, language: string) => void) | undefined;
662
+ messages?: AiMessagesOverride | undefined;
663
+ }
664
+ /**
665
+ * Renders Markdown from a model safely.
666
+ *
667
+ * - Raw HTML is dropped. Links keep only `http:`, `https:`, `mailto:`, `tel:`
668
+ * and relative URLs; external links open in a new tab with
669
+ * `rel="noopener noreferrer"` and a spoken "opens in a new tab".
670
+ * - GitHub Flavored Markdown: tables (in a scroll wrapper), task lists
671
+ * (display only), strikethrough, autolinks and footnotes.
672
+ * - Fenced code becomes a `CodeBlock`: language label and copy button, no highlighting.
673
+ * - Text blocks are `dir="auto"`, so Hebrew or Arabic paragraphs align correctly.
674
+ * - Finished blocks are cached while text streams in.
675
+ */
676
+ declare function Markdown({ children, streaming, headingOffset, images, allowDataImages, transformImageUrl, citations, sources, onLinkClick, onCopyCode, messages: override, className, ref, ...props }: MarkdownProps): JSX.Element;
677
+
678
+ interface CodeBlockProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
679
+ /** The code, exactly as it should be copied. */
680
+ code: string;
681
+ /** The language label, such as `ts`. Empty or omitted shows a generic label. */
682
+ language?: string | undefined;
683
+ onCopied?: ((code: string) => void) | undefined;
684
+ messages?: AiMessagesOverride | undefined;
685
+ }
686
+ /**
687
+ * A code block with a language label and a copy button. It is always
688
+ * left-to-right, whatever the page direction, and is never highlighted or
689
+ * run: code from a model is shown as text only. When a line is wider than the
690
+ * block, the block becomes keyboard-focusable so it can be scrolled.
691
+ */
692
+ declare function CodeBlock({ code, language, onCopied, messages: override, className, ref, ...props }: CodeBlockProps): react.JSX.Element;
693
+
694
+ interface ReasoningProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
695
+ /** The model's reasoning text. Rendered as safe Markdown. */
696
+ text: string;
697
+ /** True while the reasoning is still arriving. The panel is open then, and collapses when it ends. */
698
+ streaming?: boolean | undefined;
699
+ /** How long the model thought, in milliseconds. Shown once it has finished. */
700
+ durationMs?: number | undefined;
701
+ open?: boolean | undefined;
702
+ defaultOpen?: boolean | undefined;
703
+ onOpenChange?: ((open: boolean) => void) | undefined;
704
+ /** Locale used to format the duration. */
705
+ locale?: string | undefined;
706
+ messages?: AiMessagesOverride | undefined;
707
+ }
708
+ /**
709
+ * A collapsible view of the model's reasoning. Open while it streams, then it
710
+ * folds itself away (unless you opened or closed it yourself) so the answer
711
+ * is what you see. The header reads "Thinking…" and then "Thought for 4s".
712
+ */
713
+ declare function Reasoning({ text, streaming, durationMs, open: openProp, defaultOpen, onOpenChange, locale, messages: override, className, ref, ...props }: ReasoningProps): react.JSX.Element;
714
+
715
+ interface ToolCallProps extends Omit<ComponentPropsWithRef<"div">, "children" | "part"> {
716
+ /** The tool part to show. (Shadows the unrelated HTML `part` attribute.) */
717
+ part: ToolPart;
718
+ open?: boolean | undefined;
719
+ defaultOpen?: boolean | undefined;
720
+ onOpenChange?: ((open: boolean) => void) | undefined;
721
+ /**
722
+ * Called when the user decides on a call that needs approval. Without it, the
723
+ * approval buttons are not shown: the call is only displayed.
724
+ */
725
+ onDecision?: ((callId: string, decision: "approve" | "deny", reason?: string) => void) | undefined;
726
+ /** Replaces the JSON view of the input, for example with a table or a chart. */
727
+ renderInput?: ((input: unknown, part: ToolPart) => ReactNode) | undefined;
728
+ /** Replaces the JSON view of the output. */
729
+ renderOutput?: ((output: unknown, part: ToolPart) => ReactNode) | undefined;
730
+ locale?: string | undefined;
731
+ messages?: AiMessagesOverride | undefined;
732
+ }
733
+ /**
734
+ * Shows what the assistant is doing: the tool's name, its state as a badge,
735
+ * how long it took, and (collapsed by default) its input and output as JSON.
736
+ * A call that needs approval shows an `ApprovalPrompt` that stays visible even
737
+ * when the details are folded, so a decision can never be hidden.
738
+ */
739
+ declare function ToolCall({ part, open, defaultOpen, onOpenChange, onDecision, renderInput, renderOutput, locale, messages: override, className, ref, ...props }: ToolCallProps): react.JSX.Element;
740
+
741
+ interface ApprovalPromptProps extends Omit<ComponentPropsWithRef<"div">, "children" | "title" | "prompt"> {
742
+ /** The tool that wants to run. Shown as it is. */
743
+ toolName: string;
744
+ /** The exact arguments the tool will run with. Shown in full so the decision is informed. */
745
+ input?: unknown;
746
+ /** Why approval is needed, from the model or your policy. Falls back to a generic sentence. */
747
+ prompt?: string | undefined;
748
+ /** Called when the user approves. `reason` is the optional note they typed. */
749
+ onApprove: (reason?: string) => void;
750
+ /** Called when the user denies. `reason` is the optional note they typed. */
751
+ onDeny: (reason?: string) => void;
752
+ /**
753
+ * Move focus to the prompt when it appears, so a keyboard or screen-reader
754
+ * user notices it. It never focuses a button, so Enter cannot approve by
755
+ * accident. Skipped when focus is somewhere else on the page. Default true.
756
+ */
757
+ autoFocus?: boolean | undefined;
758
+ /** Where focus goes after a decision. Defaults to what was focused before, then the chat's prompt box. */
759
+ returnFocusTo?: RefObject<HTMLElement | null> | (() => HTMLElement | null | undefined) | undefined;
760
+ /** Show the optional "reason" field. Default true. */
761
+ allowReason?: boolean | undefined;
762
+ /** Replaces the JSON view of the input, for example with a form-like summary. */
763
+ renderInput?: ((input: unknown) => ReactNode) | undefined;
764
+ messages?: AiMessagesOverride | undefined;
765
+ }
766
+ /**
767
+ * Asks the user to allow or refuse an action. It is a non-modal group, not a
768
+ * dialog: nothing is blocked and there is no focus trap. It never decides on
769
+ * its own, and the buttons are the only way to answer.
770
+ *
771
+ * When it appears, focus moves to the prompt itself (not to a button). After
772
+ * a decision, focus returns to where it was.
773
+ */
774
+ declare function ApprovalPrompt({ toolName, input, prompt, onApprove, onDeny, autoFocus, returnFocusTo, allowReason, renderInput, messages: override, className, ref, ...props }: ApprovalPromptProps): react.JSX.Element;
775
+
776
+ interface SourcesProviderProps {
777
+ sources: readonly SourcePart[];
778
+ children?: ReactNode;
779
+ }
780
+ /**
781
+ * Connects inline citations to the source list. `Message` provides it; use it
782
+ * yourself when you render `Markdown` and `Sources` separately.
783
+ */
784
+ declare function SourcesProvider({ sources, children }: SourcesProviderProps): react.JSX.Element;
785
+ interface CitationProps extends Omit<ComponentPropsWithRef<"a">, "children" | "href"> {
786
+ /** The source number, from 1. */
787
+ index: number;
788
+ /**
789
+ * The source. Defaults to the n-th source of the surrounding
790
+ * `SourcesProvider`. Passing one makes the chip stand alone: it links to the
791
+ * source's URL instead of jumping to the provider's list.
792
+ */
793
+ source?: SourcePart | undefined;
794
+ messages?: AiMessagesOverride | undefined;
795
+ }
796
+ /**
797
+ * An inline numbered chip for a citation. Inside a `SourcesProvider` it jumps
798
+ * to the matching item of the source list (opening the list if it is
799
+ * folded); on its own it links to the source's URL. A source without a safe
800
+ * URL renders as a plain, non-interactive chip.
801
+ */
802
+ declare function Citation({ index, source: sourceProp, messages: override, className, onClick, ref, ...props }: CitationProps): react.JSX.Element;
803
+ interface SourceCardProps extends Omit<ComponentPropsWithRef<"li">, "children" | "id"> {
804
+ source: SourcePart;
805
+ /** The number shown and cited, from 1. */
806
+ index: number;
807
+ /** The DOM id, so citations can link here. */
808
+ id?: string;
809
+ messages?: AiMessagesOverride | undefined;
810
+ }
811
+ /**
812
+ * One source: number, title as a link, domain and snippet. No favicon is
813
+ * fetched, so listing sources never makes a request to the source's site.
814
+ */
815
+ declare function SourceCard({ source, index, id, messages: override, className, ref, ...props }: SourceCardProps): react.JSX.Element;
816
+ interface SourcesProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
817
+ /** Defaults to the sources of the surrounding `SourcesProvider`. */
818
+ sources?: readonly SourcePart[] | undefined;
819
+ open?: boolean | undefined;
820
+ defaultOpen?: boolean | undefined;
821
+ onOpenChange?: ((open: boolean) => void) | undefined;
822
+ messages?: AiMessagesOverride | undefined;
823
+ }
824
+ /**
825
+ * A collapsible, numbered list of sources. Citations in the message jump here:
826
+ * the list opens and the cited source takes focus.
827
+ */
828
+ declare function Sources({ sources: sourcesProp, open, defaultOpen, onOpenChange, messages: override, className, ref, ...props }: SourcesProps): react.JSX.Element | null;
829
+
830
+ interface AttachmentsProps extends Omit<ComponentPropsWithRef<"ul">, "children"> {
831
+ files: readonly FilePart[];
832
+ locale?: string | undefined;
833
+ messages?: AiMessagesOverride | undefined;
834
+ }
835
+ /**
836
+ * The files of a message. Images show as thumbnails that open the full image;
837
+ * other files show as a chip with name and size that downloads. A file whose
838
+ * URL is not safe (`javascript:` and the like) is shown as a name only. SVG is
839
+ * never shown inline, because it can carry script.
840
+ */
841
+ declare function Attachments({ files, locale, messages: override, className, ref, ...props }: AttachmentsProps): react.JSX.Element | null;
842
+
843
+ interface StreamingIndicatorProps extends Omit<ComponentPropsWithRef<"span">, "children"> {
844
+ /** Replaces the spoken label. Defaults to `messages.thinkingIndicator`. */
845
+ label?: string | undefined;
846
+ messages?: AiMessagesOverride | undefined;
847
+ }
848
+ /**
849
+ * Three pulsing dots that show the assistant is working. The motion is CSS
850
+ * and stops under `prefers-reduced-motion`, leaving three still dots. The
851
+ * label is visually hidden and not live: the thread announces progress itself.
852
+ */
853
+ declare function StreamingIndicator({ label, messages: override, className, ref, ...props }: StreamingIndicatorProps): react.JSX.Element;
854
+
855
+ interface ErrorBannerProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
856
+ error: ThreadError;
857
+ /** Shows a retry button, unless the error says it is not retryable. */
858
+ onRetry?: (() => void) | undefined;
859
+ /** Shows a dismiss button. */
860
+ onDismiss?: (() => void) | undefined;
861
+ /** For a moderation error: lets the user go back and rephrase. */
862
+ onEdit?: (() => void) | undefined;
863
+ /** Show the provider's own message under the explanation. Default true. */
864
+ showDetail?: boolean | undefined;
865
+ messages?: AiMessagesOverride | undefined;
866
+ }
867
+ /**
868
+ * Explains a failed reply in plain words that depend on the kind of failure
869
+ * (network, rate limit, moderation, auth, unknown), with a retry where
870
+ * retrying can help. It is `role="alert"`, so it is announced when it appears.
871
+ */
872
+ declare function ErrorBanner({ error, onRetry, onDismiss, onEdit, showDetail, messages: override, className, ref, ...props }: ErrorBannerProps): react.JSX.Element;
873
+
874
+ interface EmptyThreadProps extends Omit<ComponentPropsWithRef<"div">, "title"> {
875
+ /** Defaults to `messages.emptyTitle`. */
876
+ title?: ReactNode;
877
+ /** Defaults to `messages.emptyDescription`. */
878
+ description?: ReactNode;
879
+ /** An icon or logo. Defaults to a sparkles glyph. */
880
+ icon?: ReactNode;
881
+ /** Usually `Suggestions`. */
882
+ children?: ReactNode;
883
+ messages?: AiMessagesOverride | undefined;
884
+ }
885
+ /** What an empty conversation shows: a title, a line of help and, as children, starter suggestions. */
886
+ declare function EmptyThread({ title, description, icon, children, messages: override, className, ref, ...props }: EmptyThreadProps): react.JSX.Element;
887
+
888
+ interface AiMessagesProviderProps {
889
+ /** A partial catalog, merged over `defaultMessages` (or over a parent provider). */
890
+ messages?: AiMessagesOverride;
891
+ children?: ReactNode;
892
+ }
893
+ /**
894
+ * Sets the strings for every chat component below it, so you translate once
895
+ * instead of passing `messages` to each component. A component's own
896
+ * `messages` prop still wins.
897
+ */
898
+ declare function AiMessagesProvider({ messages, children }: AiMessagesProviderProps): react.JSX.Element;
899
+ /**
900
+ * The strings a component should use: the nearest provider's catalog (or the
901
+ * English default) with the component's own override on top.
902
+ */
903
+ declare function useAiMessages(override?: AiMessagesOverride): AiMessages;
904
+
905
+ export { AiMessagesProvider, ApprovalPrompt, Attachments, ChatMessage, ChatThread, Citation, CodeBlock, Conversation, EmptyThread, ErrorBanner, Markdown, Message, MessageActions, PromptInput, Reasoning, SourceCard, Sources, SourcesProvider, StreamingIndicator, Suggestions, ToolCall, defaultMessages, mergeMessages, useAiMessages, useStickToBottom, useThread };
906
+ export type { AiMessages, AiMessagesOverride, AiMessagesProviderProps, AnnounceMode, ApprovalPromptProps, AttachmentsProps, ChatMessageProps, ChatThreadProps, CitationProps, CodeBlockProps, ConversationHandle, ConversationProps, EditOptions, EmptyThreadProps, ErrorBannerProps, Feedback, MarkdownImageMode, MarkdownProps, MessageActionsProps, MessageBranchControl, MessageProps, PartRenderContext, PartRenderer, PartRenderers, PromptAttachment, PromptInputProps, ReasoningProps, SendAttachment, SlashCommand, SourceCardProps, SourcesProps, SourcesProviderProps, StickToBottom, StreamingIndicatorProps, Suggestion, SuggestionsProps, ThreadChatProps, ThreadRequest, ThreadStreamResult, ThreadTrigger, ToolCallProps, ToolDecisionRequest, UseStickToBottomOptions, UseThreadOptions, UseThreadResult };