@dudousxd/nestjs-agent-react 0.9.0 → 0.10.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.cjs CHANGED
@@ -43,25 +43,37 @@ __export(src_exports, {
43
43
  applyCompletion: () => applyCompletion,
44
44
  backgroundRunsFromThread: () => backgroundRunsFromThread,
45
45
  buildTranscriptBlocks: () => buildTranscriptBlocks,
46
+ correctedCallIds: () => correctedCallIds,
46
47
  createSkillsSource: () => createSkillsSource,
47
48
  describeTimestamp: () => describeTimestamp,
49
+ describeToolCall: () => describeToolCall,
48
50
  describeUsage: () => describeUsage,
49
51
  extractMessageText: () => extractMessageText,
52
+ fillTemplate: () => fillTemplate,
50
53
  filterAutocompleteItems: () => filterAutocompleteItems,
51
54
  findActiveTrigger: () => findActiveTrigger,
52
55
  formatElapsed: () => formatElapsed,
53
56
  formatRelativeTime: () => formatRelativeTime,
57
+ groupToolActivity: () => groupToolActivity,
58
+ inferResultView: () => inferResultView,
59
+ isActionCall: () => isActionCall,
54
60
  loadStoredSpeechLang: () => loadStoredSpeechLang,
55
61
  persistSpeechLang: () => persistSpeechLang,
62
+ phraseFor: () => phraseFor,
63
+ readPath: () => readPath,
56
64
  readReasoningMs: () => readReasoningMs,
65
+ resolveResultView: () => resolveResultView,
57
66
  storedMessageToUiMessage: () => storedMessageToUiMessage,
58
67
  storedThreadToUiMessages: () => storedThreadToUiMessages,
68
+ toolCallState: () => toolCallState,
69
+ toolCatalogFrom: () => toolCatalogFrom,
59
70
  useAgentChat: () => useAgentChat,
60
71
  useChatTranscript: () => useChatTranscript,
61
72
  useComposerAutocomplete: () => useComposerAutocomplete,
62
73
  useElapsed: () => useElapsed,
63
74
  useSpeechRecognition: () => useSpeechRecognition,
64
75
  useStickToBottom: () => useStickToBottom,
76
+ useToolCatalog: () => useToolCatalog,
65
77
  useTranscriptItem: () => useTranscriptItem
66
78
  });
67
79
  module.exports = __toCommonJS(src_exports);
@@ -744,6 +756,15 @@ var AgentClient = class {
744
756
  const query = threadId === void 0 ? "" : `?threadId=${encodeURIComponent(threadId)}`;
745
757
  return this.request("GET", `/agent/skills${query}`);
746
758
  }
759
+ /**
760
+ * The tools this caller can reach through `agent` (the default agent when omitted), each with the
761
+ * server-declared `presentation` a chat narrates it by — the same list the model is offered.
762
+ * Prefer {@link useToolCatalog}, which fetches it once and shares it.
763
+ */
764
+ listTools(agent) {
765
+ const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
766
+ return this.request("GET", `/agent/tools${query}`);
767
+ }
747
768
  getThread(id) {
748
769
  return this.request("GET", `/agent/threads/${encodeURIComponent(id)}`);
749
770
  }
@@ -1026,7 +1047,280 @@ var import_react6 = __toESM(require("react"), 1);
1026
1047
  var import_react5 = require("react");
1027
1048
 
1028
1049
  // src/transcript/model.ts
1050
+ var import_ai2 = require("ai");
1051
+
1052
+ // src/presentation/tool-activity.ts
1029
1053
  var import_ai = require("ai");
