@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.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, ToolUIPart, DynamicToolUIPart, DataUIPart, UIDataTypes } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { StoredMessage, ThreadSummary, SkillCatalogEntry, ToolCatalogEntry, ThreadDetail, MessageAttachment, QuotaView, ToolPresentation, ToolResultField, ToolResultView, ToolPresentationTone } from '@dudousxd/nestjs-agent-core';
4
+ import { StoredMessage, ThreadSummary, SkillCatalogEntry, ToolCatalogEntry, ThreadDetail, MessageAttachment, QuotaView, ElicitationQuestion, ElicitationInputType, ToolPresentation, ToolResultField, ToolResultView, ToolPresentationTone, ElicitationInput } from '@dudousxd/nestjs-agent-core';
5
+ export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
5
6
  import React from 'react';
6
7
 
7
8
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
@@ -74,6 +75,8 @@ interface AgentChatTransportOptions {
74
75
  * - `ui` → `data-ui` part, `id` = the component id (a repeat id updates it in place)
75
76
  * - `approval-requested` → `data-approval-requested` part keyed by the call id, plus the SDK's
76
77
  * native `tool-approval-request` (the part moves to `approval-requested`)
78
+ * - `approval-settled` → `data-approval-settled` part keyed by the call id (who decided, through
79
+ * what, remembered or not); the outcome still rides the call's own output
77
80
  * - `title`, `cancelled` → transient `data-title` / `data-cancelled` (never stored on the message)
78
81
  * - any other kind → `data-<kind>` part carrying the frame minus `kind`, keyed by its `id`
79
82
  * when it has one — forwarded, never dropped
@@ -233,12 +236,19 @@ declare class AgentClient {
233
236
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
234
237
  getQuotaToday(): Promise<QuotaToday>;
235
238
  cancelStream(runId: string): Promise<CancelResult>;
239
+ /**
240
+ * `remember` approves later calls of the same tool in the same thread; `via` names the surface
241
+ * the decision came through (the server records `'web'` when omitted).
242
+ */
236
243
  approveToolCall(input: {
237
244
  toolCallId: string;
245
+ remember?: boolean;
246
+ via?: string;
238
247
  }): Promise<void>;
239
248
  rejectToolCall(input: {
240
249
  toolCallId: string;
241
250
  reason?: string;
251
+ via?: string;
242
252
  }): Promise<void>;
243
253
  /**
244
254
  * Settle a parked question set. `answers` is questionId → chosen option values; a question left
@@ -305,6 +315,26 @@ interface ChatInputProps {
305
315
  */
306
316
  declare function ChatInput({ onSubmit, disabled, placeholder, rows, enableSpeech, speechLang, sendLabel, onStop, isStreaming, stopLabel, className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic, }: ChatInputProps): React.JSX.Element;
307
317
 
318
+ /** What a form control can hand over: a field's value, a checkbox's state, a picked date, a list. */
319
+ type RawAnswer = string | number | boolean | Date | null | undefined | readonly RawAnswer[];
320
+ /** The question fields {@link coerceAnswer} reads. A transcript question and a core one both fit. */
321
+ type CoercibleQuestion = Pick<ElicitationQuestion, 'multiple'> & {
322
+ input?: {
323
+ type: ElicitationInputType;
324
+ } | null;
325
+ };
326
+ /**
327
+ * Turn whatever a form control produced into the `string[]` the answer route takes, in the
328
+ * question's canonical form: numbers as decimals, booleans as `"true"`/`"false"`, dates as
329
+ * `YYYY-MM-DD` (a `Date` is read as the local calendar day), trimmed where whitespace means
330
+ * nothing. An empty value becomes `[]` — no answer, not an empty string. A single-choice question
331
+ * keeps the first value.
332
+ *
333
+ * Coercion never judges: pair it with {@link validateAnswer} (the same rules the server applies) to
334
+ * say what is wrong before sending.
335
+ */
336
+ declare function coerceAnswer(question: CoercibleQuestion, raw: RawAnswer): string[];
337
+
308
338
  /** Tool name → how the server said it is spoken about. */
309
339
  type ToolCatalog = Record<string, ToolPresentation>;
310
340
  /** Index `GET <base>/tools` by tool name, keeping only the tools that declared a presentation. */
@@ -540,16 +570,38 @@ interface TranscriptSettleState {
540
570
  isSubmitting: boolean;
541
571
  run: () => void;
542
572
  }
573
+ /** How an approval stands. */
574
+ type TranscriptApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
543
575
  /**
544
- * Who has to settle a parked call, and until when — from the stream's `approval-requested` frame.
576
+ * Who has to settle a parked call, until when, and — once it settled — how. From the stream's
577
+ * `approval-requested` / `approval-settled` frames, or the same parts a reloaded thread carries.
545
578
  * `null` on a call whose runner never said (the call can still be awaiting approval).
546
579
  */
547
580
  interface TranscriptApproval {
548
581
  /** Open vocabulary the host defines: `'requester'`, `'admin'`, a role… */
549
582
  approver: string;
550
- /** ISO-8601; `null` when the request never lapses. */
583
+ /** ISO-8601; `null` when the request never lapses. Pair with `useApprovalCountdown`. */
551
584
  expiresAt: string | null;
585
+ /** Why the call needs a person, when the runner said. */
552
586
  reason: string | null;
587
+ /**
588
+ * `pending` until a settlement arrives; then what it said. Falls back to the call's own state
589
+ * (denied → `rejected`, an output → `approved`) for a runner that streams no settlement.
590
+ */
591
+ status: TranscriptApprovalStatus;
592
+ /** The approval also covers later calls of this tool in this thread. */
593
+ remember: boolean;
594
+ /** Opaque ref of who decided; `null` while pending, on an expiry, or when the runner did not say. */
595
+ decidedBy: string | null;
596
+ /** The surface the decision came through (`'web'`, `'slack'`, `'remembered'`, …). */
597
+ decidedVia: string | null;
598
+ /** What the person said when declining. */
599
+ decisionReason: string | null;
600
+ }
601
+ /** What an approval can carry beyond yes. */
602
+ interface ApproveOptions {
603
+ /** Approve later calls of the same tool in the same thread without asking again. */
604
+ remember?: boolean;
553
605
  }
554
606
  /** One call in a tool run, with whatever human decision it is parked on. */
555
607
  interface TranscriptToolCall {
@@ -578,7 +630,10 @@ interface TranscriptToolCall {
578
630
  * IS the pending approval.
579
631
  */
580
632
  isAwaitingApproval: boolean;
581
- approve: TranscriptSettleState;
633
+ /** `run({ remember: true })` approves this tool for the rest of the thread. */
634
+ approve: TranscriptSettleState & {
635
+ run: (options?: ApproveOptions) => void;
636
+ };
582
637
  reject: TranscriptSettleState;
583
638
  /** A failed decision — the call is still parked, so the affordance stays live. */
584
639
  error: string | null;
@@ -635,6 +690,14 @@ interface TranscriptQuestionOption {
635
690
  interface TranscriptQuestion {
636
691
  id: string;
637
692
  prompt: string;
693
+ /** A line of help under the prompt; `null` when the request gave none. */
694
+ description: string | null;
695
+ /**
696
+ * How the answer is typed — `{ type, placeholder?, required?, min?, max?, pattern? }` — or `null`
697
+ * for a plain pick from `options`. Render the control from `input.type`; `select` still picks
698
+ * from `options`.
699
+ */
700
+ input: ElicitationInput | null;
638
701
  multiple: boolean;
639
702
  /** 1-based. The request carries every question up front, so "Question 1 of N" is honest. */
640
703
  position: number;
@@ -646,6 +709,20 @@ interface TranscriptQuestion {
646
709
  * first is recorded as `defaulted` rather than as a choice the user made.
647
710
  */
648
711
  isPristine: boolean;
712
+ /** The first selected value, or `''` — what a single text/number/date field shows. */
713
+ value: string;
714
+ /**
715
+ * Set a typed answer from whatever the control produced (a string, a number, a checkbox's
716
+ * boolean, a `Date`, a list); coerced to the question's canonical strings with `coerceAnswer`.
717
+ * `null`/`''` clears it. Does nothing once the set settled.
718
+ */
719
+ setValue: (raw: RawAnswer) => void;
720
+ /**
721
+ * Why the current selection would be refused (the server's own rules — `validateAnswer`), or
722
+ * `null`. A pristine required question with no default reads `requires an answer`; show it once
723
+ * the user tried to submit, or right away — the model does not decide that for you.
724
+ */
725
+ error: string | null;
649
726
  }
650
727
  /** How a question set settled, once it did. */
651
728
  interface TranscriptElicitationOutcome {
@@ -672,6 +749,8 @@ interface TranscriptElicitationBlock {
672
749
  questionCount: number;
673
750
  /** Still waiting on a human. */
674
751
  isPending: boolean;
752
+ /** Every question's current selection is acceptable (no question has an `error`). */
753
+ isValid: boolean;
675
754
  outcome: TranscriptElicitationOutcome | null;
676
755
  /** A failed submission — the run is still parked, so the form stays live. */
677
756
  error: string | null;
@@ -729,7 +808,7 @@ interface ElicitationBlockOptions {
729
808
  interface ApprovalBlockOptions {
730
809
  canApprove: boolean;
731
810
  canReject: boolean;
732
- approve: (toolCallId: string) => void;
811
+ approve: (toolCallId: string, options?: ApproveOptions) => void;
733
812
  reject: (toolCallId: string) => void;
734
813
  /** Which decision this call is sending, or `null` for none. */
735
814
  submitting: (toolCallId: string) => SettleAction | null;
@@ -904,8 +983,11 @@ interface TranscriptItemOptions {
904
983
  onAnswer?: (toolCallId: string, answers: Record<string, string[]>) => void | Promise<void>;
905
984
  /** Decline the question set and let the agent proceed on its own picks — `useAgentChat`'s `skip`. */
906
985
  onSkip?: (toolCallId: string) => void | Promise<void>;
907
- /** Settle a tool call parked on a human — `useAgentChat`'s `approve` / `reject`. */
908
- onApprove?: (toolCallId: string) => void | Promise<void>;
986
+ /**
987
+ * Settle a tool call parked on a human — `useAgentChat`'s `approve` / `reject`. `options.remember`
988
+ * is what `call.approve.run({ remember: true })` passed.
989
+ */
990
+ onApprove?: (toolCallId: string, options?: ApproveOptions) => void | Promise<void>;
909
991
  onReject?: (toolCallId: string) => void | Promise<void>;
910
992
  }
911
993
  interface TranscriptWindow {
@@ -1374,6 +1456,28 @@ interface ToolCatalogState {
1374
1456
  */
1375
1457
  declare function useToolCatalog(options: UseToolCatalogOptions): ToolCatalogState;
1376
1458
 
1459
+ interface ApprovalCountdown {
1460
+ /** Milliseconds until the request lapses, floored at 0; `null` when it never does. */
1461
+ remainingMs: number | null;
1462
+ /** The instant has passed. Always `false` for a request with no expiry. */
1463
+ isExpired: boolean;
1464
+ }
1465
+ interface UseApprovalCountdownOptions {
1466
+ /** How often the value re-renders while counting. Default 1000 — a seconds label needs no more. */
1467
+ intervalMs?: number;
1468
+ /** Injectable clock for tests. */
1469
+ now?: () => number;
1470
+ }
1471
+ /** What {@link useApprovalCountdown} reads for `expiresAt` at `now`, without the ticking. */
1472
+ declare function approvalCountdown(expiresAt: string | null | undefined, now?: number): ApprovalCountdown;
1473
+ /**
1474
+ * Time left on an approval request (`call.approval.expiresAt`), ticking until it lapses and then
1475
+ * holding at zero. Headless: pair `remainingMs` with `formatElapsed` or any label of your own, and
1476
+ * use `isExpired` to stop offering buttons the server would refuse (`410 Gone`). The server stays
1477
+ * the authority — a lapse is final only once the call settles `expired`.
1478
+ */
1479
+ declare function useApprovalCountdown(expiresAt: string | null | undefined, options?: UseApprovalCountdownOptions): ApprovalCountdown;
1480
+
1377
1481
  /** The thinking time stamped on a reasoning part, or `null` when it carries none. */
1378
1482
  declare function readReasoningMs(part: {
1379
1483
  providerMetadata?: unknown;
@@ -1621,12 +1725,16 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1621
1725
  quota: _dudousxd_nestjs_agent_core.QuotaView | null;
1622
1726
  loadQuota: () => Promise<QuotaToday>;
1623
1727
  cancel: () => Promise<void>;
1624
- approve: ({ toolCallId }: {
1728
+ approve: ({ toolCallId, remember, via, }: {
1625
1729
  toolCallId: string;
1730
+ /** Approve later calls of the same tool in this thread without asking. */
1731
+ remember?: boolean;
1732
+ via?: string;
1626
1733
  }) => Promise<void>;
1627
- reject: ({ toolCallId, reason, }: {
1734
+ reject: ({ toolCallId, reason, via, }: {
1628
1735
  toolCallId: string;
1629
1736
  reason?: string;
1737
+ via?: string;
1630
1738
  }) => Promise<void>;
1631
1739
  answer: ({ toolCallId, answers, }: {
1632
1740
  toolCallId: string;
@@ -1648,4 +1756,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1648
1756
  clearError: () => void;
1649
1757
  };
1650
1758
 
1651
- export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type ApprovalBlockOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type BuildBlocksOptions, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, type ChatStatus, type ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DescribeToolCallOptions, type ElicitationBlockOptions, type GroupToolActivityOptions, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResolvedReading, type ResolvedResultView, type RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, type ToolActivityGroup, type ToolCallDescription, type ToolCallState, type ToolCallStatus, type ToolCatalog, type ToolCatalogState, type TranscriptActionState, type TranscriptApproval, type TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, type TranscriptElicitationBlock, type TranscriptElicitationOutcome, type TranscriptFile, type TranscriptFilesBlock, type TranscriptItem, type TranscriptItemOptions, type TranscriptQuestion, type TranscriptQuestionOption, type TranscriptReasoningBlock, type TranscriptSettleState, type TranscriptSource, type TranscriptSourcesBlock, type TranscriptStopState, type TranscriptTextBlock, type TranscriptToolBlock, type TranscriptToolCall, type TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UsageSummary, type UseAgentChatOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, correctedCallIds, createSkillsSource, describeTimestamp, describeToolCall, describeUsage, extractMessageText, fillTemplate, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, groupToolActivity, inferResultView, isActionCall, loadStoredSpeechLang, persistSpeechLang, phraseFor, readPath, readReasoningMs, resolveResultView, storedMessageToUiMessage, storedThreadToUiMessages, toolCallState, toolCatalogFrom, useAgentChat, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };
1759
+ export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type ApprovalBlockOptions, type ApprovalCountdown, type ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type BuildBlocksOptions, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, type ChatStatus, type ChatTranscript, type CoercibleQuestion, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DescribeToolCallOptions, type ElicitationBlockOptions, type GroupToolActivityOptions, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RawAnswer, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResolvedReading, type ResolvedResultView, type RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, type ToolActivityGroup, type ToolCallDescription, type ToolCallState, type ToolCallStatus, type ToolCatalog, type ToolCatalogState, type TranscriptActionState, type TranscriptApproval, type TranscriptApprovalStatus, type TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, type TranscriptElicitationBlock, type TranscriptElicitationOutcome, type TranscriptFile, type TranscriptFilesBlock, type TranscriptItem, type TranscriptItemOptions, type TranscriptQuestion, type TranscriptQuestionOption, type TranscriptReasoningBlock, type TranscriptSettleState, type TranscriptSource, type TranscriptSourcesBlock, type TranscriptStopState, type TranscriptTextBlock, type TranscriptToolBlock, type TranscriptToolCall, type TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UsageSummary, type UseAgentChatOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, buildTranscriptBlocks, coerceAnswer, correctedCallIds, createSkillsSource, describeTimestamp, describeToolCall, describeUsage, extractMessageText, fillTemplate, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, groupToolActivity, inferResultView, isActionCall, loadStoredSpeechLang, persistSpeechLang, phraseFor, readPath, readReasoningMs, resolveResultView, storedMessageToUiMessage, storedThreadToUiMessages, toolCallState, toolCatalogFrom, useAgentChat, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, ToolUIPart, DynamicToolUIPart, DataUIPart, UIDataTypes } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { StoredMessage, ThreadSummary, SkillCatalogEntry, ToolCatalogEntry, ThreadDetail, MessageAttachment, QuotaView, ToolPresentation, ToolResultField, ToolResultView, ToolPresentationTone } from '@dudousxd/nestjs-agent-core';
4
+ import { StoredMessage, ThreadSummary, SkillCatalogEntry, ToolCatalogEntry, ThreadDetail, MessageAttachment, QuotaView, ElicitationQuestion, ElicitationInputType, ToolPresentation, ToolResultField, ToolResultView, ToolPresentationTone, ElicitationInput } from '@dudousxd/nestjs-agent-core';
5
+ export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
5
6
  import React from 'react';
6
7
 
7
8
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
@@ -74,6 +75,8 @@ interface AgentChatTransportOptions {
74
75
  * - `ui` → `data-ui` part, `id` = the component id (a repeat id updates it in place)
75
76
  * - `approval-requested` → `data-approval-requested` part keyed by the call id, plus the SDK's
76
77
  * native `tool-approval-request` (the part moves to `approval-requested`)
78
+ * - `approval-settled` → `data-approval-settled` part keyed by the call id (who decided, through
79
+ * what, remembered or not); the outcome still rides the call's own output
77
80
  * - `title`, `cancelled` → transient `data-title` / `data-cancelled` (never stored on the message)
78
81
  * - any other kind → `data-<kind>` part carrying the frame minus `kind`, keyed by its `id`
79
82
  * when it has one — forwarded, never dropped
@@ -233,12 +236,19 @@ declare class AgentClient {
233
236
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
234
237
  getQuotaToday(): Promise<QuotaToday>;
235
238
  cancelStream(runId: string): Promise<CancelResult>;
239
+ /**
240
+ * `remember` approves later calls of the same tool in the same thread; `via` names the surface
241
+ * the decision came through (the server records `'web'` when omitted).
242
+ */
236
243
  approveToolCall(input: {
237
244
  toolCallId: string;
245
+ remember?: boolean;
246
+ via?: string;
238
247
  }): Promise<void>;
239
248
  rejectToolCall(input: {
240
249
  toolCallId: string;
241
250
  reason?: string;
251
+ via?: string;
242
252
  }): Promise<void>;
243
253
  /**
244
254
  * Settle a parked question set. `answers` is questionId → chosen option values; a question left
@@ -305,6 +315,26 @@ interface ChatInputProps {
305
315
  */
306
316
  declare function ChatInput({ onSubmit, disabled, placeholder, rows, enableSpeech, speechLang, sendLabel, onStop, isStreaming, stopLabel, className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic, }: ChatInputProps): React.JSX.Element;
307
317
 
318
+ /** What a form control can hand over: a field's value, a checkbox's state, a picked date, a list. */
319
+ type RawAnswer = string | number | boolean | Date | null | undefined | readonly RawAnswer[];
320
+ /** The question fields {@link coerceAnswer} reads. A transcript question and a core one both fit. */
321
+ type CoercibleQuestion = Pick<ElicitationQuestion, 'multiple'> & {
322
+ input?: {
323
+ type: ElicitationInputType;
324
+ } | null;
325
+ };
326
+ /**
327
+ * Turn whatever a form control produced into the `string[]` the answer route takes, in the
328
+ * question's canonical form: numbers as decimals, booleans as `"true"`/`"false"`, dates as
329
+ * `YYYY-MM-DD` (a `Date` is read as the local calendar day), trimmed where whitespace means
330
+ * nothing. An empty value becomes `[]` — no answer, not an empty string. A single-choice question
331
+ * keeps the first value.
332
+ *
333
+ * Coercion never judges: pair it with {@link validateAnswer} (the same rules the server applies) to
334
+ * say what is wrong before sending.
335
+ */
336
+ declare function coerceAnswer(question: CoercibleQuestion, raw: RawAnswer): string[];
337
+
308
338
  /** Tool name → how the server said it is spoken about. */
309
339
  type ToolCatalog = Record<string, ToolPresentation>;
310
340
  /** Index `GET <base>/tools` by tool name, keeping only the tools that declared a presentation. */
@@ -540,16 +570,38 @@ interface TranscriptSettleState {
540
570
  isSubmitting: boolean;
541
571
  run: () => void;
542
572
  }
573
+ /** How an approval stands. */
574
+ type TranscriptApprovalStatus = 'pending' | 'approved' | 'rejected' | 'expired';
543
575
  /**
544
- * Who has to settle a parked call, and until when — from the stream's `approval-requested` frame.
576
+ * Who has to settle a parked call, until when, and — once it settled — how. From the stream's
577
+ * `approval-requested` / `approval-settled` frames, or the same parts a reloaded thread carries.
545
578
  * `null` on a call whose runner never said (the call can still be awaiting approval).
546
579
  */
547
580
  interface TranscriptApproval {
548
581
  /** Open vocabulary the host defines: `'requester'`, `'admin'`, a role… */
549
582
  approver: string;
550
- /** ISO-8601; `null` when the request never lapses. */
583
+ /** ISO-8601; `null` when the request never lapses. Pair with `useApprovalCountdown`. */
551
584
  expiresAt: string | null;
585
+ /** Why the call needs a person, when the runner said. */
552
586
  reason: string | null;
587
+ /**
588
+ * `pending` until a settlement arrives; then what it said. Falls back to the call's own state
589
+ * (denied → `rejected`, an output → `approved`) for a runner that streams no settlement.
590
+ */
591
+ status: TranscriptApprovalStatus;
592
+ /** The approval also covers later calls of this tool in this thread. */
593
+ remember: boolean;
594
+ /** Opaque ref of who decided; `null` while pending, on an expiry, or when the runner did not say. */
595
+ decidedBy: string | null;
596
+ /** The surface the decision came through (`'web'`, `'slack'`, `'remembered'`, …). */
597
+ decidedVia: string | null;
598
+ /** What the person said when declining. */
599
+ decisionReason: string | null;
600
+ }
601
+ /** What an approval can carry beyond yes. */
602
+ interface ApproveOptions {
603
+ /** Approve later calls of the same tool in the same thread without asking again. */
604
+ remember?: boolean;
553
605
  }
554
606
  /** One call in a tool run, with whatever human decision it is parked on. */
555
607
  interface TranscriptToolCall {
@@ -578,7 +630,10 @@ interface TranscriptToolCall {
578
630
  * IS the pending approval.
579
631
  */
580
632
  isAwaitingApproval: boolean;
581
- approve: TranscriptSettleState;
633
+ /** `run({ remember: true })` approves this tool for the rest of the thread. */
634
+ approve: TranscriptSettleState & {
635
+ run: (options?: ApproveOptions) => void;
636
+ };
582
637
  reject: TranscriptSettleState;
583
638
  /** A failed decision — the call is still parked, so the affordance stays live. */
584
639
  error: string | null;
@@ -635,6 +690,14 @@ interface TranscriptQuestionOption {
635
690
  interface TranscriptQuestion {
636
691
  id: string;
637
692
  prompt: string;
693
+ /** A line of help under the prompt; `null` when the request gave none. */
694
+ description: string | null;
695
+ /**
696
+ * How the answer is typed — `{ type, placeholder?, required?, min?, max?, pattern? }` — or `null`
697
+ * for a plain pick from `options`. Render the control from `input.type`; `select` still picks
698
+ * from `options`.
699
+ */
700
+ input: ElicitationInput | null;
638
701
  multiple: boolean;
639
702
  /** 1-based. The request carries every question up front, so "Question 1 of N" is honest. */
640
703
  position: number;
@@ -646,6 +709,20 @@ interface TranscriptQuestion {
646
709
  * first is recorded as `defaulted` rather than as a choice the user made.
647
710
  */
648
711
  isPristine: boolean;
712
+ /** The first selected value, or `''` — what a single text/number/date field shows. */
713
+ value: string;
714
+ /**
715
+ * Set a typed answer from whatever the control produced (a string, a number, a checkbox's
716
+ * boolean, a `Date`, a list); coerced to the question's canonical strings with `coerceAnswer`.
717
+ * `null`/`''` clears it. Does nothing once the set settled.
718
+ */
719
+ setValue: (raw: RawAnswer) => void;
720
+ /**
721
+ * Why the current selection would be refused (the server's own rules — `validateAnswer`), or
722
+ * `null`. A pristine required question with no default reads `requires an answer`; show it once
723
+ * the user tried to submit, or right away — the model does not decide that for you.
724
+ */
725
+ error: string | null;
649
726
  }
650
727
  /** How a question set settled, once it did. */
651
728
  interface TranscriptElicitationOutcome {
@@ -672,6 +749,8 @@ interface TranscriptElicitationBlock {
672
749
  questionCount: number;
673
750
  /** Still waiting on a human. */
674
751
  isPending: boolean;
752
+ /** Every question's current selection is acceptable (no question has an `error`). */
753
+ isValid: boolean;
675
754
  outcome: TranscriptElicitationOutcome | null;
676
755
  /** A failed submission — the run is still parked, so the form stays live. */
677
756
  error: string | null;
@@ -729,7 +808,7 @@ interface ElicitationBlockOptions {
729
808
  interface ApprovalBlockOptions {
730
809
  canApprove: boolean;
731
810
  canReject: boolean;
732
- approve: (toolCallId: string) => void;
811
+ approve: (toolCallId: string, options?: ApproveOptions) => void;
733
812
  reject: (toolCallId: string) => void;
734
813
  /** Which decision this call is sending, or `null` for none. */
735
814
  submitting: (toolCallId: string) => SettleAction | null;
@@ -904,8 +983,11 @@ interface TranscriptItemOptions {
904
983
  onAnswer?: (toolCallId: string, answers: Record<string, string[]>) => void | Promise<void>;
905
984
  /** Decline the question set and let the agent proceed on its own picks — `useAgentChat`'s `skip`. */
906
985
  onSkip?: (toolCallId: string) => void | Promise<void>;
907
- /** Settle a tool call parked on a human — `useAgentChat`'s `approve` / `reject`. */
908
- onApprove?: (toolCallId: string) => void | Promise<void>;
986
+ /**
987
+ * Settle a tool call parked on a human — `useAgentChat`'s `approve` / `reject`. `options.remember`
988
+ * is what `call.approve.run({ remember: true })` passed.
989
+ */
990
+ onApprove?: (toolCallId: string, options?: ApproveOptions) => void | Promise<void>;
909
991
  onReject?: (toolCallId: string) => void | Promise<void>;
910
992
  }
911
993
  interface TranscriptWindow {
@@ -1374,6 +1456,28 @@ interface ToolCatalogState {
1374
1456
  */
1375
1457
  declare function useToolCatalog(options: UseToolCatalogOptions): ToolCatalogState;
1376
1458
 
1459
+ interface ApprovalCountdown {
1460
+ /** Milliseconds until the request lapses, floored at 0; `null` when it never does. */
1461
+ remainingMs: number | null;
1462
+ /** The instant has passed. Always `false` for a request with no expiry. */
1463
+ isExpired: boolean;
1464
+ }
1465
+ interface UseApprovalCountdownOptions {
1466
+ /** How often the value re-renders while counting. Default 1000 — a seconds label needs no more. */
1467
+ intervalMs?: number;
1468
+ /** Injectable clock for tests. */
1469
+ now?: () => number;
1470
+ }
1471
+ /** What {@link useApprovalCountdown} reads for `expiresAt` at `now`, without the ticking. */
1472
+ declare function approvalCountdown(expiresAt: string | null | undefined, now?: number): ApprovalCountdown;
1473
+ /**
1474
+ * Time left on an approval request (`call.approval.expiresAt`), ticking until it lapses and then
1475
+ * holding at zero. Headless: pair `remainingMs` with `formatElapsed` or any label of your own, and
1476
+ * use `isExpired` to stop offering buttons the server would refuse (`410 Gone`). The server stays
1477
+ * the authority — a lapse is final only once the call settles `expired`.
1478
+ */
1479
+ declare function useApprovalCountdown(expiresAt: string | null | undefined, options?: UseApprovalCountdownOptions): ApprovalCountdown;
1480
+
1377
1481
  /** The thinking time stamped on a reasoning part, or `null` when it carries none. */
1378
1482
  declare function readReasoningMs(part: {
1379
1483
  providerMetadata?: unknown;
@@ -1621,12 +1725,16 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1621
1725
  quota: _dudousxd_nestjs_agent_core.QuotaView | null;
1622
1726
  loadQuota: () => Promise<QuotaToday>;
1623
1727
  cancel: () => Promise<void>;
1624
- approve: ({ toolCallId }: {
1728
+ approve: ({ toolCallId, remember, via, }: {
1625
1729
  toolCallId: string;
1730
+ /** Approve later calls of the same tool in this thread without asking. */
1731
+ remember?: boolean;
1732
+ via?: string;
1626
1733
  }) => Promise<void>;
1627
- reject: ({ toolCallId, reason, }: {
1734
+ reject: ({ toolCallId, reason, via, }: {
1628
1735
  toolCallId: string;
1629
1736
  reason?: string;
1737
+ via?: string;
1630
1738
  }) => Promise<void>;
1631
1739
  answer: ({ toolCallId, answers, }: {
1632
1740
  toolCallId: string;
@@ -1648,4 +1756,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1648
1756
  clearError: () => void;
1649
1757
  };
1650
1758
 
1651
- export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type ApprovalBlockOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type BuildBlocksOptions, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, type ChatStatus, type ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DescribeToolCallOptions, type ElicitationBlockOptions, type GroupToolActivityOptions, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResolvedReading, type ResolvedResultView, type RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, type ToolActivityGroup, type ToolCallDescription, type ToolCallState, type ToolCallStatus, type ToolCatalog, type ToolCatalogState, type TranscriptActionState, type TranscriptApproval, type TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, type TranscriptElicitationBlock, type TranscriptElicitationOutcome, type TranscriptFile, type TranscriptFilesBlock, type TranscriptItem, type TranscriptItemOptions, type TranscriptQuestion, type TranscriptQuestionOption, type TranscriptReasoningBlock, type TranscriptSettleState, type TranscriptSource, type TranscriptSourcesBlock, type TranscriptStopState, type TranscriptTextBlock, type TranscriptToolBlock, type TranscriptToolCall, type TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UsageSummary, type UseAgentChatOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, correctedCallIds, createSkillsSource, describeTimestamp, describeToolCall, describeUsage, extractMessageText, fillTemplate, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, groupToolActivity, inferResultView, isActionCall, loadStoredSpeechLang, persistSpeechLang, phraseFor, readPath, readReasoningMs, resolveResultView, storedMessageToUiMessage, storedThreadToUiMessages, toolCallState, toolCatalogFrom, useAgentChat, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };
1759
+ export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type ApprovalBlockOptions, type ApprovalCountdown, type ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type BuildBlocksOptions, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, type ChatStatus, type ChatTranscript, type CoercibleQuestion, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DescribeToolCallOptions, type ElicitationBlockOptions, type GroupToolActivityOptions, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RawAnswer, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResolvedReading, type ResolvedResultView, type RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, type ToolActivityGroup, type ToolCallDescription, type ToolCallState, type ToolCallStatus, type ToolCatalog, type ToolCatalogState, type TranscriptActionState, type TranscriptApproval, type TranscriptApprovalStatus, type TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, type TranscriptElicitationBlock, type TranscriptElicitationOutcome, type TranscriptFile, type TranscriptFilesBlock, type TranscriptItem, type TranscriptItemOptions, type TranscriptQuestion, type TranscriptQuestionOption, type TranscriptReasoningBlock, type TranscriptSettleState, type TranscriptSource, type TranscriptSourcesBlock, type TranscriptStopState, type TranscriptTextBlock, type TranscriptToolBlock, type TranscriptToolCall, type TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UsageSummary, type UseAgentChatOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseSpeechRecognitionOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, buildTranscriptBlocks, coerceAnswer, correctedCallIds, createSkillsSource, describeTimestamp, describeToolCall, describeUsage, extractMessageText, fillTemplate, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, groupToolActivity, inferResultView, isActionCall, loadStoredSpeechLang, persistSpeechLang, phraseFor, readPath, readReasoningMs, resolveResultView, storedMessageToUiMessage, storedThreadToUiMessages, toolCallState, toolCatalogFrom, useAgentChat, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useToolCatalog, useTranscriptItem };