@dudousxd/nestjs-agent-react 0.8.0 → 0.9.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
@@ -345,6 +345,12 @@ interface TranscriptReasoningBlock {
345
345
  key: string;
346
346
  text: string;
347
347
  isStreaming: boolean;
348
+ /**
349
+ * How long the model thought, in ms — the backend's measurement once the run closed (live) or as
350
+ * persisted (reloaded). `null` while it still streams, or when nothing was recorded: pair it with
351
+ * `useElapsed(block.isStreaming)` for a ticking label (`block.durationMs ?? elapsed`).
352
+ */
353
+ durationMs: number | null;
348
354
  isOpen: boolean;
349
355
  toggle: (open?: boolean) => void;
350
356
  }
@@ -1151,6 +1157,32 @@ interface ComposerAutocomplete {
1151
1157
  */
1152
1158
  declare function useComposerAutocomplete(options: UseComposerAutocompleteOptions): ComposerAutocomplete;
1153
1159
 
1160
+ /** The thinking time stamped on a reasoning part, or `null` when it carries none. */
1161
+ declare function readReasoningMs(part: {
1162
+ providerMetadata?: unknown;
1163
+ }): number | null;
1164
+ interface UseElapsedOptions {
1165
+ /** How often the value re-renders while running. Default 1000 — a seconds label needs no more. */
1166
+ intervalMs?: number;
1167
+ /** Injectable clock for tests. */
1168
+ now?: () => number;
1169
+ }
1170
+ /**
1171
+ * Milliseconds since `running` last turned true — ticking while it stays true, frozen at the final
1172
+ * value once it turns false, `0` before it has ever run. Headless: pair it with
1173
+ * {@link formatElapsed} or any label of your own.
1174
+ *
1175
+ * For a reasoning block, prefer the duration the block already carries (`block.durationMs`, the
1176
+ * server's own measurement) and fall back to this only while the block streams:
1177
+ * `block.durationMs ?? elapsed`.
1178
+ */
1179
+ declare function useElapsed(running: boolean, options?: UseElapsedOptions): number;
1180
+ /**
1181
+ * `"<1s"`, `"4s"`, `"1m 5s"`, `"1h 2m"` — whole units, the shape a "Thought for …" label wants.
1182
+ * Negative or non-finite input reads as `"<1s"` rather than a nonsense figure.
1183
+ */
1184
+ declare function formatElapsed(ms: number): string;
1185
+
1154
1186
  declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
1155
1187
 
1156
1188
  /**
@@ -1399,4 +1431,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1399
1431
  clearError: () => void;
1400
1432
  };
1401
1433
 
1402
- 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 ElicitationBlockOptions, 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 RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, 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 UseSpeechRecognitionOptions, type UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, createSkillsSource, describeTimestamp, describeUsage, extractMessageText, filterAutocompleteItems, findActiveTrigger, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useChatTranscript, useComposerAutocomplete, useSpeechRecognition, useStickToBottom, useTranscriptItem };
1434
+ 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 ElicitationBlockOptions, 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 RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, 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 UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, createSkillsSource, describeTimestamp, describeUsage, extractMessageText, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, readReasoningMs, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useTranscriptItem };
package/dist/index.d.ts CHANGED
@@ -345,6 +345,12 @@ interface TranscriptReasoningBlock {
345
345
  key: string;
346
346
  text: string;
347
347
  isStreaming: boolean;
348
+ /**
349
+ * How long the model thought, in ms — the backend's measurement once the run closed (live) or as
350
+ * persisted (reloaded). `null` while it still streams, or when nothing was recorded: pair it with
351
+ * `useElapsed(block.isStreaming)` for a ticking label (`block.durationMs ?? elapsed`).
352
+ */
353
+ durationMs: number | null;
348
354
  isOpen: boolean;
349
355
  toggle: (open?: boolean) => void;
350
356
  }
@@ -1151,6 +1157,32 @@ interface ComposerAutocomplete {
1151
1157
  */
1152
1158
  declare function useComposerAutocomplete(options: UseComposerAutocompleteOptions): ComposerAutocomplete;
1153
1159
 
1160
+ /** The thinking time stamped on a reasoning part, or `null` when it carries none. */
1161
+ declare function readReasoningMs(part: {
1162
+ providerMetadata?: unknown;
1163
+ }): number | null;
1164
+ interface UseElapsedOptions {
1165
+ /** How often the value re-renders while running. Default 1000 — a seconds label needs no more. */
1166
+ intervalMs?: number;
1167
+ /** Injectable clock for tests. */
1168
+ now?: () => number;
1169
+ }
1170
+ /**
1171
+ * Milliseconds since `running` last turned true — ticking while it stays true, frozen at the final
1172
+ * value once it turns false, `0` before it has ever run. Headless: pair it with
1173
+ * {@link formatElapsed} or any label of your own.
1174
+ *
1175
+ * For a reasoning block, prefer the duration the block already carries (`block.durationMs`, the
1176
+ * server's own measurement) and fall back to this only while the block streams:
1177
+ * `block.durationMs ?? elapsed`.
1178
+ */
1179
+ declare function useElapsed(running: boolean, options?: UseElapsedOptions): number;
1180
+ /**
1181
+ * `"<1s"`, `"4s"`, `"1m 5s"`, `"1h 2m"` — whole units, the shape a "Thought for …" label wants.
1182
+ * Negative or non-finite input reads as `"<1s"` rather than a nonsense figure.
1183
+ */
1184
+ declare function formatElapsed(ms: number): string;
1185
+
1154
1186
  declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
1155
1187
 
1156
1188
  /**
@@ -1399,4 +1431,4 @@ declare function useAgentChat(options: UseAgentChatOptions): {
1399
1431
  clearError: () => void;
1400
1432
  };
1401
1433
 
1402
- 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 ElicitationBlockOptions, 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 RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, 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 UseSpeechRecognitionOptions, type UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, createSkillsSource, describeTimestamp, describeUsage, extractMessageText, filterAutocompleteItems, findActiveTrigger, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useChatTranscript, useComposerAutocomplete, useSpeechRecognition, useStickToBottom, useTranscriptItem };
1434
+ 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 ElicitationBlockOptions, 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 RetrievedPassage, SPEECH_LANGUAGES, type SettleAction, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type ThreadPatch, type TimestampInfo, 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 UseTranscriptItemOptions, applyCompletion, backgroundRunsFromThread, buildTranscriptBlocks, createSkillsSource, describeTimestamp, describeUsage, extractMessageText, filterAutocompleteItems, findActiveTrigger, formatElapsed, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, readReasoningMs, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useChatTranscript, useComposerAutocomplete, useElapsed, useSpeechRecognition, useStickToBottom, useTranscriptItem };
package/dist/index.js CHANGED
@@ -1,6 +1,65 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
+ // src/reasoning/timing.ts
5
+ import { useEffect, useRef, useState } from "react";
6
+ var REASONING_METADATA_KEY = "agent";
7
+ function reasoningDurationMetadata(reasoningMs) {
8
+ return {
9
+ [REASONING_METADATA_KEY]: {
10
+ reasoningMs
11
+ }
12
+ };
13
+ }
14
+ __name(reasoningDurationMetadata, "reasoningDurationMetadata");
15
+ function readReasoningMs(part) {
16
+ const metadata = part.providerMetadata;
17
+ if (typeof metadata !== "object" || metadata === null) return null;
18
+ const scoped = metadata[REASONING_METADATA_KEY];
19
+ if (typeof scoped !== "object" || scoped === null) return null;
20
+ const value = scoped.reasoningMs;
21
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
22
+ }
23
+ __name(readReasoningMs, "readReasoningMs");
24
+ function useElapsed(running, options = {}) {
25
+ const { intervalMs = 1e3 } = options;
26
+ const nowRef = useRef(options.now ?? Date.now);
27
+ nowRef.current = options.now ?? Date.now;
28
+ const startedAt = useRef(null);
29
+ const [elapsed, setElapsed] = useState(0);
30
+ useEffect(() => {
31
+ if (!running) {
32
+ if (startedAt.current !== null) {
33
+ setElapsed(nowRef.current() - startedAt.current);
34
+ startedAt.current = null;
35
+ }
36
+ return;
37
+ }
38
+ startedAt.current = nowRef.current();
39
+ setElapsed(0);
40
+ const timer = setInterval(() => {
41
+ if (startedAt.current !== null) setElapsed(nowRef.current() - startedAt.current);
42
+ }, intervalMs);
43
+ return () => clearInterval(timer);
44
+ }, [
45
+ running,
46
+ intervalMs
47
+ ]);
48
+ return elapsed;
49
+ }
50
+ __name(useElapsed, "useElapsed");
51
+ function formatElapsed(ms) {
52
+ if (!Number.isFinite(ms) || ms < 1e3) return "<1s";
53
+ const totalSeconds = Math.floor(ms / 1e3);
54
+ const hours = Math.floor(totalSeconds / 3600);
55
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
56
+ const seconds = totalSeconds % 60;
57
+ if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
58
+ if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
59
+ return `${seconds}s`;
60
+ }
61
+ __name(formatElapsed, "formatElapsed");
62
+
4
63
  // src/agent-chat-transport.ts
5
64
  var HEADER_RUN_ID = "x-agent-run-id";
6
65
  var HEADER_THREAD_ID = "x-agent-thread-id";
@@ -158,6 +217,7 @@ var AgentChatTransport = class {
158
217
  let stepIndex = 0;
159
218
  let textId = null;
160
219
  let reasoningId = null;
220
+ let reasoningStartedAt = 0;
161
221
  let textSeq = 0;
162
222
  let reasoningSeq = 0;
163
223
  const announced = /* @__PURE__ */ new Set();
@@ -194,7 +254,7 @@ var AgentChatTransport = class {
194
254
  if (!stepOpen) openStep();
195
255
  }
196
256
  __name(ensureStep, "ensureStep");
197
- function closeRuns() {
257
+ function closeRuns(reasoningMs) {
198
258
  if (textId !== null) {
199
259
  controller.enqueue({
200
260
  type: "text-end",
@@ -205,15 +265,16 @@ var AgentChatTransport = class {
205
265
  if (reasoningId !== null) {
206
266
  controller.enqueue({
207
267
  type: "reasoning-end",
208
- id: reasoningId
268
+ id: reasoningId,
269
+ providerMetadata: reasoningDurationMetadata(reasoningMs ?? Math.max(0, Date.now() - reasoningStartedAt))
209
270
  });
210
271
  reasoningId = null;
211
272
  }
212
273
  }
213
274
  __name(closeRuns, "closeRuns");
214
- function closeStep() {
275
+ function closeStep(reasoningMs) {
215
276
  if (!stepOpen) return;
216
- closeRuns();
277
+ closeRuns(reasoningMs);
217
278
  controller.enqueue({
218
279
  type: "finish-step"
219
280
  });
@@ -252,7 +313,7 @@ var AgentChatTransport = class {
252
313
  openStep();
253
314
  break;
254
315
  case "step-finish":
255
- closeStep();
316
+ closeStep(event.reasoningMs);
256
317
  if (event.costUsd !== void 0) {
257
318
  controller.enqueue({
258
319
  type: "message-metadata",
@@ -283,6 +344,7 @@ var AgentChatTransport = class {
283
344
  if (reasoningId === null) {
284
345
  reasoningId = reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;
285
346
  reasoningSeq += 1;
347
+ reasoningStartedAt = Date.now();
286
348
  controller.enqueue({
287
349
  type: "reasoning-start",
288
350
  id: reasoningId
@@ -730,10 +792,10 @@ var AgentClient = class {
730
792
  };
731
793
 
732
794
  // src/components/chat-input.tsx
733
- import React2, { useEffect as useEffect2, useState as useState2 } from "react";
795
+ import React2, { useEffect as useEffect3, useState as useState3 } from "react";
734
796
 
735
797
  // src/components/use-speech-recognition.ts
736
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
798
+ import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
737
799
  function getRecognitionCtor() {
738
800
  if (typeof window === "undefined") return null;
739
801
  const scope = window;
@@ -741,15 +803,15 @@ function getRecognitionCtor() {
741
803
  }
742
804
  __name(getRecognitionCtor, "getRecognitionCtor");
743
805
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
744
- const recognitionRef = useRef(null);
745
- const [isListening, setIsListening] = useState(false);
806
+ const recognitionRef = useRef2(null);
807
+ const [isListening, setIsListening] = useState2(false);
746
808
  const ctor = useMemo(() => getRecognitionCtor(), []);
747
809
  const isSupported = ctor !== null;
748
- const finalRef = useRef(onFinalTranscript);
749
- const interimRef = useRef(onInterimTranscript);
810
+ const finalRef = useRef2(onFinalTranscript);
811
+ const interimRef = useRef2(onInterimTranscript);
750
812
  finalRef.current = onFinalTranscript;
751
813
  interimRef.current = onInterimTranscript;
752
- useEffect(() => {
814
+ useEffect2(() => {
753
815
  if (!ctor) return;
754
816
  const recognition = new ctor();
755
817
  recognition.lang = lang;
@@ -817,8 +879,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
817
879
 
818
880
  // src/components/chat-input.tsx
819
881
  function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
820
- const [value, setValue] = useState2("");
821
- const [interim, setInterim] = useState2("");
882
+ const [value, setValue] = useState3("");
883
+ const [interim, setInterim] = useState3("");
822
884
  const speech = useSpeechRecognition({
823
885
  lang: speechLang,
824
886
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -829,7 +891,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
829
891
  }, "onFinalTranscript"),
830
892
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
831
893
  });
832
- useEffect2(() => {
894
+ useEffect3(() => {
833
895
  if (!speech.isListening) setInterim("");
834
896
  }, [
835
897
  speech.isListening
@@ -896,7 +958,7 @@ __name(ChatInput, "ChatInput");
896
958
  import React3 from "react";
897
959
 
898
960
  // src/transcript/use-chat-transcript.ts
899
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
961
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
900
962
 
901
963
  // src/transcript/model.ts
902
964
  import { getToolName, isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
@@ -1017,6 +1079,7 @@ function buildTranscriptBlocks(message, options) {
1017
1079
  key,
1018
1080
  text: part.text,
1019
1081
  isStreaming,
1082
+ durationMs: readReasoningMs(part),
1020
1083
  isOpen: options.isReasoningOpen(key, isStreaming),
1021
1084
  toggle: /* @__PURE__ */ __name((open) => options.toggleReasoning(key, open), "toggle")
1022
1085
  });
@@ -1429,10 +1492,10 @@ function formatCostUsd(cost) {
1429
1492
  __name(formatCostUsd, "formatCostUsd");
1430
1493
 
1431
1494
  // src/transcript/use-stick-to-bottom.ts
1432
- import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
1495
+ import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
1433
1496
  function useStickToBottom({ contentKey, threshold = 32 }) {
1434
- const containerRef = useRef2(null);
1435
- const [isAtBottom, setIsAtBottom] = useState3(true);
1497
+ const containerRef = useRef3(null);
1498
+ const [isAtBottom, setIsAtBottom] = useState4(true);
1436
1499
  const measure = useCallback2(() => {
1437
1500
  const element = containerRef.current;
1438
1501
  if (!element) {
@@ -1459,7 +1522,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
1459
1522
  }, [
1460
1523
  measure
1461
1524
  ]);
1462
- useEffect3(() => {
1525
+ useEffect4(() => {
1463
1526
  if (isAtBottom) {
1464
1527
  scrollToBottom();
1465
1528
  }
@@ -1490,14 +1553,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
1490
1553
  var DEFAULT_COPY_RESET_MS = 1500;
1491
1554
  function useChatTranscript(options) {
1492
1555
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
1493
- const latest = useRef3(options);
1556
+ const latest = useRef4(options);
1494
1557
  latest.current = options;
1495
- const [visibleCount, setVisibleCount] = useState4(initialVisibleCount);
1496
- const [stopRequested, setStopRequested] = useState4(false);
1558
+ const [visibleCount, setVisibleCount] = useState5(initialVisibleCount);
1559
+ const [stopRequested, setStopRequested] = useState5(false);
1497
1560
  const isStreaming = status === "streaming";
1498
1561
  const isBusy = status === "submitted" || isStreaming;
1499
1562
  const isEmpty = messages.length === 0;
1500
- useEffect4(() => {
1563
+ useEffect5(() => {
1501
1564
  if (!isBusy) {
1502
1565
  setStopRequested(false);
1503
1566
  }
@@ -1559,7 +1622,7 @@ function useChatTranscript(options) {
1559
1622
  __name(useChatTranscript, "useChatTranscript");
1560
1623
  function useTranscriptItem(options) {
1561
1624
  const { message, isStreaming = false } = options;
1562
- const messagesRef = useRef3([
1625
+ const messagesRef = useRef4([
1563
1626
  message
1564
1627
  ]);
1565
1628
  if (messagesRef.current[0] !== message) {
@@ -1577,13 +1640,13 @@ function useTranscriptItem(options) {
1577
1640
  }
1578
1641
  __name(useTranscriptItem, "useTranscriptItem");
1579
1642
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
1580
- const [drafts, setDrafts] = useState4(() => /* @__PURE__ */ new Map());
1581
- const [copied, setCopied] = useState4(() => /* @__PURE__ */ new Set());
1582
- const [openReasoning, setOpenReasoning] = useState4(() => /* @__PURE__ */ new Map());
1583
- const [picks, setPicks] = useState4(() => /* @__PURE__ */ new Map());
1584
- const [settling, setSettling] = useState4(() => /* @__PURE__ */ new Map());
1585
- const [settleErrors, setSettleErrors] = useState4(() => /* @__PURE__ */ new Map());
1586
- const latest = useRef3({
1643
+ const [drafts, setDrafts] = useState5(() => /* @__PURE__ */ new Map());
1644
+ const [copied, setCopied] = useState5(() => /* @__PURE__ */ new Set());
1645
+ const [openReasoning, setOpenReasoning] = useState5(() => /* @__PURE__ */ new Map());
1646
+ const [picks, setPicks] = useState5(() => /* @__PURE__ */ new Map());
1647
+ const [settling, setSettling] = useState5(() => /* @__PURE__ */ new Map());
1648
+ const [settleErrors, setSettleErrors] = useState5(() => /* @__PURE__ */ new Map());
1649
+ const latest = useRef4({
1587
1650
  options,
1588
1651
  drafts,
1589
1652
  picks,
@@ -1595,15 +1658,15 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1595
1658
  picks,
1596
1659
  messages
1597
1660
  };
1598
- const copyTimers = useRef3(/* @__PURE__ */ new Map());
1599
- useEffect4(() => () => {
1661
+ const copyTimers = useRef4(/* @__PURE__ */ new Map());
1662
+ useEffect5(() => () => {
1600
1663
  for (const timer of copyTimers.current.values()) {
1601
1664
  clearTimeout(timer);
1602
1665
  }
1603
1666
  copyTimers.current.clear();
1604
1667
  }, []);
1605
- const callbackCache = useRef3(/* @__PURE__ */ new Map());
1606
- const reasoningToggleCache = useRef3(/* @__PURE__ */ new Map());
1668
+ const callbackCache = useRef4(/* @__PURE__ */ new Map());
1669
+ const reasoningToggleCache = useRef4(/* @__PURE__ */ new Map());
1607
1670
  const toggleReasoning = useCallback3((key, open) => {
1608
1671
  setOpenReasoning((current) => {
1609
1672
  const next = new Map(current);
@@ -2332,18 +2395,18 @@ function toItem(entry) {
2332
2395
  __name(toItem, "toItem");
2333
2396
 
2334
2397
  // src/composer/use-composer-autocomplete.ts
2335
- import { useCallback as useCallback4, useEffect as useEffect5, useId, useLayoutEffect, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
2398
+ import { useCallback as useCallback4, useEffect as useEffect6, useId, useLayoutEffect, useMemo as useMemo2, useRef as useRef5, useState as useState6 } from "react";
2336
2399
  function useComposerAutocomplete(options) {
2337
2400
  const { value, sources, acceptOnTab = true } = options;
2338
- const latest = useRef4(options);
2401
+ const latest = useRef5(options);
2339
2402
  latest.current = options;
2340
- const inputRef = useRef4(null);
2341
- const [caret, setCaret] = useState5(value.length);
2342
- const [items, setItems] = useState5([]);
2343
- const [isLoading, setLoading] = useState5(false);
2344
- const [error, setError] = useState5(null);
2345
- const [activeIndex, setActiveIndex] = useState5(0);
2346
- const [dismissedIndex, setDismissedIndex] = useState5(null);
2403
+ const inputRef = useRef5(null);
2404
+ const [caret, setCaret] = useState6(value.length);
2405
+ const [items, setItems] = useState6([]);
2406
+ const [isLoading, setLoading] = useState6(false);
2407
+ const [error, setError] = useState6(null);
2408
+ const [activeIndex, setActiveIndex] = useState6(0);
2409
+ const [dismissedIndex, setDismissedIndex] = useState6(null);
2347
2410
  const safeCaret = Math.min(caret, value.length);
2348
2411
  const match = useMemo2(() => findActiveTrigger(value, safeCaret, sources), [
2349
2412
  value,
@@ -2351,16 +2414,16 @@ function useComposerAutocomplete(options) {
2351
2414
  sources
2352
2415
  ]);
2353
2416
  const isActive = match !== null && dismissedIndex !== match.index;
2354
- const matchRef = useRef4(match);
2417
+ const matchRef = useRef5(match);
2355
2418
  matchRef.current = match;
2356
- const caretRef = useRef4(safeCaret);
2419
+ const caretRef = useRef5(safeCaret);
2357
2420
  caretRef.current = safeCaret;
2358
- const itemsRef = useRef4(items);
2421
+ const itemsRef = useRef5(items);
2359
2422
  itemsRef.current = items;
2360
- const activeIndexRef = useRef4(activeIndex);
2423
+ const activeIndexRef = useRef5(activeIndex);
2361
2424
  activeIndexRef.current = activeIndex;
2362
2425
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
2363
- useEffect5(() => {
2426
+ useEffect6(() => {
2364
2427
  const current = matchRef.current;
2365
2428
  if (requestKey === null || current === null) {
2366
2429
  setItems([]);
@@ -2425,7 +2488,7 @@ function useComposerAutocomplete(options) {
2425
2488
  const current = matchRef.current;
2426
2489
  if (current) setDismissedIndex(current.index);
2427
2490
  }, []);
2428
- const pendingCaret = useRef4(null);
2491
+ const pendingCaret = useRef5(null);
2429
2492
  const accept = useCallback4((item) => {
2430
2493
  const current = matchRef.current;
2431
2494
  if (!current) return;
@@ -2590,6 +2653,16 @@ function refusalReason(result) {
2590
2653
  __name(refusalReason, "refusalReason");
2591
2654
  function storedMessageToUiMessage(message) {
2592
2655
  const parts = [];
2656
+ if (message.reasoning) {
2657
+ parts.push({
2658
+ type: "reasoning",
2659
+ text: message.reasoning,
2660
+ state: "done",
2661
+ ...message.reasoningMs !== void 0 ? {
2662
+ providerMetadata: reasoningDurationMetadata(message.reasoningMs)
2663
+ } : {}
2664
+ });
2665
+ }
2593
2666
  if (message.content) {
2594
2667
  parts.push({
2595
2668
  type: "text",
@@ -2604,6 +2677,20 @@ function storedMessageToUiMessage(message) {
2604
2677
  url: attachment.url
2605
2678
  });
2606
2679
  }
2680
+ for (const component of message.ui ?? []) {
2681
+ parts.push({
2682
+ type: "data-ui",
2683
+ id: component.id,
2684
+ data: {
2685
+ id: component.id,
2686
+ component: component.component,
2687
+ props: component.props,
2688
+ ...component.version !== void 0 ? {
2689
+ version: component.version
2690
+ } : {}
2691
+ }
2692
+ });
2693
+ }
2607
2694
  for (const call of message.toolCalls ?? []) {
2608
2695
  const result = message.toolResults?.find((candidate) => candidate.id === call.id);
2609
2696
  const toolKind2 = call.kind;
@@ -2706,19 +2793,19 @@ __name(sumUsage, "sumUsage");
2706
2793
 
2707
2794
  // src/use-agent-chat.ts
2708
2795
  import { useChat } from "@ai-sdk/react";
2709
- import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef5, useState as useState6 } from "react";
2796
+ import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo3, useRef as useRef6, useState as useState7 } from "react";
2710
2797
  function useAgentChat(options) {
2711
- const latest = useRef5(options);
2798
+ const latest = useRef6(options);
2712
2799
  latest.current = options;
2713
- const [runId, setRunId] = useState6(options.resumeRunId);
2714
- const runIdRef = useRef5(runId);
2800
+ const [runId, setRunId] = useState7(options.resumeRunId);
2801
+ const runIdRef = useRef6(runId);
2715
2802
  runIdRef.current = runId;
2716
- const settlingRunIdRef = useRef5(void 0);
2717
- const autoResumeRunIdRef = useRef5(void 0);
2718
- const [autoResume, setAutoResume] = useState6(false);
2719
- const [activeRunId, setActiveRunId] = useState6(null);
2720
- const regenerateNext = useRef5(false);
2721
- const createdThreadId = useRef5(void 0);
2803
+ const settlingRunIdRef = useRef6(void 0);
2804
+ const autoResumeRunIdRef = useRef6(void 0);
2805
+ const [autoResume, setAutoResume] = useState7(false);
2806
+ const [activeRunId, setActiveRunId] = useState7(null);
2807
+ const regenerateNext = useRef6(false);
2808
+ const createdThreadId = useRef6(void 0);
2722
2809
  const client = useMemo3(() => {
2723
2810
  if (options.client) return options.client;
2724
2811
  return new AgentClient({
@@ -2734,7 +2821,7 @@ function useAgentChat(options) {
2734
2821
  getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
2735
2822
  });
2736
2823
  }, []);
2737
- useEffect6(() => {
2824
+ useEffect7(() => {
2738
2825
  if (!options.resume || options.threadId === void 0) return;
2739
2826
  let cancelled = false;
2740
2827
  const threadId = options.threadId;
@@ -2803,7 +2890,7 @@ function useAgentChat(options) {
2803
2890
  }, "onAttemptStart")
2804
2891
  });
2805
2892
  }, []);
2806
- const backgroundRef = useRef5(() => Promise.resolve());
2893
+ const backgroundRef = useRef6(() => Promise.resolve());
2807
2894
  const chat = useChat({
2808
2895
  transport,
2809
2896
  resume: options.resumeRunId !== void 0 || autoResume,
@@ -2834,9 +2921,9 @@ function useAgentChat(options) {
2834
2921
  }
2835
2922
  }, "onFinish")
2836
2923
  });
2837
- const chatRef = useRef5(chat);
2924
+ const chatRef = useRef6(chat);
2838
2925
  chatRef.current = chat;
2839
- const turnInFlight = useRef5(false);
2926
+ const turnInFlight = useRef6(false);
2840
2927
  const isTurnInFlight = useCallback5(() => turnInFlight.current || transport.isAttemptLive, [
2841
2928
  transport
2842
2929
  ]);
@@ -2856,9 +2943,9 @@ function useAgentChat(options) {
2856
2943
  toolCallId,
2857
2944
  output
2858
2945
  }), []);
2859
- const [threads, setThreads] = useState6([]);
2860
- const [quota, setQuota] = useState6(null);
2861
- const [backgroundRuns, setBackgroundRuns] = useState6([]);
2946
+ const [threads, setThreads] = useState7([]);
2947
+ const [quota, setQuota] = useState7(null);
2948
+ const [backgroundRuns, setBackgroundRuns] = useState7([]);
2862
2949
  const refreshBackground = useCallback5(async () => {
2863
2950
  const threadId = latest.current.threadId ?? createdThreadId.current;
2864
2951
  if (threadId === void 0) {
@@ -2884,7 +2971,7 @@ function useAgentChat(options) {
2884
2971
  ]);
2885
2972
  backgroundRef.current = refreshBackground;
2886
2973
  const isWorking = backgroundRuns.some((run) => run.status === "running");
2887
- useEffect6(() => {
2974
+ useEffect7(() => {
2888
2975
  if (options.background !== true || options.threadId === void 0) {
2889
2976
  return;
2890
2977
  }
@@ -2894,7 +2981,7 @@ function useAgentChat(options) {
2894
2981
  options.threadId,
2895
2982
  refreshBackground
2896
2983
  ]);
2897
- useEffect6(() => {
2984
+ useEffect7(() => {
2898
2985
  const every = latest.current.backgroundPollMs ?? 5e3;
2899
2986
  if (latest.current.background !== true || !isWorking || every <= 0) {
2900
2987
  return;
@@ -3067,14 +3154,17 @@ export {
3067
3154
  extractMessageText,
3068
3155
  filterAutocompleteItems,
3069
3156
  findActiveTrigger,
3157
+ formatElapsed,
3070
3158
  formatRelativeTime,
3071
3159
  loadStoredSpeechLang,
3072
3160
  persistSpeechLang,
3161
+ readReasoningMs,
3073
3162
  storedMessageToUiMessage,
3074
3163
  storedThreadToUiMessages,
3075
3164
  useAgentChat,
3076
3165
  useChatTranscript,
3077
3166
  useComposerAutocomplete,
3167
+ useElapsed,
3078
3168
  useSpeechRecognition,
3079
3169
  useStickToBottom,
3080
3170
  useTranscriptItem