@dudousxd/nestjs-agent-react 0.14.0 → 0.16.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.ts CHANGED
@@ -1,18 +1,180 @@
1
1
  import * as ai from 'ai';
2
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 } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, ModelCatalogView, AgentCatalogEntry, MessageFeedbackValue, MessageFeedback, ModelCatalogEntry, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
6
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-CMNhyau6.js';
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-CMNhyau6.js';
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.js';
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.js';
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
+ /** Pin a catalog model on the thread; `null` unpins it. */
19
+ model?: string | null;
20
+ }
21
+ /** Starting a turn: the body `POST <base>/chat` takes (see docs/stream-protocol.md). */
22
+ interface ChatStreamRequest {
23
+ /** `{ message, threadId?, agent?, model?, attachments?, pageContext?, regenerate?, … }`. */
24
+ body: Record<string, unknown>;
25
+ /** Per-request headers the AI SDK was handed for this send. */
26
+ headers?: Record<string, string>;
27
+ /** Aborted when the user stops the turn. */
28
+ signal?: AbortSignal;
29
+ }
30
+ /** Attaching to a run that is already streaming: `GET <base>/chat/:runId/stream?after=<seq>`. */
31
+ interface ResumeStreamRequest {
32
+ runId: string;
33
+ /**
34
+ * The sequence number (SSE `id:`) of the last frame the client already has. Omitted → replay
35
+ * from the first frame. A backend that cannot skip may ignore it: the transport also drops frames
36
+ * at or below it.
37
+ */
38
+ after?: number;
39
+ headers?: Record<string, string>;
40
+ signal?: AbortSignal;
41
+ }
42
+ /**
43
+ * An open chat stream: the raw `text/event-stream` bytes in the stream-protocol framing, plus the
44
+ * identity a backend may learn before the first frame (the `X-Agent-Run-Id` / `X-Agent-Thread-Id`
45
+ * headers). The body's own `event: meta` frame supplies them otherwise.
46
+ */
47
+ interface ChatStreamResponse {
48
+ body: ReadableStream<Uint8Array>;
49
+ runId?: string;
50
+ threadId?: string;
51
+ }
52
+ /** What `POST <base>/messages/:id/feedback` takes. `value: null` clears the rating. */
53
+ interface MessageFeedbackInput {
54
+ value: MessageFeedbackValue | null;
55
+ comment?: string;
56
+ }
57
+ interface UploadAttachmentOptions {
58
+ signal?: AbortSignal;
59
+ /** Called with 0..1 as the upload progresses, when the backend can observe it. */
60
+ onProgress?: (fraction: number) => void;
61
+ }
62
+ /**
63
+ * Everything the React layer asks of a server — the seam between `useAgentChat` (and the other
64
+ * hooks) and whatever serves the agent. {@link AgentClient} is the default implementation, over the
65
+ * library's own REST routes with `fetch`. An app with its own client — a generated one, a different
66
+ * auth scheme (cookie session + CSRF header), a backend that is not this library at all but speaks
67
+ * docs/stream-protocol.md — implements this instead and passes it as `useAgentChat({ backend })`.
68
+ *
69
+ * The streaming, thread and cancel members are required: without them there is no chat. The rest
70
+ * are optional; a hook that needs one the backend does not have throws
71
+ * {@link AgentBackendUnsupportedError} when it is called, so a backend only implements what its
72
+ * server supports.
73
+ */
74
+ interface AgentBackend {
75
+ /** Start a turn and return its SSE stream. Throw on a non-2xx answer. */
76
+ openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;
77
+ /** Attach to a streaming run. Resolve `null` when nothing is streaming under that id (HTTP 404). */
78
+ resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;
79
+ /** Hard-stop a run server-side. */
80
+ cancelStream(runId: string): Promise<unknown>;
81
+ listThreads(): Promise<ThreadSummary[]>;
82
+ getThread(id: string): Promise<ThreadDetail>;
83
+ updateThread(id: string, patch: ThreadPatch): Promise<unknown>;
84
+ deleteThread(id: string): Promise<unknown>;
85
+ forkFromMessage?(threadId: string, messageId: string): Promise<ThreadSummary>;
86
+ promoteThread?(id: string): Promise<unknown>;
87
+ truncateFromMessage?(threadId: string, messageId: string): Promise<unknown>;
88
+ approveToolCall?(input: {
89
+ toolCallId: string;
90
+ remember?: boolean;
91
+ via?: string;
92
+ }): Promise<unknown>;
93
+ rejectToolCall?(input: {
94
+ toolCallId: string;
95
+ reason?: string;
96
+ via?: string;
97
+ }): Promise<unknown>;
98
+ answerToolCall?(input: {
99
+ toolCallId: string;
100
+ answers?: Record<string, string[]>;
101
+ }): Promise<unknown>;
102
+ skipToolCall?(input: {
103
+ toolCallId: string;
104
+ }): Promise<unknown>;
105
+ uploadAttachment?(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
106
+ listTools?(agent?: string): Promise<ToolCatalogEntry[]>;
107
+ listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;
108
+ getQuotaToday?(): Promise<QuotaView>;
109
+ /** `GET <base>/models?agent=` — what a model picker offers. */
110
+ listModels?(agent?: string): Promise<ModelCatalogView>;
111
+ /** `GET <base>/agents` — what an agent picker offers. */
112
+ listAgents?(): Promise<AgentCatalogEntry[]>;
113
+ setMessageFeedback?(messageId: string, input: MessageFeedbackInput): Promise<{
114
+ feedback: MessageFeedback | null;
115
+ }>;
116
+ }
117
+ /** An optional {@link AgentBackend} member the bound backend does not implement was called. */
118
+ declare class AgentBackendUnsupportedError extends Error {
119
+ readonly method: string;
120
+ constructor(method: string);
121
+ }
122
+ type OptionalMethod = {
123
+ [K in keyof AgentBackend]-?: undefined extends AgentBackend[K] ? K : never;
124
+ }[keyof AgentBackend];
125
+ /**
126
+ * The optional backend method `name`, bound — or a throw naming it. For hook code that has to call
127
+ * something a backend may not offer.
128
+ */
129
+ declare function requireBackendMethod<K extends OptionalMethod>(backend: AgentBackend, name: K): NonNullable<AgentBackend[K]>;
9
130
 
10
131
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
11
132
  interface AgentStreamMeta {
12
133
  runId: string;
13
134
  threadId: string;
14
135
  }
136
+ /**
137
+ * How the transport retries a stream that dropped mid-run. It reconnects only to a server that
138
+ * numbers its frames (SSE `id:`) — without a cursor a reconnect would replay the run into the
139
+ * message it is already writing.
140
+ */
141
+ interface ReconnectOptions {
142
+ /** Attempts before giving up with an error chunk. Default 6. */
143
+ maxAttempts?: number;
144
+ /** Delay before the first attempt, doubled each attempt. Default 500 ms. */
145
+ baseDelayMs?: number;
146
+ /** Cap on the delay between attempts. Default 8000 ms. */
147
+ maxDelayMs?: number;
148
+ }
149
+ /** Where a live stream stands. `reconnecting` → it dropped and the transport is retrying. */
150
+ type StreamConnectionState = {
151
+ status: 'live';
152
+ } | {
153
+ status: 'reconnecting';
154
+ runId: string;
155
+ attempt: number;
156
+ after: number;
157
+ }
158
+ /** The run ended while the client was away (the resume answered 404): reload the thread. */
159
+ | {
160
+ status: 'gone';
161
+ runId: string;
162
+ }
163
+ /** Every attempt failed; the stream ended with an error chunk. */
164
+ | {
165
+ status: 'failed';
166
+ runId: string;
167
+ };
15
168
  interface AgentChatTransportOptions {
169
+ /**
170
+ * What the transport talks to. Default: an {@link AgentClient} built from `baseUrl`, `headers`,
171
+ * `getHeaders`, `credentials` and `fetch` below — which are ignored when a backend is given.
172
+ */
173
+ backend?: AgentBackend;
174
+ /** Retry a dropped stream from its last frame. Default on; `false` turns it off. */
175
+ reconnect?: ReconnectOptions | false;
176
+ /** Fires as a stream drops, reconnects, or gives up. */
177
+ onConnectionChange?: (state: StreamConnectionState) => void;
16
178
  /**
17
179
  * Origin + base path the agent endpoints hang off, e.g.
18
180
  * `https://api.example.com`. Endpoints are appended as
@@ -96,6 +258,7 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
96
258
  * several entries under each id — which React renders as duplicate keys.
97
259
  */
98
260
  private attemptLive;
261
+ private readonly backend;
99
262
  constructor(options?: AgentChatTransportOptions);
100
263
  /** Run id of the most recent stream — HITL approve/reject target this. */
101
264
  get runId(): string | undefined;
@@ -110,10 +273,8 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
110
273
  get isAttemptLive(): boolean;
111
274
  sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
112
275
  reconnectToStream(options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0]): Promise<ReadableStream<UIMessageChunk> | null>;
113
- private fetchImpl;
114
- private baseUrl;
115
- private resolveHeaders;
116
276
  private captureHeaderMeta;
277
+ private reconnectPolicy;
117
278
  private recordMeta;
118
279
  /**
119
280
  * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
@@ -131,6 +292,139 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
131
292
  private toChunkStream;
132
293
  }
133
294
 
295
+ interface UseAgentsOptions {
296
+ /** `useAgentChat(...).backend`, or your own. Must implement `listAgents`. */
297
+ backend: AgentBackend;
298
+ /** `false` holds the request. Default `true`. */
299
+ enabled?: boolean;
300
+ }
301
+ interface AgentsState {
302
+ /** `[]` until loaded. */
303
+ agents: AgentCatalogEntry[];
304
+ /** The agent a turn runs as when none is named. */
305
+ defaultAgent: string | null;
306
+ isLoading: boolean;
307
+ error: Error | null;
308
+ refresh: () => Promise<void>;
309
+ }
310
+ /**
311
+ * The registered agents (`GET <base>/agents`) — the data behind an agent picker. Send the pick as
312
+ * `useAgentChat({ agent })`, or pin it on a thread with `PATCH <base>/threads/:id { defaultAgent }`.
313
+ */
314
+ declare function useAgents(options: UseAgentsOptions): AgentsState;
315
+
316
+ interface UseModelsOptions {
317
+ /** `useAgentChat(...).backend`, or your own. Must implement `listModels`. */
318
+ backend: AgentBackend;
319
+ /** The agent to list models for; omitted → the default agent. */
320
+ agent?: string;
321
+ /** `false` holds the request. Default `true`. */
322
+ enabled?: boolean;
323
+ }
324
+ /** A catalog entry with the provider it sits under, for a flat list or a search. */
325
+ interface ModelOption extends ModelCatalogEntry {
326
+ providerId: string;
327
+ providerLabel: string;
328
+ }
329
+ interface ModelsState {
330
+ /** Grouped as the server sent them. `[]` until loaded. */
331
+ providers: ModelCatalogView['providers'];
332
+ /** Every model, flattened in provider order. */
333
+ models: ModelOption[];
334
+ /** The model a turn runs on when none is picked, or `null` when the provider decides. */
335
+ defaultModel: string | null;
336
+ /** The entry for `id`, or `undefined`. */
337
+ find: (id: string | null | undefined) => ModelOption | undefined;
338
+ isLoading: boolean;
339
+ error: Error | null;
340
+ refresh: () => Promise<void>;
341
+ }
342
+ /**
343
+ * The models this caller may pick (`GET <base>/models?agent=`), with badges and availability — the
344
+ * data behind a model picker. Headless: render the options however you like, then send the pick
345
+ * as `useAgentChat({ model })`, `sendMessage(msg, { body: { model } })`, or pin it on the thread
346
+ * with `chat.setThreadModel(id)`.
347
+ */
348
+ declare function useModels(options: UseModelsOptions): ModelsState;
349
+
350
+ interface UseMessageFeedbackOptions {
351
+ /** `useAgentChat(...).backend`, or your own. Must implement `setMessageFeedback`. */
352
+ backend: AgentBackend;
353
+ /**
354
+ * The thread the messages belong to — `useAgentChat(...).getThreadId`, or an id. Needed to rate a
355
+ * message streamed in this session: its id is the client's own, so the persisted row it became is
356
+ * looked up by the run that wrote it.
357
+ */
358
+ threadId?: string | (() => string | undefined);
359
+ }
360
+ interface MessageFeedbackState {
361
+ /** The rating to show: the one set in this session, else the persisted one, else `null`. */
362
+ feedbackOf: (message: UIMessage) => MessageFeedback | null;
363
+ /** A rating for this message is on its way to the server. */
364
+ isPending: (message: UIMessage) => boolean;
365
+ /** Set `'up'`/`'down'` (optionally with a comment), or clear with `null`. Optimistic. */
366
+ rate: (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => Promise<void>;
367
+ /** Thumbs-button semantics: the same value again clears it, another value replaces it. */
368
+ toggle: (message: UIMessage, value: MessageFeedbackValue) => Promise<void>;
369
+ /** The last failure; cleared by the next successful rating. */
370
+ error: Error | null;
371
+ }
372
+ /**
373
+ * Thumbs-up/down (+ comment) on assistant messages, over `POST <base>/messages/:id/feedback`.
374
+ * Headless: it holds the state and the calls, the host draws the buttons. A rating shows at once
375
+ * and rolls back if the server refuses it.
376
+ */
377
+ declare function useMessageFeedback(options: UseMessageFeedbackOptions): MessageFeedbackState;
378
+
379
+ /**
380
+ * What changed about a backend's thread list. `changed` → refetch (a thread was created, or a run
381
+ * settled and the server wrote its title); `title` → the stream announced a title, patch in place.
382
+ */
383
+ type ThreadsEvent = {
384
+ type: 'changed';
385
+ } | {
386
+ type: 'title';
387
+ threadId: string;
388
+ title: string;
389
+ } | {
390
+ type: 'removed';
391
+ threadId: string;
392
+ };
393
+ type Listener = (event: ThreadsEvent) => void;
394
+ /** Tell every {@link useThreads} on `backend` that its list moved. */
395
+ declare function notifyThreads(backend: AgentBackend, event: ThreadsEvent): void;
396
+ /** Subscribe to {@link notifyThreads} for `backend`; returns the unsubscribe. */
397
+ declare function onThreadsEvent(backend: AgentBackend, listener: Listener): () => void;
398
+
399
+ interface UseThreadsOptions {
400
+ /**
401
+ * The backend to list — `useAgentChat(...).backend`, or your own. Must be STABLE across renders:
402
+ * the list refreshes itself when a chat on the SAME backend creates a thread, settles a run or
403
+ * streams a title.
404
+ */
405
+ backend: AgentBackend;
406
+ /** `false` holds the first request (e.g. until the user is signed in). Default `true`. */
407
+ enabled?: boolean;
408
+ }
409
+ interface ThreadsState {
410
+ /** Newest first, as the server orders them. `[]` until loaded. */
411
+ threads: ThreadSummary[];
412
+ isLoading: boolean;
413
+ error: Error | null;
414
+ /** Ask the server again. */
415
+ refresh: () => Promise<void>;
416
+ /** Rename on the server; the list shows the new title at once and rolls back on failure. */
417
+ rename: (id: string, title: string) => Promise<void>;
418
+ /** Delete on the server; the thread leaves the list at once and comes back on failure. */
419
+ remove: (id: string) => Promise<void>;
420
+ }
421
+ /**
422
+ * The actor's conversations, kept current without the host wiring refetches: a chat on the same
423
+ * backend reports thread creation and settled runs (refetch) and streamed titles (patched in
424
+ * place). Headless — it renders nothing.
425
+ */
426
+ declare function useThreads(options: UseThreadsOptions): ThreadsState;
427
+
134
428
  /**
135
429
  * A sub-agent the conversation started and did not wait for. The chat is free while it works, so a
136
430
  * client has to be able to say what is still running and to show the answer when it lands — neither
@@ -180,34 +474,46 @@ interface CancelResult {
180
474
  interface OkResult {
181
475
  ok: boolean;
182
476
  }
183
- /**
184
- * Partial update accepted by `PATCH /agent/threads/:threadId`. `defaultAgent: null` clears a
185
- * previously-set default back to the module's own default; omitting it leaves the thread's
186
- * current default untouched.
187
- */
188
- interface ThreadPatch {
189
- title?: string;
190
- defaultAgent?: string | null;
191
- }
192
477
  interface AgentClientOptions {
193
478
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
194
479
  baseUrl?: string;
195
480
  /** Static headers merged into every request. */
196
481
  headers?: Record<string, string>;
197
- /** Resolved per request — for short-lived bearer tokens. */
482
+ /**
483
+ * Resolved per request — for short-lived bearer tokens, or a CSRF header read from a cookie
484
+ * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`), which has to be read at request time because
485
+ * the server may rotate it.
486
+ */
198
487
  getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
199
- /** Forwarded to fetch so cookie auth works. */
488
+ /**
489
+ * Forwarded to fetch so cookie auth works. Same-origin requests send cookies by default; set
490
+ * `'include'` when the API lives on another origin (and have it answer with credentialed CORS).
491
+ */
200
492
  credentials?: RequestCredentials;
201
493
  /** Injectable for tests / non-browser runtimes. */
202
494
  fetch?: typeof fetch;
203
495
  }
204
496
  /**
205
- * Framework-agnostic REST client for the nestjs-agent endpoints. Used by
206
- * `useAgentChat`, but standalone-usable (vanilla fetch, no React).
497
+ * Framework-agnostic REST client for the nestjs-agent endpoints — the default {@link AgentBackend}.
498
+ * Used by `useAgentChat`, but standalone-usable (vanilla fetch, no React).
207
499
  */
208
- declare class AgentClient {
500
+ declare class AgentClient implements AgentBackend {
209
501
  private readonly options;
210
502
  constructor(options?: AgentClientOptions);
503
+ /** `POST /agent/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */
504
+ openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;
505
+ /**
506
+ * `GET /agent/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is
507
+ * streaming under that id (404).
508
+ */
509
+ resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;
510
+ /**
511
+ * Rate a message (`'up'`/`'down'`, optional comment) or clear its rating (`value: null`). Answers
512
+ * the stored rating.
513
+ */
514
+ setMessageFeedback(messageId: string, input: MessageFeedbackInput): Promise<{
515
+ feedback: MessageFeedback | null;
516
+ }>;
211
517
  listThreads(): Promise<ThreadSummary[]>;
212
518
  /**
213
519
  * The skills this caller can invoke right now, scope-resolved — the same list, built by the same
@@ -233,9 +539,13 @@ declare class AgentClient {
233
539
  * mirrors the backend's `POST /agent/attachments`. The returned {@link MessageAttachment} is
234
540
  * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
235
541
  */
236
- uploadAttachment(file: File): Promise<MessageAttachment>;
542
+ uploadAttachment(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
237
543
  promoteThread(id: string): Promise<OkResult>;
238
544
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
545
+ /** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
546
+ listModels(agent?: string): Promise<ModelCatalogView>;
547
+ /** `GET /agent/agents` — the registered agents, the default one flagged. */
548
+ listAgents(): Promise<AgentCatalogEntry[]>;
239
549
  getQuotaToday(): Promise<QuotaToday>;
240
550
  cancelStream(runId: string): Promise<CancelResult>;
241
551
  /**
@@ -270,6 +580,10 @@ declare class AgentClient {
270
580
  skipToolCall(input: {
271
581
  toolCallId: string;
272
582
  }): Promise<void>;
583
+ private fetchImpl;
584
+ private baseUrl;
585
+ private resolveHeaders;
586
+ private credentials;
273
587
  private request;
274
588
  private handleResponse;
275
589
  }
@@ -785,7 +1099,8 @@ interface SkillSuggestionData {
785
1099
  shadows?: string[];
786
1100
  }
787
1101
  interface SkillsSourceOptions {
788
- client: AgentClient;
1102
+ /** Any backend with `listSkills` — `useAgentChat(...).backend`. */
1103
+ client: Pick<AgentBackend, 'listSkills'>;
789
1104
  /**
790
1105
  * Read at query time, not captured once: a threadless chat learns its id only when the backend
791
1106
  * creates one on the first send, and a skill may be scoped to a conversation.
@@ -879,12 +1194,15 @@ interface ComposerAutocomplete {
879
1194
  */
880
1195
  declare function useComposerAutocomplete(options: UseComposerAutocompleteOptions): ComposerAutocomplete;
881
1196
 
1197
+ /** What the catalog needs of a backend. */
1198
+ type ToolsBackend = Pick<AgentBackend, 'listTools'>;
1199
+
882
1200
  interface UseToolCatalogOptions {
883
1201
  /**
884
1202
  * The client to ask — `useAgentChat(...).client`, or one of your own. Must be STABLE across
885
1203
  * renders (the shared copy is keyed by it): a client constructed inline refetches every render.
886
1204
  */
887
- client: AgentClient;
1205
+ client: ToolsBackend;
888
1206
  /** The agent whose tools to list. Omitted → the server's default agent. */
889
1207
  agent?: string;
890
1208
  /** `false` holds the request (e.g. until the user is signed in). Default `true`. */
@@ -978,6 +1296,16 @@ interface AggregatedTurnUsage {
978
1296
  interface StoredTurnMetadata {
979
1297
  usage: AggregatedTurnUsage;
980
1298
  }
1299
+ /**
1300
+ * Everything a message's `metadata` may carry from this library: `usage` on a merged replayed turn,
1301
+ * `feedback` on a replayed message that was rated (a merged turn is rated through its last row,
1302
+ * whose id it carries), `runId` on a live-streamed one, `costUsd` from the stream's step ends.
1303
+ */
1304
+ interface AgentMessageMetadata extends Partial<StoredTurnMetadata> {
1305
+ feedback?: MessageFeedback;
1306
+ runId?: string;
1307
+ costUsd?: number | null;
1308
+ }
981
1309
  /**
982
1310
  * Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive
983
1311
  * assistant rows (no user message between them) into ONE `UIMessage` per turn.
@@ -1018,7 +1346,19 @@ interface StoredTurnMetadata {
1018
1346
  */
1019
1347
  declare function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[];
1020
1348
 
1021
- interface UseAgentChatOptions {
1349
+ interface UseAgentChatOptions<B extends AgentBackend = AgentClient> {
1350
+ /**
1351
+ * What the chat talks to — see {@link AgentBackend}. Omitted → an {@link AgentClient} over this
1352
+ * library's REST routes, built from `baseUrl`, `headers`, `getHeaders`, `credentials` and `fetch`
1353
+ * (which are ignored when a backend is given). Must be stable across renders.
1354
+ */
1355
+ backend?: B;
1356
+ /**
1357
+ * Retry a stream that dropped mid-run from its last frame (`GET <base>/chat/:runId/stream?after=`),
1358
+ * with exponential backoff. `status` reads `'reconnecting'` meanwhile. Default on; `false` turns
1359
+ * it off.
1360
+ */
1361
+ reconnect?: ReconnectOptions | false;
1022
1362
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
1023
1363
  baseUrl?: string;
1024
1364
  /** Static headers merged into every request. */
@@ -1029,10 +1369,16 @@ interface UseAgentChatOptions {
1029
1369
  credentials?: RequestCredentials;
1030
1370
  /** Injectable for tests / non-browser runtimes. */
1031
1371
  fetch?: typeof fetch;
1032
- /** Reuse an existing client instead of constructing one. */
1033
- client?: AgentClient;
1372
+ /** Reuse an existing client instead of constructing one. Prefer {@link backend}. */
1373
+ client?: B;
1034
1374
  /** Named agent to run each turn. */
1035
1375
  agent?: string;
1376
+ /**
1377
+ * Catalog model to run each turn on (see `useModels`), sent as the body's `model`. Read at every
1378
+ * send, so a picker can change it between turns. Omitted → the thread's pinned model, else the
1379
+ * server default. A single send can still override it with `sendMessage(msg, { body: { model } })`.
1380
+ */
1381
+ model?: string;
1036
1382
  /** Thread this chat is bound to. Omitted → backend creates one on send. */
1037
1383
  threadId?: string;
1038
1384
  /** Persisted history to seed `useChat` with (consumed on mount only). */
@@ -1138,10 +1484,13 @@ interface AddToolResultArgs {
1138
1484
  * fork, quota, cancel, and HITL approve/reject — all driven through
1139
1485
  * `AgentClient`. Mirrors flip's `useAdminChat`, generalized.
1140
1486
  */
1141
- declare function useAgentChat(options: UseAgentChatOptions): {
1487
+ declare function useAgentChat<B extends AgentBackend = AgentClient>(options: UseAgentChatOptions<B>): {
1488
+ status: ChatStatus;
1489
+ /** Where the live stream stands — see {@link StreamConnectionState}. */
1490
+ connection: StreamConnectionState;
1142
1491
  sendMessage: (message?: (Omit<UIMessage<unknown, UIDataTypes, ai.UITools>, "id" | "role"> & {
1143
1492
  id?: string;
1144
- role?: "system" | "user" | "assistant";
1493
+ role?: "user" | "assistant" | "system";
1145
1494
  } & {
1146
1495
  text?: never;
1147
1496
  files?: never;
@@ -1164,7 +1513,16 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1164
1513
  runId: string | undefined;
1165
1514
  /** The `resume`-fetched thread's active run id, or `null` once resolved with none. */
1166
1515
  activeRunId: string | null;
1167
- client: AgentClient;
1516
+ /**
1517
+ * The thread this chat is on right now: the `threadId` option, else the one the backend created
1518
+ * on the first send. A getter, because the created id is learned mid-stream.
1519
+ */
1520
+ getThreadId: () => string | undefined;
1521
+ setThreadModel: (model: string | null) => Promise<void>;
1522
+ /** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
1523
+ backend: B;
1524
+ /** Same object as {@link backend}; kept for callers that read it under its old name. */
1525
+ client: B;
1168
1526
  threads: ThreadSummary[];
1169
1527
  loadThreads: () => Promise<ThreadSummary[]>;
1170
1528
  loadThread: (id: string) => Promise<ThreadDetail>;
@@ -1199,7 +1557,6 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1199
1557
  setMessages: (messages: UIMessage<unknown, UIDataTypes, ai.UITools>[] | ((messages: UIMessage<unknown, UIDataTypes, ai.UITools>[]) => UIMessage<unknown, UIDataTypes, ai.UITools>[])) => void;
1200
1558
  error: Error | undefined;
1201
1559
  stop: () => Promise<void>;
1202
- status: ai.ChatStatus;
1203
1560
  messages: UIMessage<unknown, UIDataTypes, ai.UITools>[];
1204
1561
  resumeStream: (options?: ai.ChatRequestOptions) => Promise<void>;
1205
1562
  addToolOutput: ai.ChatAddToolOutputFunction<UIMessage<unknown, UIDataTypes, ai.UITools>>;
@@ -1207,4 +1564,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1207
1564
  clearError: () => void;
1208
1565
  };
1209
1566
 
1210
- export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, 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 ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type QuotaToday, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, 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, UsageSummary, type UseAgentChatOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, persistSpeechLang, readReasoningMs, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };
1567
+ export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AgentsState, 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 ModelOption, type ModelsState, 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 UseAgentsOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseModelsOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useAgents, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };