@dudousxd/nestjs-agent-react 0.19.0 → 0.21.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.js CHANGED
@@ -14,6 +14,11 @@ var AgentHttpError = class extends Error {
14
14
  this.name = "AgentHttpError";
15
15
  }
16
16
  };
17
+ function normalizeAgentPath(path) {
18
+ const trimmed = (path ?? "agent").replace(/^\/+|\/+$/g, "");
19
+ return trimmed === "" ? "" : `/${trimmed}`;
20
+ }
21
+ __name(normalizeAgentPath, "normalizeAgentPath");
17
22
  var HEADER_RUN_ID = "x-agent-run-id";
18
23
  var HEADER_THREAD_ID = "x-agent-thread-id";
19
24
  var AgentClient = class {
@@ -24,9 +29,9 @@ var AgentClient = class {
24
29
  constructor(options = {}) {
25
30
  this.options = options;
26
31
  }
27
- /** `POST /agent/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */
32
+ /** `POST <path>/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */
28
33
  async openChatStream(request) {
29
- const response = await this.fetchImpl()(`${this.baseUrl()}/agent/chat`, {
34
+ const response = await this.fetchImpl()(`${this.root()}/chat`, {
30
35
  method: "POST",
31
36
  headers: {
32
37
  "content-type": "application/json",
@@ -41,18 +46,18 @@ var AgentClient = class {
41
46
  } : {}
42
47
  });
43
48
  if (!response.ok || !response.body) {
44
- throw new AgentHttpError(response.status, "POST", "/agent/chat", response.statusText);
49
+ throw new AgentHttpError(response.status, "POST", `${this.agentPath()}/chat`, response.statusText);
45
50
  }
46
51
  return streamResponse(response);
47
52
  }
48
53
  /**
49
- * `GET /agent/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is
54
+ * `GET <path>/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is
50
55
  * streaming under that id (404).
51
56
  */
52
57
  async resumeChatStream(request) {
53
- const path = `/agent/chat/${encodeURIComponent(request.runId)}/stream`;
58
+ const path = `/chat/${encodeURIComponent(request.runId)}/stream`;
54
59
  const query = request.after !== void 0 && request.after > 0 ? `?after=${request.after}` : "";
55
- const response = await this.fetchImpl()(`${this.baseUrl()}${path}${query}`, {
60
+ const response = await this.fetchImpl()(`${this.root()}${path}${query}`, {
56
61
  method: "GET",
57
62
  headers: {
58
63
  accept: "text/event-stream",
@@ -68,7 +73,7 @@ var AgentClient = class {
68
73
  return null;
69
74
  }
70
75
  if (!response.ok || !response.body) {
71
- throw new AgentHttpError(response.status, "GET", path, response.statusText);
76
+ throw new AgentHttpError(response.status, "GET", `${this.agentPath()}${path}`, response.statusText);
72
77
  }
73
78
  return streamResponse(response);
74
79
  }
@@ -77,10 +82,10 @@ var AgentClient = class {
77
82
  * the stored rating.
78
83
  */
79
84
  setMessageFeedback(messageId, input) {
80
- return this.request("POST", `/agent/messages/${encodeURIComponent(messageId)}/feedback`, input);
85
+ return this.request("POST", `/messages/${encodeURIComponent(messageId)}/feedback`, input);
81
86
  }
82
87
  listThreads() {
83
- return this.request("GET", "/agent/threads");
88
+ return this.request("GET", "/threads");
84
89
  }
85
90
  /**
86
91
  * The skills this caller can invoke right now, scope-resolved — the same list, built by the same
@@ -90,7 +95,7 @@ var AgentClient = class {
90
95
  */
91
96
  listSkills(threadId) {
92
97
  const query = threadId === void 0 ? "" : `?threadId=${encodeURIComponent(threadId)}`;
93
- return this.request("GET", `/agent/skills${query}`);
98
+ return this.request("GET", `/skills${query}`);
94
99
  }
95
100
  /**
96
101
  * The tools this caller can reach through `agent` (the default agent when omitted), each with the
@@ -99,38 +104,42 @@ var AgentClient = class {
99
104
  */
100
105
  listTools(agent) {
101
106
  const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
102
- return this.request("GET", `/agent/tools${query}`);
107
+ return this.request("GET", `/tools${query}`);
103
108
  }
104
109
  getThread(id) {
105
- return this.request("GET", `/agent/threads/${encodeURIComponent(id)}`);
110
+ return this.request("GET", `/threads/${encodeURIComponent(id)}`);
106
111
  }
107
112
  deleteThread(id) {
108
- return this.request("DELETE", `/agent/threads/${encodeURIComponent(id)}`);
113
+ return this.request("DELETE", `/threads/${encodeURIComponent(id)}`);
109
114
  }
110
115
  forkFromMessage(threadId, messageId) {
111
- return this.request("POST", `/agent/threads/${encodeURIComponent(threadId)}/fork-from/${encodeURIComponent(messageId)}`);
116
+ return this.request("POST", `/threads/${encodeURIComponent(threadId)}/fork-from/${encodeURIComponent(messageId)}`);
112
117
  }
113
118
  renameThread(id, title) {
114
119
  return this.updateThread(id, {
115
120
  title
116
121
  });
117
122
  }
118
- /** General `PATCH /agent/threads/:threadId` — title and/or the thread's pinned default agent. */
123
+ /** General `PATCH <path>/threads/:threadId` — title and/or the thread's pinned default agent. */
119
124
  updateThread(id, patch) {
120
- return this.request("PATCH", `/agent/threads/${encodeURIComponent(id)}`, patch);
125
+ return this.request("PATCH", `/threads/${encodeURIComponent(id)}`, patch);
121
126
  }
122
127
  /**
123
128
  * Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —
124
- * mirrors the backend's `POST /agent/attachments`. The returned {@link MessageAttachment} is
129
+ * mirrors the backend's `POST <path>/attachments`. The returned {@link MessageAttachment} is
125
130
  * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
126
131
  */
127
132
  async uploadAttachment(file, options = {}) {
133
+ const upload = this.options.attachments?.upload;
134
+ if (upload !== void 0) {
135
+ return upload(file, options, this.connection());
136
+ }
128
137
  if (options.onProgress !== void 0 && this.options.fetch === void 0 && typeof XMLHttpRequest !== "undefined") {
129
138
  return this.uploadWithProgress(file, options);
130
139
  }
131
140
  const formData = new FormData();
132
141
  formData.append("file", file);
133
- const response = await this.fetchImpl()(`${this.baseUrl()}/agent/attachments`, {
142
+ const response = await this.fetchImpl()(`${this.root()}/attachments`, {
134
143
  method: "POST",
135
144
  headers: {
136
145
  accept: "application/json",
@@ -142,7 +151,7 @@ var AgentClient = class {
142
151
  signal: options.signal
143
152
  } : {}
144
153
  });
145
- const attachment = await this.handleResponse(response, "POST", "/agent/attachments");
154
+ const attachment = await this.handleResponse(response, "POST", `${this.agentPath()}/attachments`);
146
155
  options.onProgress?.(1);
147
156
  return attachment;
148
157
  }
@@ -151,7 +160,7 @@ var AgentClient = class {
151
160
  accept: "application/json",
152
161
  ...await this.resolveHeaders()
153
162
  };
154
- const url = `${this.baseUrl()}/agent/attachments`;
163
+ const url = `${this.root()}/attachments`;
155
164
  return new Promise((resolve, reject) => {
156
165
  const xhr = new XMLHttpRequest();
157
166
  xhr.open("POST", url);
@@ -162,7 +171,7 @@ var AgentClient = class {
162
171
  };
163
172
  xhr.onload = () => {
164
173
  if (xhr.status < 200 || xhr.status >= 300) {
165
- reject(new AgentHttpError(xhr.status, "POST", "/agent/attachments", xhr.statusText));
174
+ reject(new AgentHttpError(xhr.status, "POST", `${this.agentPath()}/attachments`, xhr.statusText));
166
175
  return;
167
176
  }
168
177
  onProgress?.(1);
@@ -185,39 +194,39 @@ var AgentClient = class {
185
194
  });
186
195
  }
187
196
  promoteThread(id) {
188
- return this.request("POST", `/agent/threads/${encodeURIComponent(id)}/promote`);
197
+ return this.request("POST", `/threads/${encodeURIComponent(id)}/promote`);
189
198
  }
190
199
  truncateFromMessage(threadId, messageId) {
191
- return this.request("DELETE", `/agent/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`);
200
+ return this.request("DELETE", `/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`);
192
201
  }
193
- /** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
202
+ /** `GET <path>/models?agent=` — the models this caller may pick, grouped by provider. */
194
203
  listModels(agent) {
195
204
  const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
196
- return this.request("GET", `/agent/models${query}`);
205
+ return this.request("GET", `/models${query}`);
197
206
  }
198
- /** `GET /agent/agents` — the registered agents, the default one flagged. */
207
+ /** `GET <path>/agents` — the registered agents, the default one flagged. */
199
208
  listAgents() {
200
- return this.request("GET", "/agent/agents");
209
+ return this.request("GET", "/agents");
201
210
  }
202
- /** `GET /agent/quota` — the caller's budget windows and the one blocking sends, if any. */
211
+ /** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */
203
212
  getQuota() {
204
- return this.request("GET", "/agent/quota");
213
+ return this.request("GET", "/quota");
205
214
  }
206
215
  getQuotaToday() {
207
- return this.request("GET", "/agent/quota/today");
216
+ return this.request("GET", "/quota/today");
208
217
  }
209
218
  cancelStream(runId) {
210
- return this.request("POST", `/agent/chat/${encodeURIComponent(runId)}/cancel`);
219
+ return this.request("POST", `/chat/${encodeURIComponent(runId)}/cancel`);
211
220
  }
212
221
  /**
213
222
  * `remember` approves later calls of the same tool in the same thread; `via` names the surface
214
223
  * the decision came through (the server records `'web'` when omitted).
215
224
  */
216
225
  approveToolCall(input) {
217
- return this.request("POST", "/agent/tool-call/approve", input);
226
+ return this.request("POST", "/tool-call/approve", input);
218
227
  }
219
228
  rejectToolCall(input) {
220
- return this.request("POST", "/agent/tool-call/reject", input);
229
+ return this.request("POST", "/tool-call/reject", input);
221
230
  }
222
231
  /**
223
232
  * Settle a parked question set. `answers` is questionId → chosen option values; a question left
@@ -226,7 +235,7 @@ var AgentClient = class {
226
235
  * answer — which is the point of the surface, so it is a valid submission rather than a blank.
227
236
  */
228
237
  answerToolCall(input) {
229
- return this.request("POST", "/agent/tool-call/answer", input);
238
+ return this.request("POST", "/tool-call/answer", input);
230
239
  }
231
240
  /**
232
241
  * Decline to answer and let the agent proceed on its own pre-picked values. Lands on the same
@@ -234,13 +243,30 @@ var AgentClient = class {
234
243
  * evidence the user chose them.
235
244
  */
236
245
  skipToolCall(input) {
237
- return this.request("POST", "/agent/tool-call/skip", input);
246
+ return this.request("POST", "/tool-call/skip", input);
238
247
  }
239
248
  fetchImpl() {
240
249
  return this.options.fetch ?? globalThis.fetch;
241
250
  }
251
+ /** This client's connection, for an {@link AttachmentUploadStrategy}. */
252
+ connection() {
253
+ return {
254
+ baseUrl: this.baseUrl(),
255
+ path: this.agentPath(),
256
+ headers: /* @__PURE__ */ __name(() => this.resolveHeaders(), "headers"),
257
+ fetch: this.fetchImpl(),
258
+ ...this.credentials()
259
+ };
260
+ }
242
261
  baseUrl() {
243
- return (this.options.baseUrl ?? "").replace(/\/$/, "");
262
+ return (this.options.baseUrl ?? "").replace(/\/+$/, "");
263
+ }
264
+ agentPath() {
265
+ return normalizeAgentPath(this.options.path);
266
+ }
267
+ /** Origin + agent path: what every route hangs off. */
268
+ root() {
269
+ return `${this.baseUrl()}${this.agentPath()}`;
244
270
  }
245
271
  async resolveHeaders() {
246
272
  const dynamic = await this.options.getHeaders?.() ?? {};
@@ -254,7 +280,8 @@ var AgentClient = class {
254
280
  credentials: this.options.credentials
255
281
  } : {};
256
282
  }
257
- async request(method, path, body) {
283
+ async request(method, route, body) {
284
+ const path = `${this.agentPath()}${route}`;
258
285
  const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {
259
286
  method,
260
287
  headers: {
@@ -385,6 +412,9 @@ var AgentChatTransport = class {
385
412
  ...options.baseUrl !== void 0 ? {
386
413
  baseUrl: options.baseUrl
387
414
  } : {},
415
+ ...options.path !== void 0 ? {
416
+ path: options.path
417
+ } : {},
388
418
  ...options.headers !== void 0 ? {
389
419
  headers: options.headers
390
420
  } : {},
@@ -1090,7 +1120,7 @@ function dragHasFiles(data) {
1090
1120
  __name(dragHasFiles, "dragHasFiles");
1091
1121
 
1092
1122
  // src/attachments/use-attachments.ts
1093
- import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
1123
+ import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
1094
1124
 
1095
1125
  // src/backend.ts
1096
1126
  var AgentBackendUnsupportedError = class extends Error {
@@ -1112,6 +1142,570 @@ function requireBackendMethod(backend, name) {
1112
1142
  }
1113
1143
  __name(requireBackendMethod, "requireBackendMethod");
1114
1144
 
1145
+ // src/provider.tsx
1146
+ import { useContext as useContext3, useMemo as useMemo3, useRef as useRef2 } from "react";
1147
+
1148
+ // src/components/ambient-ui.ts
1149
+ import { createContext, useContext } from "react";
1150
+ function sharedContext(key) {
1151
+ const symbol = Symbol.for(key);
1152
+ const holder = globalThis;
1153
+ const existing = holder[symbol];
1154
+ if (existing !== void 0) return existing;
1155
+ const created = createContext(null);
1156
+ holder[symbol] = created;
1157
+ return created;
1158
+ }
1159
+ __name(sharedContext, "sharedContext");
1160
+ var AmbientRenderUiContext = sharedContext("@dudousxd/nestjs-agent-react:ambient-render-ui");
1161
+ function useAmbientRenderUi() {
1162
+ return useContext(AmbientRenderUiContext);
1163
+ }
1164
+ __name(useAmbientRenderUi, "useAmbientRenderUi");
1165
+
1166
+ // src/genui/generative-ui.tsx
1167
+ import { Component, createContext as createContext2, useCallback, useContext as useContext2, useMemo as useMemo2 } from "react";
1168
+
1169
+ // src/genui/use-generative-ui.ts
1170
+ import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
1171
+
1172
+ // src/genui/types.ts
1173
+ var GENUI_TREE_COMPONENT = "genui:tree";
1174
+
1175
+ // src/genui/use-generative-ui.ts
1176
+ function isRecord(value) {
1177
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1178
+ }
1179
+ __name(isRecord, "isRecord");
1180
+ function toGenerativeUIItem(part) {
1181
+ if (!isRecord(part)) return null;
1182
+ const source = part.type === "data-ui" && isRecord(part.data) ? part.data : part;
1183
+ if (typeof source.component !== "string") return null;
1184
+ const id = typeof source.id === "string" ? source.id : typeof part.id === "string" ? part.id : null;
1185
+ if (id === null) return null;
1186
+ return {
1187
+ id,
1188
+ component: source.component,
1189
+ props: isRecord(source.props) ? source.props : {},
1190
+ version: typeof source.version === "number" ? source.version : null,
1191
+ toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
1192
+ };
1193
+ }
1194
+ __name(toGenerativeUIItem, "toGenerativeUIItem");
1195
+ var resolverCaches = /* @__PURE__ */ new WeakMap();
1196
+ function resolveCached(resolve, name, version) {
1197
+ let cache = resolverCaches.get(resolve);
1198
+ if (cache === void 0) {
1199
+ cache = /* @__PURE__ */ new Map();
1200
+ resolverCaches.set(resolve, cache);
1201
+ }
1202
+ const key = `${name}@${version ?? ""}`;
1203
+ const hit = cache.get(key);
1204
+ if (hit !== void 0) return hit;
1205
+ let entry;
1206
+ try {
1207
+ const result = resolve(name, version);
1208
+ if (result instanceof Promise) {
1209
+ entry = {
1210
+ resolution: {
1211
+ status: "loading"
1212
+ },
1213
+ settled: null
1214
+ };
1215
+ entry.settled = result.then((Component2) => {
1216
+ entry.resolution = Component2 ? {
1217
+ status: "ready",
1218
+ Component: Component2
1219
+ } : {
1220
+ status: "unknown"
1221
+ };
1222
+ }, (error) => {
1223
+ entry.resolution = {
1224
+ status: "error",
1225
+ error
1226
+ };
1227
+ });
1228
+ } else {
1229
+ entry = {
1230
+ resolution: result ? {
1231
+ status: "ready",
1232
+ Component: result
1233
+ } : {
1234
+ status: "unknown"
1235
+ },
1236
+ settled: null
1237
+ };
1238
+ }
1239
+ } catch (error) {
1240
+ entry = {
1241
+ resolution: {
1242
+ status: "error",
1243
+ error
1244
+ },
1245
+ settled: null
1246
+ };
1247
+ }
1248
+ cache.set(key, entry);
1249
+ return entry;
1250
+ }
1251
+ __name(resolveCached, "resolveCached");
1252
+ function useResolvedComponent(name, version, registry, resolve, fallbackTree) {
1253
+ const [, setTick] = useState2(0);
1254
+ const own = registry[name];
1255
+ const entry = own !== void 0 || resolve === void 0 ? null : resolveCached(resolve, name, version);
1256
+ const pending = entry?.resolution.status === "loading" ? entry.settled : null;
1257
+ useEffect2(() => {
1258
+ if (pending === null) return;
1259
+ let live = true;
1260
+ void pending.then(() => {
1261
+ if (live) setTick((tick) => tick + 1);
1262
+ });
1263
+ return () => {
1264
+ live = false;
1265
+ };
1266
+ }, [
1267
+ pending
1268
+ ]);
1269
+ if (own !== void 0) return {
1270
+ status: "ready",
1271
+ Component: own
1272
+ };
1273
+ if (entry !== null && entry.resolution.status !== "unknown") return entry.resolution;
1274
+ if (name === GENUI_TREE_COMPONENT && fallbackTree !== void 0) {
1275
+ return {
1276
+ status: "ready",
1277
+ Component: fallbackTree
1278
+ };
1279
+ }
1280
+ return {
1281
+ status: "unknown"
1282
+ };
1283
+ }
1284
+ __name(useResolvedComponent, "useResolvedComponent");
1285
+ function useValidatedProps(catalog, name, props) {
1286
+ const checked = catalog?.has(name) === true;
1287
+ const immediate = useMemo(() => {
1288
+ if (!checked || catalog === void 0) return {
1289
+ status: "ok",
1290
+ props
1291
+ };
1292
+ const result = catalog.validateSync?.(name, props);
1293
+ if (result === void 0) return null;
1294
+ return result.ok ? {
1295
+ status: "ok",
1296
+ props: result.value
1297
+ } : {
1298
+ status: "invalid",
1299
+ issues: result.issues
1300
+ };
1301
+ }, [
1302
+ checked,
1303
+ catalog,
1304
+ name,
1305
+ props
1306
+ ]);
1307
+ const [late, setLate] = useState2(null);
1308
+ useEffect2(() => {
1309
+ if (immediate !== null || catalog === void 0) return;
1310
+ let live = true;
1311
+ catalog.validate(name, props).then((result) => {
1312
+ if (!live) return;
1313
+ setLate({
1314
+ props,
1315
+ result: result.ok ? {
1316
+ status: "ok",
1317
+ props: result.value
1318
+ } : {
1319
+ status: "invalid",
1320
+ issues: result.issues
1321
+ }
1322
+ });
1323
+ }, (error) => {
1324
+ if (!live) return;
1325
+ setLate({
1326
+ props,
1327
+ result: {
1328
+ status: "invalid",
1329
+ issues: [
1330
+ {
1331
+ path: [],
1332
+ message: error instanceof Error ? error.message : String(error)
1333
+ }
1334
+ ]
1335
+ }
1336
+ });
1337
+ });
1338
+ return () => {
1339
+ live = false;
1340
+ };
1341
+ }, [
1342
+ immediate,
1343
+ catalog,
1344
+ name,
1345
+ props
1346
+ ]);
1347
+ if (immediate !== null) return immediate;
1348
+ return late !== null && late.props === props ? late.result : {
1349
+ status: "pending"
1350
+ };
1351
+ }
1352
+ __name(useValidatedProps, "useValidatedProps");
1353
+ function useGenerativeUIState(part, options, fallbackTree) {
1354
+ const item = useMemo(() => toGenerativeUIItem(part), [
1355
+ part
1356
+ ]);
1357
+ const name = item?.component ?? "";
1358
+ const resolution = useResolvedComponent(name, item?.version ?? null, options.registry, item === null ? void 0 : options.resolveComponent, fallbackTree);
1359
+ const empty = useMemo(() => ({}), []);
1360
+ const validation = useValidatedProps(item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog, name, item?.props ?? empty);
1361
+ if (item === null) return null;
1362
+ if (resolution.status === "loading") return {
1363
+ status: "loading",
1364
+ item
1365
+ };
1366
+ if (resolution.status === "unknown") return {
1367
+ status: "problem",
1368
+ reason: "unknown",
1369
+ item
1370
+ };
1371
+ if (resolution.status === "error") {
1372
+ return {
1373
+ status: "problem",
1374
+ reason: "error",
1375
+ item,
1376
+ error: resolution.error
1377
+ };
1378
+ }
1379
+ if (validation.status === "pending") return {
1380
+ status: "loading",
1381
+ item
1382
+ };
1383
+ if (validation.status === "invalid") {
1384
+ return {
1385
+ status: "problem",
1386
+ reason: "invalid",
1387
+ item,
1388
+ issues: validation.issues
1389
+ };
1390
+ }
1391
+ return {
1392
+ status: "ready",
1393
+ item,
1394
+ Component: resolution.Component,
1395
+ props: validation.props
1396
+ };
1397
+ }
1398
+ __name(useGenerativeUIState, "useGenerativeUIState");
1399
+
1400
+ // src/genui/generative-ui.tsx
1401
+ var TreeScopeContext = /* @__PURE__ */ createContext2(null);
1402
+ function renderFallback(fallback2, problem) {
1403
+ if (typeof fallback2 === "function") return fallback2(problem);
1404
+ return fallback2 ?? null;
1405
+ }
1406
+ __name(renderFallback, "renderFallback");
1407
+ var ItemBoundary = class ItemBoundary2 extends Component {
1408
+ static {
1409
+ __name(this, "ItemBoundary");
1410
+ }
1411
+ state = {
1412
+ error: void 0,
1413
+ failed: false
1414
+ };
1415
+ static getDerivedStateFromError(error) {
1416
+ return {
1417
+ error,
1418
+ failed: true
1419
+ };
1420
+ }
1421
+ componentDidCatch(error, _info) {
1422
+ this.props.onError?.(error, this.props.item);
1423
+ }
1424
+ componentDidUpdate(previous) {
1425
+ if (this.state.failed && previous.item !== this.props.item) {
1426
+ this.setState({
1427
+ error: void 0,
1428
+ failed: false
1429
+ });
1430
+ }
1431
+ }
1432
+ render() {
1433
+ if (this.state.failed) {
1434
+ return renderFallback(this.props.fallback, {
1435
+ reason: "error",
1436
+ item: this.props.item,
1437
+ error: this.state.error
1438
+ });
1439
+ }
1440
+ return this.props.children;
1441
+ }
1442
+ };
1443
+ function nodeItem(node, id) {
1444
+ return {
1445
+ id,
1446
+ component: node.type,
1447
+ props: node.props ?? {},
1448
+ version: null,
1449
+ toolCallId: null
1450
+ };
1451
+ }
1452
+ __name(nodeItem, "nodeItem");
1453
+ function TreeNode({ node, id }) {
1454
+ const scope = useContext2(TreeScopeContext);
1455
+ const item = useMemo2(() => nodeItem(node, id), [
1456
+ node,
1457
+ id
1458
+ ]);
1459
+ const resolution = useResolvedComponent(node.type, null, scope?.options.registry ?? {}, scope?.options.resolveComponent);
1460
+ const validation = useValidatedProps(scope?.options.catalog, node.type, item.props);
1461
+ if (scope === null) return null;
1462
+ if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
1463
+ if (resolution.status === "unknown") {
1464
+ return renderFallback(scope.fallback, {
1465
+ reason: "unknown",
1466
+ item
1467
+ });
1468
+ }
1469
+ if (resolution.status === "error") {
1470
+ return renderFallback(scope.fallback, {
1471
+ reason: "error",
1472
+ item,
1473
+ error: resolution.error
1474
+ });
1475
+ }
1476
+ if (validation.status === "invalid") {
1477
+ return renderFallback(scope.fallback, {
1478
+ reason: "invalid",
1479
+ item,
1480
+ issues: validation.issues
1481
+ });
1482
+ }
1483
+ const Renderer = resolution.Component;
1484
+ const children = Array.isArray(node.children) ? node.children : [];
1485
+ return /* @__PURE__ */ React.createElement(Renderer, validation.props, children.length > 0 ? children.map((child, index) => {
1486
+ const childId = `${id}.${index}`;
1487
+ return /* @__PURE__ */ React.createElement(ItemBoundary, {
1488
+ key: childId,
1489
+ item: nodeItem(child, childId),
1490
+ fallback: scope.fallback,
1491
+ onError: scope.onError
1492
+ }, /* @__PURE__ */ React.createElement(TreeNode, {
1493
+ node: child,
1494
+ id: childId
1495
+ }));
1496
+ }) : void 0);
1497
+ }
1498
+ __name(TreeNode, "TreeNode");
1499
+ function GenuiTree({ root }) {
1500
+ if (root === void 0 || root === null || typeof root.type !== "string") return null;
1501
+ return /* @__PURE__ */ React.createElement(TreeNode, {
1502
+ node: root,
1503
+ id: "root"
1504
+ });
1505
+ }
1506
+ __name(GenuiTree, "GenuiTree");
1507
+ function GenerativeUIScope({ registry, catalog, resolveComponent, fallback: fallback2, loading = null, onError, children }) {
1508
+ const scope = useMemo2(() => ({
1509
+ options: {
1510
+ registry,
1511
+ ...catalog !== void 0 ? {
1512
+ catalog
1513
+ } : {},
1514
+ ...resolveComponent !== void 0 ? {
1515
+ resolveComponent
1516
+ } : {}
1517
+ },
1518
+ fallback: fallback2,
1519
+ loading,
1520
+ onError
1521
+ }), [
1522
+ registry,
1523
+ catalog,
1524
+ resolveComponent,
1525
+ fallback2,
1526
+ loading,
1527
+ onError
1528
+ ]);
1529
+ return /* @__PURE__ */ React.createElement(TreeScopeContext.Provider, {
1530
+ value: scope
1531
+ }, children);
1532
+ }
1533
+ __name(GenerativeUIScope, "GenerativeUIScope");
1534
+ var GenuiContext = sharedContext("@dudousxd/nestjs-agent-react:genui-provider");
1535
+ function GenuiProvider({ registry, catalog, resolveComponent, treeRenderer, fallback: fallback2, loading, onError, children }) {
1536
+ const value = useMemo2(() => ({
1537
+ ...registry !== void 0 ? {
1538
+ registry
1539
+ } : {},
1540
+ ...catalog !== void 0 ? {
1541
+ catalog
1542
+ } : {},
1543
+ ...resolveComponent !== void 0 ? {
1544
+ resolveComponent
1545
+ } : {},
1546
+ ...treeRenderer !== void 0 ? {
1547
+ treeRenderer
1548
+ } : {},
1549
+ ...fallback2 !== void 0 ? {
1550
+ fallback: fallback2
1551
+ } : {},
1552
+ ...loading !== void 0 ? {
1553
+ loading
1554
+ } : {},
1555
+ ...onError !== void 0 ? {
1556
+ onError
1557
+ } : {}
1558
+ }), [
1559
+ registry,
1560
+ catalog,
1561
+ resolveComponent,
1562
+ treeRenderer,
1563
+ fallback2,
1564
+ loading,
1565
+ onError
1566
+ ]);
1567
+ const renderUi = useCallback((block) => /* @__PURE__ */ React.createElement(GenerativeUI, {
1568
+ part: block
1569
+ }), []);
1570
+ return /* @__PURE__ */ React.createElement(GenuiContext.Provider, {
1571
+ value
1572
+ }, /* @__PURE__ */ React.createElement(AmbientRenderUiContext.Provider, {
1573
+ value: renderUi
1574
+ }, children));
1575
+ }
1576
+ __name(GenuiProvider, "GenuiProvider");
1577
+ var NO_REGISTRY = {};
1578
+ function useMergedOptions(own) {
1579
+ const provided = useContext2(GenuiContext);
1580
+ const registry = own.registry ?? provided?.registry ?? NO_REGISTRY;
1581
+ const catalog = own.catalog ?? provided?.catalog;
1582
+ const resolveComponent = own.resolveComponent ?? provided?.resolveComponent;
1583
+ const treeRenderer = own.treeRenderer ?? provided?.treeRenderer;
1584
+ return useMemo2(() => ({
1585
+ registry,
1586
+ ...catalog !== void 0 ? {
1587
+ catalog
1588
+ } : {},
1589
+ ...resolveComponent !== void 0 ? {
1590
+ resolveComponent
1591
+ } : {},
1592
+ ...treeRenderer !== void 0 ? {
1593
+ treeRenderer
1594
+ } : {}
1595
+ }), [
1596
+ registry,
1597
+ catalog,
1598
+ resolveComponent,
1599
+ treeRenderer
1600
+ ]);
1601
+ }
1602
+ __name(useMergedOptions, "useMergedOptions");
1603
+ function GenerativeUI({ part, registry, catalog, resolveComponent, treeRenderer, fallback: ownFallback, loading: ownLoading, onError: ownOnError }) {
1604
+ const provided = useContext2(GenuiContext);
1605
+ const fallback2 = ownFallback ?? provided?.fallback;
1606
+ const loading = ownLoading ?? provided?.loading ?? null;
1607
+ const onError = ownOnError ?? provided?.onError;
1608
+ const options = useMergedOptions({
1609
+ ...registry !== void 0 ? {
1610
+ registry
1611
+ } : {},
1612
+ ...catalog !== void 0 ? {
1613
+ catalog
1614
+ } : {},
1615
+ ...resolveComponent !== void 0 ? {
1616
+ resolveComponent
1617
+ } : {},
1618
+ ...treeRenderer !== void 0 ? {
1619
+ treeRenderer
1620
+ } : {}
1621
+ });
1622
+ const state = useGenerativeUIState(part, options, options.treeRenderer ?? GenuiTree);
1623
+ if (state === null) return null;
1624
+ if (state.status === "loading") return loading;
1625
+ if (state.status === "problem") {
1626
+ const { status: _status, ...problem } = state;
1627
+ return renderFallback(fallback2, problem);
1628
+ }
1629
+ const Renderer = state.Component;
1630
+ return /* @__PURE__ */ React.createElement(GenerativeUIScope, {
1631
+ ...options,
1632
+ fallback: fallback2,
1633
+ loading,
1634
+ ...onError !== void 0 ? {
1635
+ onError
1636
+ } : {}
1637
+ }, /* @__PURE__ */ React.createElement(ItemBoundary, {
1638
+ item: state.item,
1639
+ fallback: fallback2,
1640
+ onError
1641
+ }, /* @__PURE__ */ React.createElement(Renderer, state.props)));
1642
+ }
1643
+ __name(GenerativeUI, "GenerativeUI");
1644
+
1645
+ // src/provider.tsx
1646
+ var AgentBackendContext = sharedContext("@dudousxd/nestjs-agent-react:agent-backend");
1647
+ function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, attachments, genui, children }) {
1648
+ const latestHeaders = useRef2({
1649
+ headers,
1650
+ getHeaders
1651
+ });
1652
+ latestHeaders.current = {
1653
+ headers,
1654
+ getHeaders
1655
+ };
1656
+ const upload = attachments?.upload;
1657
+ const value = useMemo3(() => backend ?? new AgentClient({
1658
+ ...baseUrl !== void 0 ? {
1659
+ baseUrl
1660
+ } : {},
1661
+ ...path !== void 0 ? {
1662
+ path
1663
+ } : {},
1664
+ ...credentials !== void 0 ? {
1665
+ credentials
1666
+ } : {},
1667
+ ...fetch !== void 0 ? {
1668
+ fetch
1669
+ } : {},
1670
+ ...upload !== void 0 ? {
1671
+ attachments: {
1672
+ upload
1673
+ }
1674
+ } : {},
1675
+ getHeaders: /* @__PURE__ */ __name(async () => {
1676
+ const current = latestHeaders.current;
1677
+ const dynamic = await current.getHeaders?.() ?? {};
1678
+ return {
1679
+ ...current.headers,
1680
+ ...dynamic
1681
+ };
1682
+ }, "getHeaders")
1683
+ }), [
1684
+ backend,
1685
+ baseUrl,
1686
+ path,
1687
+ credentials,
1688
+ fetch,
1689
+ upload
1690
+ ]);
1691
+ const content = genui !== void 0 ? /* @__PURE__ */ React.createElement(GenuiProvider, genui, children) : children;
1692
+ return /* @__PURE__ */ React.createElement(AgentBackendContext.Provider, {
1693
+ value
1694
+ }, content);
1695
+ }
1696
+ __name(AgentProvider, "AgentProvider");
1697
+ var fallback;
1698
+ function defaultBackend() {
1699
+ fallback ??= new AgentClient();
1700
+ return fallback;
1701
+ }
1702
+ __name(defaultBackend, "defaultBackend");
1703
+ function useAgentBackend(own) {
1704
+ const provided = useContext3(AgentBackendContext);
1705
+ return own ?? provided ?? defaultBackend();
1706
+ }
1707
+ __name(useAgentBackend, "useAgentBackend");
1708
+
1115
1709
  // src/attachments/use-attachments.ts
1116
1710
  var DEFAULT_REJECTION = {
1117
1711
  type: /* @__PURE__ */ __name((file) => `${file.name} is not a supported file type`, "type"),
@@ -1119,23 +1713,30 @@ var DEFAULT_REJECTION = {
1119
1713
  count: /* @__PURE__ */ __name(() => "Too many files", "count")
1120
1714
  };
1121
1715
  var sequence = 0;
1122
- function useAttachments(options) {
1123
- const latest = useRef2(options);
1124
- latest.current = options;
1125
- const [items, setItems] = useState2([]);
1126
- const itemsRef = useRef2(items);
1716
+ function useAttachments(options = {}) {
1717
+ const backend = useAgentBackend(options.backend);
1718
+ const latest = useRef3({
1719
+ ...options,
1720
+ backend
1721
+ });
1722
+ latest.current = {
1723
+ ...options,
1724
+ backend
1725
+ };
1726
+ const [items, setItems] = useState3([]);
1727
+ const itemsRef = useRef3(items);
1127
1728
  itemsRef.current = items;
1128
- const controllers = useRef2(/* @__PURE__ */ new Map());
1129
- const [dragDepth, setDragDepth] = useState2(0);
1130
- const patch = useCallback((id, change) => {
1729
+ const controllers = useRef3(/* @__PURE__ */ new Map());
1730
+ const [dragDepth, setDragDepth] = useState3(0);
1731
+ const patch = useCallback2((id, change) => {
1131
1732
  setItems((current) => current.map((item) => item.id === id ? {
1132
1733
  ...item,
1133
1734
  ...change
1134
1735
  } : item));
1135
1736
  }, []);
1136
- const start = useCallback((item) => {
1137
- const { upload, backend } = latest.current;
1138
- const run = upload ?? (backend?.uploadAttachment !== void 0 ? backend.uploadAttachment.bind(backend) : void 0);
1737
+ const start = useCallback2((item) => {
1738
+ const { upload, backend: backend2 } = latest.current;
1739
+ const run = upload ?? (backend2.uploadAttachment !== void 0 ? backend2.uploadAttachment.bind(backend2) : void 0);
1139
1740
  if (run === void 0) {
1140
1741
  patch(item.id, {
1141
1742
  status: "error",
@@ -1169,7 +1770,7 @@ function useAttachments(options) {
1169
1770
  }, [
1170
1771
  patch
1171
1772
  ]);
1172
- const add = useCallback((files) => {
1773
+ const add = useCallback2((files) => {
1173
1774
  if (files == null) return;
1174
1775
  const { accept: accept2, maxBytes, maxFiles, describeRejection } = latest.current;
1175
1776
  const describe = /* @__PURE__ */ __name((reason, file) => describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file), "describe");
@@ -1215,7 +1816,7 @@ function useAttachments(options) {
1215
1816
  }, [
1216
1817
  start
1217
1818
  ]);
1218
- const release = useCallback((item) => {
1819
+ const release = useCallback2((item) => {
1219
1820
  if (item === void 0) return;
1220
1821
  controllers.current.get(item.id)?.abort();
1221
1822
  controllers.current.delete(item.id);
@@ -1223,19 +1824,19 @@ function useAttachments(options) {
1223
1824
  URL.revokeObjectURL(item.previewUrl);
1224
1825
  }
1225
1826
  }, []);
1226
- const remove = useCallback((id) => {
1827
+ const remove = useCallback2((id) => {
1227
1828
  release(itemsRef.current.find((item) => item.id === id));
1228
1829
  setItems((current) => current.filter((item) => item.id !== id));
1229
1830
  }, [
1230
1831
  release
1231
1832
  ]);
1232
- const clear = useCallback(() => {
1833
+ const clear = useCallback2(() => {
1233
1834
  for (const item of itemsRef.current) release(item);
1234
1835
  setItems([]);
1235
1836
  }, [
1236
1837
  release
1237
1838
  ]);
1238
- const retry = useCallback((id) => {
1839
+ const retry = useCallback2((id) => {
1239
1840
  const item = itemsRef.current.find((candidate) => candidate.id === id);
1240
1841
  if (item === void 0 || item.status !== "error") return;
1241
1842
  const { error: _previous, ...rest } = item;
@@ -1249,12 +1850,12 @@ function useAttachments(options) {
1249
1850
  }, [
1250
1851
  start
1251
1852
  ]);
1252
- useEffect2(() => () => {
1853
+ useEffect3(() => () => {
1253
1854
  for (const item of itemsRef.current) release(item);
1254
1855
  }, [
1255
1856
  release
1256
1857
  ]);
1257
- const onPaste = useCallback((event) => {
1858
+ const onPaste = useCallback2((event) => {
1258
1859
  const files = filesFromClipboard(event.clipboardData);
1259
1860
  if (files.length === 0) return;
1260
1861
  event.preventDefault();
@@ -1262,7 +1863,7 @@ function useAttachments(options) {
1262
1863
  }, [
1263
1864
  add
1264
1865
  ]);
1265
- const dropZoneProps = useMemo(() => ({
1866
+ const dropZoneProps = useMemo4(() => ({
1266
1867
  onDragEnter: /* @__PURE__ */ __name((event) => {
1267
1868
  if (!dragHasFiles(event.dataTransfer)) return;
1268
1869
  event.preventDefault();
@@ -1285,7 +1886,7 @@ function useAttachments(options) {
1285
1886
  add
1286
1887
  ]);
1287
1888
  const accept = options.accept;
1288
- const inputProps = useMemo(() => ({
1889
+ const inputProps = useMemo4(() => ({
1289
1890
  type: "file",
1290
1891
  accept: typeof accept === "string" ? accept : accept?.join(","),
1291
1892
  multiple: options.maxFiles === void 0 || options.maxFiles > 1,
@@ -1299,7 +1900,7 @@ function useAttachments(options) {
1299
1900
  options.maxFiles,
1300
1901
  add
1301
1902
  ]);
1302
- return useMemo(() => {
1903
+ return useMemo4(() => {
1303
1904
  const ready = items.filter((item) => item.status === "ready" && item.attachment !== void 0);
1304
1905
  const attachments = ready.map((item) => item.attachment);
1305
1906
  return {
@@ -1333,18 +1934,18 @@ function useAttachments(options) {
1333
1934
  __name(useAttachments, "useAttachments");
1334
1935
 
1335
1936
  // src/catalog/use-agents.ts
1336
- import { useMemo as useMemo2 } from "react";
1937
+ import { useMemo as useMemo5 } from "react";
1337
1938
 
1338
1939
  // src/catalog/use-resource.ts
1339
- import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
1940
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
1340
1941
  function useResource(load2, key, enabled) {
1341
- const [data, setData] = useState3(void 0);
1342
- const [isLoading, setIsLoading] = useState3(enabled);
1343
- const [error, setError] = useState3(null);
1344
- const loadRef = useRef3(load2);
1942
+ const [data, setData] = useState4(void 0);
1943
+ const [isLoading, setIsLoading] = useState4(enabled);
1944
+ const [error, setError] = useState4(null);
1945
+ const loadRef = useRef4(load2);
1345
1946
  loadRef.current = load2;
1346
- const generation = useRef3(0);
1347
- const refresh = useCallback2(async () => {
1947
+ const generation = useRef4(0);
1948
+ const refresh = useCallback3(async () => {
1348
1949
  const mine = ++generation.current;
1349
1950
  setIsLoading(true);
1350
1951
  try {
@@ -1359,7 +1960,7 @@ function useResource(load2, key, enabled) {
1359
1960
  if (mine === generation.current) setIsLoading(false);
1360
1961
  }
1361
1962
  }, []);
1362
- useEffect3(() => {
1963
+ useEffect4(() => {
1363
1964
  if (!enabled) return;
1364
1965
  void refresh();
1365
1966
  }, [
@@ -1377,10 +1978,11 @@ function useResource(load2, key, enabled) {
1377
1978
  __name(useResource, "useResource");
1378
1979
 
1379
1980
  // src/catalog/use-agents.ts
1380
- function useAgents(options) {
1381
- const { backend, enabled = true } = options;
1981
+ function useAgents(options = {}) {
1982
+ const { enabled = true } = options;
1983
+ const backend = useAgentBackend(options.backend);
1382
1984
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
1383
- return useMemo2(() => {
1985
+ return useMemo5(() => {
1384
1986
  const agents = data ?? [];
1385
1987
  return {
1386
1988
  agents,
@@ -1399,11 +2001,12 @@ function useAgents(options) {
1399
2001
  __name(useAgents, "useAgents");
1400
2002
 
1401
2003
  // src/catalog/use-models.ts
1402
- import { useMemo as useMemo3 } from "react";
1403
- function useModels(options) {
1404
- const { backend, agent, enabled = true } = options;
2004
+ import { useMemo as useMemo6 } from "react";
2005
+ function useModels(options = {}) {
2006
+ const { agent, enabled = true } = options;
2007
+ const backend = useAgentBackend(options.backend);
1405
2008
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
1406
- return useMemo3(() => {
2009
+ return useMemo6(() => {
1407
2010
  const providers = data?.providers ?? [];
1408
2011
  const models = providers.flatMap((provider) => provider.models.map((model) => ({
1409
2012
  ...model,
@@ -1433,7 +2036,7 @@ function useModels(options) {
1433
2036
  __name(useModels, "useModels");
1434
2037
 
1435
2038
  // src/quota/use-quota.ts
1436
- import { useEffect as useEffect4, useMemo as useMemo4 } from "react";
2039
+ import { useEffect as useEffect5, useMemo as useMemo7 } from "react";
1437
2040
 
1438
2041
  // src/threads/threads-events.ts
1439
2042
  var listeners = /* @__PURE__ */ new WeakMap();
@@ -1457,10 +2060,11 @@ function onThreadsEvent(backend, listener) {
1457
2060
  __name(onThreadsEvent, "onThreadsEvent");
1458
2061
 
1459
2062
  // src/quota/use-quota.ts
1460
- function useQuota(options) {
1461
- const { backend, enabled = true, pollMs } = options;
2063
+ function useQuota(options = {}) {
2064
+ const { enabled = true, pollMs } = options;
2065
+ const backend = useAgentBackend(options.backend);
1462
2066
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
1463
- useEffect4(() => {
2067
+ useEffect5(() => {
1464
2068
  if (!enabled) return;
1465
2069
  return onThreadsEvent(backend, (event) => {
1466
2070
  if (event.type === "changed") void refresh();
@@ -1470,7 +2074,7 @@ function useQuota(options) {
1470
2074
  enabled,
1471
2075
  refresh
1472
2076
  ]);
1473
- useEffect4(() => {
2077
+ useEffect5(() => {
1474
2078
  if (!enabled || pollMs === void 0 || pollMs <= 0) return;
1475
2079
  const timer = setInterval(() => void refresh(), pollMs);
1476
2080
  return () => clearInterval(timer);
@@ -1479,7 +2083,7 @@ function useQuota(options) {
1479
2083
  pollMs,
1480
2084
  refresh
1481
2085
  ]);
1482
- return useMemo4(() => {
2086
+ return useMemo7(() => {
1483
2087
  const windows = data?.windows ?? [];
1484
2088
  return {
1485
2089
  report: data,
@@ -1501,37 +2105,44 @@ function useQuota(options) {
1501
2105
  __name(useQuota, "useQuota");
1502
2106
 
1503
2107
  // src/feedback/use-message-feedback.ts
1504
- import { useCallback as useCallback3, useRef as useRef4, useState as useState4 } from "react";
1505
- function useMessageFeedback(options) {
1506
- const latest = useRef4(options);
1507
- latest.current = options;
1508
- const [local, setLocal] = useState4(/* @__PURE__ */ new Map());
1509
- const [pending, setPending] = useState4(/* @__PURE__ */ new Set());
1510
- const [error, setError] = useState4(null);
1511
- const localRef = useRef4(local);
2108
+ import { useCallback as useCallback4, useRef as useRef5, useState as useState5 } from "react";
2109
+ function useMessageFeedback(options = {}) {
2110
+ const backend = useAgentBackend(options.backend);
2111
+ const latest = useRef5({
2112
+ ...options,
2113
+ backend
2114
+ });
2115
+ latest.current = {
2116
+ ...options,
2117
+ backend
2118
+ };
2119
+ const [local, setLocal] = useState5(/* @__PURE__ */ new Map());
2120
+ const [pending, setPending] = useState5(/* @__PURE__ */ new Set());
2121
+ const [error, setError] = useState5(null);
2122
+ const localRef = useRef5(local);
1512
2123
  localRef.current = local;
1513
- const resolved = useRef4(/* @__PURE__ */ new Map());
1514
- const feedbackOf = useCallback3((message) => {
2124
+ const resolved = useRef5(/* @__PURE__ */ new Map());
2125
+ const feedbackOf = useCallback4((message) => {
1515
2126
  const mine = local.get(message.id);
1516
2127
  if (mine !== void 0) return mine.feedback;
1517
2128
  return metadataOf(message).feedback ?? null;
1518
2129
  }, [
1519
2130
  local
1520
2131
  ]);
1521
- const isPending = useCallback3((message) => pending.has(message.id), [
2132
+ const isPending = useCallback4((message) => pending.has(message.id), [
1522
2133
  pending
1523
2134
  ]);
1524
- const storedIdFor = useCallback3(async (message) => {
2135
+ const storedIdFor = useCallback4(async (message) => {
1525
2136
  const runId = metadataOf(message).runId;
1526
2137
  if (runId === void 0) return message.id;
1527
2138
  const known = resolved.current.get(message.id);
1528
2139
  if (known !== void 0) return known;
1529
- const { backend, threadId } = latest.current;
2140
+ const { backend: backend2, threadId } = latest.current;
1530
2141
  const thread = typeof threadId === "function" ? threadId() : threadId;
1531
2142
  if (thread === void 0) {
1532
2143
  throw new Error("useMessageFeedback: a streamed message needs `threadId` to be rated");
1533
2144
  }
1534
- const detail = await backend.getThread(thread);
2145
+ const detail = await backend2.getThread(thread);
1535
2146
  const row = [
1536
2147
  ...detail.messages
1537
2148
  ].reverse().find((candidate) => candidate.role === "assistant" && candidate.runId === runId);
@@ -1541,7 +2152,7 @@ function useMessageFeedback(options) {
1541
2152
  resolved.current.set(message.id, row.id);
1542
2153
  return row.id;
1543
2154
  }, []);
1544
- const rate = useCallback3(async (message, value, comment) => {
2155
+ const rate = useCallback4(async (message, value, comment) => {
1545
2156
  const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
1546
2157
  const had = localRef.current.get(message.id);
1547
2158
  const optimistic = value === null ? null : {
@@ -1587,7 +2198,7 @@ function useMessageFeedback(options) {
1587
2198
  }, [
1588
2199
  storedIdFor
1589
2200
  ]);
1590
- const toggle = useCallback3((message, value) => {
2201
+ const toggle = useCallback4((message, value) => {
1591
2202
  const mine = localRef.current.get(message.id);
1592
2203
  const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
1593
2204
  return rate(message, current?.value === value ? null : value);
@@ -1610,16 +2221,17 @@ function metadataOf(message) {
1610
2221
  __name(metadataOf, "metadataOf");
1611
2222
 
1612
2223
  // src/threads/use-threads.ts
1613
- import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef5, useState as useState5 } from "react";
1614
- function useThreads(options) {
1615
- const { backend, enabled = true } = options;
1616
- const [threads, setThreads] = useState5([]);
1617
- const [isLoading, setIsLoading] = useState5(enabled);
1618
- const [error, setError] = useState5(null);
1619
- const threadsRef = useRef5(threads);
2224
+ import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
2225
+ function useThreads(options = {}) {
2226
+ const { enabled = true } = options;
2227
+ const backend = useAgentBackend(options.backend);
2228
+ const [threads, setThreads] = useState6([]);
2229
+ const [isLoading, setIsLoading] = useState6(enabled);
2230
+ const [error, setError] = useState6(null);
2231
+ const threadsRef = useRef6(threads);
1620
2232
  threadsRef.current = threads;
1621
- const generation = useRef5(0);
1622
- const refresh = useCallback4(async () => {
2233
+ const generation = useRef6(0);
2234
+ const refresh = useCallback5(async () => {
1623
2235
  const mine = ++generation.current;
1624
2236
  setIsLoading(true);
1625
2237
  try {
@@ -1636,7 +2248,7 @@ function useThreads(options) {
1636
2248
  }, [
1637
2249
  backend
1638
2250
  ]);
1639
- useEffect5(() => {
2251
+ useEffect6(() => {
1640
2252
  if (!enabled) return;
1641
2253
  void refresh();
1642
2254
  return onThreadsEvent(backend, (event) => {
@@ -1656,7 +2268,7 @@ function useThreads(options) {
1656
2268
  enabled,
1657
2269
  refresh
1658
2270
  ]);
1659
- const rename = useCallback4(async (id, title) => {
2271
+ const rename = useCallback5(async (id, title) => {
1660
2272
  const before = threadsRef.current;
1661
2273
  setThreads((current) => current.map((thread) => thread.id === id ? {
1662
2274
  ...thread,
@@ -1678,7 +2290,7 @@ function useThreads(options) {
1678
2290
  }, [
1679
2291
  backend
1680
2292
  ]);
1681
- const remove = useCallback4(async (id) => {
2293
+ const remove = useCallback5(async (id) => {
1682
2294
  const before = threadsRef.current;
1683
2295
  setThreads((current) => current.filter((thread) => thread.id !== id));
1684
2296
  try {
@@ -1752,29 +2364,11 @@ function backgroundRunsFromThread(messages) {
1752
2364
  }
1753
2365
  __name(backgroundRunsFromThread, "backgroundRunsFromThread");
1754
2366
 
1755
- // src/components/ambient-ui.ts
1756
- import { createContext, useContext } from "react";
1757
- function sharedContext(key) {
1758
- const symbol = Symbol.for(key);
1759
- const holder = globalThis;
1760
- const existing = holder[symbol];
1761
- if (existing !== void 0) return existing;
1762
- const created = createContext(null);
1763
- holder[symbol] = created;
1764
- return created;
1765
- }
1766
- __name(sharedContext, "sharedContext");
1767
- var AmbientRenderUiContext = sharedContext("@dudousxd/nestjs-agent-react:ambient-render-ui");
1768
- function useAmbientRenderUi() {
1769
- return useContext(AmbientRenderUiContext);
1770
- }
1771
- __name(useAmbientRenderUi, "useAmbientRenderUi");
1772
-
1773
2367
  // src/components/chat-input.tsx
1774
- import React2, { useEffect as useEffect7, useState as useState7 } from "react";
2368
+ import React2, { useEffect as useEffect8, useState as useState8 } from "react";
1775
2369
 
1776
2370
  // src/components/use-speech-recognition.ts
1777
- import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef6, useState as useState6 } from "react";
2371
+ import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo8, useRef as useRef7, useState as useState7 } from "react";
1778
2372
  function getRecognitionCtor() {
1779
2373
  if (typeof window === "undefined") return null;
1780
2374
  const scope = window;
@@ -1782,15 +2376,15 @@ function getRecognitionCtor() {
1782
2376
  }
1783
2377
  __name(getRecognitionCtor, "getRecognitionCtor");
1784
2378
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
1785
- const recognitionRef = useRef6(null);
1786
- const [isListening, setIsListening] = useState6(false);
1787
- const ctor = useMemo5(() => getRecognitionCtor(), []);
2379
+ const recognitionRef = useRef7(null);
2380
+ const [isListening, setIsListening] = useState7(false);
2381
+ const ctor = useMemo8(() => getRecognitionCtor(), []);
1788
2382
  const isSupported = ctor !== null;
1789
- const finalRef = useRef6(onFinalTranscript);
1790
- const interimRef = useRef6(onInterimTranscript);
2383
+ const finalRef = useRef7(onFinalTranscript);
2384
+ const interimRef = useRef7(onInterimTranscript);
1791
2385
  finalRef.current = onFinalTranscript;
1792
2386
  interimRef.current = onInterimTranscript;
1793
- useEffect6(() => {
2387
+ useEffect7(() => {
1794
2388
  if (!ctor) return;
1795
2389
  const recognition = new ctor();
1796
2390
  recognition.lang = lang;
@@ -1829,7 +2423,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
1829
2423
  ctor,
1830
2424
  lang
1831
2425
  ]);
1832
- const start = useCallback5(() => {
2426
+ const start = useCallback6(() => {
1833
2427
  const recognition = recognitionRef.current;
1834
2428
  if (!recognition) return;
1835
2429
  try {
@@ -1839,7 +2433,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
1839
2433
  console.warn("SpeechRecognition start failed", error);
1840
2434
  }
1841
2435
  }, []);
1842
- const stop = useCallback5(() => {
2436
+ const stop = useCallback6(() => {
1843
2437
  const recognition = recognitionRef.current;
1844
2438
  if (!recognition) return;
1845
2439
  try {
@@ -1858,8 +2452,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
1858
2452
 
1859
2453
  // src/components/chat-input.tsx
1860
2454
  function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
1861
- const [value, setValue] = useState7("");
1862
- const [interim, setInterim] = useState7("");
2455
+ const [value, setValue] = useState8("");
2456
+ const [interim, setInterim] = useState8("");
1863
2457
  const speech = useSpeechRecognition({
1864
2458
  lang: speechLang,
1865
2459
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -1870,7 +2464,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
1870
2464
  }, "onFinalTranscript"),
1871
2465
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
1872
2466
  });
1873
- useEffect7(() => {
2467
+ useEffect8(() => {
1874
2468
  if (!speech.isListening) setInterim("");
1875
2469
  }, [
1876
2470
  speech.isListening
@@ -1937,7 +2531,7 @@ __name(ChatInput, "ChatInput");
1937
2531
  import React3 from "react";
1938
2532
 
1939
2533
  // src/transcript/use-chat-transcript.ts
1940
- import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef8, useState as useState9 } from "react";
2534
+ import { useCallback as useCallback8, useEffect as useEffect10, useRef as useRef9, useState as useState10 } from "react";
1941
2535
 
1942
2536
  // src/transcript/model.ts
1943
2537
  import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
@@ -2034,21 +2628,21 @@ function fillTemplate(template, context) {
2034
2628
  }).replace(/\s{2,}/g, " ").trim();
2035
2629
  }
2036
2630
  __name(fillTemplate, "fillTemplate");
2037
- function phraseFor(presentation, input, isSettled2, fallback = {
2631
+ function phraseFor(presentation, input, isSettled2, fallback2 = {
2038
2632
  running: "Working",
2039
2633
  done: "Done"
2040
2634
  }) {
2041
- if (presentation === void 0) return isSettled2 ? fallback.done : fallback.running;
2635
+ if (presentation === void 0) return isSettled2 ? fallback2.done : fallback2.running;
2042
2636
  const filled = fillTemplate(isSettled2 ? presentation.done : presentation.running, input);
2043
2637
  return filled === "" ? presentation.label : filled;
2044
2638
  }
2045
2639
  __name(phraseFor, "phraseFor");
2046
2640
 
2047
2641
  // src/presentation/result-view.ts
2048
- function isRecord(value) {
2642
+ function isRecord2(value) {
2049
2643
  return typeof value === "object" && value !== null && !Array.isArray(value);
2050
2644
  }
2051
- __name(isRecord, "isRecord");
2645
+ __name(isRecord2, "isRecord");
2052
2646
  function toText(value) {
2053
2647
  if (value === null || value === void 0) return "\u2014";
2054
2648
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
@@ -2059,7 +2653,7 @@ function toText(value) {
2059
2653
  }
2060
2654
  __name(toText, "toText");
2061
2655
  function inferResultView(output) {
2062
- if (!isRecord(output)) return void 0;
2656
+ if (!isRecord2(output)) return void 0;
2063
2657
  for (const [key, value] of Object.entries(output)) {
2064
2658
  if (!Array.isArray(value) || value.length === 0) continue;
2065
2659
  if (value.every((entry) => typeof entry === "string")) {
@@ -2068,12 +2662,12 @@ function inferResultView(output) {
2068
2662
  lines: key
2069
2663
  };
2070
2664
  }
2071
- if (value.every(isRecord)) {
2665
+ if (value.every(isRecord2)) {
2072
2666
  const first = value[0];
2073
2667
  return {
2074
2668
  kind: "table",
2075
2669
  rows: key,
2076
- columns: Object.keys(first).filter((column) => !isRecord(first[column])).map((column) => ({
2670
+ columns: Object.keys(first).filter((column) => !isRecord2(first[column])).map((column) => ({
2077
2671
  path: column,
2078
2672
  label: column
2079
2673
  }))
@@ -2449,7 +3043,7 @@ function isSettled(state) {
2449
3043
  __name(isSettled, "isSettled");
2450
3044
  function toolKind(part) {
2451
3045
  const metadata = part.toolMetadata;
2452
- return isRecord2(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
3046
+ return isRecord3(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
2453
3047
  }
2454
3048
  __name(toolKind, "toolKind");
2455
3049
  function isAwaitingApproval(part) {
@@ -2464,7 +3058,7 @@ function isAwaitingApproval(part) {
2464
3058
  __name(isAwaitingApproval, "isAwaitingApproval");
2465
3059
  function toolParentId(part) {
2466
3060
  const metadata = part.toolMetadata;
2467
- return isRecord2(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
3061
+ return isRecord3(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
2468
3062
  }
2469
3063
  __name(toolParentId, "toolParentId");
2470
3064
  function nestToolCalls(calls) {
@@ -2531,12 +3125,12 @@ function buildToolCall(part, options, approval, catalog) {
2531
3125
  __name(buildToolCall, "buildToolCall");
2532
3126
  function readElicitationRequest(part) {
2533
3127
  const input = part.input;
2534
- if (!isRecord2(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
3128
+ if (!isRecord3(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
2535
3129
  return null;
2536
3130
  }
2537
3131
  const questions = [];
2538
3132
  for (const candidate of input.questions) {
2539
- if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
3133
+ if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
2540
3134
  return null;
2541
3135
  }
2542
3136
  const input2 = readElicitationInput(candidate.input) ?? null;
@@ -2546,7 +3140,7 @@ function readElicitationRequest(part) {
2546
3140
  }
2547
3141
  const options = [];
2548
3142
  for (const option of rawOptions) {
2549
- if (!isRecord2(option) || typeof option.value !== "string" || typeof option.label !== "string") {
3143
+ if (!isRecord3(option) || typeof option.value !== "string" || typeof option.label !== "string") {
2550
3144
  return null;
2551
3145
  }
2552
3146
  options.push({
@@ -2574,7 +3168,7 @@ function readElicitationRequest(part) {
2574
3168
  __name(readElicitationRequest, "readElicitationRequest");
2575
3169
  function readElicitationOutcome(part) {
2576
3170
  const output = part.output;
2577
- if (!isRecord2(output) || !isRecord2(output.answers) || typeof output.skipped !== "boolean") {
3171
+ if (!isRecord3(output) || !isRecord3(output.answers) || typeof output.skipped !== "boolean") {
2578
3172
  return null;
2579
3173
  }
2580
3174
  const answers = {};
@@ -2711,7 +3305,7 @@ function readApprovals(parts) {
2711
3305
  continue;
2712
3306
  }
2713
3307
  const data = part.data;
2714
- if (!isRecord2(data) || typeof data.id !== "string") {
3308
+ if (!isRecord3(data) || typeof data.id !== "string") {
2715
3309
  continue;
2716
3310
  }
2717
3311
  const approval = entry(data.id);
@@ -2767,7 +3361,7 @@ function statusFromPart(call) {
2767
3361
  __name(statusFromPart, "statusFromPart");
2768
3362
  function readUiComponent(part) {
2769
3363
  const data = part.data;
2770
- if (!isRecord2(data) || typeof data.component !== "string") {
3364
+ if (!isRecord3(data) || typeof data.component !== "string") {
2771
3365
  return null;
2772
3366
  }
2773
3367
  const id = typeof data.id === "string" ? data.id : part.id;
@@ -2777,19 +3371,19 @@ function readUiComponent(part) {
2777
3371
  return {
2778
3372
  id,
2779
3373
  component: data.component,
2780
- props: isRecord2(data.props) ? data.props : {},
3374
+ props: isRecord3(data.props) ? data.props : {},
2781
3375
  version: typeof data.version === "number" ? data.version : null,
2782
3376
  toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
2783
3377
  };
2784
3378
  }
2785
3379
  __name(readUiComponent, "readUiComponent");
2786
- function isRecord2(value) {
3380
+ function isRecord3(value) {
2787
3381
  return typeof value === "object" && value !== null;
2788
3382
  }
2789
- __name(isRecord2, "isRecord");
3383
+ __name(isRecord3, "isRecord");
2790
3384
  function readQuery(part) {
2791
3385
  const input = part.input;
2792
- if (!isRecord2(input) || typeof input.query !== "string") {
3386
+ if (!isRecord3(input) || typeof input.query !== "string") {
2793
3387
  return null;
2794
3388
  }
2795
3389
  return input.query;
@@ -2797,12 +3391,12 @@ function readQuery(part) {
2797
3391
  __name(readQuery, "readQuery");
2798
3392
  function readPassages(part) {
2799
3393
  const output = part.output;
2800
- if (!isRecord2(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
3394
+ if (!isRecord3(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
2801
3395
  return null;
2802
3396
  }
2803
3397
  const passages = [];
2804
3398
  for (const candidate of output.passages) {
2805
- if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
3399
+ if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
2806
3400
  return null;
2807
3401
  }
2808
3402
  passages.push({
@@ -2812,7 +3406,7 @@ function readPassages(part) {
2812
3406
  ...typeof candidate.source === "string" ? {
2813
3407
  source: candidate.source
2814
3408
  } : {},
2815
- ...isRecord2(candidate.metadata) ? {
3409
+ ...isRecord3(candidate.metadata) ? {
2816
3410
  metadata: candidate.metadata
2817
3411
  } : {}
2818
3412
  });
@@ -2914,11 +3508,11 @@ function formatCostUsd(cost) {
2914
3508
  __name(formatCostUsd, "formatCostUsd");
2915
3509
 
2916
3510
  // src/transcript/use-stick-to-bottom.ts
2917
- import { useCallback as useCallback6, useEffect as useEffect8, useRef as useRef7, useState as useState8 } from "react";
3511
+ import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef8, useState as useState9 } from "react";
2918
3512
  function useStickToBottom({ contentKey, threshold = 32 }) {
2919
- const containerRef = useRef7(null);
2920
- const [isAtBottom, setIsAtBottom] = useState8(true);
2921
- const measure = useCallback6(() => {
3513
+ const containerRef = useRef8(null);
3514
+ const [isAtBottom, setIsAtBottom] = useState9(true);
3515
+ const measure = useCallback7(() => {
2922
3516
  const element = containerRef.current;
2923
3517
  if (!element) {
2924
3518
  return;
@@ -2928,7 +3522,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2928
3522
  }, [
2929
3523
  threshold
2930
3524
  ]);
2931
- const scrollToBottom = useCallback6(() => {
3525
+ const scrollToBottom = useCallback7(() => {
2932
3526
  const element = containerRef.current;
2933
3527
  if (!element) {
2934
3528
  return;
@@ -2936,7 +3530,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2936
3530
  element.scrollTop = element.scrollHeight;
2937
3531
  setIsAtBottom(true);
2938
3532
  }, []);
2939
- const setContainer = useCallback6((element) => {
3533
+ const setContainer = useCallback7((element) => {
2940
3534
  containerRef.current = element;
2941
3535
  if (element) {
2942
3536
  measure();
@@ -2944,7 +3538,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2944
3538
  }, [
2945
3539
  measure
2946
3540
  ]);
2947
- useEffect8(() => {
3541
+ useEffect9(() => {
2948
3542
  if (isAtBottom) {
2949
3543
  scrollToBottom();
2950
3544
  }
@@ -2953,7 +3547,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2953
3547
  isAtBottom,
2954
3548
  scrollToBottom
2955
3549
  ]);
2956
- const getContainerProps = useCallback6(() => ({
3550
+ const getContainerProps = useCallback7(() => ({
2957
3551
  ref: setContainer,
2958
3552
  onScroll: measure
2959
3553
  }), [
@@ -2975,14 +3569,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
2975
3569
  var DEFAULT_COPY_RESET_MS = 1500;
2976
3570
  function useChatTranscript(options) {
2977
3571
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
2978
- const latest = useRef8(options);
3572
+ const latest = useRef9(options);
2979
3573
  latest.current = options;
2980
- const [visibleCount, setVisibleCount] = useState9(initialVisibleCount);
2981
- const [stopRequested, setStopRequested] = useState9(false);
3574
+ const [visibleCount, setVisibleCount] = useState10(initialVisibleCount);
3575
+ const [stopRequested, setStopRequested] = useState10(false);
2982
3576
  const isStreaming = status === "streaming" || status === "reconnecting";
2983
3577
  const isBusy = status === "submitted" || isStreaming;
2984
3578
  const isEmpty = messages.length === 0;
2985
- useEffect9(() => {
3579
+ useEffect10(() => {
2986
3580
  if (!isBusy) {
2987
3581
  setStopRequested(false);
2988
3582
  }
@@ -2999,7 +3593,7 @@ function useChatTranscript(options) {
2999
3593
  streamingMessageId,
3000
3594
  options
3001
3595
  });
3002
- const stop = useCallback7(() => {
3596
+ const stop = useCallback8(() => {
3003
3597
  const current = latest.current;
3004
3598
  if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
3005
3599
  return;
@@ -3007,8 +3601,8 @@ function useChatTranscript(options) {
3007
3601
  setStopRequested(true);
3008
3602
  void current.onStop?.();
3009
3603
  }, []);
3010
- const loadEarlier = useCallback7(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
3011
- const showAll = useCallback7(() => setVisibleCount(latest.current.messages.length), []);
3604
+ const loadEarlier = useCallback8(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
3605
+ const showAll = useCallback8(() => setVisibleCount(latest.current.messages.length), []);
3012
3606
  const scroll = useStickToBottom({
3013
3607
  contentKey: contentSignature(messages),
3014
3608
  ...stickToBottomThreshold !== void 0 ? {
@@ -3044,7 +3638,7 @@ function useChatTranscript(options) {
3044
3638
  __name(useChatTranscript, "useChatTranscript");
3045
3639
  function useTranscriptItem(options) {
3046
3640
  const { message, isStreaming = false } = options;
3047
- const messagesRef = useRef8([
3641
+ const messagesRef = useRef9([
3048
3642
  message
3049
3643
  ]);
3050
3644
  if (messagesRef.current[0] !== message) {
@@ -3062,13 +3656,13 @@ function useTranscriptItem(options) {
3062
3656
  }
3063
3657
  __name(useTranscriptItem, "useTranscriptItem");
3064
3658
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
3065
- const [drafts, setDrafts] = useState9(() => /* @__PURE__ */ new Map());
3066
- const [copied, setCopied] = useState9(() => /* @__PURE__ */ new Set());
3067
- const [openReasoning, setOpenReasoning] = useState9(() => /* @__PURE__ */ new Map());
3068
- const [picks, setPicks] = useState9(() => /* @__PURE__ */ new Map());
3069
- const [settling, setSettling] = useState9(() => /* @__PURE__ */ new Map());
3070
- const [settleErrors, setSettleErrors] = useState9(() => /* @__PURE__ */ new Map());
3071
- const latest = useRef8({
3659
+ const [drafts, setDrafts] = useState10(() => /* @__PURE__ */ new Map());
3660
+ const [copied, setCopied] = useState10(() => /* @__PURE__ */ new Set());
3661
+ const [openReasoning, setOpenReasoning] = useState10(() => /* @__PURE__ */ new Map());
3662
+ const [picks, setPicks] = useState10(() => /* @__PURE__ */ new Map());
3663
+ const [settling, setSettling] = useState10(() => /* @__PURE__ */ new Map());
3664
+ const [settleErrors, setSettleErrors] = useState10(() => /* @__PURE__ */ new Map());
3665
+ const latest = useRef9({
3072
3666
  options,
3073
3667
  drafts,
3074
3668
  picks,
@@ -3080,23 +3674,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3080
3674
  picks,
3081
3675
  messages
3082
3676
  };
3083
- const copyTimers = useRef8(/* @__PURE__ */ new Map());
3084
- useEffect9(() => () => {
3677
+ const copyTimers = useRef9(/* @__PURE__ */ new Map());
3678
+ useEffect10(() => () => {
3085
3679
  for (const timer of copyTimers.current.values()) {
3086
3680
  clearTimeout(timer);
3087
3681
  }
3088
3682
  copyTimers.current.clear();
3089
3683
  }, []);
3090
- const callbackCache = useRef8(/* @__PURE__ */ new Map());
3091
- const reasoningToggleCache = useRef8(/* @__PURE__ */ new Map());
3092
- const toggleReasoning = useCallback7((key, open) => {
3684
+ const callbackCache = useRef9(/* @__PURE__ */ new Map());
3685
+ const reasoningToggleCache = useRef9(/* @__PURE__ */ new Map());
3686
+ const toggleReasoning = useCallback8((key, open) => {
3093
3687
  setOpenReasoning((current) => {
3094
3688
  const next = new Map(current);
3095
3689
  next.set(key, open ?? !(current.get(key) ?? false));
3096
3690
  return next;
3097
3691
  });
3098
3692
  }, []);
3099
- const stableToggle = useCallback7((key) => {
3693
+ const stableToggle = useCallback8((key) => {
3100
3694
  let cached = reasoningToggleCache.current.get(key);
3101
3695
  if (!cached) {
3102
3696
  cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
@@ -3106,10 +3700,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3106
3700
  }, [
3107
3701
  toggleReasoning
3108
3702
  ]);
3109
- const pick = useCallback7((toolCallId, questionId, values) => {
3703
+ const pick = useCallback8((toolCallId, questionId, values) => {
3110
3704
  setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
3111
3705
  }, []);
3112
- const settle = useCallback7((toolCallId, action, send) => {
3706
+ const settle = useCallback8((toolCallId, action, send) => {
3113
3707
  setSettleErrors((current) => {
3114
3708
  if (!current.has(toolCallId)) {
3115
3709
  return current;
@@ -3133,7 +3727,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3133
3727
  failed(error);
3134
3728
  }
3135
3729
  }, []);
3136
- const answer = useCallback7((toolCallId) => {
3730
+ const answer = useCallback8((toolCallId) => {
3137
3731
  const current = latest.current;
3138
3732
  const onAnswer = current.options.onAnswer;
3139
3733
  if (!onAnswer) {
@@ -3143,7 +3737,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3143
3737
  }, [
3144
3738
  settle
3145
3739
  ]);
3146
- const skip = useCallback7((toolCallId) => {
3740
+ const skip = useCallback8((toolCallId) => {
3147
3741
  const onSkip = latest.current.options.onSkip;
3148
3742
  if (onSkip) {
3149
3743
  settle(toolCallId, "skip", () => onSkip(toolCallId));
@@ -3151,7 +3745,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3151
3745
  }, [
3152
3746
  settle
3153
3747
  ]);
3154
- const approve = useCallback7((toolCallId, options2) => {
3748
+ const approve = useCallback8((toolCallId, options2) => {
3155
3749
  const onApprove = latest.current.options.onApprove;
3156
3750
  if (onApprove) {
3157
3751
  settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
@@ -3159,7 +3753,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3159
3753
  }, [
3160
3754
  settle
3161
3755
  ]);
3162
- const reject = useCallback7((toolCallId) => {
3756
+ const reject = useCallback8((toolCallId) => {
3163
3757
  const onReject = latest.current.options.onReject;
3164
3758
  if (onReject) {
3165
3759
  settle(toolCallId, "reject", () => onReject(toolCallId));
@@ -3167,7 +3761,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3167
3761
  }, [
3168
3762
  settle
3169
3763
  ]);
3170
- const callbacksFor = useCallback7((id) => {
3764
+ const callbacksFor = useCallback8((id) => {
3171
3765
  const cached = callbackCache.current.get(id);
3172
3766
  if (cached) {
3173
3767
  return cached;
@@ -3795,11 +4389,11 @@ function createSkillsSource(options) {
3795
4389
  if (cached) {
3796
4390
  return cached;
3797
4391
  }
3798
- const listSkills = options.client.listSkills;
4392
+ const listSkills = options.backend.listSkills;
3799
4393
  if (listSkills === void 0) {
3800
4394
  return Promise.reject(new AgentBackendUnsupportedError("listSkills"));
3801
4395
  }
3802
- const pending = listSkills.call(options.client, threadId).then((entries) => entries.map(toItem)).catch((error) => {
4396
+ const pending = listSkills.call(options.backend, threadId).then((entries) => entries.map(toItem)).catch((error) => {
3803
4397
  byThread.delete(key);
3804
4398
  throw error;
3805
4399
  });
@@ -3829,35 +4423,35 @@ function toItem(entry) {
3829
4423
  __name(toItem, "toItem");
3830
4424
 
3831
4425
  // src/composer/use-composer-autocomplete.ts
3832
- import { useCallback as useCallback8, useEffect as useEffect10, useId, useLayoutEffect, useMemo as useMemo6, useRef as useRef9, useState as useState10 } from "react";
4426
+ import { useCallback as useCallback9, useEffect as useEffect11, useId, useLayoutEffect, useMemo as useMemo9, useRef as useRef10, useState as useState11 } from "react";
3833
4427
  function useComposerAutocomplete(options) {
3834
4428
  const { value, sources, acceptOnTab = true } = options;
3835
- const latest = useRef9(options);
4429
+ const latest = useRef10(options);
3836
4430
  latest.current = options;
3837
- const inputRef = useRef9(null);
3838
- const [caret, setCaret] = useState10(value.length);
3839
- const [items, setItems] = useState10([]);
3840
- const [isLoading, setLoading] = useState10(false);
3841
- const [error, setError] = useState10(null);
3842
- const [activeIndex, setActiveIndex] = useState10(0);
3843
- const [dismissedIndex, setDismissedIndex] = useState10(null);
4431
+ const inputRef = useRef10(null);
4432
+ const [caret, setCaret] = useState11(value.length);
4433
+ const [items, setItems] = useState11([]);
4434
+ const [isLoading, setLoading] = useState11(false);
4435
+ const [error, setError] = useState11(null);
4436
+ const [activeIndex, setActiveIndex] = useState11(0);
4437
+ const [dismissedIndex, setDismissedIndex] = useState11(null);
3844
4438
  const safeCaret = Math.min(caret, value.length);
3845
- const match = useMemo6(() => findActiveTrigger(value, safeCaret, sources), [
4439
+ const match = useMemo9(() => findActiveTrigger(value, safeCaret, sources), [
3846
4440
  value,
3847
4441
  safeCaret,
3848
4442
  sources
3849
4443
  ]);
3850
4444
  const isActive = match !== null && dismissedIndex !== match.index;
3851
- const matchRef = useRef9(match);
4445
+ const matchRef = useRef10(match);
3852
4446
  matchRef.current = match;
3853
- const caretRef = useRef9(safeCaret);
4447
+ const caretRef = useRef10(safeCaret);
3854
4448
  caretRef.current = safeCaret;
3855
- const itemsRef = useRef9(items);
4449
+ const itemsRef = useRef10(items);
3856
4450
  itemsRef.current = items;
3857
- const activeIndexRef = useRef9(activeIndex);
4451
+ const activeIndexRef = useRef10(activeIndex);
3858
4452
  activeIndexRef.current = activeIndex;
3859
4453
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
3860
- useEffect10(() => {
4454
+ useEffect11(() => {
3861
4455
  const current = matchRef.current;
3862
4456
  if (requestKey === null || current === null) {
3863
4457
  setItems([]);
@@ -3907,23 +4501,23 @@ function useComposerAutocomplete(options) {
3907
4501
  const activeItem = isOpen ? items[activeIndex] ?? null : null;
3908
4502
  const reactId = useId();
3909
4503
  const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
3910
- const optionId = useCallback8((index) => `${listboxId}-option-${index}`, [
4504
+ const optionId = useCallback9((index) => `${listboxId}-option-${index}`, [
3911
4505
  listboxId
3912
4506
  ]);
3913
- const highlight = useCallback8((index) => {
4507
+ const highlight = useCallback9((index) => {
3914
4508
  const total = itemsRef.current.length;
3915
4509
  if (total === 0) return;
3916
4510
  setActiveIndex((index % total + total) % total);
3917
4511
  }, []);
3918
- const moveHighlight = useCallback8((delta) => highlight(activeIndexRef.current + delta), [
4512
+ const moveHighlight = useCallback9((delta) => highlight(activeIndexRef.current + delta), [
3919
4513
  highlight
3920
4514
  ]);
3921
- const dismiss = useCallback8(() => {
4515
+ const dismiss = useCallback9(() => {
3922
4516
  const current = matchRef.current;
3923
4517
  if (current) setDismissedIndex(current.index);
3924
4518
  }, []);
3925
- const pendingCaret = useRef9(null);
3926
- const accept = useCallback8((item) => {
4519
+ const pendingCaret = useRef10(null);
4520
+ const accept = useCallback9((item) => {
3927
4521
  const current = matchRef.current;
3928
4522
  if (!current) return;
3929
4523
  const chosen = item ?? itemsRef.current[activeIndexRef.current];
@@ -3940,10 +4534,10 @@ function useComposerAutocomplete(options) {
3940
4534
  pendingCaret.current = null;
3941
4535
  inputRef.current?.setSelectionRange(position, position);
3942
4536
  });
3943
- const readCaret = useCallback8((element) => {
4537
+ const readCaret = useCallback9((element) => {
3944
4538
  setCaret(element.selectionStart ?? element.value.length);
3945
4539
  }, []);
3946
- const onKeyDown = useCallback8((event) => {
4540
+ const onKeyDown = useCallback9((event) => {
3947
4541
  if (!isOpen) return;
3948
4542
  const hasItems = itemsRef.current.length > 0;
3949
4543
  switch (event.key) {
@@ -3981,23 +4575,23 @@ function useComposerAutocomplete(options) {
3981
4575
  dismiss,
3982
4576
  moveHighlight
3983
4577
  ]);
3984
- const onChange = useCallback8((event) => {
4578
+ const onChange = useCallback9((event) => {
3985
4579
  readCaret(event.target);
3986
4580
  const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
3987
4581
  setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
3988
4582
  }, [
3989
4583
  readCaret
3990
4584
  ]);
3991
- const onSelect = useCallback8((event) => readCaret(event.currentTarget), [
4585
+ const onSelect = useCallback9((event) => readCaret(event.currentTarget), [
3992
4586
  readCaret
3993
4587
  ]);
3994
- const onClick = useCallback8((event) => readCaret(event.currentTarget), [
4588
+ const onClick = useCallback9((event) => readCaret(event.currentTarget), [
3995
4589
  readCaret
3996
4590
  ]);
3997
- const setInput = useCallback8((element) => {
4591
+ const setInput = useCallback9((element) => {
3998
4592
  inputRef.current = element;
3999
4593
  }, []);
4000
- const getInputProps = useCallback8(() => ({
4594
+ const getInputProps = useCallback9(() => ({
4001
4595
  ref: setInput,
4002
4596
  onChange,
4003
4597
  onKeyDown,
@@ -4025,7 +4619,7 @@ function useComposerAutocomplete(options) {
4025
4619
  activeIndex,
4026
4620
  optionId
4027
4621
  ]);
4028
- const getListboxProps = useCallback8(() => ({
4622
+ const getListboxProps = useCallback9(() => ({
4029
4623
  id: listboxId,
4030
4624
  role: "listbox",
4031
4625
  "aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
@@ -4033,7 +4627,7 @@ function useComposerAutocomplete(options) {
4033
4627
  listboxId,
4034
4628
  match
4035
4629
  ]);
4036
- const getOptionProps = useCallback8((index) => ({
4630
+ const getOptionProps = useCallback9((index) => ({
4037
4631
  id: optionId(index),
4038
4632
  role: "option",
4039
4633
  "aria-selected": index === activeIndex
@@ -4067,7 +4661,7 @@ function isPromise(value) {
4067
4661
  __name(isPromise, "isPromise");
4068
4662
 
4069
4663
  // src/presentation/use-tool-catalog.ts
4070
- import { useCallback as useCallback9, useEffect as useEffect11, useMemo as useMemo7, useState as useState11 } from "react";
4664
+ import { useCallback as useCallback10, useEffect as useEffect12, useMemo as useMemo10, useState as useState12 } from "react";
4071
4665
  var shared = /* @__PURE__ */ new WeakMap();
4072
4666
  function load(client, agent) {
4073
4667
  let byAgent = shared.get(client);
@@ -4089,13 +4683,14 @@ function load(client, agent) {
4089
4683
  return request;
4090
4684
  }
4091
4685
  __name(load, "load");
4092
- function useToolCatalog(options) {
4093
- const { client, agent, enabled = true } = options;
4094
- const [entries, setEntries] = useState11([]);
4095
- const [isLoading, setLoading] = useState11(enabled);
4096
- const [error, setError] = useState11(null);
4097
- const [generation, setGeneration] = useState11(0);
4098
- useEffect11(() => {
4686
+ function useToolCatalog(options = {}) {
4687
+ const { agent, enabled = true } = options;
4688
+ const client = useAgentBackend(options.backend);
4689
+ const [entries, setEntries] = useState12([]);
4690
+ const [isLoading, setLoading] = useState12(enabled);
4691
+ const [error, setError] = useState12(null);
4692
+ const [generation, setGeneration] = useState12(0);
4693
+ useEffect12(() => {
4099
4694
  if (!enabled) {
4100
4695
  setLoading(false);
4101
4696
  return;
@@ -4121,14 +4716,14 @@ function useToolCatalog(options) {
4121
4716
  enabled,
4122
4717
  generation
4123
4718
  ]);
4124
- const refresh = useCallback9(() => {
4719
+ const refresh = useCallback10(() => {
4125
4720
  shared.get(client)?.delete(agent ?? "");
4126
4721
  setGeneration((current) => current + 1);
4127
4722
  }, [
4128
4723
  client,
4129
4724
  agent
4130
4725
  ]);
4131
- const catalog = useMemo7(() => toolCatalogFrom(entries), [
4726
+ const catalog = useMemo10(() => toolCatalogFrom(entries), [
4132
4727
  entries
4133
4728
  ]);
4134
4729
  return {
@@ -4142,7 +4737,7 @@ function useToolCatalog(options) {
4142
4737
  __name(useToolCatalog, "useToolCatalog");
4143
4738
 
4144
4739
  // src/approvals/countdown.ts
4145
- import { useEffect as useEffect12, useRef as useRef10, useState as useState12 } from "react";
4740
+ import { useEffect as useEffect13, useRef as useRef11, useState as useState13 } from "react";
4146
4741
  function approvalCountdown(expiresAt, now = Date.now()) {
4147
4742
  const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
4148
4743
  if (!Number.isFinite(deadline)) {
@@ -4160,10 +4755,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
4160
4755
  __name(approvalCountdown, "approvalCountdown");
4161
4756
  function useApprovalCountdown(expiresAt, options = {}) {
4162
4757
  const { intervalMs = 1e3 } = options;
4163
- const nowRef = useRef10(options.now ?? Date.now);
4758
+ const nowRef = useRef11(options.now ?? Date.now);
4164
4759
  nowRef.current = options.now ?? Date.now;
4165
- const [state, setState] = useState12(() => approvalCountdown(expiresAt, nowRef.current()));
4166
- useEffect12(() => {
4760
+ const [state, setState] = useState13(() => approvalCountdown(expiresAt, nowRef.current()));
4761
+ useEffect13(() => {
4167
4762
  const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
4168
4763
  const first = read();
4169
4764
  setState(first);
@@ -4411,40 +5006,26 @@ __name(sumUsage, "sumUsage");
4411
5006
 
4412
5007
  // src/use-agent-chat.ts
4413
5008
  import { useChat } from "@ai-sdk/react";
4414
- import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef11, useState as useState13 } from "react";
4415
- function useAgentChat(options) {
4416
- const latest = useRef11(options);
5009
+ import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef12, useState as useState14 } from "react";
5010
+ function useAgentChat(options = {}) {
5011
+ const latest = useRef12(options);
4417
5012
  latest.current = options;
4418
- const [runId, setRunId] = useState13(options.resumeRunId);
4419
- const runIdRef = useRef11(runId);
5013
+ const [runId, setRunId] = useState14(options.resumeRunId);
5014
+ const runIdRef = useRef12(runId);
4420
5015
  runIdRef.current = runId;
4421
- const settlingRunIdRef = useRef11(void 0);
4422
- const autoResumeRunIdRef = useRef11(void 0);
4423
- const [autoResume, setAutoResume] = useState13(false);
4424
- const [activeRunId, setActiveRunId] = useState13(null);
4425
- const regenerateNext = useRef11(false);
4426
- const createdThreadId = useRef11(void 0);
4427
- const client = useMemo8(() => {
4428
- if (options.backend) return options.backend;
4429
- if (options.client) return options.client;
4430
- return new AgentClient({
4431
- ...options.baseUrl !== void 0 ? {
4432
- baseUrl: options.baseUrl
4433
- } : {},
4434
- ...options.credentials !== void 0 ? {
4435
- credentials: options.credentials
4436
- } : {},
4437
- ...options.fetch !== void 0 ? {
4438
- fetch: options.fetch
4439
- } : {},
4440
- getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
4441
- });
4442
- }, []);
4443
- const [connection, setConnection] = useState13({
5016
+ const settlingRunIdRef = useRef12(void 0);
5017
+ const autoResumeRunIdRef = useRef12(void 0);
5018
+ const [autoResume, setAutoResume] = useState14(false);
5019
+ const [activeRunId, setActiveRunId] = useState14(null);
5020
+ const regenerateNext = useRef12(false);
5021
+ const createdThreadId = useRef12(void 0);
5022
+ const resolved = useAgentBackend(options.backend);
5023
+ const client = useRef12(resolved).current;
5024
+ const [connection, setConnection] = useState14({
4444
5025
  status: "live"
4445
5026
  });
4446
- const resyncAfterSettle = useRef11(false);
4447
- useEffect13(() => {
5027
+ const resyncAfterSettle = useRef12(false);
5028
+ useEffect14(() => {
4448
5029
  if (!options.resume || options.threadId === void 0) return;
4449
5030
  let cancelled = false;
4450
5031
  const threadId = options.threadId;
@@ -4464,7 +5045,7 @@ function useAgentChat(options) {
4464
5045
  options.resume,
4465
5046
  options.threadId
4466
5047
  ]);
4467
- const transport = useMemo8(() => {
5048
+ const transport = useMemo11(() => {
4468
5049
  function onMeta(meta) {
4469
5050
  settlingRunIdRef.current = meta.runId;
4470
5051
  setRunId(meta.runId);
@@ -4519,7 +5100,7 @@ function useAgentChat(options) {
4519
5100
  }, "onAttemptStart")
4520
5101
  });
4521
5102
  }, []);
4522
- const backgroundRef = useRef11(() => Promise.resolve());
5103
+ const backgroundRef = useRef12(() => Promise.resolve());
4523
5104
  const chat = useChat({
4524
5105
  transport,
4525
5106
  resume: options.resumeRunId !== void 0 || autoResume,
@@ -4568,7 +5149,7 @@ function useAgentChat(options) {
4568
5149
  }
4569
5150
  }, "onFinish")
4570
5151
  });
4571
- const chatRef = useRef11(chat);
5152
+ const chatRef = useRef12(chat);
4572
5153
  chatRef.current = chat;
4573
5154
  async function resyncFromThread() {
4574
5155
  const threadId = latest.current.threadId ?? createdThreadId.current;
@@ -4580,11 +5161,11 @@ function useAgentChat(options) {
4580
5161
  }
4581
5162
  }
4582
5163
  __name(resyncFromThread, "resyncFromThread");
4583
- const turnInFlight = useRef11(false);
4584
- const isTurnInFlight = useCallback10(() => turnInFlight.current || transport.isAttemptLive, [
5164
+ const turnInFlight = useRef12(false);
5165
+ const isTurnInFlight = useCallback11(() => turnInFlight.current || transport.isAttemptLive, [
4585
5166
  transport
4586
5167
  ]);
4587
- const sendMessage = useCallback10(async (...args) => {
5168
+ const sendMessage = useCallback11(async (...args) => {
4588
5169
  const blocked = latest.current.blocked;
4589
5170
  if (blocked != null) throw new QuotaBlockedError(blocked);
4590
5171
  if (isTurnInFlight()) return;
@@ -4597,15 +5178,15 @@ function useAgentChat(options) {
4597
5178
  }, [
4598
5179
  isTurnInFlight
4599
5180
  ]);
4600
- const addToolResult = useCallback10(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
5181
+ const addToolResult = useCallback11(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
4601
5182
  tool,
4602
5183
  toolCallId,
4603
5184
  output
4604
5185
  }), []);
4605
- const [threads, setThreads] = useState13([]);
4606
- const [quota, setQuota] = useState13(null);
4607
- const [backgroundRuns, setBackgroundRuns] = useState13([]);
4608
- const refreshBackground = useCallback10(async () => {
5186
+ const [threads, setThreads] = useState14([]);
5187
+ const [quota, setQuota] = useState14(null);
5188
+ const [backgroundRuns, setBackgroundRuns] = useState14([]);
5189
+ const refreshBackground = useCallback11(async () => {
4609
5190
  const threadId = latest.current.threadId ?? createdThreadId.current;
4610
5191
  if (threadId === void 0) {
4611
5192
  return;
@@ -4630,7 +5211,7 @@ function useAgentChat(options) {
4630
5211
  ]);
4631
5212
  backgroundRef.current = refreshBackground;
4632
5213
  const isWorking = backgroundRuns.some((run) => run.status === "running");
4633
- useEffect13(() => {
5214
+ useEffect14(() => {
4634
5215
  if (options.background !== true || options.threadId === void 0) {
4635
5216
  return;
4636
5217
  }
@@ -4640,7 +5221,7 @@ function useAgentChat(options) {
4640
5221
  options.threadId,
4641
5222
  refreshBackground
4642
5223
  ]);
4643
- useEffect13(() => {
5224
+ useEffect14(() => {
4644
5225
  const every = latest.current.backgroundPollMs ?? 5e3;
4645
5226
  if (latest.current.background !== true || !isWorking || every <= 0) {
4646
5227
  return;
@@ -4651,26 +5232,26 @@ function useAgentChat(options) {
4651
5232
  isWorking,
4652
5233
  refreshBackground
4653
5234
  ]);
4654
- const loadThreads = useCallback10(async () => {
5235
+ const loadThreads = useCallback11(async () => {
4655
5236
  const list = await client.listThreads();
4656
5237
  setThreads(list);
4657
5238
  return list;
4658
5239
  }, [
4659
5240
  client
4660
5241
  ]);
4661
- const loadThread = useCallback10((id) => client.getThread(id), [
5242
+ const loadThread = useCallback11((id) => client.getThread(id), [
4662
5243
  client
4663
5244
  ]);
4664
- const deleteThread = useCallback10(async (id) => {
5245
+ const deleteThread = useCallback11(async (id) => {
4665
5246
  await client.deleteThread(id);
4666
5247
  setThreads((current) => current.filter((thread) => thread.id !== id));
4667
5248
  }, [
4668
5249
  client
4669
5250
  ]);
4670
- const forkThread = useCallback10((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
5251
+ const forkThread = useCallback11((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
4671
5252
  client
4672
5253
  ]);
4673
- const renameThread = useCallback10(async (id, title) => {
5254
+ const renameThread = useCallback11(async (id, title) => {
4674
5255
  await client.updateThread(id, {
4675
5256
  title
4676
5257
  });
@@ -4681,24 +5262,24 @@ function useAgentChat(options) {
4681
5262
  }, [
4682
5263
  client
4683
5264
  ]);
4684
- const promoteThread = useCallback10(async (id) => {
5265
+ const promoteThread = useCallback11(async (id) => {
4685
5266
  await requireBackendMethod(client, "promoteThread")(id);
4686
5267
  await loadThreads();
4687
5268
  }, [
4688
5269
  client,
4689
5270
  loadThreads
4690
5271
  ]);
4691
- const truncateFromMessage = useCallback10((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
5272
+ const truncateFromMessage = useCallback11((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
4692
5273
  client
4693
5274
  ]);
4694
- const loadQuota = useCallback10(async () => {
5275
+ const loadQuota = useCallback11(async () => {
4695
5276
  const today = await requireBackendMethod(client, "getQuotaToday")();
4696
5277
  setQuota(today);
4697
5278
  return today;
4698
5279
  }, [
4699
5280
  client
4700
5281
  ]);
4701
- const cancel = useCallback10(async () => {
5282
+ const cancel = useCallback11(async () => {
4702
5283
  chatRef.current.stop();
4703
5284
  const activeRunId2 = runIdRef.current;
4704
5285
  if (activeRunId2) {
@@ -4710,7 +5291,7 @@ function useAgentChat(options) {
4710
5291
  }, [
4711
5292
  client
4712
5293
  ]);
4713
- const approve = useCallback10(async ({ toolCallId, remember, via }) => {
5294
+ const approve = useCallback11(async ({ toolCallId, remember, via }) => {
4714
5295
  await requireBackendMethod(client, "approveToolCall")({
4715
5296
  toolCallId,
4716
5297
  ...remember === true ? {
@@ -4723,7 +5304,7 @@ function useAgentChat(options) {
4723
5304
  }, [
4724
5305
  client
4725
5306
  ]);
4726
- const reject = useCallback10(async ({ toolCallId, reason, via }) => {
5307
+ const reject = useCallback11(async ({ toolCallId, reason, via }) => {
4727
5308
  await requireBackendMethod(client, "rejectToolCall")({
4728
5309
  toolCallId,
4729
5310
  ...reason !== void 0 ? {
@@ -4736,7 +5317,7 @@ function useAgentChat(options) {
4736
5317
  }, [
4737
5318
  client
4738
5319
  ]);
4739
- const answer = useCallback10(async ({ toolCallId, answers }) => {
5320
+ const answer = useCallback11(async ({ toolCallId, answers }) => {
4740
5321
  await requireBackendMethod(client, "answerToolCall")({
4741
5322
  toolCallId,
4742
5323
  ...answers !== void 0 ? {
@@ -4746,14 +5327,14 @@ function useAgentChat(options) {
4746
5327
  }, [
4747
5328
  client
4748
5329
  ]);
4749
- const skip = useCallback10(async ({ toolCallId }) => {
5330
+ const skip = useCallback11(async ({ toolCallId }) => {
4750
5331
  await requireBackendMethod(client, "skipToolCall")({
4751
5332
  toolCallId
4752
5333
  });
4753
5334
  }, [
4754
5335
  client
4755
5336
  ]);
4756
- const regenerate = useCallback10(() => {
5337
+ const regenerate = useCallback11(() => {
4757
5338
  const blocked = latest.current.blocked;
4758
5339
  if (blocked != null) throw new QuotaBlockedError(blocked);
4759
5340
  if (isTurnInFlight()) return;
@@ -4770,7 +5351,7 @@ function useAgentChat(options) {
4770
5351
  isWorking,
4771
5352
  refresh: refreshBackground
4772
5353
  };
4773
- const setThreadModel = useCallback10(async (model) => {
5354
+ const setThreadModel = useCallback11(async (model) => {
4774
5355
  const threadId = latest.current.threadId ?? createdThreadId.current;
4775
5356
  if (threadId === void 0) {
4776
5357
  throw new Error("setThreadModel: this chat has no thread yet");
@@ -4784,7 +5365,7 @@ function useAgentChat(options) {
4784
5365
  }, [
4785
5366
  client
4786
5367
  ]);
4787
- const getThreadId = useCallback10(() => latest.current.threadId ?? createdThreadId.current, []);
5368
+ const getThreadId = useCallback11(() => latest.current.threadId ?? createdThreadId.current, []);
4788
5369
  const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
4789
5370
  return {
4790
5371
  ...chat,
@@ -4804,10 +5385,8 @@ function useAgentChat(options) {
4804
5385
  */
4805
5386
  getThreadId,
4806
5387
  setThreadModel,
4807
- /** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
5388
+ /** The backend this chat talks to — the same one every other hook under the provider uses. */
4808
5389
  backend: client,
4809
- /** Same object as {@link backend}; kept for callers that read it under its old name. */
4810
- client,
4811
5390
  threads,
4812
5391
  loadThreads,
4813
5392
  loadThread,
@@ -4837,19 +5416,12 @@ var QuotaBlockedError = class extends Error {
4837
5416
  this.name = "QuotaBlockedError";
4838
5417
  }
4839
5418
  };
4840
- async function mergeHeaders(options) {
4841
- const dynamic = await options.getHeaders?.() ?? {};
4842
- return {
4843
- ...options.headers,
4844
- ...dynamic
4845
- };
4846
- }
4847
- __name(mergeHeaders, "mergeHeaders");
4848
5419
  export {
4849
5420
  AgentBackendUnsupportedError,
4850
5421
  AgentChatTransport,
4851
5422
  AgentClient,
4852
5423
  AgentHttpError,
5424
+ AgentProvider,
4853
5425
  AmbientRenderUiContext,
4854
5426
  ChatInput,
4855
5427
  DEFAULT_SPEECH_LANG,
@@ -4895,6 +5467,7 @@ export {
4895
5467
  storedThreadToUiMessages,
4896
5468
  toolCallState,
4897
5469
  toolCatalogFrom,
5470
+ useAgentBackend,
4898
5471
  useAgentChat,
4899
5472
  useAgents,
4900
5473
  useAmbientRenderUi,