1054
+
1055
+ // src/presentation/phrasing.ts
1056
+ function toolCatalogFrom(entries) {
1057
+ const catalog = {};
1058
+ for (const entry of entries) {
1059
+ if (entry.presentation !== void 0) catalog[entry.name] = entry.presentation;
1060
+ }
1061
+ return catalog;
1062
+ }
1063
+ __name(toolCatalogFrom, "toolCatalogFrom");
1064
+ function readPath(value, path) {
1065
+ return path.split(".").reduce((current, key) => {
1066
+ if (current === null || typeof current !== "object") return void 0;
1067
+ return current[key];
1068
+ }, value);
1069
+ }
1070
+ __name(readPath, "readPath");
1071
+ function renderValue(value) {
1072
+ if (value === null || value === void 0) return "";
1073
+ if (typeof value === "string") return value;
1074
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1075
+ if (Array.isArray(value)) return value.map(renderValue).filter(Boolean).join(", ");
1076
+ return "";
1077
+ }
1078
+ __name(renderValue, "renderValue");
1079
+ function fillTemplate(template, context) {
1080
+ return template.replace(/(\s*)\{([\w.]+)\}/g, (_match, space, path) => {
1081
+ const rendered = renderValue(readPath(context, path));
1082
+ return rendered === "" ? "" : `${space}${rendered}`;
1083
+ }).replace(/\s{2,}/g, " ").trim();
1084
+ }
1085
+ __name(fillTemplate, "fillTemplate");
1086
+ function phraseFor(presentation, input, isSettled2, fallback = {
1087
+ running: "Working",
1088
+ done: "Done"
1089
+ }) {
1090
+ if (presentation === void 0) return isSettled2 ? fallback.done : fallback.running;
1091
+ const filled = fillTemplate(isSettled2 ? presentation.done : presentation.running, input);
1092
+ return filled === "" ? presentation.label : filled;
1093
+ }
1094
+ __name(phraseFor, "phraseFor");
1095
+
1096
+ // src/presentation/result-view.ts
1097
+ function isRecord(value) {
1098
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1099
+ }
1100
+ __name(isRecord, "isRecord");
1101
+ function toText(value) {
1102
+ if (value === null || value === void 0) return "\u2014";
1103
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1104
+ return String(value);
1105
+ }
1106
+ if (Array.isArray(value)) return value.map(toText).join(", ");
1107
+ return "\u2014";
1108
+ }
1109
+ __name(toText, "toText");
1110
+ function inferResultView(output) {
1111
+ if (!isRecord(output)) return void 0;
1112
+ for (const [key, value] of Object.entries(output)) {
1113
+ if (!Array.isArray(value) || value.length === 0) continue;
1114
+ if (value.every((entry) => typeof entry === "string")) {
1115
+ return {
1116
+ kind: "log",
1117
+ lines: key
1118
+ };
1119
+ }
1120
+ if (value.every(isRecord)) {
1121
+ const first = value[0];
1122
+ return {
1123
+ kind: "table",
1124
+ rows: key,
1125
+ columns: Object.keys(first).filter((column) => !isRecord(first[column])).map((column) => ({
1126
+ path: column,
1127
+ label: column
1128
+ }))
1129
+ };
1130
+ }
1131
+ }
1132
+ const fields = Object.entries(output).filter(([, value]) => [
1133
+ "string",
1134
+ "number",
1135
+ "boolean"
1136
+ ].includes(typeof value)).map(([key]) => ({
1137
+ path: key,
1138
+ label: key
1139
+ }));
1140
+ return fields.length > 0 ? {
1141
+ kind: "metrics",
1142
+ fields
1143
+ } : void 0;
1144
+ }
1145
+ __name(inferResultView, "inferResultView");
1146
+ function resolveResultView(output, view, options = {}) {
1147
+ const resolved = view ?? (options.infer === true ? inferResultView(output) : void 0);
1148
+ if (resolved === void 0 || resolved.kind === "elsewhere") return null;
1149
+ switch (resolved.kind) {
1150
+ case "note": {
1151
+ const text = fillTemplate(resolved.text, output);
1152
+ return text === "" ? null : {
1153
+ kind: "note",
1154
+ text
1155
+ };
1156
+ }
1157
+ case "metrics": {
1158
+ const readings = resolved.fields.map((field) => ({
1159
+ field,
1160
+ value: readPath(output, field.path)
1161
+ })).filter((entry) => entry.value !== void 0 && entry.value !== null).map(({ field, value }) => ({
1162
+ label: field.label,
1163
+ value: toText(value),
1164
+ unit: field.unit ?? null
1165
+ }));
1166
+ return readings.length === 0 ? null : {
1167
+ kind: "metrics",
1168
+ readings
1169
+ };
1170
+ }
1171
+ case "log": {
1172
+ const lines = readPath(output, resolved.lines);
1173
+ if (!Array.isArray(lines) || lines.length === 0) return null;
1174
+ return {
1175
+ kind: "log",
1176
+ lines: lines.map(toText)
1177
+ };
1178
+ }
1179
+ case "table": {
1180
+ const rows = readPath(output, resolved.rows);
1181
+ if (!Array.isArray(rows)) return null;
1182
+ return {
1183
+ kind: "table",
1184
+ columns: resolved.columns,
1185
+ rows: rows.map((row) => resolved.columns.map((column) => toText(readPath(row, column.path)))),
1186
+ empty: rows.length === 0 ? resolved.empty ?? null : null
1187
+ };
1188
+ }
1189
+ }
1190
+ }
1191
+ __name(resolveResultView, "resolveResultView");
1192
+
1193
+ // src/presentation/tool-activity.ts
1194
+ function isActionCall(part) {
1195
+ const metadata = part.toolMetadata;
1196
+ return typeof metadata === "object" && metadata !== null && metadata.toolKind === "action";
1197
+ }
1198
+ __name(isActionCall, "isActionCall");
1199
+ function toolCallState(part) {
1200
+ const output = "output" in part ? part.output : void 0;
1201
+ const errorText = "errorText" in part ? part.errorText : void 0;
1202
+ const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
1203
+ const isDenied = part.state === "output-denied";
1204
+ const isFailed = part.state === "output-error" || outputError !== void 0 && !isDenied;
1205
+ const isSettled2 = part.state === "output-available" || part.state === "output-error" || isDenied;
1206
+ const isAwaiting = part.state === "approval-requested" || part.state === "input-available" && isActionCall(part);
1207
+ const status = isDenied ? "denied" : isFailed ? "failed" : isSettled2 ? "done" : isAwaiting ? "awaiting-approval" : "running";
1208
+ return {
1209
+ status,
1210
+ isSettled: isSettled2,
1211
+ isFailed,
1212
+ isDenied,
1213
+ output,
1214
+ error: errorText ?? outputError ?? null
1215
+ };
1216
+ }
1217
+ __name(toolCallState, "toolCallState");
1218
+ function correctedCallIds(parts) {
1219
+ const corrected = /* @__PURE__ */ new Set();
1220
+ const lastSuccessByTool = /* @__PURE__ */ new Map();
1221
+ parts.forEach((part, index) => {
1222
+ if (part.state === "output-available" && !toolCallState(part).isFailed) {
1223
+ lastSuccessByTool.set((0, import_ai.getToolName)(part), index);
1224
+ }
1225
+ });
1226
+ parts.forEach((part, index) => {
1227
+ const successAt = lastSuccessByTool.get((0, import_ai.getToolName)(part));
1228
+ if (successAt !== void 0 && index < successAt && toolCallState(part).isFailed) {
1229
+ corrected.add(part.toolCallId);
1230
+ }
1231
+ });
1232
+ return corrected;
1233
+ }
1234
+ __name(correctedCallIds, "correctedCallIds");
1235
+ function describeToolCall(part, catalog, options = {}) {
1236
+ const presentation = catalog?.[(0, import_ai.getToolName)(part)];
1237
+ const state = toolCallState(part);
1238
+ const input = part.input;
1239
+ const confirm = presentation?.confirm;
1240
+ return {
1241
+ status: state.status,
1242
+ phrase: phraseFor(presentation, input, state.isSettled, options.fallback),
1243
+ label: presentation?.label ?? null,
1244
+ icon: presentation?.icon ?? null,
1245
+ tone: presentation?.tone ?? "neutral",
1246
+ detail: presentation?.detail ?? null,
1247
+ confirm: confirm === void 0 ? null : {
1248
+ title: fillTemplate(confirm.title, input),
1249
+ verb: confirm.verb,
1250
+ detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
1251
+ },
1252
+ result: state.status === "done" ? resolveResultView(state.output, presentation?.result, {
1253
+ ...options.inferResult !== void 0 ? {
1254
+ infer: options.inferResult
1255
+ } : {}
1256
+ }) : null,
1257
+ error: state.error,
1258
+ presentation: presentation ?? null
1259
+ };
1260
+ }
1261
+ __name(describeToolCall, "describeToolCall");
1262
+ var STATUS_WEIGHT = {
1263
+ running: 4,
1264
+ "awaiting-approval": 3,
1265
+ failed: 2,
1266
+ denied: 1,
1267
+ done: 0
1268
+ };
1269
+ function descendants(call) {
1270
+ return call.children.flatMap((child) => [
1271
+ child,
1272
+ ...descendants(child)
1273
+ ]);
1274
+ }
1275
+ __name(descendants, "descendants");
1276
+ function leaves(call) {
1277
+ return call.children.length === 0 ? [
1278
+ call
1279
+ ] : call.children.flatMap(leaves);
1280
+ }
1281
+ __name(leaves, "leaves");
1282
+ function groupToolActivity(calls, options = {}) {
1283
+ const expanded = options.expandNested === true ? calls.flatMap(leaves) : [
1284
+ ...calls
1285
+ ];
1286
+ const corrected = options.hideCorrected === true ? correctedCallIds(expanded.map((call) => call.part)) : /* @__PURE__ */ new Set();
1287
+ const groups = /* @__PURE__ */ new Map();
1288
+ for (const call of expanded) {
1289
+ if (corrected.has(call.toolCallId)) continue;
1290
+ const presentation = options.catalog?.[call.name];
1291
+ const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
1292
+ const status = toolCallState(call.part).status;
1293
+ const phrase = phraseFor(presentation, call.part.input, status !== "running" && status !== "awaiting-approval", options.fallback);
1294
+ const inner = options.expandNested === true ? 0 : descendants(call).length;
1295
+ const existing = groups.get(key);
1296
+ if (existing === void 0) {
1297
+ groups.set(key, {
1298
+ key,
1299
+ label: presentation?.label ?? null,
1300
+ icon: presentation?.icon ?? null,
1301
+ status,
1302
+ count: 1,
1303
+ phrase,
1304
+ calls: [
1305
+ call
1306
+ ],
1307
+ innerCount: inner
1308
+ });
1309
+ continue;
1310
+ }
1311
+ existing.count += 1;
1312
+ existing.calls.push(call);
1313
+ existing.phrase = phrase;
1314
+ existing.innerCount += inner;
1315
+ if (STATUS_WEIGHT[status] > STATUS_WEIGHT[existing.status]) existing.status = status;
1316
+ }
1317
+ return [
1318
+ ...groups.values()
1319
+ ];
1320
+ }
1321
+ __name(groupToolActivity, "groupToolActivity");
1322
+
1323
+ // src/transcript/model.ts
1030
1324
  function buildTranscriptBlocks(message, options) {
1031
1325
  const blocks = [];
1032
1326
  let toolBuffer = [];
@@ -1043,13 +1337,19 @@ function buildTranscriptBlocks(message, options) {
1043
1337
  if (toolBuffer.length === 0) {
1044
1338
  return;
1045
1339
  }
1046
- const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null));
1340
+ const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null, options.toolCatalog));
1341
+ const roots = nestToolCalls(calls);
1047
1342
  blocks.push({
1048
1343
  kind: "tools",
1049
1344
  key: `${message.id}-tools-${toolCounter++}`,
1050
1345
  parts: toolBuffer,
1051
1346
  calls,
1052
- roots: nestToolCalls(calls)
1347
+ roots,
1348
+ activity: groupToolActivity(roots, {
1349
+ ...options.toolCatalog !== void 0 ? {
1350
+ catalog: options.toolCatalog
1351
+ } : {}
1352
+ })
1053
1353
  });
1054
1354
  toolBuffer = [];
1055
1355
  }
@@ -1086,7 +1386,7 @@ function buildTranscriptBlocks(message, options) {
1086
1386
  }
1087
1387
  __name(flushAll, "flushAll");
1088
1388
  for (const part of message.parts ?? []) {
1089
- if ((0, import_ai.isToolUIPart)(part)) {
1389
+ if ((0, import_ai2.isToolUIPart)(part)) {
1090
1390
  const elicitation = options.elicitation;
1091
1391
  if (elicitation !== void 0) {
1092
1392
  const request = readElicitationRequest(part);
@@ -1106,7 +1406,7 @@ function buildTranscriptBlocks(message, options) {
1106
1406
  toolBuffer.push(part);
1107
1407
  continue;
1108
1408
  }
1109
- if ((0, import_ai.isFileUIPart)(part)) {
1409
+ if ((0, import_ai2.isFileUIPart)(part)) {
1110
1410
  flushTools();
1111
1411
  flushSources();
1112
1412
  fileBuffer.push(part);
@@ -1116,7 +1416,7 @@ function buildTranscriptBlocks(message, options) {
1116
1416
  continue;
1117
1417
  }
1118
1418
  flushAll();
1119
- if ((0, import_ai.isDataUIPart)(part)) {
1419
+ if ((0, import_ai2.isDataUIPart)(part)) {
1120
1420
  const ui = part.type === UI_PART ? readUiComponent(part) : null;
1121
1421
  if (ui !== null) {
1122
1422
  blocks.push({
@@ -1127,7 +1427,7 @@ function buildTranscriptBlocks(message, options) {
1127
1427
  }
1128
1428
  continue;
1129
1429
  }
1130
- if ((0, import_ai.isTextUIPart)(part)) {
1430
+ if ((0, import_ai2.isTextUIPart)(part)) {
1131
1431
  blocks.push({
1132
1432
  kind: "text",
1133
1433
  key: `${message.id}-text-${textCounter++}`,
@@ -1136,7 +1436,7 @@ function buildTranscriptBlocks(message, options) {
1136
1436
  });
1137
1437
  continue;
1138
1438
  }
1139
- if ((0, import_ai.isReasoningUIPart)(part)) {
1439
+ if ((0, import_ai2.isReasoningUIPart)(part)) {
1140
1440
  const key = `${message.id}-reasoning-${reasoningCounter++}`;
1141
1441
  const isStreaming = part.state === "streaming";
1142
1442
  blocks.push({
@@ -1198,7 +1498,7 @@ function isSettled(state) {
1198
1498
  __name(isSettled, "isSettled");
1199
1499
  function toolKind(part) {
1200
1500
  const metadata = part.toolMetadata;
1201
- return isRecord(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
1501
+ return isRecord2(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
1202
1502
  }
1203
1503
  __name(toolKind, "toolKind");
1204
1504
  function isAwaitingApproval(part) {
@@ -1213,7 +1513,7 @@ function isAwaitingApproval(part) {
1213
1513
  __name(isAwaitingApproval, "isAwaitingApproval");
1214
1514
  function toolParentId(part) {
1215
1515
  const metadata = part.toolMetadata;
1216
- return isRecord(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
1516
+ return isRecord2(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
1217
1517
  }
1218
1518
  __name(toolParentId, "toolParentId");
1219
1519
  function nestToolCalls(calls) {
@@ -1246,18 +1546,19 @@ function isAncestor(call, candidate, byId) {
1246
1546
  return false;
1247
1547
  }
1248
1548
  __name(isAncestor, "isAncestor");
1249
- function buildToolCall(part, options, approval) {
1549
+ function buildToolCall(part, options, approval, catalog) {
1250
1550
  const toolCallId = part.toolCallId;
1251
1551
  const awaiting = isAwaitingApproval(part);
1252
1552
  const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
1253
1553
  return {
1254
1554
  part,
1255
1555
  toolCallId,
1256
- name: (0, import_ai.getToolName)(part),
1556
+ name: (0, import_ai2.getToolName)(part),
1257
1557
  toolKind: toolKind(part) ?? null,
1258
1558
  parentId: toolParentId(part),
1259
1559
  children: [],
1260
1560
  approval,
1561
+ description: describeToolCall(part, catalog),
1261
1562
  isAwaitingApproval: awaiting,
1262
1563
  approve: {
1263
1564
  available: awaiting && options?.canApprove === true,
@@ -1275,17 +1576,17 @@ function buildToolCall(part, options, approval) {
1275
1576
  __name(buildToolCall, "buildToolCall");
1276
1577
  function readElicitationRequest(part) {
1277
1578
  const input = part.input;
1278
- if (!isRecord(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
1579
+ if (!isRecord2(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
1279
1580
  return null;
1280
1581
  }
1281
1582
  const questions = [];
1282
1583
  for (const candidate of input.questions) {
1283
- if (!isRecord(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string" || !Array.isArray(candidate.options) || candidate.options.length === 0) {
1584
+ if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string" || !Array.isArray(candidate.options) || candidate.options.length === 0) {
1284
1585
  return null;
1285
1586
  }
1286
1587
  const options = [];
1287
1588
  for (const option of candidate.options) {
1288
- if (!isRecord(option) || typeof option.value !== "string" || typeof option.label !== "string") {
1589
+ if (!isRecord2(option) || typeof option.value !== "string" || typeof option.label !== "string") {
1289
1590
  return null;
1290
1591
  }
1291
1592
  options.push({
@@ -1310,7 +1611,7 @@ function readElicitationRequest(part) {
1310
1611
  __name(readElicitationRequest, "readElicitationRequest");
1311
1612
  function readElicitationOutcome(part) {
1312
1613
  const output = part.output;
1313
- if (!isRecord(output) || !isRecord(output.answers) || typeof output.skipped !== "boolean") {
1614
+ if (!isRecord2(output) || !isRecord2(output.answers) || typeof output.skipped !== "boolean") {
1314
1615
  return null;
1315
1616
  }
1316
1617
  const answers = {};
@@ -1397,7 +1698,7 @@ function readApprovals(parts) {
1397
1698
  continue;
1398
1699
  }
1399
1700
  const data = part.data;
1400
- if (!isRecord(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
1701
+ if (!isRecord2(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
1401
1702
  continue;
1402
1703
  }
1403
1704
  out.set(data.id, {
@@ -1411,7 +1712,7 @@ function readApprovals(parts) {
1411
1712
  __name(readApprovals, "readApprovals");
1412
1713
  function readUiComponent(part) {
1413
1714
  const data = part.data;
1414
- if (!isRecord(data) || typeof data.component !== "string") {
1715
+ if (!isRecord2(data) || typeof data.component !== "string") {
1415
1716
  return null;
1416
1717
  }
1417
1718
  const id = typeof data.id === "string" ? data.id : part.id;
@@ -1421,18 +1722,18 @@ function readUiComponent(part) {
1421
1722
  return {
1422
1723
  id,
1423
1724
  component: data.component,
1424
- props: isRecord(data.props) ? data.props : {},
1725
+ props: isRecord2(data.props) ? data.props : {},
1425
1726
  version: typeof data.version === "number" ? data.version : null
1426
1727
  };
1427
1728
  }
1428
1729
  __name(readUiComponent, "readUiComponent");
1429
- function isRecord(value) {
1730
+ function isRecord2(value) {
1430
1731
  return typeof value === "object" && value !== null;
1431
1732
  }
1432
- __name(isRecord, "isRecord");
1733
+ __name(isRecord2, "isRecord");
1433
1734
  function readQuery(part) {
1434
1735
  const input = part.input;
1435
- if (!isRecord(input) || typeof input.query !== "string") {
1736
+ if (!isRecord2(input) || typeof input.query !== "string") {
1436
1737
  return null;
1437
1738
  }
1438
1739
  return input.query;
@@ -1440,12 +1741,12 @@ function readQuery(part) {
1440
1741
  __name(readQuery, "readQuery");
1441
1742
  function readPassages(part) {
1442
1743
  const output = part.output;
1443
- if (!isRecord(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
1744
+ if (!isRecord2(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
1444
1745
  return null;
1445
1746
  }
1446
1747
  const passages = [];
1447
1748
  for (const candidate of output.passages) {
1448
- if (!isRecord(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
1749
+ if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
1449
1750
  return null;
1450
1751
  }
1451
1752
  passages.push({
@@ -1455,7 +1756,7 @@ function readPassages(part) {
1455
1756
  ...typeof candidate.source === "string" ? {
1456
1757
  source: candidate.source
1457
1758
  } : {},
1458
- ...isRecord(candidate.metadata) ? {
1759
+ ...isRecord2(candidate.metadata) ? {
1459
1760
  metadata: candidate.metadata
1460
1761
  } : {}
1461
1762
  });
@@ -1466,7 +1767,7 @@ __name(readPassages, "readPassages");
1466
1767
  function extractMessageText(parts) {
1467
1768
  const out = [];
1468
1769
  for (const part of parts ?? []) {
1469
- if ((0, import_ai.isTextUIPart)(part)) {
1770
+ if ((0, import_ai2.isTextUIPart)(part)) {
1470
1771
  out.push(part.text);
1471
1772
  }
1472
1773
  }
@@ -1922,6 +2223,9 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1922
2223
  ...options.sources !== void 0 ? {
1923
2224
  sources: options.sources
1924
2225
  } : {},
2226
+ ...options.toolCatalog !== void 0 ? {
2227
+ toolCatalog: options.toolCatalog
2228
+ } : {},
1925
2229
  ...options.onAnswer !== void 0 ? {
1926
2230
  elicitation: {
1927
2231
  picked: /* @__PURE__ */ __name((toolCallId, questionId) => picks.get(pickKey(toolCallId, questionId)), "picked"),
@@ -2697,6 +3001,78 @@ function isPromise(value) {
2697
3001
  }
2698
3002
  __name(isPromise, "isPromise");
2699
3003
 
3004
+ // src/presentation/use-tool-catalog.ts
3005
+ var import_react8 = require("react");
3006
+ var shared = /* @__PURE__ */ new WeakMap();
3007
+ function load(client, agent) {
3008
+ let byAgent = shared.get(client);
3009
+ if (byAgent === void 0) {
3010
+ byAgent = /* @__PURE__ */ new Map();
3011
+ shared.set(client, byAgent);
3012
+ }
3013
+ const key = agent ?? "";
3014
+ const cached = byAgent.get(key);
3015
+ if (cached !== void 0) return cached;
3016
+ const request = client.listTools(agent).catch((error) => {
3017
+ byAgent.delete(key);
3018
+ throw error;
3019
+ });
3020
+ byAgent.set(key, request);
3021
+ return request;
3022
+ }
3023
+ __name(load, "load");
3024
+ function useToolCatalog(options) {
3025
+ const { client, agent, enabled = true } = options;
3026
+ const [entries, setEntries] = (0, import_react8.useState)([]);
3027
+ const [isLoading, setLoading] = (0, import_react8.useState)(enabled);
3028
+ const [error, setError] = (0, import_react8.useState)(null);
3029
+ const [generation, setGeneration] = (0, import_react8.useState)(0);
3030
+ (0, import_react8.useEffect)(() => {
3031
+ if (!enabled) {
3032
+ setLoading(false);
3033
+ return;
3034
+ }
3035
+ let cancelled = false;
3036
+ setLoading(true);
3037
+ load(client, agent).then((loaded) => {
3038
+ if (cancelled) return;
3039
+ setEntries(loaded);
3040
+ setError(null);
3041
+ setLoading(false);
3042
+ }, (failure) => {
3043
+ if (cancelled) return;
3044
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
3045
+ setLoading(false);
3046
+ });
3047
+ return () => {
3048
+ cancelled = true;
3049
+ };
3050
+ }, [
3051
+ client,
3052
+ agent,
3053
+ enabled,
3054
+ generation
3055
+ ]);
3056
+ const refresh = (0, import_react8.useCallback)(() => {
3057
+ shared.get(client)?.delete(agent ?? "");
3058
+ setGeneration((current) => current + 1);
3059
+ }, [
3060
+ client,
3061
+ agent
3062
+ ]);
3063
+ const catalog = (0, import_react8.useMemo)(() => toolCatalogFrom(entries), [
3064
+ entries
3065
+ ]);
3066
+ return {
3067
+ catalog,
3068
+ entries,
3069
+ isLoading,
3070
+ error,
3071
+ refresh
3072
+ };
3073
+ }
3074
+ __name(useToolCatalog, "useToolCatalog");
3075
+
2700
3076
  // src/stored-message-to-ui-message.ts
2701
3077
  var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
2702
3078
  function isRefusal(result) {
@@ -2857,21 +3233,21 @@ function sumUsage(rows) {
2857
3233
  __name(sumUsage, "sumUsage");
2858
3234
 
2859
3235
  // src/use-agent-chat.ts
2860
- var import_react8 = require("@ai-sdk/react");
2861
- var import_react9 = require("react");
3236
+ var import_react9 = require("@ai-sdk/react");
3237
+ var import_react10 = require("react");
2862
3238
  function useAgentChat(options) {
2863
- const latest = (0, import_react9.useRef)(options);
3239
+ const latest = (0, import_react10.useRef)(options);
2864
3240
  latest.current = options;
2865
- const [runId, setRunId] = (0, import_react9.useState)(options.resumeRunId);
2866
- const runIdRef = (0, import_react9.useRef)(runId);
3241
+ const [runId, setRunId] = (0, import_react10.useState)(options.resumeRunId);
3242
+ const runIdRef = (0, import_react10.useRef)(runId);
2867
3243
  runIdRef.current = runId;
2868
- const settlingRunIdRef = (0, import_react9.useRef)(void 0);
2869
- const autoResumeRunIdRef = (0, import_react9.useRef)(void 0);
2870
- const [autoResume, setAutoResume] = (0, import_react9.useState)(false);
2871
- const [activeRunId, setActiveRunId] = (0, import_react9.useState)(null);
2872
- const regenerateNext = (0, import_react9.useRef)(false);
2873
- const createdThreadId = (0, import_react9.useRef)(void 0);
2874
- const client = (0, import_react9.useMemo)(() => {
3244
+ const settlingRunIdRef = (0, import_react10.useRef)(void 0);
3245
+ const autoResumeRunIdRef = (0, import_react10.useRef)(void 0);
3246
+ const [autoResume, setAutoResume] = (0, import_react10.useState)(false);
3247
+ const [activeRunId, setActiveRunId] = (0, import_react10.useState)(null);
3248
+ const regenerateNext = (0, import_react10.useRef)(false);
3249
+ const createdThreadId = (0, import_react10.useRef)(void 0);
3250
+ const client = (0, import_react10.useMemo)(() => {
2875
3251
  if (options.client) return options.client;
2876
3252
  return new AgentClient({
2877
3253
  ...options.baseUrl !== void 0 ? {
@@ -2886,7 +3262,7 @@ function useAgentChat(options) {
2886
3262
  getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
2887
3263
  });
2888
3264
  }, []);
2889
- (0, import_react9.useEffect)(() => {
3265
+ (0, import_react10.useEffect)(() => {
2890
3266
  if (!options.resume || options.threadId === void 0) return;
2891
3267
  let cancelled = false;
2892
3268
  const threadId = options.threadId;
@@ -2906,7 +3282,7 @@ function useAgentChat(options) {
2906
3282
  options.resume,
2907
3283
  options.threadId
2908
3284
  ]);
2909
- const transport = (0, import_react9.useMemo)(() => {
3285
+ const transport = (0, import_react10.useMemo)(() => {
2910
3286
  function onMeta(meta) {
2911
3287
  settlingRunIdRef.current = meta.runId;
2912
3288
  setRunId(meta.runId);
@@ -2955,8 +3331,8 @@ function useAgentChat(options) {
2955
3331
  }, "onAttemptStart")
2956
3332
  });
2957
3333
  }, []);
2958
- const backgroundRef = (0, import_react9.useRef)(() => Promise.resolve());
2959
- const chat = (0, import_react8.useChat)({
3334
+ const backgroundRef = (0, import_react10.useRef)(() => Promise.resolve());
3335
+ const chat = (0, import_react9.useChat)({
2960
3336
  transport,
2961
3337
  resume: options.resumeRunId !== void 0 || autoResume,
2962
3338
  ...options.threadId !== void 0 ? {
@@ -2986,13 +3362,13 @@ function useAgentChat(options) {
2986
3362
  }
2987
3363
  }, "onFinish")
2988
3364
  });
2989
- const chatRef = (0, import_react9.useRef)(chat);
3365
+ const chatRef = (0, import_react10.useRef)(chat);
2990
3366
  chatRef.current = chat;
2991
- const turnInFlight = (0, import_react9.useRef)(false);
2992
- const isTurnInFlight = (0, import_react9.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
3367
+ const turnInFlight = (0, import_react10.useRef)(false);
3368
+ const isTurnInFlight = (0, import_react10.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
2993
3369
  transport
2994
3370
  ]);
2995
- const sendMessage = (0, import_react9.useCallback)(async (...args) => {
3371
+ const sendMessage = (0, import_react10.useCallback)(async (...args) => {
2996
3372
  if (isTurnInFlight()) return;
2997
3373
  turnInFlight.current = true;
2998
3374
  try {
@@ -3003,15 +3379,15 @@ function useAgentChat(options) {
3003
3379
  }, [
3004
3380
  isTurnInFlight
3005
3381
  ]);
3006
- const addToolResult = (0, import_react9.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
3382
+ const addToolResult = (0, import_react10.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
3007
3383
  tool,
3008
3384
  toolCallId,
3009
3385
  output
3010
3386
  }), []);
3011
- const [threads, setThreads] = (0, import_react9.useState)([]);
3012
- const [quota, setQuota] = (0, import_react9.useState)(null);
3013
- const [backgroundRuns, setBackgroundRuns] = (0, import_react9.useState)([]);
3014
- const refreshBackground = (0, import_react9.useCallback)(async () => {
3387
+ const [threads, setThreads] = (0, import_react10.useState)([]);
3388
+ const [quota, setQuota] = (0, import_react10.useState)(null);
3389
+ const [backgroundRuns, setBackgroundRuns] = (0, import_react10.useState)([]);
3390
+ const refreshBackground = (0, import_react10.useCallback)(async () => {
3015
3391
  const threadId = latest.current.threadId ?? createdThreadId.current;
3016
3392
  if (threadId === void 0) {
3017
3393
  return;
@@ -3036,7 +3412,7 @@ function useAgentChat(options) {
3036
3412
  ]);
3037
3413
  backgroundRef.current = refreshBackground;
3038
3414
  const isWorking = backgroundRuns.some((run) => run.status === "running");
3039
- (0, import_react9.useEffect)(() => {
3415
+ (0, import_react10.useEffect)(() => {
3040
3416
  if (options.background !== true || options.threadId === void 0) {
3041
3417
  return;
3042
3418
  }
@@ -3046,7 +3422,7 @@ function useAgentChat(options) {
3046
3422
  options.threadId,
3047
3423
  refreshBackground
3048
3424
  ]);
3049
- (0, import_react9.useEffect)(() => {
3425
+ (0, import_react10.useEffect)(() => {
3050
3426
  const every = latest.current.backgroundPollMs ?? 5e3;
3051
3427
  if (latest.current.background !== true || !isWorking || every <= 0) {
3052
3428
  return;
@@ -3057,26 +3433,26 @@ function useAgentChat(options) {
3057
3433
  isWorking,
3058
3434
  refreshBackground
3059
3435
  ]);
3060
- const loadThreads = (0, import_react9.useCallback)(async () => {
3436
+ const loadThreads = (0, import_react10.useCallback)(async () => {
3061
3437
  const list = await client.listThreads();
3062
3438
  setThreads(list);
3063
3439
  return list;
3064
3440
  }, [
3065
3441
  client
3066
3442
  ]);
3067
- const loadThread = (0, import_react9.useCallback)((id) => client.getThread(id), [
3443
+ const loadThread = (0, import_react10.useCallback)((id) => client.getThread(id), [
3068
3444
  client
3069
3445
  ]);
3070
- const deleteThread = (0, import_react9.useCallback)(async (id) => {
3446
+ const deleteThread = (0, import_react10.useCallback)(async (id) => {
3071
3447
  await client.deleteThread(id);
3072
3448
  setThreads((current) => current.filter((thread) => thread.id !== id));
3073
3449
  }, [
3074
3450
  client
3075
3451
  ]);
3076
- const forkThread = (0, import_react9.useCallback)((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
3452
+ const forkThread = (0, import_react10.useCallback)((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
3077
3453
  client
3078
3454
  ]);
3079
- const renameThread = (0, import_react9.useCallback)(async (id, title) => {
3455
+ const renameThread = (0, import_react10.useCallback)(async (id, title) => {
3080
3456
  await client.renameThread(id, title);
3081
3457
  setThreads((current) => current.map((thread) => thread.id === id ? {
3082
3458
  ...thread,
@@ -3085,24 +3461,24 @@ function useAgentChat(options) {
3085
3461
  }, [
3086
3462
  client
3087
3463
  ]);
3088
- const promoteThread = (0, import_react9.useCallback)(async (id) => {
3464
+ const promoteThread = (0, import_react10.useCallback)(async (id) => {
3089
3465
  await client.promoteThread(id);
3090
3466
  await loadThreads();
3091
3467
  }, [
3092
3468
  client,
3093
3469
  loadThreads
3094
3470
  ]);
3095
- const truncateFromMessage = (0, import_react9.useCallback)((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
3471
+ const truncateFromMessage = (0, import_react10.useCallback)((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
3096
3472
  client
3097
3473
  ]);
3098
- const loadQuota = (0, import_react9.useCallback)(async () => {
3474
+ const loadQuota = (0, import_react10.useCallback)(async () => {
3099
3475
  const today = await client.getQuotaToday();
3100
3476
  setQuota(today);
3101
3477
  return today;
3102
3478
  }, [
3103
3479
  client
3104
3480
  ]);
3105
- const cancel = (0, import_react9.useCallback)(async () => {
3481
+ const cancel = (0, import_react10.useCallback)(async () => {
3106
3482
  chatRef.current.stop();
3107
3483
  const activeRunId2 = runIdRef.current;
3108
3484
  if (activeRunId2) {
@@ -3114,14 +3490,14 @@ function useAgentChat(options) {
3114
3490
  }, [
3115
3491
  client
3116
3492
  ]);
3117
- const approve = (0, import_react9.useCallback)(async ({ toolCallId }) => {
3493
+ const approve = (0, import_react10.useCallback)(async ({ toolCallId }) => {
3118
3494
  await client.approveToolCall({
3119
3495
  toolCallId
3120
3496
  });
3121
3497
  }, [
3122
3498
  client
3123
3499
  ]);
3124
- const reject = (0, import_react9.useCallback)(async ({ toolCallId, reason }) => {
3500
+ const reject = (0, import_react10.useCallback)(async ({ toolCallId, reason }) => {
3125
3501
  await client.rejectToolCall({
3126
3502
  toolCallId,
3127
3503
  ...reason !== void 0 ? {
@@ -3131,7 +3507,7 @@ function useAgentChat(options) {
3131
3507
  }, [
3132
3508
  client
3133
3509
  ]);
3134
- const answer = (0, import_react9.useCallback)(async ({ toolCallId, answers }) => {
3510
+ const answer = (0, import_react10.useCallback)(async ({ toolCallId, answers }) => {
3135
3511
  await client.answerToolCall({
3136
3512
  toolCallId,
3137
3513
  ...answers !== void 0 ? {
@@ -3141,14 +3517,14 @@ function useAgentChat(options) {
3141
3517
  }, [
3142
3518
  client
3143
3519
  ]);
3144
- const skip = (0, import_react9.useCallback)(async ({ toolCallId }) => {
3520
+ const skip = (0, import_react10.useCallback)(async ({ toolCallId }) => {
3145
3521
  await client.skipToolCall({
3146
3522
  toolCallId
3147
3523
  });
3148
3524
  }, [
3149
3525
  client
3150
3526
  ]);
3151
- const regenerate = (0, import_react9.useCallback)(() => {
3527
+ const regenerate = (0, import_react10.useCallback)(() => {
3152
3528
  if (isTurnInFlight()) return;
3153
3529
  regenerateNext.current = true;
3154
3530
  turnInFlight.current = true;
@@ -3214,25 +3590,37 @@ __name(mergeHeaders, "mergeHeaders");
3214
3590
  applyCompletion,
3215
3591
  backgroundRunsFromThread,
3216
3592
  buildTranscriptBlocks,
3593
+ correctedCallIds,
3217
3594
  createSkillsSource,
3218
3595
  describeTimestamp,
3596
+ describeToolCall,
3219
3597
  describeUsage,
3220
3598
  extractMessageText,
3599
+ fillTemplate,
3221
3600
  filterAutocompleteItems,
3222
3601
  findActiveTrigger,
3223
3602
  formatElapsed,
3224
3603
  formatRelativeTime,
3604
+ groupToolActivity,
3605
+ inferResultView,
3606
+ isActionCall,
3225
3607
  loadStoredSpeechLang,
3226
3608
  persistSpeechLang,
3609
+ phraseFor,
3610
+ readPath,
3227
3611
  readReasoningMs,
3612
+ resolveResultView,
3228
3613
  storedMessageToUiMessage,
3229
3614
  storedThreadToUiMessages,
3615
+ toolCallState,
3616
+ toolCatalogFrom,
3230
3617
  useAgentChat,
3231
3618
  useChatTranscript,
3232
3619
  useComposerAutocomplete,
3233
3620
  useElapsed,
3234
3621
  useSpeechRecognition,
3235
3622
  useStickToBottom,
3623
+ useToolCatalog,
3236
3624
  useTranscriptItem
3237
3625
  });
3238
3626
  //# sourceMappingURL=index.cjs.map