@dudousxd/nestjs-agent-react 0.7.5 → 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.cjs CHANGED
@@ -49,20 +49,82 @@ __export(src_exports, {
49
49
  extractMessageText: () => extractMessageText,
50
50
  filterAutocompleteItems: () => filterAutocompleteItems,
51
51
  findActiveTrigger: () => findActiveTrigger,
52
+ formatElapsed: () => formatElapsed,
52
53
  formatRelativeTime: () => formatRelativeTime,
53
54
  loadStoredSpeechLang: () => loadStoredSpeechLang,
54
55
  persistSpeechLang: () => persistSpeechLang,
56
+ readReasoningMs: () => readReasoningMs,
55
57
  storedMessageToUiMessage: () => storedMessageToUiMessage,
56
58
  storedThreadToUiMessages: () => storedThreadToUiMessages,
57
59
  useAgentChat: () => useAgentChat,
58
60
  useChatTranscript: () => useChatTranscript,
59
61
  useComposerAutocomplete: () => useComposerAutocomplete,
62
+ useElapsed: () => useElapsed,
60
63
  useSpeechRecognition: () => useSpeechRecognition,
61
64
  useStickToBottom: () => useStickToBottom,
62
65
  useTranscriptItem: () => useTranscriptItem
63
66
  });
64
67
  module.exports = __toCommonJS(src_exports);
65
68
 
69
+ // src/reasoning/timing.ts
70
+ var import_react = require("react");
71
+ var REASONING_METADATA_KEY = "agent";
72
+ function reasoningDurationMetadata(reasoningMs) {
73
+ return {
74
+ [REASONING_METADATA_KEY]: {
75
+ reasoningMs
76
+ }
77
+ };
78
+ }
79
+ __name(reasoningDurationMetadata, "reasoningDurationMetadata");
80
+ function readReasoningMs(part) {
81
+ const metadata = part.providerMetadata;
82
+ if (typeof metadata !== "object" || metadata === null) return null;
83
+ const scoped = metadata[REASONING_METADATA_KEY];
84
+ if (typeof scoped !== "object" || scoped === null) return null;
85
+ const value = scoped.reasoningMs;
86
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
87
+ }
88
+ __name(readReasoningMs, "readReasoningMs");
89
+ function useElapsed(running, options = {}) {
90
+ const { intervalMs = 1e3 } = options;
91
+ const nowRef = (0, import_react.useRef)(options.now ?? Date.now);
92
+ nowRef.current = options.now ?? Date.now;
93
+ const startedAt = (0, import_react.useRef)(null);
94
+ const [elapsed, setElapsed] = (0, import_react.useState)(0);
95
+ (0, import_react.useEffect)(() => {
96
+ if (!running) {
97
+ if (startedAt.current !== null) {
98
+ setElapsed(nowRef.current() - startedAt.current);
99
+ startedAt.current = null;
100
+ }
101
+ return;
102
+ }
103
+ startedAt.current = nowRef.current();
104
+ setElapsed(0);
105
+ const timer = setInterval(() => {
106
+ if (startedAt.current !== null) setElapsed(nowRef.current() - startedAt.current);
107
+ }, intervalMs);
108
+ return () => clearInterval(timer);
109
+ }, [
110
+ running,
111
+ intervalMs
112
+ ]);
113
+ return elapsed;
114
+ }
115
+ __name(useElapsed, "useElapsed");
116
+ function formatElapsed(ms) {
117
+ if (!Number.isFinite(ms) || ms < 1e3) return "<1s";
118
+ const totalSeconds = Math.floor(ms / 1e3);
119
+ const hours = Math.floor(totalSeconds / 3600);
120
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
121
+ const seconds = totalSeconds % 60;
122
+ if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
123
+ if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
124
+ return `${seconds}s`;
125
+ }
126
+ __name(formatElapsed, "formatElapsed");
127
+
66
128
  // src/agent-chat-transport.ts
67
129
  var HEADER_RUN_ID = "x-agent-run-id";
68
130
  var HEADER_THREAD_ID = "x-agent-thread-id";
@@ -202,7 +264,8 @@ var AgentChatTransport = class {
202
264
  * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
203
265
  * Recognized frames:
204
266
  * - `event: meta` `data: {"runId","threadId"}` → records identity
205
- * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool)
267
+ * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool /
268
+ * `data-*`; see {@link AgentChatTransport} docs)
206
269
  * - `event: done` `data: {}` → terminates
207
270
  * - `event: error` `data: {code,message}` → error chunk
208
271
  *
@@ -219,7 +282,11 @@ var AgentChatTransport = class {
219
282
  let stepIndex = 0;
220
283
  let textId = null;
221
284
  let reasoningId = null;
285
+ let reasoningStartedAt = 0;
286
+ let textSeq = 0;
287
+ let reasoningSeq = 0;
222
288
  const announced = /* @__PURE__ */ new Set();
289
+ const toolMetadata = /* @__PURE__ */ new Map();
223
290
  const record = /* @__PURE__ */ __name((meta) => this.recordMeta(meta), "record");
224
291
  const endAttempt = /* @__PURE__ */ __name(() => {
225
292
  this.attemptLive = false;
@@ -241,6 +308,8 @@ var AgentChatTransport = class {
241
308
  stepIndex += 1;
242
309
  textId = null;
243
310
  reasoningId = null;
311
+ textSeq = 0;
312
+ reasoningSeq = 0;
244
313
  controller.enqueue({
245
314
  type: "start-step"
246
315
  });
@@ -250,8 +319,7 @@ var AgentChatTransport = class {
250
319
  if (!stepOpen) openStep();
251
320
  }
252
321
  __name(ensureStep, "ensureStep");
253
- function closeStep() {
254
- if (!stepOpen) return;
322
+ function closeRuns(reasoningMs) {
255
323
  if (textId !== null) {
256
324
  controller.enqueue({
257
325
  type: "text-end",
@@ -262,23 +330,55 @@ var AgentChatTransport = class {
262
330
  if (reasoningId !== null) {
263
331
  controller.enqueue({
264
332
  type: "reasoning-end",
265
- id: reasoningId
333
+ id: reasoningId,
334
+ providerMetadata: reasoningDurationMetadata(reasoningMs ?? Math.max(0, Date.now() - reasoningStartedAt))
266
335
  });
267
336
  reasoningId = null;
268
337
  }
338
+ }
339
+ __name(closeRuns, "closeRuns");
340
+ function closeStep(reasoningMs) {
341
+ if (!stepOpen) return;
342
+ closeRuns(reasoningMs);
269
343
  controller.enqueue({
270
344
  type: "finish-step"
271
345
  });
272
346
  stepOpen = false;
273
347
  }
274
348
  __name(closeStep, "closeStep");
349
+ function metadataFor(id, toolKind2, parentId) {
350
+ const merged = {
351
+ ...toolMetadata.get(id)
352
+ };
353
+ if (toolKind2 !== void 0) merged.toolKind = toolKind2;
354
+ if (parentId !== void 0 && merged.parentId === void 0) merged.parentId = parentId;
355
+ if (Object.keys(merged).length === 0) return void 0;
356
+ toolMetadata.set(id, merged);
357
+ return merged;
358
+ }
359
+ __name(metadataFor, "metadataFor");
360
+ function forwardAsData(event, transient) {
361
+ ensureStarted();
362
+ const { kind, ...data } = event;
363
+ controller.enqueue({
364
+ type: `data-${kind}`,
365
+ ...typeof data.id === "string" ? {
366
+ id: data.id
367
+ } : {},
368
+ data,
369
+ ...transient ? {
370
+ transient: true
371
+ } : {}
372
+ });
373
+ }
374
+ __name(forwardAsData, "forwardAsData");
275
375
  function emit(event) {
276
376
  switch (event.kind) {
277
377
  case "step-start":
278
378
  openStep();
279
379
  break;
280
380
  case "step-finish":
281
- closeStep();
381
+ closeStep(event.reasoningMs);
282
382
  if (event.costUsd !== void 0) {
283
383
  controller.enqueue({
284
384
  type: "message-metadata",
@@ -291,7 +391,8 @@ var AgentChatTransport = class {
291
391
  case "text":
292
392
  ensureStep();
293
393
  if (textId === null) {
294
- textId = `txt-${stepIndex}`;
394
+ textId = textSeq === 0 ? `txt-${stepIndex}` : `txt-${stepIndex}.${textSeq}`;
395
+ textSeq += 1;
295
396
  controller.enqueue({
296
397
  type: "text-start",
297
398
  id: textId
@@ -306,7 +407,9 @@ var AgentChatTransport = class {
306
407
  case "reasoning":
307
408
  ensureStep();
308
409
  if (reasoningId === null) {
309
- reasoningId = `rsn-${stepIndex}`;
410
+ reasoningId = reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;
411
+ reasoningSeq += 1;
412
+ reasoningStartedAt = Date.now();
310
413
  controller.enqueue({
311
414
  type: "reasoning-start",
312
415
  id: reasoningId
@@ -318,23 +421,20 @@ var AgentChatTransport = class {
318
421
  delta: event.text
319
422
  });
320
423
  break;
321
- case "tool-input-start":
424
+ case "tool-input-start": {
322
425
  ensureStep();
323
426
  announced.add(event.id);
427
+ const metadata = metadataFor(event.id, event.toolKind, event.parentId);
324
428
  controller.enqueue({
325
429
  type: "tool-input-start",
326
430
  toolCallId: event.id,
327
431
  toolName: event.name,
328
- // `toolKind` is absent on older backends — omitted (not `undefined`-valued) so
329
- // `toolMetadata` itself is only present when there's something to say, letting a
330
- // UI gate approval affordances on `kind === 'action'` without hardcoding tool names.
331
- ...event.toolKind !== void 0 ? {
332
- toolMetadata: {
333
- toolKind: event.toolKind
334
- }
432
+ ...metadata !== void 0 ? {
433
+ toolMetadata: metadata
335
434
  } : {}
336
435
  });
337
436
  break;
437
+ }
338
438
  case "tool-input-delta":
339
439
  ensureStep();
340
440
  controller.enqueue({
@@ -343,21 +443,21 @@ var AgentChatTransport = class {
343
443
  inputTextDelta: event.delta
344
444
  });
345
445
  break;
346
- case "tool-input-available":
446
+ case "tool-input-available": {
347
447
  ensureStep();
348
448
  announced.add(event.id);
449
+ const metadata = metadataFor(event.id, event.toolKind, event.parentId);
349
450
  controller.enqueue({
350
451
  type: "tool-input-available",
351
452
  toolCallId: event.id,
352
453
  toolName: event.name,
353
454
  input: event.input,
354
- ...event.toolKind !== void 0 ? {
355
- toolMetadata: {
356
- toolKind: event.toolKind
357
- }
455
+ ...metadata !== void 0 ? {
456
+ toolMetadata: metadata
358
457
  } : {}
359
458
  });
360
459
  break;
460
+ }
361
461
  case "elicitation":
362
462
  ensureStep();
363
463
  if (!announced.has(event.id)) {
@@ -398,7 +498,39 @@ var AgentChatTransport = class {
398
498
  toolCallId: event.id
399
499
  });
400
500
  break;
501
+ case "approval-requested":
502
+ ensureStep();
503
+ forwardAsData(event, false);
504
+ if (announced.has(event.id)) {
505
+ controller.enqueue({
506
+ type: "tool-approval-request",
507
+ approvalId: event.id,
508
+ toolCallId: event.id
509
+ });
510
+ }
511
+ break;
512
+ case "ui":
513
+ ensureStep();
514
+ closeRuns();
515
+ controller.enqueue({
516
+ type: "data-ui",
517
+ id: event.id,
518
+ data: {
519
+ id: event.id,
520
+ component: event.component,
521
+ props: event.props,
522
+ ...event.version !== void 0 ? {
523
+ version: event.version
524
+ } : {}
525
+ }
526
+ });
527
+ break;
528
+ case "title":
529
+ case "cancelled":
530
+ forwardAsData(event, true);
531
+ break;
401
532
  default:
533
+ forwardAsData(event, false);
402
534
  break;
403
535
  }
404
536
  }
@@ -725,10 +857,10 @@ var AgentClient = class {
725
857
  };
726
858
 
727
859
  // src/components/chat-input.tsx
728
- var import_react2 = __toESM(require("react"), 1);
860
+ var import_react3 = __toESM(require("react"), 1);
729
861
 
730
862
  // src/components/use-speech-recognition.ts
731
- var import_react = require("react");
863
+ var import_react2 = require("react");
732
864
  function getRecognitionCtor() {
733
865
  if (typeof window === "undefined") return null;
734
866
  const scope = window;
@@ -736,15 +868,15 @@ function getRecognitionCtor() {
736
868
  }
737
869
  __name(getRecognitionCtor, "getRecognitionCtor");
738
870
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
739
- const recognitionRef = (0, import_react.useRef)(null);
740
- const [isListening, setIsListening] = (0, import_react.useState)(false);
741
- const ctor = (0, import_react.useMemo)(() => getRecognitionCtor(), []);
871
+ const recognitionRef = (0, import_react2.useRef)(null);
872
+ const [isListening, setIsListening] = (0, import_react2.useState)(false);
873
+ const ctor = (0, import_react2.useMemo)(() => getRecognitionCtor(), []);
742
874
  const isSupported = ctor !== null;
743
- const finalRef = (0, import_react.useRef)(onFinalTranscript);
744
- const interimRef = (0, import_react.useRef)(onInterimTranscript);
875
+ const finalRef = (0, import_react2.useRef)(onFinalTranscript);
876
+ const interimRef = (0, import_react2.useRef)(onInterimTranscript);
745
877
  finalRef.current = onFinalTranscript;
746
878
  interimRef.current = onInterimTranscript;
747
- (0, import_react.useEffect)(() => {
879
+ (0, import_react2.useEffect)(() => {
748
880
  if (!ctor) return;
749
881
  const recognition = new ctor();
750
882
  recognition.lang = lang;
@@ -783,7 +915,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
783
915
  ctor,
784
916
  lang
785
917
  ]);
786
- const start = (0, import_react.useCallback)(() => {
918
+ const start = (0, import_react2.useCallback)(() => {
787
919
  const recognition = recognitionRef.current;
788
920
  if (!recognition) return;
789
921
  try {
@@ -793,7 +925,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
793
925
  console.warn("SpeechRecognition start failed", error);
794
926
  }
795
927
  }, []);
796
- const stop = (0, import_react.useCallback)(() => {
928
+ const stop = (0, import_react2.useCallback)(() => {
797
929
  const recognition = recognitionRef.current;
798
930
  if (!recognition) return;
799
931
  try {
@@ -812,8 +944,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
812
944
 
813
945
  // src/components/chat-input.tsx
814
946
  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 }) {
815
- const [value, setValue] = (0, import_react2.useState)("");
816
- const [interim, setInterim] = (0, import_react2.useState)("");
947
+ const [value, setValue] = (0, import_react3.useState)("");
948
+ const [interim, setInterim] = (0, import_react3.useState)("");
817
949
  const speech = useSpeechRecognition({
818
950
  lang: speechLang,
819
951
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -824,7 +956,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
824
956
  }, "onFinalTranscript"),
825
957
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
826
958
  });
827
- (0, import_react2.useEffect)(() => {
959
+ (0, import_react3.useEffect)(() => {
828
960
  if (!speech.isListening) setInterim("");
829
961
  }, [
830
962
  speech.isListening
@@ -852,9 +984,9 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
852
984
  const displayValue = speech.isListening && interim ? `${value}${value && !value.endsWith(" ") ? " " : ""}${interim}` : value;
853
985
  const showMic = enableSpeech && speech.isSupported;
854
986
  const showStop = isStreaming && onStop !== void 0;
855
- return /* @__PURE__ */ import_react2.default.createElement("div", {
987
+ return /* @__PURE__ */ import_react3.default.createElement("div", {
856
988
  className
857
- }, /* @__PURE__ */ import_react2.default.createElement("textarea", {
989
+ }, /* @__PURE__ */ import_react3.default.createElement("textarea", {
858
990
  className: textareaClassName,
859
991
  rows,
860
992
  value: displayValue,
@@ -865,17 +997,17 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
865
997
  }, "onChange"),
866
998
  onKeyDown: handleKeyDown,
867
999
  placeholder: placeholder ?? "Ask something (Enter to send, Shift+Enter for newline)"
868
- }), /* @__PURE__ */ import_react2.default.createElement("button", {
1000
+ }), /* @__PURE__ */ import_react3.default.createElement("button", {
869
1001
  type: "button",
870
1002
  className: sendButtonClassName,
871
1003
  onClick: submit,
872
1004
  disabled: disabled || !value.trim()
873
- }, sendLabel), showStop ? /* @__PURE__ */ import_react2.default.createElement("button", {
1005
+ }, sendLabel), showStop ? /* @__PURE__ */ import_react3.default.createElement("button", {
874
1006
  type: "button",
875
1007
  className: stopButtonClassName,
876
1008
  onClick: /* @__PURE__ */ __name(() => void onStop(), "onClick"),
877
1009
  "aria-label": "Stop generating"
878
- }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react2.default.createElement("button", {
1010
+ }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react3.default.createElement("button", {
879
1011
  type: "button",
880
1012
  className: micButtonClassName,
881
1013
  onClick: toggleMic,
@@ -888,10 +1020,10 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
888
1020
  __name(ChatInput, "ChatInput");
889
1021
 
890
1022
  // src/components/message-item.tsx
891
- var import_react5 = __toESM(require("react"), 1);
1023
+ var import_react6 = __toESM(require("react"), 1);
892
1024
 
893
1025
  // src/transcript/use-chat-transcript.ts
894
- var import_react4 = require("react");
1026
+ var import_react5 = require("react");
895
1027
 
896
1028
  // src/transcript/model.ts
897
1029
  var import_ai = require("ai");
@@ -906,15 +1038,18 @@ function buildTranscriptBlocks(message, options) {
906
1038
  let reasoningCounter = 0;
907
1039
  let sourcesCounter = 0;
908
1040
  let elicitationCounter = 0;
1041
+ const approvals = readApprovals(message.parts ?? []);
909
1042
  function flushTools() {
910
1043
  if (toolBuffer.length === 0) {
911
1044
  return;
912
1045
  }
1046
+ const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null));
913
1047
  blocks.push({
914
1048
  kind: "tools",
915
1049
  key: `${message.id}-tools-${toolCounter++}`,
916
1050
  parts: toolBuffer,
917
- calls: toolBuffer.map((part) => buildToolCall(part, options.approval))
1051
+ calls,
1052
+ roots: nestToolCalls(calls)
918
1053
  });
919
1054
  toolBuffer = [];
920
1055
  }
@@ -977,7 +1112,21 @@ function buildTranscriptBlocks(message, options) {
977
1112
  fileBuffer.push(part);
978
1113
  continue;
979
1114
  }
1115
+ if (part.type === APPROVAL_PART) {
1116
+ continue;
1117
+ }
980
1118
  flushAll();
1119
+ if ((0, import_ai.isDataUIPart)(part)) {
1120
+ const ui = part.type === UI_PART ? readUiComponent(part) : null;
1121
+ if (ui !== null) {
1122
+ blocks.push({
1123
+ kind: "ui",
1124
+ key: `${message.id}-ui-${ui.id}`,
1125
+ ...ui
1126
+ });
1127
+ }
1128
+ continue;
1129
+ }
981
1130
  if ((0, import_ai.isTextUIPart)(part)) {
982
1131
  blocks.push({
983
1132
  kind: "text",
@@ -995,6 +1144,7 @@ function buildTranscriptBlocks(message, options) {
995
1144
  key,
996
1145
  text: part.text,
997
1146
  isStreaming,
1147
+ durationMs: readReasoningMs(part),
998
1148
  isOpen: options.isReasoningOpen(key, isStreaming),
999
1149
  toggle: /* @__PURE__ */ __name((open) => options.toggleReasoning(key, open), "toggle")
1000
1150
  });
@@ -1061,7 +1211,42 @@ function isAwaitingApproval(part) {
1061
1211
  return toolKind(part) === "action" && readElicitationRequest(part) === null;
1062
1212
  }
1063
1213
  __name(isAwaitingApproval, "isAwaitingApproval");
1064
- function buildToolCall(part, options) {
1214
+ function toolParentId(part) {
1215
+ const metadata = part.toolMetadata;
1216
+ return isRecord(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
1217
+ }
1218
+ __name(toolParentId, "toolParentId");
1219
+ function nestToolCalls(calls) {
1220
+ const byId = new Map(calls.map((call) => [
1221
+ call.toolCallId,
1222
+ call
1223
+ ]));
1224
+ const roots = [];
1225
+ for (const call of calls) {
1226
+ const parent = call.parentId !== null ? byId.get(call.parentId) : void 0;
1227
+ if (parent === void 0 || isAncestor(call, parent, byId)) {
1228
+ roots.push(call);
1229
+ continue;
1230
+ }
1231
+ parent.children.push(call);
1232
+ }
1233
+ return roots;
1234
+ }
1235
+ __name(nestToolCalls, "nestToolCalls");
1236
+ function isAncestor(call, candidate, byId) {
1237
+ const seen = /* @__PURE__ */ new Set();
1238
+ let current = candidate;
1239
+ while (current !== void 0 && !seen.has(current.toolCallId)) {
1240
+ if (current.toolCallId === call.toolCallId) {
1241
+ return true;
1242
+ }
1243
+ seen.add(current.toolCallId);
1244
+ current = current.parentId !== null ? byId.get(current.parentId) : void 0;
1245
+ }
1246
+ return false;
1247
+ }
1248
+ __name(isAncestor, "isAncestor");
1249
+ function buildToolCall(part, options, approval) {
1065
1250
  const toolCallId = part.toolCallId;
1066
1251
  const awaiting = isAwaitingApproval(part);
1067
1252
  const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
@@ -1069,6 +1254,10 @@ function buildToolCall(part, options) {
1069
1254
  part,
1070
1255
  toolCallId,
1071
1256
  name: (0, import_ai.getToolName)(part),
1257
+ toolKind: toolKind(part) ?? null,
1258
+ parentId: toolParentId(part),
1259
+ children: [],
1260
+ approval,
1072
1261
  isAwaitingApproval: awaiting,
1073
1262
  approve: {
1074
1263
  available: awaiting && options?.canApprove === true,
@@ -1199,6 +1388,44 @@ function buildElicitationBlock(key, part, request, options) {
1199
1388
  };
1200
1389
  }
1201
1390
  __name(buildElicitationBlock, "buildElicitationBlock");
1391
+ var UI_PART = "data-ui";
1392
+ var APPROVAL_PART = "data-approval-requested";
1393
+ function readApprovals(parts) {
1394
+ const out = /* @__PURE__ */ new Map();
1395
+ for (const part of parts) {
1396
+ if (part.type !== APPROVAL_PART) {
1397
+ continue;
1398
+ }
1399
+ const data = part.data;
1400
+ if (!isRecord(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
1401
+ continue;
1402
+ }
1403
+ out.set(data.id, {
1404
+ approver: data.approver,
1405
+ expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : null,
1406
+ reason: typeof data.reason === "string" ? data.reason : null
1407
+ });
1408
+ }
1409
+ return out;
1410
+ }
1411
+ __name(readApprovals, "readApprovals");
1412
+ function readUiComponent(part) {
1413
+ const data = part.data;
1414
+ if (!isRecord(data) || typeof data.component !== "string") {
1415
+ return null;
1416
+ }
1417
+ const id = typeof data.id === "string" ? data.id : part.id;
1418
+ if (id === void 0) {
1419
+ return null;
1420
+ }
1421
+ return {
1422
+ id,
1423
+ component: data.component,
1424
+ props: isRecord(data.props) ? data.props : {},
1425
+ version: typeof data.version === "number" ? data.version : null
1426
+ };
1427
+ }
1428
+ __name(readUiComponent, "readUiComponent");
1202
1429
  function isRecord(value) {
1203
1430
  return typeof value === "object" && value !== null;
1204
1431
  }
@@ -1330,11 +1557,11 @@ function formatCostUsd(cost) {
1330
1557
  __name(formatCostUsd, "formatCostUsd");
1331
1558
 
1332
1559
  // src/transcript/use-stick-to-bottom.ts
1333
- var import_react3 = require("react");
1560
+ var import_react4 = require("react");
1334
1561
  function useStickToBottom({ contentKey, threshold = 32 }) {
1335
- const containerRef = (0, import_react3.useRef)(null);
1336
- const [isAtBottom, setIsAtBottom] = (0, import_react3.useState)(true);
1337
- const measure = (0, import_react3.useCallback)(() => {
1562
+ const containerRef = (0, import_react4.useRef)(null);
1563
+ const [isAtBottom, setIsAtBottom] = (0, import_react4.useState)(true);
1564
+ const measure = (0, import_react4.useCallback)(() => {
1338
1565
  const element = containerRef.current;
1339
1566
  if (!element) {
1340
1567
  return;
@@ -1344,7 +1571,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
1344
1571
  }, [
1345
1572
  threshold
1346
1573
  ]);
1347
- const scrollToBottom = (0, import_react3.useCallback)(() => {
1574
+ const scrollToBottom = (0, import_react4.useCallback)(() => {
1348
1575
  const element = containerRef.current;
1349
1576
  if (!element) {
1350
1577
  return;
@@ -1352,7 +1579,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
1352
1579
  element.scrollTop = element.scrollHeight;
1353
1580
  setIsAtBottom(true);
1354
1581
  }, []);
1355
- const setContainer = (0, import_react3.useCallback)((element) => {
1582
+ const setContainer = (0, import_react4.useCallback)((element) => {
1356
1583
  containerRef.current = element;
1357
1584
  if (element) {
1358
1585
  measure();
@@ -1360,7 +1587,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
1360
1587
  }, [
1361
1588
  measure
1362
1589
  ]);
1363
- (0, import_react3.useEffect)(() => {
1590
+ (0, import_react4.useEffect)(() => {
1364
1591
  if (isAtBottom) {
1365
1592
  scrollToBottom();
1366
1593
  }
@@ -1369,7 +1596,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
1369
1596
  isAtBottom,
1370
1597
  scrollToBottom
1371
1598
  ]);
1372
- const getContainerProps = (0, import_react3.useCallback)(() => ({
1599
+ const getContainerProps = (0, import_react4.useCallback)(() => ({
1373
1600
  ref: setContainer,
1374
1601
  onScroll: measure
1375
1602
  }), [
@@ -1391,14 +1618,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
1391
1618
  var DEFAULT_COPY_RESET_MS = 1500;
1392
1619
  function useChatTranscript(options) {
1393
1620
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
1394
- const latest = (0, import_react4.useRef)(options);
1621
+ const latest = (0, import_react5.useRef)(options);
1395
1622
  latest.current = options;
1396
- const [visibleCount, setVisibleCount] = (0, import_react4.useState)(initialVisibleCount);
1397
- const [stopRequested, setStopRequested] = (0, import_react4.useState)(false);
1623
+ const [visibleCount, setVisibleCount] = (0, import_react5.useState)(initialVisibleCount);
1624
+ const [stopRequested, setStopRequested] = (0, import_react5.useState)(false);
1398
1625
  const isStreaming = status === "streaming";
1399
1626
  const isBusy = status === "submitted" || isStreaming;
1400
1627
  const isEmpty = messages.length === 0;
1401
- (0, import_react4.useEffect)(() => {
1628
+ (0, import_react5.useEffect)(() => {
1402
1629
  if (!isBusy) {
1403
1630
  setStopRequested(false);
1404
1631
  }
@@ -1415,7 +1642,7 @@ function useChatTranscript(options) {
1415
1642
  streamingMessageId,
1416
1643
  options
1417
1644
  });
1418
- const stop = (0, import_react4.useCallback)(() => {
1645
+ const stop = (0, import_react5.useCallback)(() => {
1419
1646
  const current = latest.current;
1420
1647
  if (current.status !== "submitted" && current.status !== "streaming") {
1421
1648
  return;
@@ -1423,8 +1650,8 @@ function useChatTranscript(options) {
1423
1650
  setStopRequested(true);
1424
1651
  void current.onStop?.();
1425
1652
  }, []);
1426
- const loadEarlier = (0, import_react4.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
1427
- const showAll = (0, import_react4.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
1653
+ const loadEarlier = (0, import_react5.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
1654
+ const showAll = (0, import_react5.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
1428
1655
  const scroll = useStickToBottom({
1429
1656
  contentKey: contentSignature(messages),
1430
1657
  ...stickToBottomThreshold !== void 0 ? {
@@ -1460,7 +1687,7 @@ function useChatTranscript(options) {
1460
1687
  __name(useChatTranscript, "useChatTranscript");
1461
1688
  function useTranscriptItem(options) {
1462
1689
  const { message, isStreaming = false } = options;
1463
- const messagesRef = (0, import_react4.useRef)([
1690
+ const messagesRef = (0, import_react5.useRef)([
1464
1691
  message
1465
1692
  ]);
1466
1693
  if (messagesRef.current[0] !== message) {
@@ -1478,13 +1705,13 @@ function useTranscriptItem(options) {
1478
1705
  }
1479
1706
  __name(useTranscriptItem, "useTranscriptItem");
1480
1707
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
1481
- const [drafts, setDrafts] = (0, import_react4.useState)(() => /* @__PURE__ */ new Map());
1482
- const [copied, setCopied] = (0, import_react4.useState)(() => /* @__PURE__ */ new Set());
1483
- const [openReasoning, setOpenReasoning] = (0, import_react4.useState)(() => /* @__PURE__ */ new Map());
1484
- const [picks, setPicks] = (0, import_react4.useState)(() => /* @__PURE__ */ new Map());
1485
- const [settling, setSettling] = (0, import_react4.useState)(() => /* @__PURE__ */ new Map());
1486
- const [settleErrors, setSettleErrors] = (0, import_react4.useState)(() => /* @__PURE__ */ new Map());
1487
- const latest = (0, import_react4.useRef)({
1708
+ const [drafts, setDrafts] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
1709
+ const [copied, setCopied] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
1710
+ const [openReasoning, setOpenReasoning] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
1711
+ const [picks, setPicks] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
1712
+ const [settling, setSettling] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
1713
+ const [settleErrors, setSettleErrors] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
1714
+ const latest = (0, import_react5.useRef)({
1488
1715
  options,
1489
1716
  drafts,
1490
1717
  picks,
@@ -1496,23 +1723,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1496
1723
  picks,
1497
1724
  messages
1498
1725
  };
1499
- const copyTimers = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
1500
- (0, import_react4.useEffect)(() => () => {
1726
+ const copyTimers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
1727
+ (0, import_react5.useEffect)(() => () => {
1501
1728
  for (const timer of copyTimers.current.values()) {
1502
1729
  clearTimeout(timer);
1503
1730
  }
1504
1731
  copyTimers.current.clear();
1505
1732
  }, []);
1506
- const callbackCache = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
1507
- const reasoningToggleCache = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
1508
- const toggleReasoning = (0, import_react4.useCallback)((key, open) => {
1733
+ const callbackCache = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
1734
+ const reasoningToggleCache = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
1735
+ const toggleReasoning = (0, import_react5.useCallback)((key, open) => {
1509
1736
  setOpenReasoning((current) => {
1510
1737
  const next = new Map(current);
1511
1738
  next.set(key, open ?? !(current.get(key) ?? false));
1512
1739
  return next;
1513
1740
  });
1514
1741
  }, []);
1515
- const stableToggle = (0, import_react4.useCallback)((key) => {
1742
+ const stableToggle = (0, import_react5.useCallback)((key) => {
1516
1743
  let cached = reasoningToggleCache.current.get(key);
1517
1744
  if (!cached) {
1518
1745
  cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
@@ -1522,10 +1749,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1522
1749
  }, [
1523
1750
  toggleReasoning
1524
1751
  ]);
1525
- const pick = (0, import_react4.useCallback)((toolCallId, questionId, values) => {
1752
+ const pick = (0, import_react5.useCallback)((toolCallId, questionId, values) => {
1526
1753
  setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
1527
1754
  }, []);
1528
- const settle = (0, import_react4.useCallback)((toolCallId, action, send) => {
1755
+ const settle = (0, import_react5.useCallback)((toolCallId, action, send) => {
1529
1756
  setSettleErrors((current) => {
1530
1757
  if (!current.has(toolCallId)) {
1531
1758
  return current;
@@ -1549,7 +1776,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1549
1776
  failed(error);
1550
1777
  }
1551
1778
  }, []);
1552
- const answer = (0, import_react4.useCallback)((toolCallId) => {
1779
+ const answer = (0, import_react5.useCallback)((toolCallId) => {
1553
1780
  const current = latest.current;
1554
1781
  const onAnswer = current.options.onAnswer;
1555
1782
  if (!onAnswer) {
@@ -1559,7 +1786,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1559
1786
  }, [
1560
1787
  settle
1561
1788
  ]);
1562
- const skip = (0, import_react4.useCallback)((toolCallId) => {
1789
+ const skip = (0, import_react5.useCallback)((toolCallId) => {
1563
1790
  const onSkip = latest.current.options.onSkip;
1564
1791
  if (onSkip) {
1565
1792
  settle(toolCallId, "skip", () => onSkip(toolCallId));
@@ -1567,7 +1794,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1567
1794
  }, [
1568
1795
  settle
1569
1796
  ]);
1570
- const approve = (0, import_react4.useCallback)((toolCallId) => {
1797
+ const approve = (0, import_react5.useCallback)((toolCallId) => {
1571
1798
  const onApprove = latest.current.options.onApprove;
1572
1799
  if (onApprove) {
1573
1800
  settle(toolCallId, "approve", () => onApprove(toolCallId));
@@ -1575,7 +1802,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1575
1802
  }, [
1576
1803
  settle
1577
1804
  ]);
1578
- const reject = (0, import_react4.useCallback)((toolCallId) => {
1805
+ const reject = (0, import_react5.useCallback)((toolCallId) => {
1579
1806
  const onReject = latest.current.options.onReject;
1580
1807
  if (onReject) {
1581
1808
  settle(toolCallId, "reject", () => onReject(toolCallId));
@@ -1583,7 +1810,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
1583
1810
  }, [
1584
1811
  settle
1585
1812
  ]);
1586
- const callbacksFor = (0, import_react4.useCallback)((id) => {
1813
+ const callbacksFor = (0, import_react5.useCallback)((id) => {
1587
1814
  const cached = callbackCache.current.get(id);
1588
1815
  if (cached) {
1589
1816
  return cached;
@@ -1822,7 +2049,7 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
1822
2049
  getCreatedAt: /* @__PURE__ */ __name(() => createdAt, "getCreatedAt")
1823
2050
  } : {}
1824
2051
  });
1825
- return /* @__PURE__ */ import_react5.default.createElement(MessageItemView, {
2052
+ return /* @__PURE__ */ import_react6.default.createElement(MessageItemView, {
1826
2053
  item,
1827
2054
  ...slots
1828
2055
  });
@@ -1830,51 +2057,51 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
1830
2057
  __name(MessageItem, "MessageItem");
1831
2058
  function MessageItemView({ item, ...slots }) {
1832
2059
  const { classNames } = slots;
1833
- const actionRow = /* @__PURE__ */ import_react5.default.createElement("div", {
2060
+ const actionRow = /* @__PURE__ */ import_react6.default.createElement("div", {
1834
2061
  className: classNames?.actions,
1835
2062
  "data-actions-for": item.role
1836
- }, item.copy.available ? /* @__PURE__ */ import_react5.default.createElement("button", {
2063
+ }, item.copy.available ? /* @__PURE__ */ import_react6.default.createElement("button", {
1837
2064
  type: "button",
1838
2065
  onClick: item.copy.copy,
1839
2066
  className: classNames?.actionButton,
1840
2067
  title: item.copy.copied ? "Copied!" : "Copy message text"
1841
- }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react5.default.createElement("button", {
2068
+ }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react6.default.createElement("button", {
1842
2069
  type: "button",
1843
2070
  onClick: item.fork.run,
1844
2071
  className: classNames?.actionButton,
1845
2072
  title: "Fork thread from this message"
1846
- }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react5.default.createElement("button", {
2073
+ }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react6.default.createElement("button", {
1847
2074
  type: "button",
1848
2075
  onClick: item.regenerate.run,
1849
2076
  className: classNames?.actionButton,
1850
2077
  title: "Regenerate response"
1851
- }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react5.default.createElement("span", {
2078
+ }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react6.default.createElement("span", {
1852
2079
  className: classNames?.usage,
1853
2080
  title: `Input ${item.usage.inputTokens.toLocaleString()} \xB7 Output ${item.usage.outputTokens.toLocaleString()} tokens`
1854
- }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react5.default.createElement("span", {
2081
+ }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react6.default.createElement("span", {
1855
2082
  className: classNames?.timestamp,
1856
2083
  title: item.timestamp.absolute
1857
2084
  }, item.timestamp.relative) : null);
1858
2085
  if (item.edit.available) {
1859
- return /* @__PURE__ */ import_react5.default.createElement(EditableUserBubble, {
2086
+ return /* @__PURE__ */ import_react6.default.createElement(EditableUserBubble, {
1860
2087
  item,
1861
2088
  slots,
1862
2089
  actions: actionRow
1863
2090
  });
1864
2091
  }
1865
2092
  const className = joinClasses(classNames?.root, classNames?.byRole?.[item.role]);
1866
- return /* @__PURE__ */ import_react5.default.createElement("div", {
2093
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
1867
2094
  className,
1868
2095
  "data-role": item.role,
1869
2096
  "data-streaming": item.isStreaming ? "true" : void 0
1870
- }, /* @__PURE__ */ import_react5.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
2097
+ }, /* @__PURE__ */ import_react6.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
1871
2098
  }
1872
2099
  __name(MessageItemView, "MessageItemView");
1873
2100
  function renderBlocks(item, slots) {
1874
2101
  const nodes = [];
1875
2102
  for (const block of item.blocks) {
1876
2103
  if (block.kind === "text") {
1877
- nodes.push(/* @__PURE__ */ import_react5.default.createElement("div", {
2104
+ nodes.push(/* @__PURE__ */ import_react6.default.createElement("div", {
1878
2105
  key: block.key,
1879
2106
  className: slots.classNames?.text
1880
2107
  }, slots.renderText ? slots.renderText(block.text, {
@@ -1892,24 +2119,32 @@ function renderBlocks(item, slots) {
1892
2119
  }
1893
2120
  if (block.kind === "tools") {
1894
2121
  nodes.push(...renderToolBlock(item, block, slots));
2122
+ continue;
2123
+ }
2124
+ if (block.kind === "ui" && slots.renderUi) {
2125
+ nodes.push(/* @__PURE__ */ import_react6.default.createElement("div", {
2126
+ key: block.key,
2127
+ "data-slot": "ui",
2128
+ "data-component": block.component
2129
+ }, slots.renderUi(block)));
1895
2130
  }
1896
2131
  }
1897
2132
  return nodes;
1898
2133
  }
1899
2134
  __name(renderBlocks, "renderBlocks");
1900
2135
  function renderFilesBlock(block, slots) {
1901
- return /* @__PURE__ */ import_react5.default.createElement("div", {
2136
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
1902
2137
  key: block.key,
1903
2138
  className: slots.classNames?.files,
1904
2139
  "data-files": "true"
1905
- }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react5.default.createElement("a", {
2140
+ }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react6.default.createElement("a", {
1906
2141
  key: file.url,
1907
2142
  href: file.url,
1908
2143
  target: "_blank",
1909
2144
  rel: "noreferrer",
1910
2145
  className: slots.classNames?.file,
1911
2146
  title: file.filename ?? file.mediaType
1912
- }, file.isImage ? /* @__PURE__ */ import_react5.default.createElement("img", {
2147
+ }, file.isImage ? /* @__PURE__ */ import_react6.default.createElement("img", {
1913
2148
  src: file.url,
1914
2149
  alt: file.filename ?? "image",
1915
2150
  className: slots.classNames?.fileImage
@@ -1917,17 +2152,17 @@ function renderFilesBlock(block, slots) {
1917
2152
  }
1918
2153
  __name(renderFilesBlock, "renderFilesBlock");
1919
2154
  function renderReasoningBlock(block, slots) {
1920
- return /* @__PURE__ */ import_react5.default.createElement("div", {
2155
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
1921
2156
  key: block.key,
1922
2157
  className: slots.classNames?.reasoning,
1923
2158
  "data-reasoning": "true",
1924
2159
  "data-streaming": block.isStreaming ? "true" : void 0
1925
- }, /* @__PURE__ */ import_react5.default.createElement("button", {
2160
+ }, /* @__PURE__ */ import_react6.default.createElement("button", {
1926
2161
  type: "button",
1927
2162
  className: slots.classNames?.reasoningToggle,
1928
2163
  onClick: /* @__PURE__ */ __name(() => block.toggle(), "onClick"),
1929
2164
  "aria-expanded": block.isOpen
1930
- }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react5.default.createElement("div", {
2165
+ }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react6.default.createElement("div", {
1931
2166
  className: slots.classNames?.reasoningText
1932
2167
  }, slots.renderReasoning ? slots.renderReasoning(block.text, {
1933
2168
  isStreaming: block.isStreaming,
@@ -1938,7 +2173,7 @@ __name(renderReasoningBlock, "renderReasoningBlock");
1938
2173
  function renderToolBlock(item, block, slots) {
1939
2174
  if (slots.renderToolGroup) {
1940
2175
  return [
1941
- /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, {
2176
+ /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, {
1942
2177
  key: block.key
1943
2178
  }, slots.renderToolGroup(block.parts, block.key))
1944
2179
  ];
@@ -1949,7 +2184,7 @@ function renderToolBlock(item, block, slots) {
1949
2184
  const renderToolPart = slots.renderToolPart;
1950
2185
  return block.parts.map((part) => {
1951
2186
  const partKey = `${item.id}-${part.toolCallId}`;
1952
- return /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, {
2187
+ return /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, {
1953
2188
  key: partKey
1954
2189
  }, renderToolPart(part, partKey));
1955
2190
  });
@@ -1959,14 +2194,14 @@ function EditableUserBubble({ item, slots, actions }) {
1959
2194
  const { classNames } = slots;
1960
2195
  const { edit } = item;
1961
2196
  if (!edit.isEditing) {
1962
- return /* @__PURE__ */ import_react5.default.createElement("div", {
2197
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
1963
2198
  className: joinClasses(classNames?.root, classNames?.byRole?.user),
1964
2199
  "data-role": "user"
1965
- }, /* @__PURE__ */ import_react5.default.createElement("div", {
2200
+ }, /* @__PURE__ */ import_react6.default.createElement("div", {
1966
2201
  className: classNames?.text
1967
2202
  }, slots.renderText ? slots.renderText(item.text, {
1968
2203
  isStreaming: false
1969
- }) : item.text), /* @__PURE__ */ import_react5.default.createElement("button", {
2204
+ }) : item.text), /* @__PURE__ */ import_react6.default.createElement("button", {
1970
2205
  type: "button",
1971
2206
  onClick: edit.start,
1972
2207
  className: classNames?.actionButton,
@@ -1974,18 +2209,18 @@ function EditableUserBubble({ item, slots, actions }) {
1974
2209
  }, "Edit"), actions);
1975
2210
  }
1976
2211
  const textareaProps = edit.getTextareaProps();
1977
- return /* @__PURE__ */ import_react5.default.createElement("div", {
2212
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
1978
2213
  "data-editing": "true"
1979
- }, /* @__PURE__ */ import_react5.default.createElement("textarea", {
2214
+ }, /* @__PURE__ */ import_react6.default.createElement("textarea", {
1980
2215
  ...textareaProps,
1981
2216
  rows: Math.min(8, edit.draft.split("\n").length + 1),
1982
2217
  className: classNames?.editTextarea
1983
- }), /* @__PURE__ */ import_react5.default.createElement("div", {
2218
+ }), /* @__PURE__ */ import_react6.default.createElement("div", {
1984
2219
  className: classNames?.editActions
1985
- }, /* @__PURE__ */ import_react5.default.createElement("button", {
2220
+ }, /* @__PURE__ */ import_react6.default.createElement("button", {
1986
2221
  type: "button",
1987
2222
  onClick: edit.cancel
1988
- }, "Cancel"), /* @__PURE__ */ import_react5.default.createElement("button", {
2223
+ }, "Cancel"), /* @__PURE__ */ import_react6.default.createElement("button", {
1989
2224
  type: "button",
1990
2225
  onClick: edit.save,
1991
2226
  disabled: !edit.canSave
@@ -1999,7 +2234,7 @@ function joinClasses(...entries) {
1999
2234
  __name(joinClasses, "joinClasses");
2000
2235
 
2001
2236
  // src/components/message-list.tsx
2002
- function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames }) {
2237
+ function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, renderUi, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames }) {
2003
2238
  const transcript = useChatTranscript({
2004
2239
  messages,
2005
2240
  status,
@@ -2049,6 +2284,9 @@ function MessageList({ messages, status, renderToolPart, renderToolGroup, render
2049
2284
  ...renderFiles ? {
2050
2285
  renderFiles
2051
2286
  } : {},
2287
+ ...renderUi ? {
2288
+ renderUi
2289
+ } : {},
2052
2290
  ...reasoningLabel !== void 0 ? {
2053
2291
  reasoningLabel
2054
2292
  } : {},
@@ -2222,35 +2460,35 @@ function toItem(entry) {
2222
2460
  __name(toItem, "toItem");
2223
2461
 
2224
2462
  // src/composer/use-composer-autocomplete.ts
2225
- var import_react6 = require("react");
2463
+ var import_react7 = require("react");
2226
2464
  function useComposerAutocomplete(options) {
2227
2465
  const { value, sources, acceptOnTab = true } = options;
2228
- const latest = (0, import_react6.useRef)(options);
2466
+ const latest = (0, import_react7.useRef)(options);
2229
2467
  latest.current = options;
2230
- const inputRef = (0, import_react6.useRef)(null);
2231
- const [caret, setCaret] = (0, import_react6.useState)(value.length);
2232
- const [items, setItems] = (0, import_react6.useState)([]);
2233
- const [isLoading, setLoading] = (0, import_react6.useState)(false);
2234
- const [error, setError] = (0, import_react6.useState)(null);
2235
- const [activeIndex, setActiveIndex] = (0, import_react6.useState)(0);
2236
- const [dismissedIndex, setDismissedIndex] = (0, import_react6.useState)(null);
2468
+ const inputRef = (0, import_react7.useRef)(null);
2469
+ const [caret, setCaret] = (0, import_react7.useState)(value.length);
2470
+ const [items, setItems] = (0, import_react7.useState)([]);
2471
+ const [isLoading, setLoading] = (0, import_react7.useState)(false);
2472
+ const [error, setError] = (0, import_react7.useState)(null);
2473
+ const [activeIndex, setActiveIndex] = (0, import_react7.useState)(0);
2474
+ const [dismissedIndex, setDismissedIndex] = (0, import_react7.useState)(null);
2237
2475
  const safeCaret = Math.min(caret, value.length);
2238
- const match = (0, import_react6.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
2476
+ const match = (0, import_react7.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
2239
2477
  value,
2240
2478
  safeCaret,
2241
2479
  sources
2242
2480
  ]);
2243
2481
  const isActive = match !== null && dismissedIndex !== match.index;
2244
- const matchRef = (0, import_react6.useRef)(match);
2482
+ const matchRef = (0, import_react7.useRef)(match);
2245
2483
  matchRef.current = match;
2246
- const caretRef = (0, import_react6.useRef)(safeCaret);
2484
+ const caretRef = (0, import_react7.useRef)(safeCaret);
2247
2485
  caretRef.current = safeCaret;
2248
- const itemsRef = (0, import_react6.useRef)(items);
2486
+ const itemsRef = (0, import_react7.useRef)(items);
2249
2487
  itemsRef.current = items;
2250
- const activeIndexRef = (0, import_react6.useRef)(activeIndex);
2488
+ const activeIndexRef = (0, import_react7.useRef)(activeIndex);
2251
2489
  activeIndexRef.current = activeIndex;
2252
2490
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
2253
- (0, import_react6.useEffect)(() => {
2491
+ (0, import_react7.useEffect)(() => {
2254
2492
  const current = matchRef.current;
2255
2493
  if (requestKey === null || current === null) {
2256
2494
  setItems([]);
@@ -2298,25 +2536,25 @@ function useComposerAutocomplete(options) {
2298
2536
  ]);
2299
2537
  const isOpen = isActive;
2300
2538
  const activeItem = isOpen ? items[activeIndex] ?? null : null;
2301
- const reactId = (0, import_react6.useId)();
2539
+ const reactId = (0, import_react7.useId)();
2302
2540
  const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
2303
- const optionId = (0, import_react6.useCallback)((index) => `${listboxId}-option-${index}`, [
2541
+ const optionId = (0, import_react7.useCallback)((index) => `${listboxId}-option-${index}`, [
2304
2542
  listboxId
2305
2543
  ]);
2306
- const highlight = (0, import_react6.useCallback)((index) => {
2544
+ const highlight = (0, import_react7.useCallback)((index) => {
2307
2545
  const total = itemsRef.current.length;
2308
2546
  if (total === 0) return;
2309
2547
  setActiveIndex((index % total + total) % total);
2310
2548
  }, []);
2311
- const moveHighlight = (0, import_react6.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
2549
+ const moveHighlight = (0, import_react7.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
2312
2550
  highlight
2313
2551
  ]);
2314
- const dismiss = (0, import_react6.useCallback)(() => {
2552
+ const dismiss = (0, import_react7.useCallback)(() => {
2315
2553
  const current = matchRef.current;
2316
2554
  if (current) setDismissedIndex(current.index);
2317
2555
  }, []);
2318
- const pendingCaret = (0, import_react6.useRef)(null);
2319
- const accept = (0, import_react6.useCallback)((item) => {
2556
+ const pendingCaret = (0, import_react7.useRef)(null);
2557
+ const accept = (0, import_react7.useCallback)((item) => {
2320
2558
  const current = matchRef.current;
2321
2559
  if (!current) return;
2322
2560
  const chosen = item ?? itemsRef.current[activeIndexRef.current];
@@ -2327,16 +2565,16 @@ function useComposerAutocomplete(options) {
2327
2565
  setDismissedIndex(null);
2328
2566
  pendingCaret.current = edit.caret;
2329
2567
  }, []);
2330
- (0, import_react6.useLayoutEffect)(() => {
2568
+ (0, import_react7.useLayoutEffect)(() => {
2331
2569
  const position = pendingCaret.current;
2332
2570
  if (position === null) return;
2333
2571
  pendingCaret.current = null;
2334
2572
  inputRef.current?.setSelectionRange(position, position);
2335
2573
  });
2336
- const readCaret = (0, import_react6.useCallback)((element) => {
2574
+ const readCaret = (0, import_react7.useCallback)((element) => {
2337
2575
  setCaret(element.selectionStart ?? element.value.length);
2338
2576
  }, []);
2339
- const onKeyDown = (0, import_react6.useCallback)((event) => {
2577
+ const onKeyDown = (0, import_react7.useCallback)((event) => {
2340
2578
  if (!isOpen) return;
2341
2579
  const hasItems = itemsRef.current.length > 0;
2342
2580
  switch (event.key) {
@@ -2374,23 +2612,23 @@ function useComposerAutocomplete(options) {
2374
2612
  dismiss,
2375
2613
  moveHighlight
2376
2614
  ]);
2377
- const onChange = (0, import_react6.useCallback)((event) => {
2615
+ const onChange = (0, import_react7.useCallback)((event) => {
2378
2616
  readCaret(event.target);
2379
2617
  const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
2380
2618
  setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
2381
2619
  }, [
2382
2620
  readCaret
2383
2621
  ]);
2384
- const onSelect = (0, import_react6.useCallback)((event) => readCaret(event.currentTarget), [
2622
+ const onSelect = (0, import_react7.useCallback)((event) => readCaret(event.currentTarget), [
2385
2623
  readCaret
2386
2624
  ]);
2387
- const onClick = (0, import_react6.useCallback)((event) => readCaret(event.currentTarget), [
2625
+ const onClick = (0, import_react7.useCallback)((event) => readCaret(event.currentTarget), [
2388
2626
  readCaret
2389
2627
  ]);
2390
- const setInput = (0, import_react6.useCallback)((element) => {
2628
+ const setInput = (0, import_react7.useCallback)((element) => {
2391
2629
  inputRef.current = element;
2392
2630
  }, []);
2393
- const getInputProps = (0, import_react6.useCallback)(() => ({
2631
+ const getInputProps = (0, import_react7.useCallback)(() => ({
2394
2632
  ref: setInput,
2395
2633
  onChange,
2396
2634
  onKeyDown,
@@ -2418,7 +2656,7 @@ function useComposerAutocomplete(options) {
2418
2656
  activeIndex,
2419
2657
  optionId
2420
2658
  ]);
2421
- const getListboxProps = (0, import_react6.useCallback)(() => ({
2659
+ const getListboxProps = (0, import_react7.useCallback)(() => ({
2422
2660
  id: listboxId,
2423
2661
  role: "listbox",
2424
2662
  "aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
@@ -2426,7 +2664,7 @@ function useComposerAutocomplete(options) {
2426
2664
  listboxId,
2427
2665
  match
2428
2666
  ]);
2429
- const getOptionProps = (0, import_react6.useCallback)((index) => ({
2667
+ const getOptionProps = (0, import_react7.useCallback)((index) => ({
2430
2668
  id: optionId(index),
2431
2669
  role: "option",
2432
2670
  "aria-selected": index === activeIndex
@@ -2480,6 +2718,16 @@ function refusalReason(result) {
2480
2718
  __name(refusalReason, "refusalReason");
2481
2719
  function storedMessageToUiMessage(message) {
2482
2720
  const parts = [];
2721
+ if (message.reasoning) {
2722
+ parts.push({
2723
+ type: "reasoning",
2724
+ text: message.reasoning,
2725
+ state: "done",
2726
+ ...message.reasoningMs !== void 0 ? {
2727
+ providerMetadata: reasoningDurationMetadata(message.reasoningMs)
2728
+ } : {}
2729
+ });
2730
+ }
2483
2731
  if (message.content) {
2484
2732
  parts.push({
2485
2733
  type: "text",
@@ -2494,6 +2742,20 @@ function storedMessageToUiMessage(message) {
2494
2742
  url: attachment.url
2495
2743
  });
2496
2744
  }
2745
+ for (const component of message.ui ?? []) {
2746
+ parts.push({
2747
+ type: "data-ui",
2748
+ id: component.id,
2749
+ data: {
2750
+ id: component.id,
2751
+ component: component.component,
2752
+ props: component.props,
2753
+ ...component.version !== void 0 ? {
2754
+ version: component.version
2755
+ } : {}
2756
+ }
2757
+ });
2758
+ }
2497
2759
  for (const call of message.toolCalls ?? []) {
2498
2760
  const result = message.toolResults?.find((candidate) => candidate.id === call.id);
2499
2761
  const toolKind2 = call.kind;
@@ -2595,21 +2857,21 @@ function sumUsage(rows) {
2595
2857
  __name(sumUsage, "sumUsage");
2596
2858
 
2597
2859
  // src/use-agent-chat.ts
2598
- var import_react7 = require("@ai-sdk/react");
2599
- var import_react8 = require("react");
2860
+ var import_react8 = require("@ai-sdk/react");
2861
+ var import_react9 = require("react");
2600
2862
  function useAgentChat(options) {
2601
- const latest = (0, import_react8.useRef)(options);
2863
+ const latest = (0, import_react9.useRef)(options);
2602
2864
  latest.current = options;
2603
- const [runId, setRunId] = (0, import_react8.useState)(options.resumeRunId);
2604
- const runIdRef = (0, import_react8.useRef)(runId);
2865
+ const [runId, setRunId] = (0, import_react9.useState)(options.resumeRunId);
2866
+ const runIdRef = (0, import_react9.useRef)(runId);
2605
2867
  runIdRef.current = runId;
2606
- const settlingRunIdRef = (0, import_react8.useRef)(void 0);
2607
- const autoResumeRunIdRef = (0, import_react8.useRef)(void 0);
2608
- const [autoResume, setAutoResume] = (0, import_react8.useState)(false);
2609
- const [activeRunId, setActiveRunId] = (0, import_react8.useState)(null);
2610
- const regenerateNext = (0, import_react8.useRef)(false);
2611
- const createdThreadId = (0, import_react8.useRef)(void 0);
2612
- const client = (0, import_react8.useMemo)(() => {
2868
+ const settlingRunIdRef = (0, import_react9.useRef)(void 0);
2869
+ const autoResumeRunIdRef = (0, import_react9.useRef)(void 0);
2870
+ const [autoResume, setAutoResume] = (0, import_react9.useState)(false);
2871
+ const [activeRunId, setActiveRunId] = (0, import_react9.useState)(null);
2872
+ const regenerateNext = (0, import_react9.useRef)(false);
2873
+ const createdThreadId = (0, import_react9.useRef)(void 0);
2874
+ const client = (0, import_react9.useMemo)(() => {
2613
2875
  if (options.client) return options.client;
2614
2876
  return new AgentClient({
2615
2877
  ...options.baseUrl !== void 0 ? {
@@ -2624,7 +2886,7 @@ function useAgentChat(options) {
2624
2886
  getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
2625
2887
  });
2626
2888
  }, []);
2627
- (0, import_react8.useEffect)(() => {
2889
+ (0, import_react9.useEffect)(() => {
2628
2890
  if (!options.resume || options.threadId === void 0) return;
2629
2891
  let cancelled = false;
2630
2892
  const threadId = options.threadId;
@@ -2644,7 +2906,7 @@ function useAgentChat(options) {
2644
2906
  options.resume,
2645
2907
  options.threadId
2646
2908
  ]);
2647
- const transport = (0, import_react8.useMemo)(() => {
2909
+ const transport = (0, import_react9.useMemo)(() => {
2648
2910
  function onMeta(meta) {
2649
2911
  settlingRunIdRef.current = meta.runId;
2650
2912
  setRunId(meta.runId);
@@ -2693,8 +2955,8 @@ function useAgentChat(options) {
2693
2955
  }, "onAttemptStart")
2694
2956
  });
2695
2957
  }, []);
2696
- const backgroundRef = (0, import_react8.useRef)(() => Promise.resolve());
2697
- const chat = (0, import_react7.useChat)({
2958
+ const backgroundRef = (0, import_react9.useRef)(() => Promise.resolve());
2959
+ const chat = (0, import_react8.useChat)({
2698
2960
  transport,
2699
2961
  resume: options.resumeRunId !== void 0 || autoResume,
2700
2962
  ...options.threadId !== void 0 ? {
@@ -2703,6 +2965,13 @@ function useAgentChat(options) {
2703
2965
  ...options.initialMessages !== void 0 ? {
2704
2966
  messages: options.initialMessages
2705
2967
  } : {},
2968
+ onData: /* @__PURE__ */ __name((part) => {
2969
+ latest.current.onData?.(part);
2970
+ if (part.type === "data-title") {
2971
+ const title = part.data?.title;
2972
+ if (typeof title === "string") latest.current.onTitle?.(title);
2973
+ }
2974
+ }, "onData"),
2706
2975
  onFinish: /* @__PURE__ */ __name(({ isError }) => {
2707
2976
  latest.current.onFinish?.();
2708
2977
  if (latest.current.background === true) {
@@ -2717,13 +2986,13 @@ function useAgentChat(options) {
2717
2986
  }
2718
2987
  }, "onFinish")
2719
2988
  });
2720
- const chatRef = (0, import_react8.useRef)(chat);
2989
+ const chatRef = (0, import_react9.useRef)(chat);
2721
2990
  chatRef.current = chat;
2722
- const turnInFlight = (0, import_react8.useRef)(false);
2723
- const isTurnInFlight = (0, import_react8.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
2991
+ const turnInFlight = (0, import_react9.useRef)(false);
2992
+ const isTurnInFlight = (0, import_react9.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
2724
2993
  transport
2725
2994
  ]);
2726
- const sendMessage = (0, import_react8.useCallback)(async (...args) => {
2995
+ const sendMessage = (0, import_react9.useCallback)(async (...args) => {
2727
2996
  if (isTurnInFlight()) return;
2728
2997
  turnInFlight.current = true;
2729
2998
  try {
@@ -2734,15 +3003,15 @@ function useAgentChat(options) {
2734
3003
  }, [
2735
3004
  isTurnInFlight
2736
3005
  ]);
2737
- const addToolResult = (0, import_react8.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
3006
+ const addToolResult = (0, import_react9.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
2738
3007
  tool,
2739
3008
  toolCallId,
2740
3009
  output
2741
3010
  }), []);
2742
- const [threads, setThreads] = (0, import_react8.useState)([]);
2743
- const [quota, setQuota] = (0, import_react8.useState)(null);
2744
- const [backgroundRuns, setBackgroundRuns] = (0, import_react8.useState)([]);
2745
- const refreshBackground = (0, import_react8.useCallback)(async () => {
3011
+ const [threads, setThreads] = (0, import_react9.useState)([]);
3012
+ const [quota, setQuota] = (0, import_react9.useState)(null);
3013
+ const [backgroundRuns, setBackgroundRuns] = (0, import_react9.useState)([]);
3014
+ const refreshBackground = (0, import_react9.useCallback)(async () => {
2746
3015
  const threadId = latest.current.threadId ?? createdThreadId.current;
2747
3016
  if (threadId === void 0) {
2748
3017
  return;
@@ -2767,7 +3036,7 @@ function useAgentChat(options) {
2767
3036
  ]);
2768
3037
  backgroundRef.current = refreshBackground;
2769
3038
  const isWorking = backgroundRuns.some((run) => run.status === "running");
2770
- (0, import_react8.useEffect)(() => {
3039
+ (0, import_react9.useEffect)(() => {
2771
3040
  if (options.background !== true || options.threadId === void 0) {
2772
3041
  return;
2773
3042
  }
@@ -2777,7 +3046,7 @@ function useAgentChat(options) {
2777
3046
  options.threadId,
2778
3047
  refreshBackground
2779
3048
  ]);
2780
- (0, import_react8.useEffect)(() => {
3049
+ (0, import_react9.useEffect)(() => {
2781
3050
  const every = latest.current.backgroundPollMs ?? 5e3;
2782
3051
  if (latest.current.background !== true || !isWorking || every <= 0) {
2783
3052
  return;
@@ -2788,26 +3057,26 @@ function useAgentChat(options) {
2788
3057
  isWorking,
2789
3058
  refreshBackground
2790
3059
  ]);
2791
- const loadThreads = (0, import_react8.useCallback)(async () => {
3060
+ const loadThreads = (0, import_react9.useCallback)(async () => {
2792
3061
  const list = await client.listThreads();
2793
3062
  setThreads(list);
2794
3063
  return list;
2795
3064
  }, [
2796
3065
  client
2797
3066
  ]);
2798
- const loadThread = (0, import_react8.useCallback)((id) => client.getThread(id), [
3067
+ const loadThread = (0, import_react9.useCallback)((id) => client.getThread(id), [
2799
3068
  client
2800
3069
  ]);
2801
- const deleteThread = (0, import_react8.useCallback)(async (id) => {
3070
+ const deleteThread = (0, import_react9.useCallback)(async (id) => {
2802
3071
  await client.deleteThread(id);
2803
3072
  setThreads((current) => current.filter((thread) => thread.id !== id));
2804
3073
  }, [
2805
3074
  client
2806
3075
  ]);
2807
- const forkThread = (0, import_react8.useCallback)((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
3076
+ const forkThread = (0, import_react9.useCallback)((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
2808
3077
  client
2809
3078
  ]);
2810
- const renameThread = (0, import_react8.useCallback)(async (id, title) => {
3079
+ const renameThread = (0, import_react9.useCallback)(async (id, title) => {
2811
3080
  await client.renameThread(id, title);
2812
3081
  setThreads((current) => current.map((thread) => thread.id === id ? {
2813
3082
  ...thread,
@@ -2816,24 +3085,24 @@ function useAgentChat(options) {
2816
3085
  }, [
2817
3086
  client
2818
3087
  ]);
2819
- const promoteThread = (0, import_react8.useCallback)(async (id) => {
3088
+ const promoteThread = (0, import_react9.useCallback)(async (id) => {
2820
3089
  await client.promoteThread(id);
2821
3090
  await loadThreads();
2822
3091
  }, [
2823
3092
  client,
2824
3093
  loadThreads
2825
3094
  ]);
2826
- const truncateFromMessage = (0, import_react8.useCallback)((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
3095
+ const truncateFromMessage = (0, import_react9.useCallback)((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
2827
3096
  client
2828
3097
  ]);
2829
- const loadQuota = (0, import_react8.useCallback)(async () => {
3098
+ const loadQuota = (0, import_react9.useCallback)(async () => {
2830
3099
  const today = await client.getQuotaToday();
2831
3100
  setQuota(today);
2832
3101
  return today;
2833
3102
  }, [
2834
3103
  client
2835
3104
  ]);
2836
- const cancel = (0, import_react8.useCallback)(async () => {
3105
+ const cancel = (0, import_react9.useCallback)(async () => {
2837
3106
  chatRef.current.stop();
2838
3107
  const activeRunId2 = runIdRef.current;
2839
3108
  if (activeRunId2) {
@@ -2845,14 +3114,14 @@ function useAgentChat(options) {
2845
3114
  }, [
2846
3115
  client
2847
3116
  ]);
2848
- const approve = (0, import_react8.useCallback)(async ({ toolCallId }) => {
3117
+ const approve = (0, import_react9.useCallback)(async ({ toolCallId }) => {
2849
3118
  await client.approveToolCall({
2850
3119
  toolCallId
2851
3120
  });
2852
3121
  }, [
2853
3122
  client
2854
3123
  ]);
2855
- const reject = (0, import_react8.useCallback)(async ({ toolCallId, reason }) => {
3124
+ const reject = (0, import_react9.useCallback)(async ({ toolCallId, reason }) => {
2856
3125
  await client.rejectToolCall({
2857
3126
  toolCallId,
2858
3127
  ...reason !== void 0 ? {
@@ -2862,7 +3131,7 @@ function useAgentChat(options) {
2862
3131
  }, [
2863
3132
  client
2864
3133
  ]);
2865
- const answer = (0, import_react8.useCallback)(async ({ toolCallId, answers }) => {
3134
+ const answer = (0, import_react9.useCallback)(async ({ toolCallId, answers }) => {
2866
3135
  await client.answerToolCall({
2867
3136
  toolCallId,
2868
3137
  ...answers !== void 0 ? {
@@ -2872,14 +3141,14 @@ function useAgentChat(options) {
2872
3141
  }, [
2873
3142
  client
2874
3143
  ]);
2875
- const skip = (0, import_react8.useCallback)(async ({ toolCallId }) => {
3144
+ const skip = (0, import_react9.useCallback)(async ({ toolCallId }) => {
2876
3145
  await client.skipToolCall({
2877
3146
  toolCallId
2878
3147
  });
2879
3148
  }, [
2880
3149
  client
2881
3150
  ]);
2882
- const regenerate = (0, import_react8.useCallback)(() => {
3151
+ const regenerate = (0, import_react9.useCallback)(() => {
2883
3152
  if (isTurnInFlight()) return;
2884
3153
  regenerateNext.current = true;
2885
3154
  turnInFlight.current = true;
@@ -2951,14 +3220,17 @@ __name(mergeHeaders, "mergeHeaders");
2951
3220
  extractMessageText,
2952
3221
  filterAutocompleteItems,
2953
3222
  findActiveTrigger,
3223
+ formatElapsed,
2954
3224
  formatRelativeTime,
2955
3225
  loadStoredSpeechLang,
2956
3226
  persistSpeechLang,
3227
+ readReasoningMs,
2957
3228
  storedMessageToUiMessage,
2958
3229
  storedThreadToUiMessages,
2959
3230
  useAgentChat,
2960
3231
  useChatTranscript,
2961
3232
  useComposerAutocomplete,
3233
+ useElapsed,
2962
3234
  useSpeechRecognition,
2963
3235
  useStickToBottom,
2964
3236
  useTranscriptItem