@dudousxd/nestjs-agent-react 0.13.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/dist/index.d.cts CHANGED
@@ -1,16 +1,174 @@
1
1
  import * as ai from 'ai';
2
- import { ChatTransport, UIMessage, UIMessageChunk, ToolUIPart, DynamicToolUIPart, DataUIPart, UIDataTypes } from 'ai';
2
+ import { ChatTransport, UIMessage, UIMessageChunk, DataUIPart, UIDataTypes } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { StoredMessage, ThreadSummary, SkillCatalogEntry, ToolCatalogEntry, ThreadDetail, MessageAttachment, QuotaView, ElicitationQuestion, ElicitationInputType, ToolPresentation, ToolResultField, ToolResultView, ToolPresentationTone, ElicitationInput } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, MessageFeedbackValue, MessageFeedback, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
6
- import React from 'react';
6
+ import React__default from 'react';
7
+ import { a as TranscriptBlock, U as UsageSummary, b as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, c as ToolCatalog, A as ApproveOptions, d as AnyToolUIPart, e as TranscriptFile, T as TranscriptUiBlock } from './model-gHqjNjLJ.cjs';
8
+ export { f as ApprovalBlockOptions, B as BuildBlocksOptions, g as CoercibleQuestion, D as DescribeToolCallOptions, E as ElicitationBlockOptions, G as GroupToolActivityOptions, R as RawAnswer, h as ResolvedReading, i as ResolvedResultView, j as RetrievedPassage, S as SettleAction, k as ToolActivityGroup, l as ToolCallDescription, m as ToolCallState, n as ToolCallStatus, o as TranscriptApproval, p as TranscriptApprovalStatus, q as TranscriptElicitationBlock, r as TranscriptElicitationOutcome, s as TranscriptFilesBlock, t as TranscriptQuestion, u as TranscriptQuestionOption, v as TranscriptReasoningBlock, w as TranscriptSettleState, x as TranscriptSource, y as TranscriptSourcesBlock, z as TranscriptTextBlock, F as TranscriptToolBlock, H as TranscriptToolCall, I as buildTranscriptBlocks, J as coerceAnswer, K as correctedCallIds, L as describeTimestamp, N as describeToolCall, O as describeUsage, P as extractMessageText, Q as fillTemplate, V as formatRelativeTime, W as groupToolActivity, X as inferResultView, Y as isActionCall, Z as phraseFor, _ as readPath, $ as resolveResultView, a0 as toolCallState, a1 as toolCatalogFrom } from './model-gHqjNjLJ.cjs';
9
+
10
+ /**
11
+ * Partial update accepted by `PATCH <base>/threads/:threadId`. `defaultAgent: null` clears a
12
+ * previously-set default back to the module's own default; omitting it leaves the thread's
13
+ * current default untouched.
14
+ */
15
+ interface ThreadPatch {
16
+ title?: string;
17
+ defaultAgent?: string | null;
18
+ }
19
+ /** Starting a turn: the body `POST <base>/chat` takes (see docs/stream-protocol.md). */
20
+ interface ChatStreamRequest {
21
+ /** `{ message, threadId?, agent?, attachments?, pageContext?, regenerate?, … }`. */
22
+ body: Record<string, unknown>;
23
+ /** Per-request headers the AI SDK was handed for this send. */
24
+ headers?: Record<string, string>;
25
+ /** Aborted when the user stops the turn. */
26
+ signal?: AbortSignal;
27
+ }
28
+ /** Attaching to a run that is already streaming: `GET <base>/chat/:runId/stream?after=<seq>`. */
29
+ interface ResumeStreamRequest {
30
+ runId: string;
31
+ /**
32
+ * The sequence number (SSE `id:`) of the last frame the client already has. Omitted → replay
33
+ * from the first frame. A backend that cannot skip may ignore it: the transport also drops frames
34
+ * at or below it.
35
+ */
36
+ after?: number;
37
+ headers?: Record<string, string>;
38
+ signal?: AbortSignal;
39
+ }
40
+ /**
41
+ * An open chat stream: the raw `text/event-stream` bytes in the stream-protocol framing, plus the
42
+ * identity a backend may learn before the first frame (the `X-Agent-Run-Id` / `X-Agent-Thread-Id`
43
+ * headers). The body's own `event: meta` frame supplies them otherwise.
44
+ */
45
+ interface ChatStreamResponse {
46
+ body: ReadableStream<Uint8Array>;
47
+ runId?: string;
48
+ threadId?: string;
49
+ }
50
+ /** What `POST <base>/messages/:id/feedback` takes. `value: null` clears the rating. */
51
+ interface MessageFeedbackInput {
52
+ value: MessageFeedbackValue | null;
53
+ comment?: string;
54
+ }
55
+ interface UploadAttachmentOptions {
56
+ signal?: AbortSignal;
57
+ /** Called with 0..1 as the upload progresses, when the backend can observe it. */
58
+ onProgress?: (fraction: number) => void;
59
+ }
60
+ /**
61
+ * Everything the React layer asks of a server — the seam between `useAgentChat` (and the other
62
+ * hooks) and whatever serves the agent. {@link AgentClient} is the default implementation, over the
63
+ * library's own REST routes with `fetch`. An app with its own client — a generated one, a different
64
+ * auth scheme (cookie session + CSRF header), a backend that is not this library at all but speaks
65
+ * docs/stream-protocol.md — implements this instead and passes it as `useAgentChat({ backend })`.
66
+ *
67
+ * The streaming, thread and cancel members are required: without them there is no chat. The rest
68
+ * are optional; a hook that needs one the backend does not have throws
69
+ * {@link AgentBackendUnsupportedError} when it is called, so a backend only implements what its
70
+ * server supports.
71
+ */
72
+ interface AgentBackend {
73
+ /** Start a turn and return its SSE stream. Throw on a non-2xx answer. */
74
+ openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;
75
+ /** Attach to a streaming run. Resolve `null` when nothing is streaming under that id (HTTP 404). */
76
+ resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;
77
+ /** Hard-stop a run server-side. */
78
+ cancelStream(runId: string): Promise<unknown>;
79
+ listThreads(): Promise<ThreadSummary[]>;
80
+ getThread(id: string): Promise<ThreadDetail>;
81
+ updateThread(id: string, patch: ThreadPatch): Promise<unknown>;
82
+ deleteThread(id: string): Promise<unknown>;
83
+ forkFromMessage?(threadId: string, messageId: string): Promise<ThreadSummary>;
84
+ promoteThread?(id: string): Promise<unknown>;
85
+ truncateFromMessage?(threadId: string, messageId: string): Promise<unknown>;
86
+ approveToolCall?(input: {
87
+ toolCallId: string;
88
+ remember?: boolean;
89
+ via?: string;
90
+ }): Promise<unknown>;
91
+ rejectToolCall?(input: {
92
+ toolCallId: string;
93
+ reason?: string;
94
+ via?: string;
95
+ }): Promise<unknown>;
96
+ answerToolCall?(input: {
97
+ toolCallId: string;
98
+ answers?: Record<string, string[]>;
99
+ }): Promise<unknown>;
100
+ skipToolCall?(input: {
101
+ toolCallId: string;
102
+ }): Promise<unknown>;
103
+ uploadAttachment?(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
104
+ listTools?(agent?: string): Promise<ToolCatalogEntry[]>;
105
+ listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;
106
+ getQuotaToday?(): Promise<QuotaView>;
107
+ setMessageFeedback?(messageId: string, input: MessageFeedbackInput): Promise<{
108
+ feedback: MessageFeedback | null;
109
+ }>;
110
+ }
111
+ /** An optional {@link AgentBackend} member the bound backend does not implement was called. */
112
+ declare class AgentBackendUnsupportedError extends Error {
113
+ readonly method: string;
114
+ constructor(method: string);
115
+ }
116
+ type OptionalMethod = {
117
+ [K in keyof AgentBackend]-?: undefined extends AgentBackend[K] ? K : never;
118
+ }[keyof AgentBackend];
119
+ /**
120
+ * The optional backend method `name`, bound — or a throw naming it. For hook code that has to call
121
+ * something a backend may not offer.
122
+ */
123
+ declare function requireBackendMethod<K extends OptionalMethod>(backend: AgentBackend, name: K): NonNullable<AgentBackend[K]>;
7
124
 
8
125
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
9
126
  interface AgentStreamMeta {
10
127
  runId: string;
11
128
  threadId: string;
12
129
  }
130
+ /**
131
+ * How the transport retries a stream that dropped mid-run. It reconnects only to a server that
132
+ * numbers its frames (SSE `id:`) — without a cursor a reconnect would replay the run into the
133
+ * message it is already writing.
134
+ */
135
+ interface ReconnectOptions {
136
+ /** Attempts before giving up with an error chunk. Default 6. */
137
+ maxAttempts?: number;
138
+ /** Delay before the first attempt, doubled each attempt. Default 500 ms. */
139
+ baseDelayMs?: number;
140
+ /** Cap on the delay between attempts. Default 8000 ms. */
141
+ maxDelayMs?: number;
142
+ }
143
+ /** Where a live stream stands. `reconnecting` → it dropped and the transport is retrying. */
144
+ type StreamConnectionState = {
145
+ status: 'live';
146
+ } | {
147
+ status: 'reconnecting';
148
+ runId: string;
149
+ attempt: number;
150
+ after: number;
151
+ }
152
+ /** The run ended while the client was away (the resume answered 404): reload the thread. */
153
+ | {
154
+ status: 'gone';
155
+ runId: string;
156
+ }
157
+ /** Every attempt failed; the stream ended with an error chunk. */
158
+ | {
159
+ status: 'failed';
160
+ runId: string;
161
+ };
13
162
  interface AgentChatTransportOptions {
163
+ /**
164
+ * What the transport talks to. Default: an {@link AgentClient} built from `baseUrl`, `headers`,
165
+ * `getHeaders`, `credentials` and `fetch` below — which are ignored when a backend is given.
166
+ */
167
+ backend?: AgentBackend;
168
+ /** Retry a dropped stream from its last frame. Default on; `false` turns it off. */
169
+ reconnect?: ReconnectOptions | false;
170
+ /** Fires as a stream drops, reconnects, or gives up. */
171
+ onConnectionChange?: (state: StreamConnectionState) => void;
14
172
  /**
15
173
  * Origin + base path the agent endpoints hang off, e.g.
16
174
  * `https://api.example.com`. Endpoints are appended as
@@ -94,6 +252,7 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
94
252
  * several entries under each id — which React renders as duplicate keys.
95
253
  */
96
254
  private attemptLive;
255
+ private readonly backend;
97
256
  constructor(options?: AgentChatTransportOptions);
98
257
  /** Run id of the most recent stream — HITL approve/reject target this. */
99
258
  get runId(): string | undefined;
@@ -108,10 +267,8 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
108
267
  get isAttemptLive(): boolean;
109
268
  sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
110
269
  reconnectToStream(options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0]): Promise<ReadableStream<UIMessageChunk> | null>;
111
- private fetchImpl;
112
- private baseUrl;
113
- private resolveHeaders;
114
270
  private captureHeaderMeta;
271
+ private reconnectPolicy;
115
272
  private recordMeta;
116
273
  /**
117
274
  * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
@@ -129,6 +286,84 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
129
286
  private toChunkStream;
130
287
  }
131
288
 
289
+ interface UseMessageFeedbackOptions {
290
+ /** `useAgentChat(...).backend`, or your own. Must implement `setMessageFeedback`. */
291
+ backend: AgentBackend;
292
+ /**
293
+ * The thread the messages belong to — `useAgentChat(...).getThreadId`, or an id. Needed to rate a
294
+ * message streamed in this session: its id is the client's own, so the persisted row it became is
295
+ * looked up by the run that wrote it.
296
+ */
297
+ threadId?: string | (() => string | undefined);
298
+ }
299
+ interface MessageFeedbackState {
300
+ /** The rating to show: the one set in this session, else the persisted one, else `null`. */
301
+ feedbackOf: (message: UIMessage) => MessageFeedback | null;
302
+ /** A rating for this message is on its way to the server. */
303
+ isPending: (message: UIMessage) => boolean;
304
+ /** Set `'up'`/`'down'` (optionally with a comment), or clear with `null`. Optimistic. */
305
+ rate: (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => Promise<void>;
306
+ /** Thumbs-button semantics: the same value again clears it, another value replaces it. */
307
+ toggle: (message: UIMessage, value: MessageFeedbackValue) => Promise<void>;
308
+ /** The last failure; cleared by the next successful rating. */
309
+ error: Error | null;
310
+ }
311
+ /**
312
+ * Thumbs-up/down (+ comment) on assistant messages, over `POST <base>/messages/:id/feedback`.
313
+ * Headless: it holds the state and the calls, the host draws the buttons. A rating shows at once
314
+ * and rolls back if the server refuses it.
315
+ */
316
+ declare function useMessageFeedback(options: UseMessageFeedbackOptions): MessageFeedbackState;
317
+
318
+ /**
319
+ * What changed about a backend's thread list. `changed` → refetch (a thread was created, or a run
320
+ * settled and the server wrote its title); `title` → the stream announced a title, patch in place.
321
+ */
322
+ type ThreadsEvent = {
323
+ type: 'changed';
324
+ } | {
325
+ type: 'title';
326
+ threadId: string;
327
+ title: string;
328
+ } | {
329
+ type: 'removed';
330
+ threadId: string;
331
+ };
332
+ type Listener = (event: ThreadsEvent) => void;
333
+ /** Tell every {@link useThreads} on `backend` that its list moved. */
334
+ declare function notifyThreads(backend: AgentBackend, event: ThreadsEvent): void;
335
+ /** Subscribe to {@link notifyThreads} for `backend`; returns the unsubscribe. */
336
+ declare function onThreadsEvent(backend: AgentBackend, listener: Listener): () => void;
337
+
338
+ interface UseThreadsOptions {
339
+ /**
340
+ * The backend to list — `useAgentChat(...).backend`, or your own. Must be STABLE across renders:
341
+ * the list refreshes itself when a chat on the SAME backend creates a thread, settles a run or
342
+ * streams a title.
343
+ */
344
+ backend: AgentBackend;
345
+ /** `false` holds the first request (e.g. until the user is signed in). Default `true`. */
346
+ enabled?: boolean;
347
+ }
348
+ interface ThreadsState {
349
+ /** Newest first, as the server orders them. `[]` until loaded. */
350
+ threads: ThreadSummary[];
351
+ isLoading: boolean;
352
+ error: Error | null;
353
+ /** Ask the server again. */
354
+ refresh: () => Promise<void>;
355
+ /** Rename on the server; the list shows the new title at once and rolls back on failure. */
356
+ rename: (id: string, title: string) => Promise<void>;
357
+ /** Delete on the server; the thread leaves the list at once and comes back on failure. */
358
+ remove: (id: string) => Promise<void>;
359
+ }
360
+ /**
361
+ * The actor's conversations, kept current without the host wiring refetches: a chat on the same
362
+ * backend reports thread creation and settled runs (refetch) and streamed titles (patched in
363
+ * place). Headless — it renders nothing.
364
+ */
365
+ declare function useThreads(options: UseThreadsOptions): ThreadsState;
366
+
132
367
  /**
133
368
  * A sub-agent the conversation started and did not wait for. The chat is free while it works, so a
134
369
  * client has to be able to say what is still running and to show the answer when it lands — neither
@@ -178,34 +413,46 @@ interface CancelResult {
178
413
  interface OkResult {
179
414
  ok: boolean;
180
415
  }
181
- /**
182
- * Partial update accepted by `PATCH /agent/threads/:threadId`. `defaultAgent: null` clears a
183
- * previously-set default back to the module's own default; omitting it leaves the thread's
184
- * current default untouched.
185
- */
186
- interface ThreadPatch {
187
- title?: string;
188
- defaultAgent?: string | null;
189
- }
190
416
  interface AgentClientOptions {
191
417
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
192
418
  baseUrl?: string;
193
419
  /** Static headers merged into every request. */
194
420
  headers?: Record<string, string>;
195
- /** Resolved per request — for short-lived bearer tokens. */
421
+ /**
422
+ * Resolved per request — for short-lived bearer tokens, or a CSRF header read from a cookie
423
+ * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`), which has to be read at request time because
424
+ * the server may rotate it.
425
+ */
196
426
  getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
197
- /** Forwarded to fetch so cookie auth works. */
427
+ /**
428
+ * Forwarded to fetch so cookie auth works. Same-origin requests send cookies by default; set
429
+ * `'include'` when the API lives on another origin (and have it answer with credentialed CORS).
430
+ */
198
431
  credentials?: RequestCredentials;
199
432
  /** Injectable for tests / non-browser runtimes. */
200
433
  fetch?: typeof fetch;
201
434
  }
202
435
  /**
203
- * Framework-agnostic REST client for the nestjs-agent endpoints. Used by
204
- * `useAgentChat`, but standalone-usable (vanilla fetch, no React).
436
+ * Framework-agnostic REST client for the nestjs-agent endpoints — the default {@link AgentBackend}.
437
+ * Used by `useAgentChat`, but standalone-usable (vanilla fetch, no React).
205
438
  */
206
- declare class AgentClient {
439
+ declare class AgentClient implements AgentBackend {
207
440
  private readonly options;
208
441
  constructor(options?: AgentClientOptions);
442
+ /** `POST /agent/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */
443
+ openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;
444
+ /**
445
+ * `GET /agent/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is
446
+ * streaming under that id (404).
447
+ */
448
+ resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;
449
+ /**
450
+ * Rate a message (`'up'`/`'down'`, optional comment) or clear its rating (`value: null`). Answers
451
+ * the stored rating.
452
+ */
453
+ setMessageFeedback(messageId: string, input: MessageFeedbackInput): Promise<{
454
+ feedback: MessageFeedback | null;
455
+ }>;
209
456
  listThreads(): Promise<ThreadSummary[]>;
210
457
  /**
211
458
  * The skills this caller can invoke right now, scope-resolved — the same list, built by the same
@@ -231,7 +478,7 @@ declare class AgentClient {
231
478
  * mirrors the backend's `POST /agent/attachments`. The returned {@link MessageAttachment} is
232
479
  * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
233
480
  */
234
- uploadAttachment(file: File): Promise<MessageAttachment>;
481
+ uploadAttachment(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
235
482
  promoteThread(id: string): Promise<OkResult>;
236
483
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
237
484
  getQuotaToday(): Promise<QuotaToday>;
@@ -268,6 +515,10 @@ declare class AgentClient {
268
515
  skipToolCall(input: {
269
516
  toolCallId: string;
270
517
  }): Promise<void>;
518
+ private fetchImpl;
519
+ private baseUrl;
520
+ private resolveHeaders;
521
+ private credentials;
271
522
  private request;
272
523
  private handleResponse;
273
524
  }
@@ -282,7 +533,7 @@ interface ChatInputProps {
282
533
  /** BCP-47 locale for dictation. Default `en-US`. */
283
534
  speechLang?: string;
284
535
  /** Label/content for the send button. Default `"Send"`. */
285
- sendLabel?: React.ReactNode;
536
+ sendLabel?: React__default.ReactNode;
286
537
  /**
287
538
  * Cancel the turn in flight — wire to `useAgentChat`'s `cancel`. Rendered only alongside
288
539
  * `isStreaming`, so the affordance exists exactly while there is something to cancel.
@@ -291,7 +542,7 @@ interface ChatInputProps {
291
542
  /** Whether a turn is currently in flight. Gates the stop affordance. */
292
543
  isStreaming?: boolean;
293
544
  /** Label/content for the stop button. Default `"Stop generating"` — the mic's own is `"Stop"`. */
294
- stopLabel?: React.ReactNode;
545
+ stopLabel?: React__default.ReactNode;
295
546
  /** Wrapper class. The component ships no styles of its own. */
296
547
  className?: string;
297
548
  textareaClassName?: string;
@@ -304,7 +555,7 @@ interface ChatInputProps {
304
555
  */
305
556
  renderMic?: (state: {
306
557
  isListening: boolean;
307
- }) => React.ReactNode;
558
+ }) => React__default.ReactNode;
308
559
  }
309
560
  /**
310
561
  * Styling-agnostic chat composer. Enter submits, Shift+Enter inserts a
@@ -313,560 +564,7 @@ interface ChatInputProps {
313
564
  * cancel next to send. No design-system or icon-library deps —
314
565
  * style it entirely through the `*ClassName` props.
315
566
  */
316
- declare function ChatInput({ onSubmit, disabled, placeholder, rows, enableSpeech, speechLang, sendLabel, onStop, isStreaming, stopLabel, className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic, }: ChatInputProps): React.JSX.Element;
317
-
318
- /** What a form control can hand over: a field's value, a checkbox's state, a picked date, a list. */
319
- type RawAnswer = string | number | boolean | Date | null | undefined | readonly RawAnswer[];
320
- /** The question fields {@link coerceAnswer} reads. A transcript question and a core one both fit. */
321
- type CoercibleQuestion = Pick<ElicitationQuestion, 'multiple'> & {
322
- input?: {
323
- type: ElicitationInputType;
324
- } | null;
325
- };
326
- /**
327
- * Turn whatever a form control produced into the `string[]` the answer route takes, in the
328
- * question's canonical form: numbers as decimals, booleans as `"true"`/`"false"`, dates as
329
- * `YYYY-MM-DD` (a `Date` is read as the local calendar day), trimmed where whitespace means
330
- * nothing. An empty value becomes `[]` — no answer, not an empty string. A single-choice question
331
- * keeps the first value.
332
- *
333
- * Coercion never judges: pair it with {@link validateAnswer} (the same rules the server applies) to
334
- * say what is wrong before sending.
335
- */
336
- declare function coerceAnswer(question: CoercibleQuestion, raw: RawAnswer): string[];
337
-
338
- /** Tool name → how the server said it is spoken about. */
339
- type ToolCatalog = Record<string, ToolPresentation>;
340
- /** Index `GET <base>/tools` by tool name, keeping only the tools that declared a presentation. */
341
- declare function toolCatalogFrom(entries: readonly ToolCatalogEntry[]): ToolCatalog;
342
- /** Dotted-path read. `undefined` rather than a throw, so a template can outlive a field. */
343
- declare function readPath(value: unknown, path: string): unknown;
344
- /**
345
- * Fill `{dotted.path}` placeholders from `context`. A placeholder with nothing behind it collapses
346
- * along with the whitespace in front of it, so "Reading {key}" degrades to "Reading" rather than
347
- * printing braces at a person; a filled one keeps the whitespace the author wrote ("({n} files)").
348
- */
349
- declare function fillTemplate(template: string, context: unknown): string;
350
- /**
351
- * The sentence for one call: the presentation's `running` or `done` template over the call's input.
352
- *
353
- * Nothing here reads the tool's name. A tool the catalog does not describe — added since the catalog
354
- * loaded, or declared without a presentation — is narrated generically (`fallback`), because the only
355
- * other thing available to say is its identifier.
356
- */
357
- declare function phraseFor(presentation: ToolPresentation | undefined, input: unknown, isSettled: boolean, fallback?: {
358
- running: string;
359
- done: string;
360
- }): string;
361
-
362
- /** One labelled reading of a `metrics` view. */
363
- interface ResolvedReading {
364
- label: string;
365
- /** The value as text (`—` for nothing). */
366
- value: string;
367
- unit: string | null;
368
- }
369
- /**
370
- * A tool's output resolved through its view into plain data a renderer draws — never the payload
371
- * itself. `null` from {@link resolveResultView} means "draw nothing".
372
- */
373
- type ResolvedResultView = {
374
- kind: 'metrics';
375
- readings: ResolvedReading[];
376
- } | {
377
- kind: 'table';
378
- columns: ToolResultField[];
379
- rows: string[][];
380
- empty: string | null;
381
- } | {
382
- kind: 'log';
383
- lines: string[];
384
- } | {
385
- kind: 'note';
386
- text: string;
387
- };
388
- /**
389
- * A view for an output whose tool declared none, from its shape: an array of flat records is a
390
- * table, an array of strings a log, a flat record a set of readings. `undefined` when nothing fits —
391
- * a serialized payload is what a person-facing surface exists to avoid, so failing to infer must not
392
- * fall back to one.
393
- */
394
- declare function inferResultView(output: unknown): ToolResultView | undefined;
395
- /**
396
- * Read `output` through `view` (or one inferred from its shape when `view` is omitted and `infer` is
397
- * on). `null` when there is nothing to draw: an `elsewhere` view, an empty reading set, a missing
398
- * array. A table whose rows array is present but empty resolves with no rows and its `empty` line.
399
- */
400
- declare function resolveResultView(output: unknown, view: ToolResultView | undefined, options?: {
401
- infer?: boolean;
402
- }): ResolvedResultView | null;
403
-
404
- /**
405
- * Where one call stands, as a person reads it:
406
- * - `running` — input streaming or the tool executing;
407
- * - `awaiting-approval` — an `action` call parked on a person;
408
- * - `done` / `failed` / `denied` — settled. A tool that RETURNS `{ error }` has failed just as much
409
- * as one that threw; the two arrive differently and read the same to a person.
410
- */
411
- type ToolCallStatus = 'running' | 'awaiting-approval' | 'done' | 'failed' | 'denied';
412
- interface ToolCallState {
413
- status: ToolCallStatus;
414
- isSettled: boolean;
415
- isFailed: boolean;
416
- isDenied: boolean;
417
- output: unknown;
418
- error: string | null;
419
- }
420
- /** Whether the stream classified this call as an `action` (it parks for approval before it runs). */
421
- declare function isActionCall(part: AnyToolUIPart): boolean;
422
- declare function toolCallState(part: AnyToolUIPart): ToolCallState;
423
- /**
424
- * Which failed calls the model went on to correct, by call id: a call that failed and was followed,
425
- * in the same run, by a SUCCESS of the same tool. The operator wants to know a retry happened, not
426
- * to read every attempt. A failed read is not corrected by a successful query.
427
- */
428
- declare function correctedCallIds(parts: readonly AnyToolUIPart[]): Set<string>;
429
- /** Everything a surface needs to talk about one call without naming it. */
430
- interface ToolCallDescription {
431
- status: ToolCallStatus;
432
- /** "Querying orders" / "Queried orders" — or the generic fallback when the tool declared nothing. */
433
- phrase: string;
434
- /** The server's noun phrase for the tool; `null` when it declared no presentation. */
435
- label: string | null;
436
- icon: string | null;
437
- tone: ToolPresentationTone;
438
- detail: string | null;
439
- /** The approval prompt, templated over the call's input; `null` when the tool declared none. */
440
- confirm: {
441
- title: string;
442
- verb: string;
443
- detail: string | null;
444
- } | null;
445
- /** The output read through its view, once the call is `done`; `null` otherwise or when nothing to draw. */
446
- result: ResolvedResultView | null;
447
- error: string | null;
448
- presentation: ToolPresentation | null;
449
- }
450
- interface DescribeToolCallOptions {
451
- /** Words for a tool the catalog does not describe. Default `Working` / `Done`. */
452
- fallback?: {
453
- running: string;
454
- done: string;
455
- };
456
- /** Infer a result view from the output's shape when the tool declared none. Default `false`. */
457
- inferResult?: boolean;
458
- }
459
- declare function describeToolCall(part: AnyToolUIPart, catalog: ToolCatalog | undefined, options?: DescribeToolCallOptions): ToolCallDescription;
460
- /**
461
- * Calls folded under one key — "Database query ×3" — with the state that matters most across them.
462
- */
463
- interface ToolActivityGroup {
464
- key: string;
465
- /** The server's label for the group's tool; `null` when it declared no presentation. */
466
- label: string | null;
467
- icon: string | null;
468
- /** Worst-first across the calls: running › awaiting-approval › failed › denied › done. */
469
- status: ToolCallStatus;
470
- count: number;
471
- /** The phrase of the group's LATEST call — what is happening now. */
472
- phrase: string;
473
- calls: TranscriptToolCall[];
474
- /** Calls nested under the group's calls (all depths), when nesting was not expanded. */
475
- innerCount: number;
476
- }
477
- interface GroupToolActivityOptions {
478
- catalog?: ToolCatalog;
479
- /**
480
- * What makes two calls "the same activity". Default: the tool's presentation `label`, else its
481
- * name. Flippy-style source grouping passes its own (e.g. `github:search`).
482
- */
483
- keyOf?: (call: TranscriptToolCall, presentation: ToolPresentation | undefined) => string;
484
- /**
485
- * Replace a call that has nested calls with those calls (recursively), so the activity reads as
486
- * what the code-mode run DID rather than "ran code". Default `false`: groups are built over the
487
- * top-level calls, and `innerCount` says how much ran beneath them.
488
- */
489
- expandNested?: boolean;
490
- /** Drop failed calls the model corrected with a later success of the same tool. Default `false`. */
491
- hideCorrected?: boolean;
492
- fallback?: {
493
- running: string;
494
- done: string;
495
- };
496
- }
497
- /**
498
- * Fold a tool run into activity groups, in order of first appearance. Pass `block.roots` (the
499
- * transcript's call tree) so nesting is honoured; a flat `block.calls` works too and simply has
500
- * nothing nested.
501
- */
502
- declare function groupToolActivity(calls: readonly TranscriptToolCall[], options?: GroupToolActivityOptions): ToolActivityGroup[];
503
-
504
- /** A tool UI part on a `UIMessage` — a static `tool-*` part or the `dynamic-tool` part. */
505
- type AnyToolUIPart = ToolUIPart | DynamicToolUIPart;
506
- type ChatStatus = 'ready' | 'submitted' | 'streaming' | 'error';
507
- /** Server-aggregated usage for an assistant turn. */
508
- interface MessageUsageInfo {
509
- inputTokens: number;
510
- outputTokens: number;
511
- /**
512
- * `null` when no price is on record for the model that ran the turn. Distinct from `0`, which is
513
- * a turn that genuinely cost nothing — printing `$0` for an unpriced turn states a number the
514
- * store never had.
515
- */
516
- costUsd: number | null;
517
- }
518
- /** A run of contiguous prose. `isStreaming` is the PART's own state, not the message's. */
519
- interface TranscriptTextBlock {
520
- kind: 'text';
521
- key: string;
522
- text: string;
523
- isStreaming: boolean;
524
- }
525
- /** One file on a message — an uploaded attachment, or one the model produced. */
526
- interface TranscriptFile {
527
- /** Presigned or otherwise directly fetchable. Display-only: the model reads its own copy. */
528
- url: string;
529
- mediaType: string;
530
- filename: string | null;
531
- /** `image/*`, which a renderer can show inline rather than as a link. */
532
- isImage: boolean;
533
- }
534
- /** A run of contiguous files. Grouped so a renderer can lay several out as one strip. */
535
- interface TranscriptFilesBlock {
536
- kind: 'files';
537
- key: string;
538
- files: TranscriptFile[];
539
- }
540
- /**
541
- * A run of contiguous reasoning. Carries its own disclosure state because a thread can hold many
542
- * of them and each is toggled independently; `isOpen` defaults to `isStreaming` (thinking is worth
543
- * watching live, worth folding away once answered) until `toggle` is called for that run.
544
- */
545
- interface TranscriptReasoningBlock {
546
- kind: 'reasoning';
547
- key: string;
548
- text: string;
549
- isStreaming: boolean;
550
- /**
551
- * How long the model thought, in ms — the backend's measurement once the run closed (live) or as
552
- * persisted (reloaded). `null` while it still streams, or when nothing was recorded: pair it with
553
- * `useElapsed(block.isStreaming)` for a ticking label (`block.durationMs ?? elapsed`).
554
- */
555
- durationMs: number | null;
556
- isOpen: boolean;
557
- toggle: (open?: boolean) => void;
558
- }
559
- /**
560
- * A decision a run is waiting on a human for, and which one a parked call is currently sending.
561
- *
562
- * One call settles one way at a time, and WHICH one is what lets a surface report progress on the
563
- * affordance the person pressed instead of on all of them.
564
- */
565
- type SettleAction = 'approve' | 'reject' | 'answer' | 'skip';
566
- /** One such decision: whether it can be made, whether it is on its way, and how to send it. */
567
- interface TranscriptSettleState {
568
- available: boolean;
569
- /** True from the click until the run resumes and settles the call. */
570
- isSubmitting: boolean;
571
- run: () => void;
572
- }
573
- /** How an approval stands. */
574
- type TranscriptApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
575
- /**
576
- * Who has to settle a parked call, until when, and — once it settled — how. From the stream's
577
- * `approval-requested` / `approval-settled` frames, or the same parts a reloaded thread carries.
578
- * `null` on a call whose runner never said (the call can still be awaiting approval).
579
- */
580
- interface TranscriptApproval {
581
- /** Open vocabulary the host defines: `'requester'`, `'admin'`, a role… */
582
- approver: string;
583
- /** ISO-8601; `null` when the request never lapses. Pair with `useApprovalCountdown`. */
584
- expiresAt: string | null;
585
- /** Why the call needs a person, when the runner said. */
586
- reason: string | null;
587
- /**
588
- * `pending` until a settlement arrives; then what it said. Falls back to the call's own state
589
- * (denied → `rejected`, an output → `approved`) for a runner that streams no settlement.
590
- */
591
- status: TranscriptApprovalStatus;
592
- /** The approval also covers later calls of this tool in this thread. */
593
- remember: boolean;
594
- /** Opaque ref of who decided; `null` while pending, on an expiry, or when the runner did not say. */
595
- decidedBy: string | null;
596
- /** The surface the decision came through (`'web'`, `'slack'`, `'remembered'`, …). */
597
- decidedVia: string | null;
598
- /** What the person said when declining. */
599
- decisionReason: string | null;
600
- }
601
- /** What an approval can carry beyond yes. */
602
- interface ApproveOptions {
603
- /** Approve later calls of the same tool in the same thread without asking again. */
604
- remember?: boolean;
605
- }
606
- /** One call in a tool run, with whatever human decision it is parked on. */
607
- interface TranscriptToolCall {
608
- part: AnyToolUIPart;
609
- toolCallId: string;
610
- name: string;
611
- /** `read` / `action` as the stream classified the call; `null` when the backend did not say. */
612
- toolKind: string | null;
613
- /** The call this one ran inside (a code-mode `execute`, a delegated agent); `null` for a top-level call. */
614
- parentId: string | null;
615
- /**
616
- * Calls nested under this one within the same block, in stream order. Always empty for a call
617
- * nothing names as its parent.
618
- */
619
- children: TranscriptToolCall[];
620
- /** Who has to decide, when the runner said so. See {@link TranscriptApproval}. */
621
- approval: TranscriptApproval | null;
622
- /**
623
- * How to talk about this call without naming it — status, phrase, label, icon, approval prompt,
624
- * resolved result — from the server's presentation when `toolCatalog` was given, generic otherwise.
625
- */
626
- description: ToolCallDescription;
627
- /**
628
- * Parked on a person. An `action` tool's input lands and its output never follows on its own —
629
- * the loop waits for an approval between the two — so a settled-looking card that never settles
630
- * IS the pending approval.
631
- */
632
- isAwaitingApproval: boolean;
633
- /** `run({ remember: true })` approves this tool for the rest of the thread. */
634
- approve: TranscriptSettleState & {
635
- run: (options?: ApproveOptions) => void;
636
- };
637
- reject: TranscriptSettleState;
638
- /** A failed decision — the call is still parked, so the affordance stays live. */
639
- error: string | null;
640
- }
641
- /**
642
- * A run of CONSECUTIVE tool parts, grouped so a UI can collapse "5 tools ran" into one affordance.
643
- * Any non-tool part between two tool parts ends the run — including the AI SDK's `step-start`
644
- * markers, so tools from different steps never merge into one group.
645
- */
646
- interface TranscriptToolBlock {
647
- kind: 'tools';
648
- key: string;
649
- parts: AnyToolUIPart[];
650
- /** The same calls, each with its human-decision state. Same order as `parts`. */
651
- calls: TranscriptToolCall[];
652
- /**
653
- * The same calls as a tree: every call whose parent is NOT in this block, each carrying its
654
- * nested calls in `children`. Equal to `calls` when nothing is nested.
655
- */
656
- roots: TranscriptToolCall[];
657
- /**
658
- * The run folded into activity groups ("Database query ×3"), over `roots`, keyed by each tool's
659
- * presentation label (else its name). For another grouping, call `groupToolActivity` yourself.
660
- */
661
- activity: ToolActivityGroup[];
662
- }
663
- /**
664
- * A component the server pushed into the message (the stream's `ui` frame, or a persisted
665
- * `data-ui` part). Rendered by looking `component` up in the host's own registry.
666
- */
667
- interface TranscriptUiBlock {
668
- kind: 'ui';
669
- key: string;
670
- /** The component's identity within the message. */
671
- id: string;
672
- component: string;
673
- props: Record<string, unknown>;
674
- /** Schema version of `props`; `null` when the server did not stamp one. */
675
- version: number | null;
676
- /** The tool call that pushed it (`ctx.emitUi`); `null` for a component pushed outside a tool. */
677
- toolCallId: string | null;
678
- }
679
- /** One choice a question offers, with its live selection state. */
680
- interface TranscriptQuestionOption {
681
- value: string;
682
- label: string;
683
- /** A single character the request suggested as a shortcut; `null` when it suggested none. */
684
- hotkey: string | null;
685
- isSelected: boolean;
686
- /** Pre-picked by the agent — what an untouched question submits as. */
687
- isDefault: boolean;
688
- /** Single choice: replaces the selection. Multiple: adds or removes this value. */
689
- select: () => void;
690
- }
691
- /** One question of a set, numbered against the whole. */
692
- interface TranscriptQuestion {
693
- id: string;
694
- prompt: string;
695
- /** A line of help under the prompt; `null` when the request gave none. */
696
- description: string | null;
697
- /**
698
- * How the answer is typed — `{ type, placeholder?, required?, min?, max?, pattern? }` — or `null`
699
- * for a plain pick from `options`. Render the control from `input.type`; `select` still picks
700
- * from `options`.
701
- */
702
- input: ElicitationInput | null;
703
- multiple: boolean;
704
- /** 1-based. The request carries every question up front, so "Question 1 of N" is honest. */
705
- position: number;
706
- options: TranscriptQuestionOption[];
707
- selected: string[];
708
- /**
709
- * The user has not touched this question, so a submission leaves it out and the server applies
710
- * the same defaults it showed. Distinct from "selected happens to equal the defaults": only the
711
- * first is recorded as `defaulted` rather than as a choice the user made.
712
- */
713
- isPristine: boolean;
714
- /** The first selected value, or `''` — what a single text/number/date field shows. */
715
- value: string;
716
- /**
717
- * Set a typed answer from whatever the control produced (a string, a number, a checkbox's
718
- * boolean, a `Date`, a list); coerced to the question's canonical strings with `coerceAnswer`.
719
- * `null`/`''` clears it. Does nothing once the set settled.
720
- */
721
- setValue: (raw: RawAnswer) => void;
722
- /**
723
- * Why the current selection would be refused (the server's own rules — `validateAnswer`), or
724
- * `null`. A pristine required question with no default reads `requires an answer`; show it once
725
- * the user tried to submit, or right away — the model does not decide that for you.
726
- */
727
- error: string | null;
728
- }
729
- /** How a question set settled, once it did. */
730
- interface TranscriptElicitationOutcome {
731
- answers: Record<string, string[]>;
732
- /** The user declined to answer and let the agent proceed on its own picks. */
733
- skipped: boolean;
734
- /** Questions filled from their own defaults rather than by the human. */
735
- defaulted: string[];
736
- /** The questions against the chosen labels, as the model read them back. */
737
- summary: string | null;
738
- }
739
- /**
740
- * A question set the run put to the user, parked until someone settles it — the intake an agent
741
- * declares and the model's own `ask` produce the same block, because the loop streams the same
742
- * frame for both.
743
- */
744
- interface TranscriptElicitationBlock {
745
- kind: 'elicitation';
746
- key: string;
747
- /** The parked tool call — what `answer`/`skip` route by. */
748
- toolCallId: string;
749
- preamble: string | null;
750
- questions: TranscriptQuestion[];
751
- questionCount: number;
752
- /** Still waiting on a human. */
753
- isPending: boolean;
754
- /** Every question's current selection is acceptable (no question has an `error`). */
755
- isValid: boolean;
756
- outcome: TranscriptElicitationOutcome | null;
757
- /** A failed submission — the run is still parked, so the form stays live. */
758
- error: string | null;
759
- answer: TranscriptSettleState;
760
- skip: TranscriptSettleState;
761
- }
762
- /** One retrieved passage, as it rides a retrieval tool call's output. Mirrors core's `Passage`. */
763
- interface RetrievedPassage {
764
- id: string;
765
- text: string;
766
- score: number;
767
- /** Citation-facing origin — a document title, URL or row id. */
768
- source?: string;
769
- metadata?: Record<string, unknown>;
770
- }
771
- /** The passages of one origin, folded together so a citation line reads once per source. */
772
- interface TranscriptSource {
773
- /** The `source` string the retriever stamped, falling back to the passage id when it stamped none. */
774
- id: string;
775
- label: string;
776
- passageCount: number;
777
- /** Highest relevance among this source's passages; the scale is the retriever's. */
778
- topScore: number;
779
- passages: RetrievedPassage[];
780
- }
781
- /**
782
- * The provenance behind an answer: a run of CONSECUTIVE retrieval tool parts, aggregated by origin.
783
- * Detection is structural — a tool output shaped `{ passages: [{ id, text, ... }] }` — because the
784
- * tool's NAME is not fixed: inject-mode retrieval persists as `retrieve`, and `createRetrievalTool`
785
- * lets the host rename `search_knowledge` to anything.
786
- */
787
- interface TranscriptSourcesBlock {
788
- kind: 'sources';
789
- key: string;
790
- /** What was searched, when the tool call recorded a `{ query }` input. */
791
- query: string | null;
792
- sources: TranscriptSource[];
793
- passageCount: number;
794
- }
795
- type TranscriptBlock = TranscriptTextBlock | TranscriptFilesBlock | TranscriptReasoningBlock | TranscriptToolBlock | TranscriptSourcesBlock | TranscriptElicitationBlock | TranscriptUiBlock;
796
- /** Where a question set's selection state is held, and where its settlement is sent. */
797
- interface ElicitationBlockOptions {
798
- /** The values a question is showing, or `undefined` while the user has not touched it. */
799
- picked: (toolCallId: string, questionId: string) => string[] | undefined;
800
- pick: (toolCallId: string, questionId: string, values: string[]) => void;
801
- canAnswer: boolean;
802
- canSkip: boolean;
803
- answer: (toolCallId: string) => void;
804
- skip: (toolCallId: string) => void;
805
- /** Which decision this call is sending, or `null` for none. */
806
- submitting: (toolCallId: string) => SettleAction | null;
807
- errorOf: (toolCallId: string) => string | null;
808
- }
809
- /** Where an approval decision is sent, and what the last one did. */
810
- interface ApprovalBlockOptions {
811
- canApprove: boolean;
812
- canReject: boolean;
813
- approve: (toolCallId: string, options?: ApproveOptions) => void;
814
- reject: (toolCallId: string) => void;
815
- /** Which decision this call is sending, or `null` for none. */
816
- submitting: (toolCallId: string) => SettleAction | null;
817
- errorOf: (toolCallId: string) => string | null;
818
- }
819
- interface BuildBlocksOptions {
820
- /** Disclosure lookup for a reasoning run; `isStreaming` is the fallback when untouched. */
821
- isReasoningOpen: (key: string, isStreaming: boolean) => boolean;
822
- toggleReasoning: (key: string, open?: boolean) => void;
823
- /**
824
- * Lift retrieval tool parts out of the tool run into a `sources` block. Off by default, so a
825
- * renderer wired to draw tool cards keeps receiving them as the tool calls they are.
826
- */
827
- sources?: boolean;
828
- /**
829
- * Lift a question set out of the tool run into an `elicitation` block. Omitted → it stays a tool
830
- * card, which is all a host that has nowhere to send an answer could render anyway.
831
- */
832
- elicitation?: ElicitationBlockOptions;
833
- /** Wire approve/reject onto the calls parked on a human. Omitted → they are reported, not actionable. */
834
- approval?: ApprovalBlockOptions;
835
- /** Server-declared tool presentations (`useToolCatalog`), for each call's `description`. */
836
- toolCatalog?: ToolCatalog;
837
- }
838
- /**
839
- * Walk a message's parts into renderable blocks, buffering consecutive tool parts into one run and
840
- * consecutive files into one strip. A `data-ui` part becomes a `ui` block. A
841
- * `data-approval-requested` part is metadata about a call — it is folded into that call's
842
- * `approval` and takes no position of its own. Other `data-*` parts are dropped rather than guessed
843
- * at, but they still terminate a tool run — their position in the transcript is meaningful even
844
- * when their content is not modelled here.
845
- */
846
- declare function buildTranscriptBlocks(message: UIMessage, options: BuildBlocksOptions): TranscriptBlock[];
847
- /** The message's prose, joined for the clipboard. Reasoning is excluded — it is not the answer. */
848
- declare function extractMessageText(parts: UIMessage['parts'] | undefined): string;
849
- interface UsageSummary extends MessageUsageInfo {
850
- totalTokens: number;
851
- /** `$0`, `$0.0123`, `$0.012`, `$1.23` — precision follows magnitude so sub-cent turns stay legible. */
852
- costLabel: string;
853
- tokensLabel: string;
854
- }
855
- declare function describeUsage(usage: MessageUsageInfo): UsageSummary;
856
- interface TimestampInfo {
857
- iso: string;
858
- date: Date;
859
- /** "just now" / "5 min. ago" / "Mar 3" — see {@link formatRelativeTime}. */
860
- relative: string;
861
- absolute: string;
862
- }
863
- /** `null` for an unparseable stamp, so a bad `created_at` renders nothing instead of "Invalid Date". */
864
- declare function describeTimestamp(createdAt: string | null | undefined): TimestampInfo | null;
865
- /**
866
- * "just now" within ±10s (server `created_at` can land a few ms ahead of the client clock), a
867
- * relative phrase up to a week, then a calendar date. Uses Intl.RelativeTimeFormat — no date-fns.
868
- */
869
- declare function formatRelativeTime(date: Date): string;
567
+ declare function ChatInput({ onSubmit, disabled, placeholder, rows, enableSpeech, speechLang, sendLabel, onStop, isStreaming, stopLabel, className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic, }: ChatInputProps): React__default.JSX.Element;
870
568
 
871
569
  interface StickToBottomOptions {
872
570
  /**
@@ -921,8 +619,8 @@ interface TranscriptEditState {
921
619
  getTextareaProps: () => {
922
620
  ref: (element: HTMLTextAreaElement | null) => void;
923
621
  value: string;
924
- onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
925
- onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
622
+ onChange: (event: React__default.ChangeEvent<HTMLTextAreaElement>) => void;
623
+ onKeyDown: (event: React__default.KeyboardEvent<HTMLTextAreaElement>) => void;
926
624
  };
927
625
  }
928
626
  interface TranscriptActionState {
@@ -1052,26 +750,26 @@ interface UseTranscriptItemOptions extends TranscriptItemOptions {
1052
750
  */
1053
751
  declare function useTranscriptItem(options: UseTranscriptItemOptions): TranscriptItem;
1054
752
 
1055
- type RenderToolPartFn = (part: AnyToolUIPart, key: string) => React.ReactNode;
753
+ type RenderToolPartFn = (part: AnyToolUIPart, key: string) => React__default.ReactNode;
1056
754
  /** Render a run of consecutive tool parts as one block (e.g. a collapsible tool group). */
1057
- type RenderToolGroupFn = (parts: AnyToolUIPart[], key: string) => React.ReactNode;
755
+ type RenderToolGroupFn = (parts: AnyToolUIPart[], key: string) => React__default.ReactNode;
1058
756
  /** Render a message's text — pass a markdown renderer (e.g. `AgentMarkdown`) here if desired. */
1059
757
  type RenderTextFn = (text: string, ctx: {
1060
758
  isStreaming: boolean;
1061
- }) => React.ReactNode;
759
+ }) => React__default.ReactNode;
1062
760
  /** Render a run of files — attachments on a user turn, or files the model produced. */
1063
- type RenderFilesFn = (files: TranscriptFile[]) => React.ReactNode;
761
+ type RenderFilesFn = (files: TranscriptFile[]) => React__default.ReactNode;
1064
762
  /**
1065
763
  * Render a component the server pushed into the message — look `block.component` up in your own
1066
764
  * registry. Omitted → pushed components are not drawn (there is no sensible default for an app's
1067
765
  * own component).
1068
766
  */
1069
- type RenderUiFn = (block: TranscriptUiBlock) => React.ReactNode;
767
+ type RenderUiFn = (block: TranscriptUiBlock) => React__default.ReactNode;
1070
768
  /** Render the body of a reasoning run; the disclosure toggle around it stays this component's. */
1071
769
  type RenderReasoningFn = (text: string, ctx: {
1072
770
  isStreaming: boolean;
1073
771
  isOpen: boolean;
1074
- }) => React.ReactNode;
772
+ }) => React__default.ReactNode;
1075
773
  interface MessageItemClassNames {
1076
774
  root?: string;
1077
775
  /** Resolved per role so user/assistant/system bubbles can differ. */
@@ -1105,9 +803,9 @@ interface MessageRenderSlots {
1105
803
  * Extra content for the action row, after the built-in affordances and before usage — a badge
1106
804
  * naming which agent answered, a status pill. Rendered for every message that has an action row.
1107
805
  */
1108
- meta?: React.ReactNode;
806
+ meta?: React__default.ReactNode;
1109
807
  /** Label on the reasoning disclosure toggle. Default `"Reasoning"`. */
1110
- reasoningLabel?: React.ReactNode;
808
+ reasoningLabel?: React__default.ReactNode;
1111
809
  classNames?: MessageItemClassNames;
1112
810
  }
1113
811
  interface MessageItemProps extends MessageRenderSlots {
@@ -1140,9 +838,9 @@ interface MessageItemViewProps extends MessageRenderSlots {
1140
838
  * All of the logic lives in `useTranscriptItem`; this is one rendering of it. An app that wants
1141
839
  * different markup drives that hook and writes its own.
1142
840
  */
1143
- declare function MessageItem({ message, isStreaming, editable, onEditSubmit, regeneratable, onRegenerate, onFork, usage, createdAt, ...slots }: MessageItemProps): React.JSX.Element;
841
+ declare function MessageItem({ message, isStreaming, editable, onEditSubmit, regeneratable, onRegenerate, onFork, usage, createdAt, ...slots }: MessageItemProps): React__default.JSX.Element;
1144
842
  /** The default markup for one modelled message — what `MessageItem` renders once it has an item. */
1145
- declare function MessageItemView({ item, ...slots }: MessageItemViewProps): React.JSX.Element;
843
+ declare function MessageItemView({ item, ...slots }: MessageItemViewProps): React__default.JSX.Element;
1146
844
 
1147
845
  interface MessageListClassNames {
1148
846
  root?: string;
@@ -1167,9 +865,9 @@ interface MessageListProps {
1167
865
  renderFiles?: RenderFilesFn;
1168
866
  /** Draw a server-pushed component (a `ui` stream frame). Omitted → not drawn. */
1169
867
  renderUi?: RenderUiFn;
1170
- reasoningLabel?: React.ReactNode;
868
+ reasoningLabel?: React__default.ReactNode;
1171
869
  /** Extra content for one message's action row — e.g. a badge naming which agent answered. */
1172
- getMeta?: (message: UIMessage) => React.ReactNode;
870
+ getMeta?: (message: UIMessage) => React__default.ReactNode;
1173
871
  /** When set, every message gets a "Fork" affordance calling back with its id. */
1174
872
  onFork?: (uiMessageId: string) => void | Promise<void>;
1175
873
  /** User messages get an inline edit-and-resubmit affordance. */
@@ -1182,9 +880,9 @@ interface MessageListProps {
1182
880
  getUsage?: (message: UIMessage) => MessageUsageInfo | null;
1183
881
  getCreatedAt?: (message: UIMessage) => string | null;
1184
882
  /** Shown (with example/follow-up chips) when idle and empty. */
1185
- emptyState?: React.ReactNode;
883
+ emptyState?: React__default.ReactNode;
1186
884
  /** Node rendered while waiting for the first assistant token. */
1187
- typingIndicator?: React.ReactNode;
885
+ typingIndicator?: React__default.ReactNode;
1188
886
  /** AI-generated follow-up prompts under the last assistant message. */
1189
887
  followUps?: string[] | null;
1190
888
  onFollowUpClick?: (text: string) => void;
@@ -1202,7 +900,7 @@ interface MessageListProps {
1202
900
  * Every decision here comes from `useChatTranscript`; the file below it is markup. A host that
1203
901
  * wants a different layout drives that hook directly and never imports this component.
1204
902
  */
1205
- declare function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, renderUi, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames, }: MessageListProps): React.JSX.Element;
903
+ declare function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, renderUi, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames, }: MessageListProps): React__default.JSX.Element;
1206
904
 
1207
905
  /**
1208
906
  * Languages the dictation mic offers. The Web Speech API expects a
@@ -1336,7 +1034,8 @@ interface SkillSuggestionData {
1336
1034
  shadows?: string[];
1337
1035
  }
1338
1036
  interface SkillsSourceOptions {
1339
- client: AgentClient;
1037
+ /** Any backend with `listSkills` — `useAgentChat(...).backend`. */
1038
+ client: Pick<AgentBackend, 'listSkills'>;
1340
1039
  /**
1341
1040
  * Read at query time, not captured once: a threadless chat learns its id only when the backend
1342
1041
  * creates one on the first send, and a skill may be scoped to a conversation.
@@ -1372,10 +1071,10 @@ interface UseComposerAutocompleteOptions {
1372
1071
  }
1373
1072
  interface AutocompleteInputProps {
1374
1073
  ref: (element: HTMLTextAreaElement | HTMLInputElement | null) => void;
1375
- onChange: (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1376
- onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1377
- onSelect: (event: React.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1378
- onClick: (event: React.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1074
+ onChange: (event: React__default.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1075
+ onKeyDown: (event: React__default.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1076
+ onSelect: (event: React__default.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1077
+ onClick: (event: React__default.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
1379
1078
  role: 'combobox';
1380
1079
  'aria-expanded': boolean;
1381
1080
  'aria-autocomplete': 'list';
@@ -1430,12 +1129,15 @@ interface ComposerAutocomplete {
1430
1129
  */
1431
1130
  declare function useComposerAutocomplete(options: UseComposerAutocompleteOptions): ComposerAutocomplete;
1432
1131
 
1132
+ /** What the catalog needs of a backend. */
1133
+ type ToolsBackend = Pick<AgentBackend, 'listTools'>;
1134
+
1433
1135
  interface UseToolCatalogOptions {
1434
1136
  /**
1435
1137
  * The client to ask — `useAgentChat(...).client`, or one of your own. Must be STABLE across
1436
1138
  * renders (the shared copy is keyed by it): a client constructed inline refetches every render.
1437
1139
  */
1438
- client: AgentClient;
1140
+ client: ToolsBackend;
1439
1141
  /** The agent whose tools to list. Omitted → the server's default agent. */
1440
1142
  agent?: string;
1441
1143
  /** `false` holds the request (e.g. until the user is signed in). Default `true`. */
@@ -1529,6 +1231,16 @@ interface AggregatedTurnUsage {
1529
1231
  interface StoredTurnMetadata {
1530
1232
  usage: AggregatedTurnUsage;
1531
1233
  }
1234
+ /**
1235
+ * Everything a message's `metadata` may carry from this library: `usage` on a merged replayed turn,
1236
+ * `feedback` on a replayed message that was rated (a merged turn is rated through its last row,
1237
+ * whose id it carries), `runId` on a live-streamed one, `costUsd` from the stream's step ends.
1238
+ */
1239
+ interface AgentMessageMetadata extends Partial<StoredTurnMetadata> {
1240
+ feedback?: MessageFeedback;
1241
+ runId?: string;
1242
+ costUsd?: number | null;
1243
+ }
1532
1244
  /**
1533
1245
  * Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive
1534
1246
  * assistant rows (no user message between them) into ONE `UIMessage` per turn.
@@ -1569,7 +1281,19 @@ interface StoredTurnMetadata {
1569
1281
  */
1570
1282
  declare function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[];
1571
1283
 
1572
- interface UseAgentChatOptions {
1284
+ interface UseAgentChatOptions<B extends AgentBackend = AgentClient> {
1285
+ /**
1286
+ * What the chat talks to — see {@link AgentBackend}. Omitted → an {@link AgentClient} over this
1287
+ * library's REST routes, built from `baseUrl`, `headers`, `getHeaders`, `credentials` and `fetch`
1288
+ * (which are ignored when a backend is given). Must be stable across renders.
1289
+ */
1290
+ backend?: B;
1291
+ /**
1292
+ * Retry a stream that dropped mid-run from its last frame (`GET <base>/chat/:runId/stream?after=`),
1293
+ * with exponential backoff. `status` reads `'reconnecting'` meanwhile. Default on; `false` turns
1294
+ * it off.
1295
+ */
1296
+ reconnect?: ReconnectOptions | false;
1573
1297
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
1574
1298
  baseUrl?: string;
1575
1299
  /** Static headers merged into every request. */
@@ -1580,8 +1304,8 @@ interface UseAgentChatOptions {
1580
1304
  credentials?: RequestCredentials;
1581
1305
  /** Injectable for tests / non-browser runtimes. */
1582
1306
  fetch?: typeof fetch;
1583
- /** Reuse an existing client instead of constructing one. */
1584
- client?: AgentClient;
1307
+ /** Reuse an existing client instead of constructing one. Prefer {@link backend}. */
1308
+ client?: B;
1585
1309
  /** Named agent to run each turn. */
1586
1310
  agent?: string;
1587
1311
  /** Thread this chat is bound to. Omitted → backend creates one on send. */
@@ -1689,10 +1413,13 @@ interface AddToolResultArgs {
1689
1413
  * fork, quota, cancel, and HITL approve/reject — all driven through
1690
1414
  * `AgentClient`. Mirrors flip's `useAdminChat`, generalized.
1691
1415
  */
1692
- declare function useAgentChat(options: UseAgentChatOptions): {
1416
+ declare function useAgentChat<B extends AgentBackend = AgentClient>(options: UseAgentChatOptions<B>): {
1417
+ status: ChatStatus;
1418
+ /** Where the live stream stands — see {@link StreamConnectionState}. */
1419
+ connection: StreamConnectionState;
1693
1420
  sendMessage: (message?: (Omit<UIMessage<unknown, UIDataTypes, ai.UITools>, "id" | "role"> & {
1694
1421
  id?: string;
1695
- role?: "system" | "user" | "assistant";
1422
+ role?: "user" | "assistant" | "system";
1696
1423
  } & {
1697
1424
  text?: never;
1698
1425
  files?: never;
@@ -1715,7 +1442,15 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1715
1442
  runId: string | undefined;
1716
1443
  /** The `resume`-fetched thread's active run id, or `null` once resolved with none. */
1717
1444
  activeRunId: string | null;
1718
- client: AgentClient;
1445
+ /**
1446
+ * The thread this chat is on right now: the `threadId` option, else the one the backend created
1447
+ * on the first send. A getter, because the created id is learned mid-stream.
1448
+ */
1449
+ getThreadId: () => string | undefined;
1450
+ /** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
1451
+ backend: B;
1452
+ /** Same object as {@link backend}; kept for callers that read it under its old name. */
1453
+ client: B;
1719
1454
  threads: ThreadSummary[];
1720
1455
  loadThreads: () => Promise<ThreadSummary[]>;
1721
1456
  loadThread: (id: string) => Promise<ThreadDetail>;
@@ -1750,7 +1485,6 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1750
1485
  setMessages: (messages: UIMessage<unknown, UIDataTypes, ai.UITools>[] | ((messages: UIMessage<unknown, UIDataTypes, ai.UITools>[]) => UIMessage<unknown, UIDataTypes, ai.UITools>[])) => void;
1751
1486
  error: Error | undefined;
1752
1487
  stop: () => Promise<void>;
1753
- status: ai.ChatStatus;
1754
1488
  messages: UIMessage<unknown, UIDataTypes, ai.UITools>[];
1755
1489
  resumeStream: (options?: ai.ChatRequestOptions) => Promise<void>;
1756
1490
  addToolOutput: ai.ChatAddToolOutputFunction<UIMessage<unknown, UIDataTypes, ai.UITools>>;
@@ -1758,4 +1492,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1758
1492
  clearError: () => void;
1759
1493
  };
1760
1494
 
1761
- export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type ApprovalBlockOptions, type ApprovalCountdown, type ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type BuildBlocksOptions, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, type ChatStatus, type ChatTranscript, type CoercibleQuestion, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DescribeToolCallOptions, type ElicitationBlockOptions, type GroupToolActivityOptions, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RawAnswer, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResolvedReading, type ResolvedResultView, type RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, type ToolActivityGroup, type ToolCallDescription, type ToolCallState, type ToolCallStatus, type ToolCatalog, type ToolCatalogState, type TranscriptActionState, type TranscriptApproval, type TranscriptApprovalStatus, type TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, type TranscriptElicitationBlock, type TranscriptElicitationOutcome, type TranscriptFile, type TranscriptFilesBlock, type TranscriptItem, type TranscriptItemOptions, type TranscriptQuestion, type TranscriptQuestionOption, type TranscriptReasoningBlock, type TranscriptSettleState, type TranscriptSource, type TranscriptSourcesBlock, type TranscriptStopState, type TranscriptTextBlock, type TranscriptToolBlock, type TranscriptToolCall, type TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UsageSummary, type UseAgentChatOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, buildTranscriptBlocks, coerceAnswer, correctedCallIds, createSkillsSource, describeTimestamp, describeToolCall, describeUsage, extractMessageText, fillTemplate, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, groupToolActivity, inferResultView, isActionCall, loadStoredSpeechLang, persistSpeechLang, phraseFor, readPath, readReasoningMs, resolveResultView, storedMessageToUiMessage, storedThreadToUiMessages, toolCallState, toolCatalogFrom, useAgentChat, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };
1495
+ export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AggregatedTurnUsage, AnyToolUIPart, type ApprovalCountdown, ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatStreamRequest, type ChatStreamResponse, type ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type MessageFeedbackInput, type MessageFeedbackState, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type QuotaToday, type ReconnectOptions, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResumeStreamRequest, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, type ThreadPatch, type ThreadsEvent, type ThreadsState, TimestampInfo, ToolCatalog, type ToolCatalogState, type TranscriptActionState, TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, TranscriptFile, type TranscriptItem, type TranscriptItemOptions, type TranscriptStopState, TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };