@dudousxd/nestjs-agent-react 0.10.0 → 0.12.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
@@ -444,6 +444,10 @@ var AgentChatTransport = class {
444
444
  });
445
445
  }
446
446
  break;
447
+ case "approval-settled":
448
+ ensureStep();
449
+ forwardAsData(event, false);
450
+ break;
447
451
  case "ui":
448
452
  ensureStep();
449
453
  closeRuns();
@@ -743,6 +747,10 @@ var AgentClient = class {
743
747
  cancelStream(runId) {
744
748
  return this.request("POST", `/agent/chat/${encodeURIComponent(runId)}/cancel`);
745
749
  }
750
+ /**
751
+ * `remember` approves later calls of the same tool in the same thread; `via` names the surface
752
+ * the decision came through (the server records `'web'` when omitted).
753
+ */
746
754
  approveToolCall(input) {
747
755
  return this.request("POST", "/agent/tool-call/approve", input);
748
756
  }
@@ -970,8 +978,66 @@ import React3 from "react";
970
978
  import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
971
979
 
972
980
  // src/transcript/model.ts
981
+ import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
973
982
  import { getToolName as getToolName2, isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
974
983
 
984
+ // src/elicitation/answers.ts
985
+ import { validateElicitationAnswer, validateElicitationValue } from "@dudousxd/nestjs-agent-core";
986
+ function pad(value) {
987
+ return String(value).padStart(2, "0");
988
+ }
989
+ __name(pad, "pad");
990
+ function toDay(date) {
991
+ if (Number.isNaN(date.getTime())) {
992
+ return null;
993
+ }
994
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
995
+ }
996
+ __name(toDay, "toDay");
997
+ function coerceOne(type, raw) {
998
+ if (raw === null || raw === void 0) {
999
+ return null;
1000
+ }
1001
+ if (Array.isArray(raw)) {
1002
+ return null;
1003
+ }
1004
+ if (raw instanceof Date) {
1005
+ return type === "date" || type === void 0 ? toDay(raw) : raw.toISOString();
1006
+ }
1007
+ if (typeof raw === "boolean") {
1008
+ return raw ? "true" : "false";
1009
+ }
1010
+ if (typeof raw === "number") {
1011
+ return Number.isFinite(raw) ? String(raw) : null;
1012
+ }
1013
+ const text = raw;
1014
+ switch (type) {
1015
+ case "number":
1016
+ case "email":
1017
+ case "url":
1018
+ case "date":
1019
+ return text.trim() === "" ? null : text.trim();
1020
+ case "boolean": {
1021
+ const lowered = text.trim().toLowerCase();
1022
+ if (lowered === "true" || lowered === "on" || lowered === "yes") return "true";
1023
+ if (lowered === "false" || lowered === "off" || lowered === "no") return "false";
1024
+ return lowered === "" ? null : text;
1025
+ }
1026
+ default:
1027
+ return text === "" ? null : text;
1028
+ }
1029
+ }
1030
+ __name(coerceOne, "coerceOne");
1031
+ function coerceAnswer(question, raw) {
1032
+ const type = question.input?.type;
1033
+ const items = Array.isArray(raw) ? raw : [
1034
+ raw
1035
+ ];
1036
+ const values = items.map((item) => coerceOne(type, item)).filter((value) => value !== null);
1037
+ return question.multiple === true ? values : values.slice(0, 1);
1038
+ }
1039
+ __name(coerceAnswer, "coerceAnswer");
1040
+
975
1041
  // src/presentation/tool-activity.ts
976
1042
  import { getToolName } from "ai";
977
1043
 
@@ -1260,7 +1326,7 @@ function buildTranscriptBlocks(message, options) {
1260
1326
  if (toolBuffer.length === 0) {
1261
1327
  return;
1262
1328
  }
1263
- const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null, options.toolCatalog));
1329
+ const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvalOf(approvals.get(part.toolCallId), part), options.toolCatalog));
1264
1330
  const roots = nestToolCalls(calls);
1265
1331
  blocks.push({
1266
1332
  kind: "tools",
@@ -1335,7 +1401,7 @@ function buildTranscriptBlocks(message, options) {
1335
1401
  fileBuffer.push(part);
1336
1402
  continue;
1337
1403
  }
1338
- if (part.type === APPROVAL_PART) {
1404
+ if (part.type === APPROVAL_PART || part.type === SETTLED_PART) {
1339
1405
  continue;
1340
1406
  }
1341
1407
  flushAll();
@@ -1486,7 +1552,11 @@ function buildToolCall(part, options, approval, catalog) {
1486
1552
  approve: {
1487
1553
  available: awaiting && options?.canApprove === true,
1488
1554
  isSubmitting: sending === "approve",
1489
- run: /* @__PURE__ */ __name(() => options?.approve(toolCallId), "run")
1555
+ // Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
1556
+ // and a host's handler must not receive that as its options.
1557
+ run: /* @__PURE__ */ __name((approveOptions) => approveOptions?.remember === true ? options?.approve(toolCallId, {
1558
+ remember: true
1559
+ }) : options?.approve(toolCallId), "run")
1490
1560
  },
1491
1561
  reject: {
1492
1562
  available: awaiting && options?.canReject === true,
@@ -1504,11 +1574,16 @@ function readElicitationRequest(part) {
1504
1574
  }
1505
1575
  const questions = [];
1506
1576
  for (const candidate of input.questions) {
1507
- if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string" || !Array.isArray(candidate.options) || candidate.options.length === 0) {
1577
+ if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
1578
+ return null;
1579
+ }
1580
+ const input2 = readElicitationInput(candidate.input) ?? null;
1581
+ const rawOptions = Array.isArray(candidate.options) ? candidate.options : [];
1582
+ if (rawOptions.length === 0 && (input2 === null || input2.type === "select")) {
1508
1583
  return null;
1509
1584
  }
1510
1585
  const options = [];
1511
- for (const option of candidate.options) {
1586
+ for (const option of rawOptions) {
1512
1587
  if (!isRecord2(option) || typeof option.value !== "string" || typeof option.label !== "string") {
1513
1588
  return null;
1514
1589
  }
@@ -1521,7 +1596,10 @@ function readElicitationRequest(part) {
1521
1596
  questions.push({
1522
1597
  id: candidate.id,
1523
1598
  prompt: candidate.prompt,
1599
+ description: typeof candidate.description === "string" ? candidate.description : null,
1600
+ input: input2,
1524
1601
  multiple: candidate.multiple === true,
1602
+ allowFreeText: candidate.allowFreeText === true,
1525
1603
  defaults: Array.isArray(candidate.defaults) ? candidate.defaults.filter((value) => typeof value === "string") : [],
1526
1604
  options
1527
1605
  });
@@ -1557,12 +1635,38 @@ function buildElicitationBlock(key, part, request, options) {
1557
1635
  const picked = isPending ? options.picked(toolCallId, question.id) : void 0;
1558
1636
  const selected = picked ?? outcome?.answers[question.id] ?? question.defaults;
1559
1637
  const pick = /* @__PURE__ */ __name((values) => options.pick(toolCallId, question.id, values), "pick");
1638
+ const error = isPending ? validateElicitationAnswer2({
1639
+ id: question.id,
1640
+ prompt: question.prompt,
1641
+ options: question.options.map(({ value, label }) => ({
1642
+ value,
1643
+ label
1644
+ })),
1645
+ ...question.input !== null ? {
1646
+ input: question.input
1647
+ } : {},
1648
+ ...question.multiple ? {
1649
+ multiple: true
1650
+ } : {},
1651
+ ...question.allowFreeText ? {
1652
+ allowFreeText: true
1653
+ } : {}
1654
+ }, selected) : null;
1560
1655
  return {
1561
1656
  id: question.id,
1562
1657
  prompt: question.prompt,
1658
+ description: question.description,
1659
+ input: question.input,
1563
1660
  multiple: question.multiple,
1564
1661
  position: index + 1,
1565
1662
  selected,
1663
+ value: selected[0] ?? "",
1664
+ error,
1665
+ setValue: /* @__PURE__ */ __name((raw) => {
1666
+ if (isPending) {
1667
+ pick(coerceAnswer(question, raw));
1668
+ }
1669
+ }, "setValue"),
1566
1670
  isPristine: isPending ? picked === void 0 : outcome?.defaulted.includes(question.id) ?? true,
1567
1671
  options: question.options.map((option) => ({
1568
1672
  value: option.value,
@@ -1597,6 +1701,7 @@ function buildElicitationBlock(key, part, request, options) {
1597
1701
  questions,
1598
1702
  questionCount: questions.length,
1599
1703
  isPending,
1704
+ isValid: questions.every((question) => question.error === null),
1600
1705
  outcome,
1601
1706
  error: options.errorOf(toolCallId),
1602
1707
  answer: {
@@ -1614,25 +1719,90 @@ function buildElicitationBlock(key, part, request, options) {
1614
1719
  __name(buildElicitationBlock, "buildElicitationBlock");
1615
1720
  var UI_PART = "data-ui";
1616
1721
  var APPROVAL_PART = "data-approval-requested";
1722
+ var SETTLED_PART = "data-approval-settled";
1723
+ var SETTLED_STATUSES = [
1724
+ "approved",
1725
+ "rejected",
1726
+ "expired"
1727
+ ];
1617
1728
  function readApprovals(parts) {
1618
1729
  const out = /* @__PURE__ */ new Map();
1730
+ const entry = /* @__PURE__ */ __name((id) => {
1731
+ let found = out.get(id);
1732
+ if (found === void 0) {
1733
+ found = {
1734
+ approver: null,
1735
+ expiresAt: null,
1736
+ reason: null,
1737
+ status: null,
1738
+ remember: false,
1739
+ decidedBy: null,
1740
+ decidedVia: null,
1741
+ decisionReason: null
1742
+ };
1743
+ out.set(id, found);
1744
+ }
1745
+ return found;
1746
+ }, "entry");
1619
1747
  for (const part of parts) {
1620
- if (part.type !== APPROVAL_PART) {
1748
+ if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
1621
1749
  continue;
1622
1750
  }
1623
1751
  const data = part.data;
1624
- if (!isRecord2(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
1752
+ if (!isRecord2(data) || typeof data.id !== "string") {
1625
1753
  continue;
1626
1754
  }
1627
- out.set(data.id, {
1628
- approver: data.approver,
1629
- expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : null,
1630
- reason: typeof data.reason === "string" ? data.reason : null
1631
- });
1755
+ const approval = entry(data.id);
1756
+ if (part.type === APPROVAL_PART) {
1757
+ if (typeof data.approver !== "string") {
1758
+ continue;
1759
+ }
1760
+ approval.approver = data.approver;
1761
+ approval.expiresAt = typeof data.expiresAt === "string" ? data.expiresAt : null;
1762
+ approval.reason = typeof data.reason === "string" ? data.reason : null;
1763
+ continue;
1764
+ }
1765
+ if (typeof data.status !== "string" || !SETTLED_STATUSES.includes(data.status)) {
1766
+ continue;
1767
+ }
1768
+ approval.status = data.status;
1769
+ if (approval.approver === null && typeof data.approver === "string") {
1770
+ approval.approver = data.approver;
1771
+ }
1772
+ approval.remember = data.remember === true;
1773
+ approval.decidedBy = typeof data.decidedBy === "string" ? data.decidedBy : null;
1774
+ approval.decidedVia = typeof data.decidedVia === "string" ? data.decidedVia : null;
1775
+ approval.decisionReason = typeof data.reason === "string" ? data.reason : null;
1632
1776
  }
1633
1777
  return out;
1634
1778
  }
1635
1779
  __name(readApprovals, "readApprovals");
1780
+ function approvalOf(parts, call) {
1781
+ if (parts === void 0 || parts.approver === null) {
1782
+ return null;
1783
+ }
1784
+ return {
1785
+ approver: parts.approver,
1786
+ expiresAt: parts.expiresAt,
1787
+ reason: parts.reason,
1788
+ status: parts.status ?? statusFromPart(call),
1789
+ remember: parts.remember,
1790
+ decidedBy: parts.decidedBy,
1791
+ decidedVia: parts.decidedVia,
1792
+ decisionReason: parts.decisionReason
1793
+ };
1794
+ }
1795
+ __name(approvalOf, "approvalOf");
1796
+ function statusFromPart(call) {
1797
+ if (call.state === "output-denied") {
1798
+ return "rejected";
1799
+ }
1800
+ if (call.state === "output-available" || call.state === "output-error") {
1801
+ return "approved";
1802
+ }
1803
+ return "pending";
1804
+ }
1805
+ __name(statusFromPart, "statusFromPart");
1636
1806
  function readUiComponent(part) {
1637
1807
  const data = part.data;
1638
1808
  if (!isRecord2(data) || typeof data.component !== "string") {
@@ -2018,10 +2188,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2018
2188
  }, [
2019
2189
  settle
2020
2190
  ]);
2021
- const approve = useCallback3((toolCallId) => {
2191
+ const approve = useCallback3((toolCallId, options2) => {
2022
2192
  const onApprove = latest.current.options.onApprove;
2023
2193
  if (onApprove) {
2024
- settle(toolCallId, "approve", () => onApprove(toolCallId));
2194
+ settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
2025
2195
  }
2026
2196
  }, [
2027
2197
  settle
@@ -2996,6 +3166,49 @@ function useToolCatalog(options) {
2996
3166
  }
2997
3167
  __name(useToolCatalog, "useToolCatalog");
2998
3168
 
3169
+ // src/approvals/countdown.ts
3170
+ import { useEffect as useEffect8, useRef as useRef6, useState as useState8 } from "react";
3171
+ function approvalCountdown(expiresAt, now = Date.now()) {
3172
+ const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
3173
+ if (!Number.isFinite(deadline)) {
3174
+ return {
3175
+ remainingMs: null,
3176
+ isExpired: false
3177
+ };
3178
+ }
3179
+ const remainingMs = Math.max(0, deadline - now);
3180
+ return {
3181
+ remainingMs,
3182
+ isExpired: remainingMs === 0
3183
+ };
3184
+ }
3185
+ __name(approvalCountdown, "approvalCountdown");
3186
+ function useApprovalCountdown(expiresAt, options = {}) {
3187
+ const { intervalMs = 1e3 } = options;
3188
+ const nowRef = useRef6(options.now ?? Date.now);
3189
+ nowRef.current = options.now ?? Date.now;
3190
+ const [state, setState] = useState8(() => approvalCountdown(expiresAt, nowRef.current()));
3191
+ useEffect8(() => {
3192
+ const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
3193
+ const first = read();
3194
+ setState(first);
3195
+ if (first.remainingMs === null || first.isExpired) {
3196
+ return;
3197
+ }
3198
+ const timer = setInterval(() => {
3199
+ const next = read();
3200
+ setState(next);
3201
+ if (next.isExpired) clearInterval(timer);
3202
+ }, intervalMs);
3203
+ return () => clearInterval(timer);
3204
+ }, [
3205
+ expiresAt,
3206
+ intervalMs
3207
+ ]);
3208
+ return state;
3209
+ }
3210
+ __name(useApprovalCountdown, "useApprovalCountdown");
3211
+
2999
3212
  // src/stored-message-to-ui-message.ts
3000
3213
  import { DEFAULT_REFUSAL_REASON } from "@dudousxd/nestjs-agent-core";
3001
3214
  function isRefusal(result) {
@@ -3055,6 +3268,41 @@ function storedMessageToUiMessage(message) {
3055
3268
  }
3056
3269
  });
3057
3270
  }
3271
+ for (const approval of message.approvals ?? []) {
3272
+ parts.push({
3273
+ type: "data-approval-requested",
3274
+ id: approval.toolCallId,
3275
+ data: {
3276
+ id: approval.toolCallId,
3277
+ approver: approval.approver,
3278
+ ...approval.expiresAt !== void 0 ? {
3279
+ expiresAt: approval.expiresAt
3280
+ } : {}
3281
+ }
3282
+ });
3283
+ if (approval.status !== "pending") {
3284
+ parts.push({
3285
+ type: "data-approval-settled",
3286
+ id: approval.toolCallId,
3287
+ data: {
3288
+ id: approval.toolCallId,
3289
+ status: approval.status,
3290
+ ...approval.decidedBy !== void 0 ? {
3291
+ decidedBy: approval.decidedBy
3292
+ } : {},
3293
+ ...approval.decidedVia !== void 0 ? {
3294
+ decidedVia: approval.decidedVia
3295
+ } : {},
3296
+ ...approval.remember === true ? {
3297
+ remember: true
3298
+ } : {},
3299
+ ...approval.reason !== void 0 ? {
3300
+ reason: approval.reason
3301
+ } : {}
3302
+ }
3303
+ });
3304
+ }
3305
+ }
3058
3306
  for (const call of message.toolCalls ?? []) {
3059
3307
  const result = message.toolResults?.find((candidate) => candidate.id === call.id);
3060
3308
  const toolKind2 = call.kind;
@@ -3157,19 +3405,19 @@ __name(sumUsage, "sumUsage");
3157
3405
 
3158
3406
  // src/use-agent-chat.ts
3159
3407
  import { useChat } from "@ai-sdk/react";
3160
- import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef6, useState as useState8 } from "react";
3408
+ import { useCallback as useCallback6, useEffect as useEffect9, useMemo as useMemo4, useRef as useRef7, useState as useState9 } from "react";
3161
3409
  function useAgentChat(options) {
3162
- const latest = useRef6(options);
3410
+ const latest = useRef7(options);
3163
3411
  latest.current = options;
3164
- const [runId, setRunId] = useState8(options.resumeRunId);
3165
- const runIdRef = useRef6(runId);
3412
+ const [runId, setRunId] = useState9(options.resumeRunId);
3413
+ const runIdRef = useRef7(runId);
3166
3414
  runIdRef.current = runId;
3167
- const settlingRunIdRef = useRef6(void 0);
3168
- const autoResumeRunIdRef = useRef6(void 0);
3169
- const [autoResume, setAutoResume] = useState8(false);
3170
- const [activeRunId, setActiveRunId] = useState8(null);
3171
- const regenerateNext = useRef6(false);
3172
- const createdThreadId = useRef6(void 0);
3415
+ const settlingRunIdRef = useRef7(void 0);
3416
+ const autoResumeRunIdRef = useRef7(void 0);
3417
+ const [autoResume, setAutoResume] = useState9(false);
3418
+ const [activeRunId, setActiveRunId] = useState9(null);
3419
+ const regenerateNext = useRef7(false);
3420
+ const createdThreadId = useRef7(void 0);
3173
3421
  const client = useMemo4(() => {
3174
3422
  if (options.client) return options.client;
3175
3423
  return new AgentClient({
@@ -3185,7 +3433,7 @@ function useAgentChat(options) {
3185
3433
  getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
3186
3434
  });
3187
3435
  }, []);
3188
- useEffect8(() => {
3436
+ useEffect9(() => {
3189
3437
  if (!options.resume || options.threadId === void 0) return;
3190
3438
  let cancelled = false;
3191
3439
  const threadId = options.threadId;
@@ -3254,7 +3502,7 @@ function useAgentChat(options) {
3254
3502
  }, "onAttemptStart")
3255
3503
  });
3256
3504
  }, []);
3257
- const backgroundRef = useRef6(() => Promise.resolve());
3505
+ const backgroundRef = useRef7(() => Promise.resolve());
3258
3506
  const chat = useChat({
3259
3507
  transport,
3260
3508
  resume: options.resumeRunId !== void 0 || autoResume,
@@ -3285,9 +3533,9 @@ function useAgentChat(options) {
3285
3533
  }
3286
3534
  }, "onFinish")
3287
3535
  });
3288
- const chatRef = useRef6(chat);
3536
+ const chatRef = useRef7(chat);
3289
3537
  chatRef.current = chat;
3290
- const turnInFlight = useRef6(false);
3538
+ const turnInFlight = useRef7(false);
3291
3539
  const isTurnInFlight = useCallback6(() => turnInFlight.current || transport.isAttemptLive, [
3292
3540
  transport
3293
3541
  ]);
@@ -3307,9 +3555,9 @@ function useAgentChat(options) {
3307
3555
  toolCallId,
3308
3556
  output
3309
3557
  }), []);
3310
- const [threads, setThreads] = useState8([]);
3311
- const [quota, setQuota] = useState8(null);
3312
- const [backgroundRuns, setBackgroundRuns] = useState8([]);
3558
+ const [threads, setThreads] = useState9([]);
3559
+ const [quota, setQuota] = useState9(null);
3560
+ const [backgroundRuns, setBackgroundRuns] = useState9([]);
3313
3561
  const refreshBackground = useCallback6(async () => {
3314
3562
  const threadId = latest.current.threadId ?? createdThreadId.current;
3315
3563
  if (threadId === void 0) {
@@ -3335,7 +3583,7 @@ function useAgentChat(options) {
3335
3583
  ]);
3336
3584
  backgroundRef.current = refreshBackground;
3337
3585
  const isWorking = backgroundRuns.some((run) => run.status === "running");
3338
- useEffect8(() => {
3586
+ useEffect9(() => {
3339
3587
  if (options.background !== true || options.threadId === void 0) {
3340
3588
  return;
3341
3589
  }
@@ -3345,7 +3593,7 @@ function useAgentChat(options) {
3345
3593
  options.threadId,
3346
3594
  refreshBackground
3347
3595
  ]);
3348
- useEffect8(() => {
3596
+ useEffect9(() => {
3349
3597
  const every = latest.current.backgroundPollMs ?? 5e3;
3350
3598
  if (latest.current.background !== true || !isWorking || every <= 0) {
3351
3599
  return;
@@ -3413,18 +3661,27 @@ function useAgentChat(options) {
3413
3661
  }, [
3414
3662
  client
3415
3663
  ]);
3416
- const approve = useCallback6(async ({ toolCallId }) => {
3664
+ const approve = useCallback6(async ({ toolCallId, remember, via }) => {
3417
3665
  await client.approveToolCall({
3418
- toolCallId
3666
+ toolCallId,
3667
+ ...remember === true ? {
3668
+ remember: true
3669
+ } : {},
3670
+ ...via !== void 0 ? {
3671
+ via
3672
+ } : {}
3419
3673
  });
3420
3674
  }, [
3421
3675
  client
3422
3676
  ]);
3423
- const reject = useCallback6(async ({ toolCallId, reason }) => {
3677
+ const reject = useCallback6(async ({ toolCallId, reason, via }) => {
3424
3678
  await client.rejectToolCall({
3425
3679
  toolCallId,
3426
3680
  ...reason !== void 0 ? {
3427
3681
  reason
3682
+ } : {},
3683
+ ...via !== void 0 ? {
3684
+ via
3428
3685
  } : {}
3429
3686
  });
3430
3687
  }, [
@@ -3510,8 +3767,10 @@ export {
3510
3767
  MessageList,
3511
3768
  SPEECH_LANGUAGES,
3512
3769
  applyCompletion,
3770
+ approvalCountdown,
3513
3771
  backgroundRunsFromThread,
3514
3772
  buildTranscriptBlocks,
3773
+ coerceAnswer,
3515
3774
  correctedCallIds,
3516
3775
  createSkillsSource,
3517
3776
  describeTimestamp,
@@ -3537,12 +3796,15 @@ export {
3537
3796
  toolCallState,
3538
3797
  toolCatalogFrom,
3539
3798
  useAgentChat,
3799
+ useApprovalCountdown,
3540
3800
  useChatTranscript,
3541
3801
  useComposerAutocomplete,
3542
3802
  useElapsed,
3543
3803
  useSpeechRecognition,
3544
3804
  useStickToBottom,
3545
3805
  useToolCatalog,
3546
- useTranscriptItem
3806
+ useTranscriptItem,
3807
+ validateElicitationAnswer as validateAnswer,
3808
+ validateElicitationValue as validateAnswerValue
3547
3809
  };
3548
3810
  //# sourceMappingURL=index.js.map