@qredence/fleet 0.6.0 → 0.6.1

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.
Files changed (127) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/web/client/assets/action-swap-roll-COzQ86wm.js +1 -0
  3. package/dist/web/client/assets/agent-activity-svETLf_5.js +1 -0
  4. package/dist/web/client/assets/agent-disclosure-DAMuuGcM.js +1 -0
  5. package/dist/web/client/assets/analytics-stub-B6zGMuSV.js +1 -0
  6. package/dist/web/client/assets/{artifacts-panel-CJ75gQub.js → artifacts-panel-HVjqBMyx.js} +1 -1
  7. package/dist/web/client/assets/button-C5wFDY5_.js +1 -0
  8. package/dist/web/client/assets/card-DA3Vnqay.js +1 -0
  9. package/dist/web/client/assets/chat-BhYseKd6.js +52 -0
  10. package/dist/web/client/assets/{chat-command-palette-CkISHfKE.js → chat-command-palette-LILDO_vG.js} +1 -1
  11. package/dist/web/client/assets/{citations-C_tPOJE_.js → citations-BPv8HIpf.js} +2 -2
  12. package/dist/web/client/assets/command-PhicLCoO.js +1 -0
  13. package/dist/web/client/assets/dialog-pBGUjAQ7.js +1 -0
  14. package/dist/web/client/assets/{fleet-message-queue-BCno4XP-.js → fleet-message-queue-fbYYwMj0.js} +1 -1
  15. package/dist/web/client/assets/{fleet-pi-tool-renderer-BEDIO3al.js → fleet-pi-tool-renderer-BRgNnmaJ.js} +28 -28
  16. package/dist/web/client/assets/fleet-reasoning-panel-CjA2dwUJ.js +1 -0
  17. package/dist/web/client/assets/{fork-picker-dialog-ByBOGVsa.js → fork-picker-dialog-B7NNpVmW.js} +1 -1
  18. package/dist/web/client/assets/globals-CuIiqOTg.css +2 -0
  19. package/dist/web/client/assets/horizontal-resize-Cp3iHMH7.js +1 -0
  20. package/dist/web/client/assets/index-CSGplyr_.js +12 -0
  21. package/dist/web/client/assets/{input-0wwjWjKq.js → input-PcdubeKn.js} +1 -1
  22. package/dist/web/client/assets/input-group-C2HJEZvl.js +1 -0
  23. package/dist/web/client/assets/ipython-tool-CyuMOxz1.js +3 -0
  24. package/dist/web/client/assets/{markdown-code-CuQcR3UO.js → markdown-code-xNyjdZ4g.js} +1 -1
  25. package/dist/web/client/assets/{markdown-DInPmRUG.js → markdown-lvexwooo.js} +2 -2
  26. package/dist/web/client/assets/{model-selector-list-Ch05B2nZ.js → model-selector-list-CoXX358G.js} +1 -1
  27. package/dist/web/client/assets/{notify-DgMKgZZW.js → notify-DxL0VD7Z.js} +1 -1
  28. package/dist/web/client/assets/openui-renderer-TLNe5e_Q.js +378 -0
  29. package/dist/web/client/assets/prompt-input-fwP8TsgQ.js +1 -0
  30. package/dist/web/client/assets/{prompt-suggestions-Cc--lSNR.js → prompt-suggestions-BlGXmWS7.js} +1 -1
  31. package/dist/web/client/assets/provider-catalog-DYMFdbKc.js +1 -0
  32. package/dist/web/client/assets/provider-label-B4q5mI65.js +1 -0
  33. package/dist/web/client/assets/{repl-panel-DsPX04Xr.js → repl-panel-C5om8MGU.js} +1 -1
  34. package/dist/web/client/assets/{right-panel-registry-Dp8yX-oL.js → right-panel-registry-BBlxLxnx.js} +2 -2
  35. package/dist/web/client/assets/routes-XGsAIqBJ.js +16 -0
  36. package/dist/web/client/assets/settings-dialog-BSBasR3o.js +2 -0
  37. package/dist/web/client/assets/{subagent-chat-panel-Yujplxpb.js → subagent-chat-panel-oeLDPDAK.js} +1 -1
  38. package/dist/web/client/assets/{subagent-transcript-CnI-mqN0.js → subagent-transcript-DaVHjNUH.js} +1 -1
  39. package/dist/web/client/assets/{subagents-panel-CjXEdimj.js → subagents-panel-D_aVgSCi.js} +1 -1
  40. package/dist/web/client/assets/surfaces-BhAXz9So.js +1 -0
  41. package/dist/web/client/assets/{switch-9rTeg6J6.js → switch-WhXeJNNY.js} +1 -1
  42. package/dist/web/client/assets/{toast-Bt9p2OL4.js → toast-D3c9XeGe.js} +1 -1
  43. package/dist/web/client/assets/{tool-result-DfnPN0FQ.js → tool-result-Cki8WUNc.js} +3 -3
  44. package/dist/web/client/assets/virtualized-turn-list-CdMa-ydT.js +6 -0
  45. package/dist/web/client/assets/workspace-panel-77bDbprs.js +1 -0
  46. package/dist/web/client/bundle-budget.json +5 -5
  47. package/dist/web/launcher.mjs +10 -1
  48. package/dist/web/server/{_tanstack-start-manifest_v-DS_CSIFQ-WB3VTKF3.js → _tanstack-start-manifest_v-0L7fqnH4-KMVGUFE4.js} +24 -24
  49. package/dist/web/server/{agent-activity-CS2rbF_C-A3R26CYH.js → agent-activity-BuEE6iVw-CDZLK4D2.js} +4 -4
  50. package/dist/web/server/{artifacts-panel-CaKrX2XC-R37I4BHF.js → artifacts-panel-D3ySO--V-XSL53CXL.js} +18 -18
  51. package/dist/web/server/{chat-command-palette-7gbqEnm9-6XICQZN7.js → chat-command-palette-kAbXhWVg-TJWXH2WW.js} +9 -9
  52. package/dist/web/server/{chunk-CNXJN5HN.js → chunk-2DDWXTVG.js} +5 -5
  53. package/dist/web/server/{chunk-TWYHHG5N.js → chunk-2JHTYWD5.js} +15 -15
  54. package/dist/web/server/{chunk-EAE2QXRK.js → chunk-3TIMGWWI.js} +1 -2
  55. package/dist/web/server/{chunk-AGFRJQZ7.js → chunk-4WBFCB4O.js} +257 -257
  56. package/dist/web/server/{chunk-P6UMR32I.js → chunk-5UCAJBAH.js} +4 -4
  57. package/dist/web/server/{chunk-DZ2IC3FH.js → chunk-D27LRYVT.js} +42 -42
  58. package/dist/web/server/{chunk-YXXRP3NS.js → chunk-DLUZFOG3.js} +5 -5
  59. package/dist/web/server/{chunk-K3BXQG3N.js → chunk-EBG3XFGQ.js} +60 -60
  60. package/dist/web/server/{chunk-2ATMSG7U.js → chunk-EJEPDVK6.js} +3 -3
  61. package/dist/web/server/{chunk-IJPCV6DH.js → chunk-FYDQK6UX.js} +1 -1
  62. package/dist/web/server/{chunk-WHBVQJ4K.js → chunk-HF7DG7PC.js} +73 -73
  63. package/dist/web/server/{chunk-WYL2DW5R.js → chunk-JTCCQZLN.js} +2 -2
  64. package/dist/web/server/{chunk-UAPNEWCA.js → chunk-KP2PNDGL.js} +6 -6
  65. package/dist/web/server/{chunk-7SR6WDM2.js → chunk-MNBGB2SP.js} +2 -2
  66. package/dist/web/server/{chunk-HSJMLO36.js → chunk-MNPHMZU7.js} +3 -3
  67. package/dist/web/server/{chunk-JQDLJ7KI.js → chunk-NGCQJ33Y.js} +1134 -1134
  68. package/dist/web/server/{chunk-7SD2ZSEA.js → chunk-NIDBN7BQ.js} +1 -1
  69. package/dist/web/server/{chunk-ZJFA4F5X.js → chunk-NIZBFVJF.js} +2 -2
  70. package/dist/web/server/{chunk-PIOFZUOU.js → chunk-NJ4QEZHK.js} +3 -4
  71. package/dist/web/server/{chunk-WM4PUT6M.js → chunk-NNKJTKOQ.js} +234 -234
  72. package/dist/web/server/{chunk-N6NOTURM.js → chunk-NWDI3OWB.js} +4 -4
  73. package/dist/web/server/{chunk-KELEYPVK.js → chunk-O3HDELZ2.js} +74826 -74825
  74. package/dist/web/server/{chunk-YNUWKMNQ.js → chunk-PLYZ7P2Y.js} +1 -152
  75. package/dist/web/server/{chunk-LXJD6IGW.js → chunk-QFRCJWQQ.js} +7 -7
  76. package/dist/web/server/{chunk-NXJ32VFR.js → chunk-QIULBRTU.js} +13 -13
  77. package/dist/web/server/{chunk-DI7XRK2H.js → chunk-RIP3PBWT.js} +3 -3
  78. package/dist/web/server/{chunk-YKVGQBZA.js → chunk-S5LFXXDY.js} +625 -622
  79. package/dist/web/server/{chunk-XLNCWZMZ.js → chunk-UCUFC553.js} +3 -1
  80. package/dist/web/server/{chunk-KOUEJ3NU.js → chunk-UL2725KQ.js} +3 -3
  81. package/dist/web/server/{chunk-HFQTI7AX.js → chunk-VPKX7QRU.js} +3 -3
  82. package/dist/web/server/{chunk-LZ4Q5KUJ.js → chunk-WNCAL4HN.js} +133 -133
  83. package/dist/web/server/{chunk-C5X6G26O.js → chunk-XIB6XNUX.js} +436 -436
  84. package/dist/web/server/{chunk-EH4BZ6QM.js → chunk-YGYOBX7G.js} +2 -2
  85. package/dist/web/server/{chunk-BBBS5AS7.js → chunk-ZIFSJ3HQ.js} +626 -626
  86. package/dist/web/server/{fleet-message-queue-BS-cZ56r-GLZXUKDF.js → fleet-message-queue-D_w8lSeY-T3HB7HVQ.js} +5 -5
  87. package/dist/web/server/{fleet-pi-tool-renderer-umKunT3K-O4GBH35V.js → fleet-pi-tool-renderer-qwc-qZFq-4U556N5Q.js} +12 -12
  88. package/dist/web/server/{fleet-reasoning-panel-BxC2COxi-GPLMQSTT.js → fleet-reasoning-panel-DG_vuvv0-NCZWEEIT.js} +26 -26
  89. package/dist/web/server/{fleet-subagent-list-CpSYzCIq-JDH2LHSS.js → fleet-subagent-list-BGb0PjhF-2X67FMUV.js} +1 -1
  90. package/dist/web/server/{fleet-tool-timeline-IB36_PB2-XJENTO6I.js → fleet-tool-timeline-D6yM4ZMz-ZSFVRRRI.js} +1 -1
  91. package/dist/web/server/{fork-picker-dialog-DlINz9UQ-UWIXFDJX.js → fork-picker-dialog-Ds6Tgtu3-DIBWN7MV.js} +5 -5
  92. package/dist/web/server/{model-selector-list-jBTZc2Mu-OXJOS5NA.js → model-selector-list-DxeGZoD2-P6S6FSJH.js} +9 -9
  93. package/dist/web/server/{openui-renderer-Biyyjhjn-SJOEKPTJ.js → openui-renderer-MKFv6LlH-MDRSVFEY.js} +11 -11
  94. package/dist/web/server/{prompt-suggestions-D4AEEY7K-RZSP7PWV.js → prompt-suggestions-BOItmGnD-YQA7RHLG.js} +2 -2
  95. package/dist/web/server/{repl-panel-D5KsoJik-BQKO53JO.js → repl-panel-CuyF8wt5-CHDT2Q3N.js} +2 -2
  96. package/dist/web/server/{router-DWALoX_M-I5CBL7FQ.js → router-Dg72SESP-PCWKLFRG.js} +16 -16
  97. package/dist/web/server/{routes-BBVirYfL-5WXMOT7M.js → routes-BGrVtPYF-SURPAJN6.js} +6432 -6413
  98. package/dist/web/server/server.js +2 -2
  99. package/dist/web/server/{settings-dialog-DndPbM-v-RFNXXEAN.js → settings-dialog-CK0FJlTg-HZRBAXDZ.js} +1392 -1402
  100. package/dist/web/server/{subagent-chat-panel-C0RpnXav-J7VYO7QY.js → subagent-chat-panel-gzamnTgK-PQ2TLLJF.js} +21 -21
  101. package/dist/web/server/{subagents-panel-jDqIn9Nh-YEV6QLUY.js → subagents-panel-Berjd7HJ-EI5ZKC6V.js} +20 -20
  102. package/dist/web/server/{workspace-panel-CX_Vo6As-EWO6AMPI.js → workspace-panel-CBBa_3UO-B4PPFPMA.js} +45 -20
  103. package/package.json +1 -1
  104. package/dist/web/client/assets/action-swap-roll-BB8DFMuf.js +0 -1
  105. package/dist/web/client/assets/agent-activity-CwMDU7aP.js +0 -1
  106. package/dist/web/client/assets/agent-disclosure-B8SnhQXL.js +0 -1
  107. package/dist/web/client/assets/analytics-stub-Cas1He0w.js +0 -1
  108. package/dist/web/client/assets/button-BR2WWrFo.js +0 -1
  109. package/dist/web/client/assets/card-BKl76a3R.js +0 -1
  110. package/dist/web/client/assets/chat-Ci2cEQrR.js +0 -52
  111. package/dist/web/client/assets/command-_WjnervL.js +0 -1
  112. package/dist/web/client/assets/dialog-BEZuZhzk.js +0 -1
  113. package/dist/web/client/assets/fleet-reasoning-panel-CbkO7u-v.js +0 -1
  114. package/dist/web/client/assets/globals-B_I1Eq1u.css +0 -2
  115. package/dist/web/client/assets/horizontal-resize-CwoDojST.js +0 -1
  116. package/dist/web/client/assets/index-DJ1fFbQu.js +0 -12
  117. package/dist/web/client/assets/input-group-Tb5TYbzi.js +0 -1
  118. package/dist/web/client/assets/ipython-tool-ldJ9F1Cw.js +0 -3
  119. package/dist/web/client/assets/openui-renderer-Bf60nxNi.js +0 -378
  120. package/dist/web/client/assets/prompt-input-qPIXZ-Rb.js +0 -1
  121. package/dist/web/client/assets/provider-catalog-D8G66gwc.js +0 -1
  122. package/dist/web/client/assets/provider-label-DDLRnZyC.js +0 -1
  123. package/dist/web/client/assets/routes-DpgMJZ5n.js +0 -16
  124. package/dist/web/client/assets/settings-dialog-YJkvt5EB.js +0 -2
  125. package/dist/web/client/assets/surfaces-DI-U-_2a.js +0 -1
  126. package/dist/web/client/assets/virtualized-turn-list--Vynre4D.js +0 -6
  127. package/dist/web/client/assets/workspace-panel-CPPIznT9.js +0 -1
@@ -6,14 +6,14 @@ import {
6
6
  MessageCircleQuestionMark,
7
7
  PI_TOOL_RENDERERS,
8
8
  useHoverCapable
9
- } from "./chunk-N6NOTURM.js";
9
+ } from "./chunk-NWDI3OWB.js";
10
10
  import {
11
11
  pct,
12
12
  progressOf
13
13
  } from "./chunk-V3S6BVXO.js";
14
14
  import {
15
15
  mono
16
- } from "./chunk-XLNCWZMZ.js";
16
+ } from "./chunk-UCUFC553.js";
17
17
  import {
18
18
  Eye
19
19
  } from "./chunk-2ST2ULW7.js";
@@ -47,19 +47,19 @@ import {
47
47
  FileDiff,
48
48
  ToolResult,
49
49
  ToolResultOutput
50
- } from "./chunk-YXXRP3NS.js";
50
+ } from "./chunk-DLUZFOG3.js";
51
51
  import {
52
52
  ActionSwapRollText,
53
53
  FileCodeCorner
54
- } from "./chunk-2ATMSG7U.js";
54
+ } from "./chunk-EJEPDVK6.js";
55
55
  import {
56
56
  AgentDisclosure
57
- } from "./chunk-HFQTI7AX.js";
57
+ } from "./chunk-VPKX7QRU.js";
58
58
  import {
59
59
  Collapsible,
60
60
  CollapsibleContent,
61
61
  CollapsibleTrigger
62
- } from "./chunk-HSJMLO36.js";
62
+ } from "./chunk-MNPHMZU7.js";
63
63
  import {
64
64
  RotateCcw
65
65
  } from "./chunk-OOXWPL22.js";
@@ -76,7 +76,7 @@ import {
76
76
  import {
77
77
  AnimatePresence,
78
78
  useReducedMotion
79
- } from "./chunk-ZJFA4F5X.js";
79
+ } from "./chunk-NIZBFVJF.js";
80
80
  import {
81
81
  ChevronRight
82
82
  } from "./chunk-3C4CFCIS.js";
@@ -87,7 +87,7 @@ import {
87
87
  SPRING_PRESS,
88
88
  SPRING_SWAP,
89
89
  m
90
- } from "./chunk-K3BXQG3N.js";
90
+ } from "./chunk-EBG3XFGQ.js";
91
91
  import {
92
92
  ChevronUp
93
93
  } from "./chunk-OZO5ARFA.js";
@@ -115,7 +115,7 @@ import {
115
115
  ToolTextShimmer,
116
116
  adaptToolPart,
117
117
  useToolComplete
118
- } from "./chunk-NXJ32VFR.js";
118
+ } from "./chunk-QIULBRTU.js";
119
119
  import {
120
120
  createLucideIcon
121
121
  } from "./chunk-4ZIEVI5O.js";
@@ -126,7 +126,7 @@ import {
126
126
  __exportAll
127
127
  } from "./chunk-L547YHC4.js";
128
128
 
129
- // web/app/dist/server/assets/fleet-pi-tool-renderer-umKunT3K.js
129
+ // web/app/dist/server/assets/fleet-pi-tool-renderer-qwc-qZFq.js
130
130
  import React, { createContext, memo, useCallback, useContext, useEffect, useId, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
131
131
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
132
132
  var ChevronsDown = createLucideIcon("chevrons-down", [["path", {
@@ -177,64 +177,6 @@ var FolderSearch = createLucideIcon("folder-search", [
177
177
  key: "18b49y"
178
178
  }]
179
179
  ]);
180
- var toolStateCache = /* @__PURE__ */ new Map();
181
- function getToolStateSnapshot(part) {
182
- return {
183
- state: part.state,
184
- inputJson: JSON.stringify(part.input || {}),
185
- outputJson: JSON.stringify(part.output || {})
186
- };
187
- }
188
- function hasToolStateChanged(toolCallId, part) {
189
- const cached = toolStateCache.get(toolCallId);
190
- const current = getToolStateSnapshot(part);
191
- if (!cached) {
192
- toolStateCache.set(toolCallId, current);
193
- return true;
194
- }
195
- const changed = cached.state !== current.state || cached.inputJson !== current.inputJson || cached.outputJson !== current.outputJson;
196
- if (changed) toolStateCache.set(toolCallId, current);
197
- return changed;
198
- }
199
- function arePartsEqual(prev, next) {
200
- if (prev.toolCallId !== next.toolCallId) return false;
201
- if (prev.type !== next.type) return false;
202
- const toolCallId = next.toolCallId;
203
- if (!toolCallId) return prev.state === next.state;
204
- return !hasToolStateChanged(toolCallId, next);
205
- }
206
- function isToolCompleted(part) {
207
- if (part.output !== void 0 && part.output !== null) return true;
208
- if (part.state === "error") return true;
209
- if (part.state === "result") return true;
210
- return false;
211
- }
212
- function areToolPropsEqual(prevProps, nextProps) {
213
- if (!arePartsEqual(prevProps.part, nextProps.part)) return false;
214
- if (isToolCompleted(nextProps.part)) return true;
215
- if (prevProps.chatStatus !== nextProps.chatStatus) return false;
216
- return true;
217
- }
218
- function formatElapsedTime(ms) {
219
- if (ms < 1e3) return "";
220
- const seconds = Math.floor(ms / 1e3);
221
- if (seconds < 60) return `${seconds}s`;
222
- const minutes = Math.floor(seconds / 60);
223
- const remainingSeconds = seconds % 60;
224
- if (remainingSeconds === 0) return `${minutes}m`;
225
- return `${minutes}m ${remainingSeconds}s`;
226
- }
227
- function getToolStatus(part, chatStatus) {
228
- const basePending = part.state !== "output-available" && part.state !== "output-error";
229
- const isError = part.state === "output-error" || part.state === "output-available" && part.output?.success === false;
230
- const isSuccess = part.state === "output-available" && !isError;
231
- return {
232
- isPending: basePending && chatStatus === "streaming",
233
- isError,
234
- isSuccess,
235
- isInterrupted: basePending && chatStatus !== "streaming" && chatStatus !== void 0
236
- };
237
- }
238
180
  var QUESTION_CUSTOM_ID = "__custom__";
239
181
  function optionBadge(idx) {
240
182
  return String.fromCharCode(65 + idx);
@@ -553,406 +495,64 @@ function QuestionTool({ part }) {
553
495
  }, `${clampedIndex}-${question.title}`)]
554
496
  });
555
497
  }
556
- function getDisplayPath(filePath) {
557
- if (!filePath) return "";
558
- const stripped = stripSandboxPrefixes(filePath);
559
- if (stripped !== filePath) return stripped;
560
- if (filePath.startsWith("/")) {
561
- const parts = filePath.split("/");
562
- const rootIndicators = [
563
- "apps",
564
- "packages",
565
- "src",
566
- "lib",
567
- "components"
568
- ];
569
- const rootIndex = parts.findIndex((p) => rootIndicators.includes(p));
570
- if (rootIndex > 0) return parts.slice(rootIndex).join("/");
498
+ var toolStateCache = /* @__PURE__ */ new Map();
499
+ function getToolStateSnapshot(part) {
500
+ return {
501
+ state: part.state,
502
+ inputJson: JSON.stringify(part.input || {}),
503
+ outputJson: JSON.stringify(part.output || {})
504
+ };
505
+ }
506
+ function hasToolStateChanged(toolCallId, part) {
507
+ const cached = toolStateCache.get(toolCallId);
508
+ const current = getToolStateSnapshot(part);
509
+ if (!cached) {
510
+ toolStateCache.set(toolCallId, current);
511
+ return true;
571
512
  }
572
- return filePath;
513
+ const changed = cached.state !== current.state || cached.inputJson !== current.inputJson || cached.outputJson !== current.outputJson;
514
+ if (changed) toolStateCache.set(toolCallId, current);
515
+ return changed;
573
516
  }
574
- function calculateDiffStats(oldString, newString) {
575
- const oldLines = oldString.split("\n");
576
- const newLines = newString.split("\n");
577
- const maxLines = Math.max(oldLines.length, newLines.length);
578
- let addedLines = 0;
579
- let removedLines = 0;
580
- for (let i = 0; i < maxLines; i++) if (oldLines[i] !== void 0 && newLines[i] !== void 0) {
581
- if (oldLines[i] !== newLines[i]) {
582
- removedLines++;
583
- addedLines++;
584
- }
585
- } else if (oldLines[i] !== void 0) removedLines++;
586
- else if (newLines[i] !== void 0) addedLines++;
517
+ function arePartsEqual(prev, next) {
518
+ if (prev.toolCallId !== next.toolCallId) return false;
519
+ if (prev.type !== next.type) return false;
520
+ const toolCallId = next.toolCallId;
521
+ if (!toolCallId) return prev.state === next.state;
522
+ return !hasToolStateChanged(toolCallId, next);
523
+ }
524
+ function isToolCompleted(part) {
525
+ if (part.output !== void 0 && part.output !== null) return true;
526
+ if (part.state === "error") return true;
527
+ if (part.state === "result") return true;
528
+ return false;
529
+ }
530
+ function areToolPropsEqual(prevProps, nextProps) {
531
+ if (!arePartsEqual(prevProps.part, nextProps.part)) return false;
532
+ if (isToolCompleted(nextProps.part)) return true;
533
+ if (prevProps.chatStatus !== nextProps.chatStatus) return false;
534
+ return true;
535
+ }
536
+ function formatElapsedTime(ms) {
537
+ if (ms < 1e3) return "";
538
+ const seconds = Math.floor(ms / 1e3);
539
+ if (seconds < 60) return `${seconds}s`;
540
+ const minutes = Math.floor(seconds / 60);
541
+ const remainingSeconds = seconds % 60;
542
+ if (remainingSeconds === 0) return `${minutes}m`;
543
+ return `${minutes}m ${remainingSeconds}s`;
544
+ }
545
+ function getToolStatus(part, chatStatus) {
546
+ const basePending = part.state !== "output-available" && part.state !== "output-error";
547
+ const isError = part.state === "output-error" || part.state === "output-available" && part.output?.success === false;
548
+ const isSuccess = part.state === "output-available" && !isError;
587
549
  return {
588
- addedLines,
589
- removedLines
550
+ isPending: basePending && chatStatus === "streaming",
551
+ isError,
552
+ isSuccess,
553
+ isInterrupted: basePending && chatStatus !== "streaming" && chatStatus !== void 0
590
554
  };
591
555
  }
592
- var toolRegistry = {
593
- "tool-Task": {
594
- icon: Sparkles,
595
- title: (part) => {
596
- const isPending = part.state !== "output-available" && part.state !== "output-error";
597
- const subagentType = part.input?.subagent_type || "Agent";
598
- return isPending ? `Running ${subagentType}` : `${subagentType} completed`;
599
- },
600
- subtitle: (part) => {
601
- const desc = part.input?.description || "";
602
- return desc.length > 50 ? `${desc.slice(0, 47)}...` : desc;
603
- },
604
- variant: "simple"
605
- },
606
- "tool-Agent": {
607
- icon: Sparkles,
608
- title: (part) => {
609
- const isPending = part.state !== "output-available" && part.state !== "output-error";
610
- const subagentType = part.input?.subagent_type || "Agent";
611
- return isPending ? `Running ${subagentType}` : `${subagentType} completed`;
612
- },
613
- subtitle: (part) => {
614
- const desc = part.input?.description || "";
615
- return desc.length > 50 ? `${desc.slice(0, 47)}...` : desc;
616
- },
617
- variant: "simple"
618
- },
619
- "tool-Skill": {
620
- icon: Sparkles,
621
- title: () => "Skill",
622
- subtitle: (part) => part.input?.skill || "",
623
- variant: "simple"
624
- },
625
- "tool-Grep": {
626
- icon: Search,
627
- title: (part) => {
628
- if (part.state !== "output-available" && part.state !== "output-error") return "Grepping";
629
- const numFiles = part.output?.numFiles || 0;
630
- return numFiles > 0 ? `Grepped ${numFiles} files` : "No matches";
631
- },
632
- subtitle: (part) => {
633
- const pattern = part.input?.pattern || "";
634
- const path = part.input?.path || "";
635
- if (path) {
636
- const combined = `${pattern} in ${getDisplayPath(path)}`;
637
- return combined.length > 40 ? `${combined.slice(0, 37)}...` : combined;
638
- }
639
- return pattern.length > 40 ? `${pattern.slice(0, 37)}...` : pattern;
640
- },
641
- variant: "simple"
642
- },
643
- "tool-Glob": {
644
- icon: FolderSearch,
645
- title: (part) => {
646
- if (part.state !== "output-available" && part.state !== "output-error") return "Exploring files";
647
- const numFiles = part.output?.numFiles || 0;
648
- return numFiles > 0 ? `Found ${numFiles} files` : "No files found";
649
- },
650
- subtitle: (part) => {
651
- const pattern = part.input?.pattern || "";
652
- return pattern.length > 40 ? `${pattern.slice(0, 37)}...` : pattern;
653
- },
654
- variant: "simple"
655
- },
656
- "tool-Read": {
657
- icon: Eye,
658
- title: (part) => {
659
- return part.state !== "output-available" && part.state !== "output-error" ? "Reading" : "Read";
660
- },
661
- subtitle: (part) => {
662
- const filePath = part.input?.file_path || "";
663
- if (!filePath) return "";
664
- return filePath.split("/").pop() || "";
665
- },
666
- variant: "simple"
667
- },
668
- "tool-Edit": {
669
- icon: FileCodeCorner,
670
- title: (part) => {
671
- const filePath = part.input?.file_path || "";
672
- if (!filePath) return "Edit";
673
- return filePath.split("/").pop() || "Edit";
674
- },
675
- subtitle: (part) => {
676
- if (part.state !== "output-available" && part.state !== "output-error") return "";
677
- const oldString = part.input?.old_string || "";
678
- const newString = part.input?.new_string || "";
679
- if (!oldString && !newString) return "";
680
- if (oldString !== newString) {
681
- const { addedLines, removedLines } = calculateDiffStats(oldString, newString);
682
- return `+${addedLines} -${removedLines}`;
683
- }
684
- return "";
685
- },
686
- variant: "simple"
687
- },
688
- "tool-Write": {
689
- icon: FilePlus,
690
- title: () => "Create",
691
- subtitle: (part) => {
692
- const filePath = part.input?.file_path || "";
693
- if (!filePath) return "";
694
- return filePath.split("/").pop() || "";
695
- },
696
- variant: "simple"
697
- },
698
- "tool-Bash": {
699
- icon: Terminal,
700
- title: (part) => {
701
- return part.state !== "output-available" && part.state !== "output-error" ? "Running command" : "Ran command";
702
- },
703
- subtitle: (part) => {
704
- const command = part.input?.command || "";
705
- if (!command) return "";
706
- let normalized = command.replace(/\\\s*\n\s*/g, " ").trim();
707
- normalized = normalized.replace(/\/(?:Users|home|root)\/[^\s"']+/g, (match) => getDisplayPath(match));
708
- return normalized.length > 50 ? `${normalized.slice(0, 47)}...` : normalized;
709
- },
710
- variant: "simple"
711
- },
712
- "tool-IPython": {
713
- icon: FileCodeCorner,
714
- title: (part) => {
715
- return part.state !== "output-available" && part.state !== "output-error" ? "Running cell" : "Ran cell";
716
- },
717
- subtitle: (part) => {
718
- const code = part.input?.code || "";
719
- if (!code) return "";
720
- const firstLine = code.split("\n", 1)[0].trim();
721
- return firstLine.length > 50 ? `${firstLine.slice(0, 47)}...` : firstLine;
722
- },
723
- variant: "simple"
724
- },
725
- "tool-WebFetch": {
726
- icon: Globe,
727
- title: (part) => {
728
- return part.state !== "output-available" && part.state !== "output-error" ? "Fetching" : "Fetched";
729
- },
730
- subtitle: (part) => {
731
- const url = part.input?.url || "";
732
- try {
733
- return new URL(url).hostname.replace("www.", "");
734
- } catch {
735
- return url.slice(0, 30);
736
- }
737
- },
738
- variant: "simple"
739
- },
740
- "tool-WebSearch": {
741
- icon: Search,
742
- title: (part) => {
743
- return part.state !== "output-available" && part.state !== "output-error" ? "Searching web" : "Searched web";
744
- },
745
- subtitle: (part) => {
746
- const query = part.input?.query || "";
747
- return query.length > 40 ? `${query.slice(0, 37)}...` : query;
748
- },
749
- variant: "collapsible"
750
- },
751
- "tool-TodoWrite": {
752
- icon: ListTodo,
753
- title: (part) => {
754
- const isPending = part.state !== "output-available" && part.state !== "output-error";
755
- const action = part.input?.action || "update";
756
- if (isPending) return action === "add" ? "Adding todo" : "Updating todos";
757
- return action === "add" ? "Added todo" : "Updated todos";
758
- },
759
- subtitle: (part) => {
760
- const todos = part.input?.todos || [];
761
- if (todos.length === 0) return "";
762
- return `${todos.length} ${todos.length === 1 ? "item" : "items"}`;
763
- },
764
- variant: "simple"
765
- },
766
- "tool-PlanWrite": {
767
- icon: Sparkles,
768
- title: (part) => {
769
- const isPending = part.state !== "output-available" && part.state !== "output-error";
770
- const action = part.input?.action || "create";
771
- if (isPending) {
772
- if (action === "create") return "Creating plan";
773
- if (action === "approve") return "Approving plan";
774
- return "Updating plan";
775
- }
776
- const status = part.input?.plan?.status;
777
- if (status === "awaiting_approval") return "Plan ready for review";
778
- if (status === "approved") return "Plan approved";
779
- if (status === "completed") return "Plan completed";
780
- return action === "create" ? "Created plan" : "Updated plan";
781
- },
782
- variant: "simple"
783
- },
784
- "tool-ExitPlanMode": {
785
- icon: LogOut,
786
- title: (part) => {
787
- return part.state !== "output-available" && part.state !== "output-error" ? "Finishing plan" : "Plan complete";
788
- },
789
- variant: "simple"
790
- },
791
- "tool-NotebookEdit": {
792
- icon: FileCodeCorner,
793
- title: (part) => {
794
- return part.state !== "output-available" && part.state !== "output-error" ? "Editing notebook" : "Edited notebook";
795
- },
796
- subtitle: (part) => {
797
- const filePath = part.input?.file_path || "";
798
- if (!filePath) return "";
799
- return filePath.split("/").pop() || "";
800
- },
801
- variant: "simple"
802
- },
803
- "tool-BashOutput": {
804
- icon: Terminal,
805
- title: (part) => {
806
- return part.state !== "output-available" && part.state !== "output-error" ? "Getting output" : "Command output";
807
- },
808
- subtitle: (part) => {
809
- const output = part.output;
810
- if (typeof output === "string" && output.trim()) return output.trim();
811
- const command = part.input?.command || "";
812
- if (!command) return "";
813
- let normalized = command.replace(/\\\s*\n\s*/g, " ").trim();
814
- normalized = normalized.replace(/\/(?:Users|home|root)\/[^\s"']+/g, (match) => getDisplayPath(match));
815
- return normalized.length > 50 ? `${normalized.slice(0, 47)}...` : normalized;
816
- },
817
- variant: "simple"
818
- },
819
- "tool-KillShell": {
820
- icon: CircleX,
821
- title: (part) => {
822
- return part.state !== "output-available" && part.state !== "output-error" ? "Stopping shell" : "Shell stopped";
823
- },
824
- subtitle: (part) => {
825
- const pid = part.input?.pid;
826
- return typeof pid === "number" ? `pid ${pid}` : "";
827
- },
828
- variant: "simple"
829
- },
830
- "tool-cloning": {
831
- icon: GitBranch,
832
- title: (part) => {
833
- return part.state !== "output-available" && part.state !== "output-error" ? "Cloning repo" : "Repo cloned";
834
- },
835
- subtitle: (part) => part.input?.repo ?? "",
836
- variant: "simple"
837
- },
838
- "tool-Thinking": {
839
- icon: Sparkles,
840
- title: (part) => {
841
- return part.state !== "output-available" && part.state !== "output-error" ? "Thinking..." : "Thought";
842
- },
843
- variant: "collapsible"
844
- }
845
- };
846
- var MCP_TOOL_PREFIX = "tool-mcp__";
847
- var BUILTIN_MCP_TOOLS = {
848
- "tool-ListMcpResources": {
849
- serverName: "mcp",
850
- toolName: "list_resources",
851
- displayName: "List Resources",
852
- category: "list"
853
- },
854
- "tool-ListMcpResourcesTool": {
855
- serverName: "mcp",
856
- toolName: "list_resources",
857
- displayName: "List Resources",
858
- category: "list"
859
- },
860
- "tool-ReadMcpResource": {
861
- serverName: "mcp",
862
- toolName: "read_resource",
863
- displayName: "Read Resource",
864
- category: "get"
865
- },
866
- "tool-ReadMcpResourceTool": {
867
- serverName: "mcp",
868
- toolName: "read_resource",
869
- displayName: "Read Resource",
870
- category: "get"
871
- }
872
- };
873
- function parseMcpToolType(partType) {
874
- const builtin = BUILTIN_MCP_TOOLS[partType];
875
- if (builtin) return builtin;
876
- if (!partType.startsWith(MCP_TOOL_PREFIX)) return null;
877
- const withoutPrefix = partType.slice(10);
878
- const separatorIndex = withoutPrefix.indexOf("__");
879
- if (separatorIndex === -1) return null;
880
- const serverName = withoutPrefix.slice(0, separatorIndex);
881
- const toolName2 = withoutPrefix.slice(separatorIndex + 2);
882
- return {
883
- serverName,
884
- toolName: toolName2,
885
- displayName: toolName2.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim(),
886
- category: "other"
887
- };
888
- }
889
- function ToolRowBase({ icon, shimmerLabel, completeLabel, isAnimating, detail, onDetailClick, trailingContent, expandable = false, expanded, defaultOpen = false, onToggleExpand, children }) {
890
- const isComplete = !isAnimating;
891
- const isExpanded = expanded ?? false;
892
- const canToggle = expandable && (isComplete || isExpanded || isAnimating);
893
- const row = /* @__PURE__ */ jsxs("div", {
894
- className: cn("flex max-w-full items-center gap-1 rounded-an-tool-border-radius select-none", canToggle ? "cursor-pointer" : "cursor-default"),
895
- children: [/* @__PURE__ */ jsxs("div", {
896
- className: "flex min-w-0 items-center gap-2 text-sm text-muted-foreground",
897
- children: [
898
- icon && /* @__PURE__ */ jsx("span", {
899
- className: "flex size-3 shrink-0 items-center justify-center",
900
- children: icon
901
- }),
902
- /* @__PURE__ */ jsx("span", {
903
- className: "shrink-0 font-[450] whitespace-nowrap",
904
- children: isAnimating && shimmerLabel ? /* @__PURE__ */ jsx(ToolTextShimmer, {
905
- as: "span",
906
- duration: 1.2,
907
- className: "m-0 inline-flex h-4 items-center leading-none",
908
- children: shimmerLabel
909
- }) : completeLabel
910
- }),
911
- detail && (onDetailClick ? /* @__PURE__ */ jsx("button", {
912
- type: "button",
913
- onClick: onDetailClick,
914
- className: "min-w-0 flex-1 truncate text-left font-normal text-an-foreground-muted/60 underline-offset-2 hover:text-an-foreground-muted hover:underline",
915
- children: detail
916
- }) : /* @__PURE__ */ jsx("span", {
917
- className: "min-w-0 flex-1 truncate font-normal text-an-foreground-muted/60",
918
- children: detail
919
- })),
920
- trailingContent
921
- ]
922
- }), expandable && (isComplete || isExpanded || isAnimating) && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ChevronRight, { className: cn("shrink-0 text-muted-foreground transition-transform duration-150 ease-out", "size-3", "rotate-0 group-data-panel-open:rotate-90") }) })]
923
- });
924
- if (!expandable) return /* @__PURE__ */ jsx("div", {
925
- className: "flex flex-col gap-1",
926
- children: row
927
- });
928
- return /* @__PURE__ */ jsxs(Collapsible, {
929
- className: "flex w-full flex-col gap-2",
930
- ...expanded === void 0 ? { defaultOpen } : {
931
- open: expanded,
932
- onOpenChange: onToggleExpand
933
- },
934
- children: [/* @__PURE__ */ jsx(CollapsibleTrigger, {
935
- className: "group flex",
936
- disabled: !canToggle,
937
- "aria-disabled": !canToggle,
938
- children: row
939
- }), /* @__PURE__ */ jsx(CollapsibleContent, {
940
- className: cn("overflow-hidden", "h-[var(--collapsible-panel-height)] transition-all duration-150 ease-out", "data-ending-style:h-0 data-starting-style:h-0", "[&[hidden]:not([hidden='until-found'])]:hidden"),
941
- children
942
- })]
943
- });
944
- }
945
- var GenericTool = memo(function GenericTool2({ icon, title, subtitle, isPending, onSubtitleClick }) {
946
- const Icon = icon;
947
- return /* @__PURE__ */ jsx(ToolRowBase, {
948
- icon: Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-full w-full shrink-0 text-muted-foreground" }) : void 0,
949
- shimmerLabel: title,
950
- completeLabel: title,
951
- isAnimating: isPending,
952
- detail: subtitle,
953
- onDetailClick: onSubtitleClick
954
- });
955
- });
956
556
  function extractCommandSummary(cmd) {
957
557
  return cmd.split("|").map((s) => s.trim().split(/\s+/)[0] ?? "").filter(Boolean).slice(0, 4).join(", ");
958
558
  }
@@ -997,9 +597,9 @@ function BashToolTerminalCard({ step, state, onComplete, approval }) {
997
597
  className: "overflow-hidden border-t border-border bg-background px-2.5 py-1.5 font-mono text-[0.75rem] leading-[16px]",
998
598
  children: [/* @__PURE__ */ jsxs("div", {
999
599
  className: "break-all",
1000
- children: [/* @__PURE__ */ jsxs("span", {
600
+ children: [/* @__PURE__ */ jsx("span", {
1001
601
  className: "text-amber-600 select-none dark:text-amber-400",
1002
- children: ["$", " "]
602
+ children: "$ "
1003
603
  }), /* @__PURE__ */ jsx("span", {
1004
604
  className: "text-foreground",
1005
605
  children: command
@@ -12007,10 +11607,253 @@ var EditTool = memo(function EditTool2({ part, isCollapsible = false, onFilePath
12007
11607
  onFilePathClick
12008
11608
  });
12009
11609
  });
12010
- function IconSpinner({ className, ...rest }) {
12011
- return /* @__PURE__ */ jsxs("svg", {
12012
- viewBox: "0 0 24 24",
12013
- width: "16",
11610
+ function ToolRowBase({ icon, shimmerLabel, completeLabel, isAnimating, detail, onDetailClick, trailingContent, expandable = false, expanded, defaultOpen = false, onToggleExpand, children }) {
11611
+ const isComplete = !isAnimating;
11612
+ const isExpanded = expanded ?? false;
11613
+ const canToggle = expandable && (isComplete || isExpanded || isAnimating);
11614
+ const row = /* @__PURE__ */ jsxs("div", {
11615
+ className: cn("flex max-w-full items-center gap-1 rounded-an-tool-border-radius select-none", canToggle ? "cursor-pointer" : "cursor-default"),
11616
+ children: [/* @__PURE__ */ jsxs("div", {
11617
+ className: "flex min-w-0 items-center gap-2 text-sm text-muted-foreground",
11618
+ children: [
11619
+ icon && /* @__PURE__ */ jsx("span", {
11620
+ className: "flex size-3 shrink-0 items-center justify-center",
11621
+ children: icon
11622
+ }),
11623
+ /* @__PURE__ */ jsx("span", {
11624
+ className: "shrink-0 font-[450] whitespace-nowrap",
11625
+ children: isAnimating && shimmerLabel ? /* @__PURE__ */ jsx(ToolTextShimmer, {
11626
+ as: "span",
11627
+ duration: 1.2,
11628
+ className: "m-0 inline-flex h-4 items-center leading-none",
11629
+ children: shimmerLabel
11630
+ }) : completeLabel
11631
+ }),
11632
+ detail && (onDetailClick ? /* @__PURE__ */ jsx("button", {
11633
+ type: "button",
11634
+ onClick: onDetailClick,
11635
+ className: "min-w-0 flex-1 truncate text-left font-normal text-an-foreground-muted/60 underline-offset-2 hover:text-an-foreground-muted hover:underline",
11636
+ children: detail
11637
+ }) : /* @__PURE__ */ jsx("span", {
11638
+ className: "min-w-0 flex-1 truncate font-normal text-an-foreground-muted/60",
11639
+ children: detail
11640
+ })),
11641
+ trailingContent
11642
+ ]
11643
+ }), expandable && (isComplete || isExpanded || isAnimating) && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ChevronRight, { className: cn("shrink-0 text-muted-foreground transition-transform duration-150 ease-out", "size-3", "rotate-0 group-data-panel-open:rotate-90") }) })]
11644
+ });
11645
+ if (!expandable) return /* @__PURE__ */ jsx("div", {
11646
+ className: "flex flex-col gap-1",
11647
+ children: row
11648
+ });
11649
+ return /* @__PURE__ */ jsxs(Collapsible, {
11650
+ className: "flex w-full flex-col gap-2",
11651
+ ...expanded === void 0 ? { defaultOpen } : {
11652
+ open: expanded,
11653
+ onOpenChange: onToggleExpand
11654
+ },
11655
+ children: [/* @__PURE__ */ jsx(CollapsibleTrigger, {
11656
+ className: "group flex",
11657
+ disabled: !canToggle,
11658
+ "aria-disabled": !canToggle,
11659
+ children: row
11660
+ }), /* @__PURE__ */ jsx(CollapsibleContent, {
11661
+ className: cn("overflow-hidden", "h-[var(--collapsible-panel-height)] transition-all duration-150 ease-out", "data-ending-style:h-0 data-starting-style:h-0", "[&[hidden]:not([hidden='until-found'])]:hidden"),
11662
+ children
11663
+ })]
11664
+ });
11665
+ }
11666
+ var GenericTool = memo(function GenericTool2({ icon, title, subtitle, isPending, onSubtitleClick }) {
11667
+ const Icon = icon;
11668
+ return /* @__PURE__ */ jsx(ToolRowBase, {
11669
+ icon: Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-full w-full shrink-0 text-muted-foreground" }) : void 0,
11670
+ shimmerLabel: title,
11671
+ completeLabel: title,
11672
+ isAnimating: isPending,
11673
+ detail: subtitle,
11674
+ onDetailClick: onSubtitleClick
11675
+ });
11676
+ });
11677
+ var PRIORITY_ARGS = [
11678
+ "query",
11679
+ "question",
11680
+ "email",
11681
+ "name",
11682
+ "id",
11683
+ "customer",
11684
+ "url",
11685
+ "issue",
11686
+ "body",
11687
+ "summary",
11688
+ "title"
11689
+ ];
11690
+ var ACTIVE_VERBS = {
11691
+ List: "Listing",
11692
+ Get: "Getting",
11693
+ Create: "Creating",
11694
+ Update: "Updating",
11695
+ Delete: "Deleting",
11696
+ Search: "Searching",
11697
+ Fetch: "Fetching",
11698
+ Retrieve: "Retrieving",
11699
+ Send: "Sending",
11700
+ Generate: "Generating",
11701
+ Add: "Adding",
11702
+ Remove: "Removing",
11703
+ Modify: "Modifying",
11704
+ Draft: "Drafting",
11705
+ Manage: "Managing",
11706
+ Query: "Querying",
11707
+ Start: "Starting",
11708
+ Set: "Setting",
11709
+ Check: "Checking",
11710
+ Find: "Finding"
11711
+ };
11712
+ var COMPLETED_VERBS = {
11713
+ List: "Listed",
11714
+ Get: "Got",
11715
+ Create: "Created",
11716
+ Update: "Updated",
11717
+ Delete: "Deleted",
11718
+ Search: "Searched",
11719
+ Fetch: "Fetched",
11720
+ Retrieve: "Retrieved",
11721
+ Send: "Sent",
11722
+ Generate: "Generated",
11723
+ Add: "Added",
11724
+ Remove: "Removed",
11725
+ Modify: "Modified",
11726
+ Draft: "Drafted",
11727
+ Manage: "Managed",
11728
+ Query: "Queried",
11729
+ Start: "Started",
11730
+ Set: "Set",
11731
+ Check: "Checked",
11732
+ Find: "Found"
11733
+ };
11734
+ function getActiveTitle(info) {
11735
+ const words = info.displayName.split(" ");
11736
+ const verb = words[0];
11737
+ const rest = words.slice(1).join(" ");
11738
+ const active = ACTIVE_VERBS[verb];
11739
+ if (active) return rest ? `${active} ${rest}` : active;
11740
+ return info.displayName;
11741
+ }
11742
+ function getCompletedTitle(info) {
11743
+ const words = info.displayName.split(" ");
11744
+ const verb = words[0];
11745
+ const rest = words.slice(1).join(" ");
11746
+ const completed = COMPLETED_VERBS[verb];
11747
+ return completed ? rest ? `${completed} ${rest}` : completed : info.displayName;
11748
+ }
11749
+ function formatMcpArgs(input) {
11750
+ if (!input || typeof input !== "object") return "";
11751
+ const entries = Object.entries(input).filter(([, v]) => v !== void 0 && v !== null && v !== "");
11752
+ if (entries.length === 0) return "";
11753
+ const sorted = [...entries].sort(([a], [b]) => {
11754
+ const ai = PRIORITY_ARGS.indexOf(a);
11755
+ const bi = PRIORITY_ARGS.indexOf(b);
11756
+ if (ai !== -1 && bi !== -1) return ai - bi;
11757
+ if (ai !== -1) return -1;
11758
+ if (bi !== -1) return 1;
11759
+ return 0;
11760
+ });
11761
+ const parts = [];
11762
+ for (const [key, value] of sorted) {
11763
+ if (parts.length >= 2) break;
11764
+ const val = typeof value === "string" ? value : JSON.stringify(value);
11765
+ const display = val.length > 30 ? val.slice(0, 27) + "..." : val;
11766
+ parts.push(`${key}: ${display}`);
11767
+ }
11768
+ return parts.join(" ");
11769
+ }
11770
+ function unwrapMcpOutput(output) {
11771
+ if (!output) return output;
11772
+ if (Array.isArray(output)) {
11773
+ const textParts = [];
11774
+ for (const block of output) if (block?.type === "text" && typeof block?.text === "string") textParts.push(block.text);
11775
+ if (textParts.length > 0) {
11776
+ const combined = textParts.join("");
11777
+ try {
11778
+ return JSON.parse(combined);
11779
+ } catch {
11780
+ return combined;
11781
+ }
11782
+ }
11783
+ return output;
11784
+ }
11785
+ if (output?.type === "text" && typeof output?.text === "string") try {
11786
+ return JSON.parse(output.text);
11787
+ } catch {
11788
+ return output.text;
11789
+ }
11790
+ if (typeof output === "string") try {
11791
+ return JSON.parse(output);
11792
+ } catch {
11793
+ return output;
11794
+ }
11795
+ return output;
11796
+ }
11797
+ function formatOutputForDisplay(output) {
11798
+ const unwrapped = unwrapMcpOutput(output);
11799
+ if (typeof unwrapped === "string") return unwrapped.length > 3e3 ? unwrapped.slice(0, 3e3) + "\n..." : unwrapped;
11800
+ const text = JSON.stringify(unwrapped, null, 2);
11801
+ return text.length > 3e3 ? text.slice(0, 3e3) + "\n..." : text;
11802
+ }
11803
+ var McpTool = memo(function McpTool2({ part, mcpInfo, chatStatus, defaultOpen }) {
11804
+ const { isPending, isInterrupted } = getToolStatus(part, chatStatus);
11805
+ const title = useMemo(() => {
11806
+ if (part.state === "input-streaming") return `Preparing ${mcpInfo.displayName}`;
11807
+ if (isPending) return getActiveTitle(mcpInfo);
11808
+ return getCompletedTitle(mcpInfo);
11809
+ }, [
11810
+ part.state,
11811
+ isPending,
11812
+ mcpInfo
11813
+ ]);
11814
+ const subtitle = useMemo(() => {
11815
+ if (part.state === "input-streaming") return "";
11816
+ return formatMcpArgs(part.input);
11817
+ }, [part.input, part.state]);
11818
+ const displayOutput = useMemo(() => {
11819
+ if (!part.output) return null;
11820
+ return formatOutputForDisplay(part.output);
11821
+ }, [part.output]);
11822
+ const codeBlock = useMemo(() => {
11823
+ if (!displayOutput) return null;
11824
+ const trimmed = displayOutput.trim();
11825
+ if (!trimmed) return null;
11826
+ return `\`\`\`${trimmed.startsWith("{") || trimmed.startsWith("[") ? "json" : "text"}
11827
+ ${displayOutput}
11828
+ \`\`\``;
11829
+ }, [displayOutput]);
11830
+ const hasExpandableContent = !!codeBlock && !isPending;
11831
+ if (isInterrupted && !part.output) return /* @__PURE__ */ jsxs("span", {
11832
+ className: "text-sm text-an-tool-color-muted",
11833
+ children: [mcpInfo.displayName, " interrupted"]
11834
+ });
11835
+ return /* @__PURE__ */ jsx("div", {
11836
+ className: "an-tool-mcp",
11837
+ children: /* @__PURE__ */ jsx(ToolRowBase, {
11838
+ shimmerLabel: title,
11839
+ completeLabel: title,
11840
+ isAnimating: isPending,
11841
+ detail: subtitle || void 0,
11842
+ trailingContent: void 0,
11843
+ expandable: hasExpandableContent,
11844
+ defaultOpen,
11845
+ children: codeBlock && /* @__PURE__ */ jsx(LazyMarkdown, {
11846
+ className: "text-[0.75rem]",
11847
+ codeControls: false,
11848
+ content: codeBlock
11849
+ })
11850
+ })
11851
+ });
11852
+ }, areToolPropsEqual);
11853
+ function IconSpinner({ className, ...rest }) {
11854
+ return /* @__PURE__ */ jsxs("svg", {
11855
+ viewBox: "0 0 24 24",
11856
+ width: "16",
12014
11857
  height: "16",
12015
11858
  fill: "none",
12016
11859
  className: className ?? "animate-spin text-muted-foreground will-change-transform",
@@ -12069,110 +11912,6 @@ function IconArrowRight(props) {
12069
11912
  })]
12070
11913
  });
12071
11914
  }
12072
- function detectChanges(oldTodos, newTodos) {
12073
- if (!oldTodos || oldTodos.length === 0) return {
12074
- type: "creation",
12075
- items: newTodos.map((todo, index) => ({
12076
- todo,
12077
- newStatus: todo.status,
12078
- index
12079
- }))
12080
- };
12081
- const changes = [];
12082
- newTodos.forEach((newTodo, index) => {
12083
- const oldTodo = oldTodos[index];
12084
- if (!oldTodo || oldTodo.status !== newTodo.status) changes.push({
12085
- todo: newTodo,
12086
- oldStatus: oldTodo?.status,
12087
- newStatus: newTodo.status,
12088
- index
12089
- });
12090
- });
12091
- if (changes.length === 1) return {
12092
- type: "single",
12093
- items: changes
12094
- };
12095
- return {
12096
- type: "multiple",
12097
- items: changes
12098
- };
12099
- }
12100
- var TodoStatusIcon$1 = ({ status, isPending }) => {
12101
- if (isPending && status === "in_progress") return /* @__PURE__ */ jsx("div", {
12102
- className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60",
12103
- children: /* @__PURE__ */ jsx(IconArrowRight, { className: "h-2 w-2 text-an-foreground-muted/70" })
12104
- });
12105
- switch (status) {
12106
- case "completed":
12107
- return /* @__PURE__ */ jsx("div", {
12108
- className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/40",
12109
- children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-2 w-2 text-an-foreground-muted/70" })
12110
- });
12111
- case "in_progress":
12112
- return /* @__PURE__ */ jsx("div", {
12113
- className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60",
12114
- children: /* @__PURE__ */ jsx(IconArrowRight, { className: "h-2 w-2 text-an-foreground-muted/70" })
12115
- });
12116
- default:
12117
- return /* @__PURE__ */ jsx("div", { className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60" });
12118
- }
12119
- };
12120
- var TodoListItem = memo(function TodoListItem2({ todo, isPending }) {
12121
- return /* @__PURE__ */ jsxs("div", {
12122
- className: cn("flex items-start gap-2"),
12123
- children: [/* @__PURE__ */ jsx("div", {
12124
- className: "mt-[2px]",
12125
- children: /* @__PURE__ */ jsx(TodoStatusIcon$1, {
12126
- status: todo.status,
12127
- isPending
12128
- })
12129
- }), /* @__PURE__ */ jsx("span", {
12130
- className: cn("text-sm", todo.status === "completed" && "line-through", isPending || todo.status === "completed" || todo.status === "pending" ? "text-an-foreground/60" : "text-an-foreground/80"),
12131
- children: todo.content
12132
- })]
12133
- });
12134
- });
12135
- var TodoTool = memo(function TodoTool2({ part, chatStatus }) {
12136
- const { isPending } = getToolStatus(part, chatStatus);
12137
- const isStreaming = part.state === "input-streaming";
12138
- const oldTodos = part.output?.oldTodos || [];
12139
- const newTodos = part.input?.todos || part.output?.newTodos || [];
12140
- const isCreation = oldTodos.length === 0;
12141
- const changes = useMemo(() => detectChanges(oldTodos, newTodos), [oldTodos, newTodos]);
12142
- if (isStreaming || newTodos.length === 0) return /* @__PURE__ */ jsx("div", {
12143
- className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12144
- children: /* @__PURE__ */ jsx("div", {
12145
- className: "text-an-foreground/60",
12146
- children: /* @__PURE__ */ jsx(ToolTextShimmer, {
12147
- as: "span",
12148
- duration: 1.2,
12149
- className: "m-0 inline-flex h-4 items-center text-sm leading-none",
12150
- children: isCreation ? "Creating to-do list..." : "Updating to-dos..."
12151
- })
12152
- })
12153
- });
12154
- if (changes.type === "single") return /* @__PURE__ */ jsx("div", {
12155
- className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12156
- children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12157
- todo,
12158
- isPending
12159
- }, todo.content))
12160
- });
12161
- if (changes.type === "multiple") return /* @__PURE__ */ jsx("div", {
12162
- className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12163
- children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12164
- todo,
12165
- isPending
12166
- }, todo.content))
12167
- });
12168
- return /* @__PURE__ */ jsx("div", {
12169
- className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12170
- children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12171
- todo,
12172
- isPending
12173
- }, todo.content))
12174
- });
12175
- }, areToolPropsEqual);
12176
11915
  function getPlanFileName(plan) {
12177
11916
  const rawId = plan.id?.trim();
12178
11917
  if (!rawId) return "plan-working.md";
@@ -12342,513 +12081,774 @@ var PlanTool = memo(function PlanTool2({ part, chatStatus }) {
12342
12081
  })]
12343
12082
  });
12344
12083
  }, areToolPropsEqual);
12345
- function useElapsedTime(startedAt, isPending) {
12346
- const [elapsedMs, setElapsedMs] = useState(0);
12347
- useEffect(() => {
12348
- if (isPending && startedAt) {
12349
- setElapsedMs(Date.now() - startedAt);
12350
- const interval = setInterval(() => {
12351
- setElapsedMs(Date.now() - startedAt);
12352
- }, 1e3);
12353
- return () => clearInterval(interval);
12354
- }
12355
- }, [isPending, startedAt]);
12356
- return elapsedMs;
12357
- }
12358
- function formatCount(value, label) {
12359
- return `${value} ${value === 1 ? label : `${label}s`}`;
12084
+ function SearchGroupRich({ toolSteps, stepStates, onStepComplete, results = [], defaultOpen }) {
12085
+ const anyAnimating = toolSteps.some((s) => stepStates[s.id] === "animating");
12086
+ const searchQuery = toolSteps.find((s) => s.searchQuery)?.searchQuery ?? "searching...";
12087
+ const totalResults = results.length;
12088
+ const hasExpandableContent = totalResults > 0;
12089
+ function CompleteTracker({ step }) {
12090
+ useToolComplete(stepStates[step.id] === "animating", step.duration, () => onStepComplete(step.id));
12091
+ return null;
12092
+ }
12093
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [toolSteps.map((step) => /* @__PURE__ */ jsx(CompleteTracker, { step }, step.id)), /* @__PURE__ */ jsx(ToolRowBase, {
12094
+ shimmerLabel: "Searching...",
12095
+ completeLabel: `Found ${totalResults} results`,
12096
+ isAnimating: anyAnimating,
12097
+ expandable: hasExpandableContent,
12098
+ defaultOpen,
12099
+ children: /* @__PURE__ */ jsxs("div", {
12100
+ className: "overflow-hidden rounded-an-tool-border-radius border border-border bg-an-tool-background",
12101
+ children: [/* @__PURE__ */ jsxs("div", {
12102
+ className: "flex h-7 items-center gap-1 border-b border-an-tool-border-color px-2.5 py-0 text-xs",
12103
+ children: [
12104
+ /* @__PURE__ */ jsx("span", {
12105
+ className: "font-medium text-foreground",
12106
+ children: "Searched for"
12107
+ }),
12108
+ " ",
12109
+ /* @__PURE__ */ jsxs("span", {
12110
+ className: "truncate text-muted-foreground",
12111
+ children: [
12112
+ "\u201C",
12113
+ searchQuery,
12114
+ "\u201D"
12115
+ ]
12116
+ })
12117
+ ]
12118
+ }), /* @__PURE__ */ jsx("div", {
12119
+ className: "max-h-[200px] overflow-y-auto bg-background",
12120
+ children: /* @__PURE__ */ jsx("div", {
12121
+ className: "flex flex-col gap-1 p-1",
12122
+ children: results.map((result) => /* @__PURE__ */ jsxs("div", {
12123
+ className: cn("flex cursor-default items-center gap-2 rounded-[calc(var(--an-tool-border-radius)-4px)] px-2 py-1", "hover:bg-muted/50"),
12124
+ children: [
12125
+ /* @__PURE__ */ jsx("div", {
12126
+ className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground",
12127
+ children: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" })
12128
+ }),
12129
+ /* @__PURE__ */ jsx("span", {
12130
+ className: "min-w-0 flex-1 truncate text-sm text-foreground/90",
12131
+ children: result.title
12132
+ }),
12133
+ /* @__PURE__ */ jsx("span", {
12134
+ className: "shrink-0 text-xs whitespace-nowrap text-muted-foreground",
12135
+ children: result.date || result.source
12136
+ })
12137
+ ]
12138
+ }, `${result.title}-${result.source}-${result.date}`))
12139
+ })
12140
+ })]
12141
+ })
12142
+ })] });
12360
12143
  }
12361
- function summarizeNestedTools(nestedTools) {
12362
- if (nestedTools.length === 0) return "";
12363
- const fileTypes = /* @__PURE__ */ new Set([
12364
- "tool-Read",
12365
- "tool-Edit",
12366
- "tool-Write"
12367
- ]);
12368
- const searchTypes = /* @__PURE__ */ new Set([
12369
- "tool-Search",
12370
- "tool-Grep",
12371
- "tool-Glob",
12372
- "tool-WebSearch"
12373
- ]);
12374
- const commandTypes = /* @__PURE__ */ new Set(["tool-Bash"]);
12375
- let fileCount = 0;
12376
- let searchCount = 0;
12377
- let commandCount = 0;
12378
- for (const tool of nestedTools) if (fileTypes.has(tool.type)) fileCount += 1;
12379
- else if (searchTypes.has(tool.type)) searchCount += 1;
12380
- else if (commandTypes.has(tool.type)) commandCount += 1;
12381
- const parts = [];
12382
- if (fileCount > 0) parts.push(formatCount(fileCount, "file"));
12383
- if (searchCount > 0) parts.push(`${searchCount} ${searchCount === 1 ? "search" : "searches"}`);
12384
- if (commandCount > 0) parts.push(formatCount(commandCount, "command"));
12385
- if (parts.length === 0) return "";
12386
- if (parts.length === 1) return parts[0];
12387
- if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;
12388
- return `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
12144
+ function normalizeResults(value) {
12145
+ if (!Array.isArray(value)) return void 0;
12146
+ const parsed = value.map((item) => {
12147
+ if (!item || typeof item !== "object") return null;
12148
+ const source = item.source;
12149
+ const title = item.title;
12150
+ const date = item.date;
12151
+ if (typeof source !== "string" || typeof title !== "string" || typeof date !== "string") return null;
12152
+ return {
12153
+ source,
12154
+ title,
12155
+ date
12156
+ };
12157
+ }).filter((item) => Boolean(item));
12158
+ return parsed.length > 0 ? parsed : void 0;
12389
12159
  }
12390
- function getNestedCounts(nestedTools) {
12391
- const fileTypes = /* @__PURE__ */ new Set([
12392
- "tool-Read",
12393
- "tool-Edit",
12394
- "tool-Write"
12395
- ]);
12396
- const searchTypes = /* @__PURE__ */ new Set([
12397
- "tool-Search",
12398
- "tool-Grep",
12399
- "tool-Glob",
12400
- "tool-WebSearch"
12401
- ]);
12402
- let fileCount = 0;
12403
- let searchCount = 0;
12404
- for (const tool of nestedTools) if (fileTypes.has(tool.type)) fileCount += 1;
12405
- else if (searchTypes.has(tool.type)) searchCount += 1;
12406
- return {
12407
- fileCount,
12408
- searchCount
12160
+ var SearchTool = memo(function SearchTool2({ part, results, defaultOpen }) {
12161
+ const toolName2 = part.type?.replace("tool-", "") || "WebSearch";
12162
+ const { step, stepState } = adaptToolPart(part, toolName2);
12163
+ const stepStates = { [step.id]: stepState };
12164
+ const noop = () => {
12409
12165
  };
12410
- }
12411
- function formatStreamCounts(fileCount, searchCount) {
12412
- const parts = [];
12413
- if (fileCount > 0) parts.push(formatCount(fileCount, "file"));
12414
- if (searchCount > 0) parts.push(`${searchCount} ${searchCount === 1 ? "search" : "searches"}`);
12415
- return parts.join(", ");
12416
- }
12417
- var ToolGroup = memo(function ToolGroup2({ part, nestedTools = [], chatStatus, completeLabel, shimmerLabel, interruptedLabel, maxVisibleTools = 5, defaultOpen, showElapsed = true }) {
12418
- const { isPending, isInterrupted } = getToolStatus(part, chatStatus);
12419
- const description = part.input?.description || "";
12420
- const [expanded, setExpanded] = useState(defaultOpen ?? false);
12421
- const [visibleCount, setVisibleCount] = useState(0);
12422
- const startedAt = part.callProviderMetadata?.custom?.startedAt ?? part.startedAt;
12423
- const hasNestedTools = nestedTools.length > 0;
12424
- const streamKey = part.toolCallId ?? part.id ?? "";
12425
- const outputDuration = part.output?.totalDurationMs || part.output?.duration || part.output?.duration_ms;
12426
- const maskThreshold = 4;
12427
- const streamHeight = Math.max(1, maxVisibleTools) * 28;
12428
- const visibleToolCount = isPending ? Math.max(visibleCount, 0) : nestedTools.length;
12429
- const wasPendingRef = useRef(isPending);
12430
- const userToggledRef = useRef(false);
12431
- const openTimerRef = useRef(null);
12432
- const { fileCount, searchCount } = useMemo(() => {
12433
- return getNestedCounts(isPending ? nestedTools.slice(0, Math.max(visibleCount, 0)) : nestedTools);
12434
- }, [
12435
- isPending,
12436
- nestedTools,
12437
- visibleCount
12438
- ]);
12439
- const streamCounts = formatStreamCounts(fileCount, searchCount);
12440
- const listRef = useRef(null);
12441
- const elapsedMs = useElapsedTime(startedAt, isPending);
12442
- useEffect(() => {
12443
- const wasPending = wasPendingRef.current;
12444
- if (openTimerRef.current) {
12445
- window.clearTimeout(openTimerRef.current);
12446
- openTimerRef.current = null;
12447
- }
12448
- if (isPending && !wasPending) {
12449
- if (!userToggledRef.current && defaultOpen !== false) {
12450
- setExpanded(false);
12451
- openTimerRef.current = window.setTimeout(() => {
12452
- setExpanded(true);
12453
- }, 60);
12454
- }
12455
- }
12456
- if (!isPending && wasPending) {
12457
- setExpanded(false);
12458
- userToggledRef.current = false;
12459
- }
12460
- wasPendingRef.current = isPending;
12461
- return () => {
12462
- if (openTimerRef.current) {
12463
- window.clearTimeout(openTimerRef.current);
12464
- openTimerRef.current = null;
12465
- }
12466
- };
12467
- }, [defaultOpen, isPending]);
12468
- useEffect(() => {
12469
- if (!isPending || nestedTools.length === 0) {
12470
- setVisibleCount(nestedTools.length);
12471
- return;
12472
- }
12473
- let index = 1;
12474
- setVisibleCount(Math.min(index, nestedTools.length));
12475
- const interval = setInterval(() => {
12476
- index += 1;
12477
- setVisibleCount(Math.min(index, nestedTools.length));
12478
- if (index >= nestedTools.length) clearInterval(interval);
12479
- }, 450);
12480
- return () => clearInterval(interval);
12481
- }, [
12482
- isPending,
12483
- nestedTools.length,
12484
- streamKey
12485
- ]);
12486
- useEffect(() => {
12487
- if (!isPending || !listRef.current) return;
12488
- listRef.current.scrollTop = listRef.current.scrollHeight;
12489
- }, [isPending, visibleCount]);
12490
- const subtitle = (() => {
12491
- if (isPending && hasNestedTools) return streamCounts;
12492
- if (!isPending && hasNestedTools) {
12493
- const summary = summarizeNestedTools(nestedTools);
12494
- if (summary) return summary;
12495
- }
12496
- if (!description) return "";
12497
- return description.length > 60 ? `${description.slice(0, 57)}...` : description;
12498
- })();
12499
- const elapsedTimeDisplay = formatElapsedTime(!isPending && outputDuration ? outputDuration : elapsedMs);
12500
- if (isInterrupted && !part.output) return /* @__PURE__ */ jsx(ToolRowBase, {
12501
- completeLabel: interruptedLabel,
12502
- isAnimating: false
12166
+ return /* @__PURE__ */ jsx(SearchGroupRich, {
12167
+ toolSteps: [step],
12168
+ stepStates,
12169
+ onStepComplete: noop,
12170
+ results: results ?? normalizeResults(part.output?.results) ?? normalizeResults(part.result?.results),
12171
+ defaultOpen
12503
12172
  });
12173
+ });
12174
+ function ThinkingCollapsed({ step, state, onComplete, defaultOpen, expanded, onToggleExpand }) {
12175
+ useToolComplete(state === "animating", step.duration, onComplete);
12504
12176
  return /* @__PURE__ */ jsx(ToolRowBase, {
12505
- completeLabel,
12506
- shimmerLabel,
12507
- isAnimating: isPending,
12508
- detail: subtitle,
12509
- expandable: hasNestedTools,
12177
+ shimmerLabel: "Thinking",
12178
+ completeLabel: "Thought",
12179
+ isAnimating: state === "animating",
12180
+ expandable: !!step.thoughtContent,
12181
+ defaultOpen,
12510
12182
  expanded,
12511
- onToggleExpand: () => {
12512
- userToggledRef.current = true;
12513
- setExpanded((prev) => !prev);
12514
- },
12515
- trailingContent: showElapsed && elapsedTimeDisplay ? /* @__PURE__ */ jsx("span", {
12516
- className: "shrink-0 font-normal text-an-foreground-muted/60 tabular-nums",
12517
- children: elapsedTimeDisplay
12518
- }) : void 0,
12519
- children: /* @__PURE__ */ jsxs("div", {
12520
- className: "relative",
12521
- children: [isPending && expanded && visibleToolCount > maskThreshold && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 z-10 h-10 bg-linear-to-b from-an-background to-transparent" }), /* @__PURE__ */ jsx("div", {
12522
- ref: listRef,
12523
- className: cn(nestedTools.length > 1 ? "flex flex-col gap-2" : void 0, isPending && expanded && visibleToolCount > maskThreshold && "overflow-y-auto"),
12524
- style: isPending && expanded && visibleToolCount > maskThreshold ? { height: `${streamHeight}px` } : void 0,
12525
- children: (isPending ? nestedTools.slice(0, Math.max(visibleCount, 0)) : nestedTools).map((nestedPart, idx) => {
12526
- const derivedPart = isPending ? {
12527
- ...nestedPart,
12528
- state: idx === visibleCount - 1 ? "input-streaming" : "output-available"
12529
- } : nestedPart;
12530
- const nestedMeta = toolRegistry[derivedPart.type];
12531
- if (!nestedMeta) return null;
12532
- const { isPending: nestedIsPending, isError: nestedIsError } = getToolStatus(derivedPart, chatStatus);
12533
- return /* @__PURE__ */ jsx(GenericTool, {
12534
- icon: nestedMeta.icon,
12535
- title: nestedMeta.title(derivedPart),
12536
- subtitle: nestedMeta.subtitle?.(derivedPart),
12537
- isPending: nestedIsPending,
12538
- isError: nestedIsError
12539
- }, derivedPart.toolCallId ?? derivedPart.id ?? `${derivedPart.type}-${nestedMeta.title(derivedPart)}`);
12540
- })
12541
- })]
12183
+ onToggleExpand,
12184
+ children: /* @__PURE__ */ jsx("div", {
12185
+ className: "max-h-[175px] overflow-y-auto",
12186
+ children: /* @__PURE__ */ jsx("p", {
12187
+ className: "text-sm whitespace-pre-wrap text-muted-foreground",
12188
+ children: step.thoughtContent
12189
+ })
12542
12190
  })
12543
12191
  });
12544
- });
12545
- var PRIORITY_ARGS = [
12546
- "query",
12547
- "question",
12548
- "email",
12549
- "name",
12550
- "id",
12551
- "customer",
12552
- "url",
12553
- "issue",
12554
- "body",
12555
- "summary",
12556
- "title"
12557
- ];
12558
- var ACTIVE_VERBS = {
12559
- List: "Listing",
12560
- Get: "Getting",
12561
- Create: "Creating",
12562
- Update: "Updating",
12563
- Delete: "Deleting",
12564
- Search: "Searching",
12565
- Fetch: "Fetching",
12566
- Retrieve: "Retrieving",
12567
- Send: "Sending",
12568
- Generate: "Generating",
12569
- Add: "Adding",
12570
- Remove: "Removing",
12571
- Modify: "Modifying",
12572
- Draft: "Drafting",
12573
- Manage: "Managing",
12574
- Query: "Querying",
12575
- Start: "Starting",
12576
- Set: "Setting",
12577
- Check: "Checking",
12578
- Find: "Finding"
12579
- };
12580
- var COMPLETED_VERBS = {
12581
- List: "Listed",
12582
- Get: "Got",
12583
- Create: "Created",
12584
- Update: "Updated",
12585
- Delete: "Deleted",
12586
- Search: "Searched",
12587
- Fetch: "Fetched",
12588
- Retrieve: "Retrieved",
12589
- Send: "Sent",
12590
- Generate: "Generated",
12591
- Add: "Added",
12592
- Remove: "Removed",
12593
- Modify: "Modified",
12594
- Draft: "Drafted",
12595
- Manage: "Managed",
12596
- Query: "Queried",
12597
- Start: "Started",
12598
- Set: "Set",
12599
- Check: "Checked",
12600
- Find: "Found"
12601
- };
12602
- function getActiveTitle(info) {
12603
- const words = info.displayName.split(" ");
12604
- const verb = words[0];
12605
- const rest = words.slice(1).join(" ");
12606
- const active = ACTIVE_VERBS[verb];
12607
- if (active) return rest ? `${active} ${rest}` : active;
12608
- return info.displayName;
12609
- }
12610
- function getCompletedTitle(info) {
12611
- const words = info.displayName.split(" ");
12612
- const verb = words[0];
12613
- const rest = words.slice(1).join(" ");
12614
- const completed = COMPLETED_VERBS[verb];
12615
- return completed ? rest ? `${completed} ${rest}` : completed : info.displayName;
12616
12192
  }
12617
- function formatMcpArgs(input) {
12618
- if (!input || typeof input !== "object") return "";
12619
- const entries = Object.entries(input).filter(([, v]) => v !== void 0 && v !== null && v !== "");
12620
- if (entries.length === 0) return "";
12621
- const sorted = [...entries].sort(([a], [b]) => {
12622
- const ai = PRIORITY_ARGS.indexOf(a);
12623
- const bi = PRIORITY_ARGS.indexOf(b);
12624
- if (ai !== -1 && bi !== -1) return ai - bi;
12625
- if (ai !== -1) return -1;
12626
- if (bi !== -1) return 1;
12627
- return 0;
12193
+ var ThinkingTool = memo(function ThinkingTool2({ part, step: externalStep, state: externalState, onComplete: externalOnComplete, defaultOpen, expanded, onToggleExpand }) {
12194
+ let step;
12195
+ let stepState;
12196
+ let onComplete;
12197
+ if (externalStep && externalState && externalOnComplete) {
12198
+ step = externalStep;
12199
+ stepState = externalState;
12200
+ onComplete = externalOnComplete;
12201
+ } else if (part) {
12202
+ const adapted = adaptToolPart(part, "Thinking");
12203
+ step = adapted.step;
12204
+ stepState = adapted.stepState;
12205
+ onComplete = () => {
12206
+ };
12207
+ } else return null;
12208
+ return /* @__PURE__ */ jsx(ThinkingCollapsed, {
12209
+ step,
12210
+ state: stepState,
12211
+ onComplete,
12212
+ defaultOpen,
12213
+ expanded,
12214
+ onToggleExpand
12215
+ });
12216
+ });
12217
+ function detectChanges(oldTodos, newTodos) {
12218
+ if (!oldTodos || oldTodos.length === 0) return {
12219
+ type: "creation",
12220
+ items: newTodos.map((todo, index) => ({
12221
+ todo,
12222
+ newStatus: todo.status,
12223
+ index
12224
+ }))
12225
+ };
12226
+ const changes = [];
12227
+ newTodos.forEach((newTodo, index) => {
12228
+ const oldTodo = oldTodos[index];
12229
+ if (!oldTodo || oldTodo.status !== newTodo.status) changes.push({
12230
+ todo: newTodo,
12231
+ oldStatus: oldTodo?.status,
12232
+ newStatus: newTodo.status,
12233
+ index
12234
+ });
12628
12235
  });
12236
+ if (changes.length === 1) return {
12237
+ type: "single",
12238
+ items: changes
12239
+ };
12240
+ return {
12241
+ type: "multiple",
12242
+ items: changes
12243
+ };
12244
+ }
12245
+ var TodoStatusIcon$1 = ({ status, isPending }) => {
12246
+ if (isPending && status === "in_progress") return /* @__PURE__ */ jsx("div", {
12247
+ className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60",
12248
+ children: /* @__PURE__ */ jsx(IconArrowRight, { className: "h-2 w-2 text-an-foreground-muted/70" })
12249
+ });
12250
+ switch (status) {
12251
+ case "completed":
12252
+ return /* @__PURE__ */ jsx("div", {
12253
+ className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/40",
12254
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-2 w-2 text-an-foreground-muted/70" })
12255
+ });
12256
+ case "in_progress":
12257
+ return /* @__PURE__ */ jsx("div", {
12258
+ className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60",
12259
+ children: /* @__PURE__ */ jsx(IconArrowRight, { className: "h-2 w-2 text-an-foreground-muted/70" })
12260
+ });
12261
+ default:
12262
+ return /* @__PURE__ */ jsx("div", { className: "flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full border border-an-foreground-muted/60" });
12263
+ }
12264
+ };
12265
+ var TodoListItem = memo(function TodoListItem2({ todo, isPending }) {
12266
+ return /* @__PURE__ */ jsxs("div", {
12267
+ className: cn("flex items-start gap-2"),
12268
+ children: [/* @__PURE__ */ jsx("div", {
12269
+ className: "mt-[2px]",
12270
+ children: /* @__PURE__ */ jsx(TodoStatusIcon$1, {
12271
+ status: todo.status,
12272
+ isPending
12273
+ })
12274
+ }), /* @__PURE__ */ jsx("span", {
12275
+ className: cn("text-sm", todo.status === "completed" && "line-through", isPending || todo.status === "completed" || todo.status === "pending" ? "text-an-foreground/60" : "text-an-foreground/80"),
12276
+ children: todo.content
12277
+ })]
12278
+ });
12279
+ });
12280
+ var TodoTool = memo(function TodoTool2({ part, chatStatus }) {
12281
+ const { isPending } = getToolStatus(part, chatStatus);
12282
+ const isStreaming = part.state === "input-streaming";
12283
+ const oldTodos = part.output?.oldTodos || [];
12284
+ const newTodos = part.input?.todos || part.output?.newTodos || [];
12285
+ const isCreation = oldTodos.length === 0;
12286
+ const changes = useMemo(() => detectChanges(oldTodos, newTodos), [oldTodos, newTodos]);
12287
+ if (isStreaming || newTodos.length === 0) return /* @__PURE__ */ jsx("div", {
12288
+ className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12289
+ children: /* @__PURE__ */ jsx("div", {
12290
+ className: "text-an-foreground/60",
12291
+ children: /* @__PURE__ */ jsx(ToolTextShimmer, {
12292
+ as: "span",
12293
+ duration: 1.2,
12294
+ className: "m-0 inline-flex h-4 items-center text-sm leading-none",
12295
+ children: isCreation ? "Creating to-do list..." : "Updating to-dos..."
12296
+ })
12297
+ })
12298
+ });
12299
+ if (changes.type === "single") return /* @__PURE__ */ jsx("div", {
12300
+ className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12301
+ children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12302
+ todo,
12303
+ isPending
12304
+ }, todo.content))
12305
+ });
12306
+ if (changes.type === "multiple") return /* @__PURE__ */ jsx("div", {
12307
+ className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12308
+ children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12309
+ todo,
12310
+ isPending
12311
+ }, todo.content))
12312
+ });
12313
+ return /* @__PURE__ */ jsx("div", {
12314
+ className: "flex flex-col gap-2 text-sm leading-relaxed text-an-foreground/80",
12315
+ children: newTodos.map((todo) => /* @__PURE__ */ jsx(TodoListItem, {
12316
+ todo,
12317
+ isPending
12318
+ }, todo.content))
12319
+ });
12320
+ }, areToolPropsEqual);
12321
+ function useElapsedTime(startedAt, isPending) {
12322
+ const [elapsedMs, setElapsedMs] = useState(0);
12323
+ useEffect(() => {
12324
+ if (isPending && startedAt) {
12325
+ setElapsedMs(Date.now() - startedAt);
12326
+ const interval = setInterval(() => {
12327
+ setElapsedMs(Date.now() - startedAt);
12328
+ }, 1e3);
12329
+ return () => clearInterval(interval);
12330
+ }
12331
+ }, [isPending, startedAt]);
12332
+ return elapsedMs;
12333
+ }
12334
+ function getDisplayPath(filePath) {
12335
+ if (!filePath) return "";
12336
+ const stripped = stripSandboxPrefixes(filePath);
12337
+ if (stripped !== filePath) return stripped;
12338
+ if (filePath.startsWith("/")) {
12339
+ const parts = filePath.split("/");
12340
+ const rootIndicators = [
12341
+ "apps",
12342
+ "packages",
12343
+ "src",
12344
+ "lib",
12345
+ "components"
12346
+ ];
12347
+ const rootIndex = parts.findIndex((p) => rootIndicators.includes(p));
12348
+ if (rootIndex > 0) return parts.slice(rootIndex).join("/");
12349
+ }
12350
+ return filePath;
12351
+ }
12352
+ function calculateDiffStats(oldString, newString) {
12353
+ const oldLines = oldString.split("\n");
12354
+ const newLines = newString.split("\n");
12355
+ const maxLines = Math.max(oldLines.length, newLines.length);
12356
+ let addedLines = 0;
12357
+ let removedLines = 0;
12358
+ for (let i = 0; i < maxLines; i++) if (oldLines[i] !== void 0 && newLines[i] !== void 0) {
12359
+ if (oldLines[i] !== newLines[i]) {
12360
+ removedLines++;
12361
+ addedLines++;
12362
+ }
12363
+ } else if (oldLines[i] !== void 0) removedLines++;
12364
+ else if (newLines[i] !== void 0) addedLines++;
12365
+ return {
12366
+ addedLines,
12367
+ removedLines
12368
+ };
12369
+ }
12370
+ var toolRegistry = {
12371
+ "tool-Task": {
12372
+ icon: Sparkles,
12373
+ title: (part) => {
12374
+ const isPending = part.state !== "output-available" && part.state !== "output-error";
12375
+ const subagentType = part.input?.subagent_type || "Agent";
12376
+ return isPending ? `Running ${subagentType}` : `${subagentType} completed`;
12377
+ },
12378
+ subtitle: (part) => {
12379
+ const desc = part.input?.description || "";
12380
+ return desc.length > 50 ? `${desc.slice(0, 47)}...` : desc;
12381
+ },
12382
+ variant: "simple"
12383
+ },
12384
+ "tool-Agent": {
12385
+ icon: Sparkles,
12386
+ title: (part) => {
12387
+ const isPending = part.state !== "output-available" && part.state !== "output-error";
12388
+ const subagentType = part.input?.subagent_type || "Agent";
12389
+ return isPending ? `Running ${subagentType}` : `${subagentType} completed`;
12390
+ },
12391
+ subtitle: (part) => {
12392
+ const desc = part.input?.description || "";
12393
+ return desc.length > 50 ? `${desc.slice(0, 47)}...` : desc;
12394
+ },
12395
+ variant: "simple"
12396
+ },
12397
+ "tool-Skill": {
12398
+ icon: Sparkles,
12399
+ title: () => "Skill",
12400
+ subtitle: (part) => part.input?.skill || "",
12401
+ variant: "simple"
12402
+ },
12403
+ "tool-Grep": {
12404
+ icon: Search,
12405
+ title: (part) => {
12406
+ if (part.state !== "output-available" && part.state !== "output-error") return "Grepping";
12407
+ const numFiles = part.output?.numFiles || 0;
12408
+ return numFiles > 0 ? `Grepped ${numFiles} files` : "No matches";
12409
+ },
12410
+ subtitle: (part) => {
12411
+ const pattern = part.input?.pattern || "";
12412
+ const path = part.input?.path || "";
12413
+ if (path) {
12414
+ const combined = `${pattern} in ${getDisplayPath(path)}`;
12415
+ return combined.length > 40 ? `${combined.slice(0, 37)}...` : combined;
12416
+ }
12417
+ return pattern.length > 40 ? `${pattern.slice(0, 37)}...` : pattern;
12418
+ },
12419
+ variant: "simple"
12420
+ },
12421
+ "tool-Glob": {
12422
+ icon: FolderSearch,
12423
+ title: (part) => {
12424
+ if (part.state !== "output-available" && part.state !== "output-error") return "Exploring files";
12425
+ const numFiles = part.output?.numFiles || 0;
12426
+ return numFiles > 0 ? `Found ${numFiles} files` : "No files found";
12427
+ },
12428
+ subtitle: (part) => {
12429
+ const pattern = part.input?.pattern || "";
12430
+ return pattern.length > 40 ? `${pattern.slice(0, 37)}...` : pattern;
12431
+ },
12432
+ variant: "simple"
12433
+ },
12434
+ "tool-Read": {
12435
+ icon: Eye,
12436
+ title: (part) => {
12437
+ return part.state !== "output-available" && part.state !== "output-error" ? "Reading" : "Read";
12438
+ },
12439
+ subtitle: (part) => {
12440
+ const filePath = part.input?.file_path || "";
12441
+ if (!filePath) return "";
12442
+ return filePath.split("/").pop() || "";
12443
+ },
12444
+ variant: "simple"
12445
+ },
12446
+ "tool-Edit": {
12447
+ icon: FileCodeCorner,
12448
+ title: (part) => {
12449
+ const filePath = part.input?.file_path || "";
12450
+ if (!filePath) return "Edit";
12451
+ return filePath.split("/").pop() || "Edit";
12452
+ },
12453
+ subtitle: (part) => {
12454
+ if (part.state !== "output-available" && part.state !== "output-error") return "";
12455
+ const oldString = part.input?.old_string || "";
12456
+ const newString = part.input?.new_string || "";
12457
+ if (!oldString && !newString) return "";
12458
+ if (oldString !== newString) {
12459
+ const { addedLines, removedLines } = calculateDiffStats(oldString, newString);
12460
+ return `+${addedLines} -${removedLines}`;
12461
+ }
12462
+ return "";
12463
+ },
12464
+ variant: "simple"
12465
+ },
12466
+ "tool-Write": {
12467
+ icon: FilePlus,
12468
+ title: () => "Create",
12469
+ subtitle: (part) => {
12470
+ const filePath = part.input?.file_path || "";
12471
+ if (!filePath) return "";
12472
+ return filePath.split("/").pop() || "";
12473
+ },
12474
+ variant: "simple"
12475
+ },
12476
+ "tool-Bash": {
12477
+ icon: Terminal,
12478
+ title: (part) => {
12479
+ return part.state !== "output-available" && part.state !== "output-error" ? "Running command" : "Ran command";
12480
+ },
12481
+ subtitle: (part) => {
12482
+ const command = part.input?.command || "";
12483
+ if (!command) return "";
12484
+ let normalized = command.replace(/\\\s*\n\s*/g, " ").trim();
12485
+ normalized = normalized.replace(/\/(?:Users|home|root)\/[^\s"']+/g, (match) => getDisplayPath(match));
12486
+ return normalized.length > 50 ? `${normalized.slice(0, 47)}...` : normalized;
12487
+ },
12488
+ variant: "simple"
12489
+ },
12490
+ "tool-IPython": {
12491
+ icon: FileCodeCorner,
12492
+ title: (part) => {
12493
+ return part.state !== "output-available" && part.state !== "output-error" ? "Running cell" : "Ran cell";
12494
+ },
12495
+ subtitle: (part) => {
12496
+ const code = part.input?.code || "";
12497
+ if (!code) return "";
12498
+ const firstLine = code.split("\n", 1)[0].trim();
12499
+ return firstLine.length > 50 ? `${firstLine.slice(0, 47)}...` : firstLine;
12500
+ },
12501
+ variant: "simple"
12502
+ },
12503
+ "tool-WebFetch": {
12504
+ icon: Globe,
12505
+ title: (part) => {
12506
+ return part.state !== "output-available" && part.state !== "output-error" ? "Fetching" : "Fetched";
12507
+ },
12508
+ subtitle: (part) => {
12509
+ const url = part.input?.url || "";
12510
+ try {
12511
+ return new URL(url).hostname.replace("www.", "");
12512
+ } catch {
12513
+ return url.slice(0, 30);
12514
+ }
12515
+ },
12516
+ variant: "simple"
12517
+ },
12518
+ "tool-WebSearch": {
12519
+ icon: Search,
12520
+ title: (part) => {
12521
+ return part.state !== "output-available" && part.state !== "output-error" ? "Searching web" : "Searched web";
12522
+ },
12523
+ subtitle: (part) => {
12524
+ const query = part.input?.query || "";
12525
+ return query.length > 40 ? `${query.slice(0, 37)}...` : query;
12526
+ },
12527
+ variant: "collapsible"
12528
+ },
12529
+ "tool-TodoWrite": {
12530
+ icon: ListTodo,
12531
+ title: (part) => {
12532
+ const isPending = part.state !== "output-available" && part.state !== "output-error";
12533
+ const action = part.input?.action || "update";
12534
+ if (isPending) return action === "add" ? "Adding todo" : "Updating todos";
12535
+ return action === "add" ? "Added todo" : "Updated todos";
12536
+ },
12537
+ subtitle: (part) => {
12538
+ const todos = part.input?.todos || [];
12539
+ if (todos.length === 0) return "";
12540
+ return `${todos.length} ${todos.length === 1 ? "item" : "items"}`;
12541
+ },
12542
+ variant: "simple"
12543
+ },
12544
+ "tool-PlanWrite": {
12545
+ icon: Sparkles,
12546
+ title: (part) => {
12547
+ const isPending = part.state !== "output-available" && part.state !== "output-error";
12548
+ const action = part.input?.action || "create";
12549
+ if (isPending) {
12550
+ if (action === "create") return "Creating plan";
12551
+ if (action === "approve") return "Approving plan";
12552
+ return "Updating plan";
12553
+ }
12554
+ const status = part.input?.plan?.status;
12555
+ if (status === "awaiting_approval") return "Plan ready for review";
12556
+ if (status === "approved") return "Plan approved";
12557
+ if (status === "completed") return "Plan completed";
12558
+ return action === "create" ? "Created plan" : "Updated plan";
12559
+ },
12560
+ variant: "simple"
12561
+ },
12562
+ "tool-ExitPlanMode": {
12563
+ icon: LogOut,
12564
+ title: (part) => {
12565
+ return part.state !== "output-available" && part.state !== "output-error" ? "Finishing plan" : "Plan complete";
12566
+ },
12567
+ variant: "simple"
12568
+ },
12569
+ "tool-NotebookEdit": {
12570
+ icon: FileCodeCorner,
12571
+ title: (part) => {
12572
+ return part.state !== "output-available" && part.state !== "output-error" ? "Editing notebook" : "Edited notebook";
12573
+ },
12574
+ subtitle: (part) => {
12575
+ const filePath = part.input?.file_path || "";
12576
+ if (!filePath) return "";
12577
+ return filePath.split("/").pop() || "";
12578
+ },
12579
+ variant: "simple"
12580
+ },
12581
+ "tool-BashOutput": {
12582
+ icon: Terminal,
12583
+ title: (part) => {
12584
+ return part.state !== "output-available" && part.state !== "output-error" ? "Getting output" : "Command output";
12585
+ },
12586
+ subtitle: (part) => {
12587
+ const output = part.output;
12588
+ if (typeof output === "string" && output.trim()) return output.trim();
12589
+ const command = part.input?.command || "";
12590
+ if (!command) return "";
12591
+ let normalized = command.replace(/\\\s*\n\s*/g, " ").trim();
12592
+ normalized = normalized.replace(/\/(?:Users|home|root)\/[^\s"']+/g, (match) => getDisplayPath(match));
12593
+ return normalized.length > 50 ? `${normalized.slice(0, 47)}...` : normalized;
12594
+ },
12595
+ variant: "simple"
12596
+ },
12597
+ "tool-KillShell": {
12598
+ icon: CircleX,
12599
+ title: (part) => {
12600
+ return part.state !== "output-available" && part.state !== "output-error" ? "Stopping shell" : "Shell stopped";
12601
+ },
12602
+ subtitle: (part) => {
12603
+ const pid = part.input?.pid;
12604
+ return typeof pid === "number" ? `pid ${pid}` : "";
12605
+ },
12606
+ variant: "simple"
12607
+ },
12608
+ "tool-cloning": {
12609
+ icon: GitBranch,
12610
+ title: (part) => {
12611
+ return part.state !== "output-available" && part.state !== "output-error" ? "Cloning repo" : "Repo cloned";
12612
+ },
12613
+ subtitle: (part) => part.input?.repo ?? "",
12614
+ variant: "simple"
12615
+ },
12616
+ "tool-Thinking": {
12617
+ icon: Sparkles,
12618
+ title: (part) => {
12619
+ return part.state !== "output-available" && part.state !== "output-error" ? "Thinking..." : "Thought";
12620
+ },
12621
+ variant: "collapsible"
12622
+ }
12623
+ };
12624
+ var MCP_TOOL_PREFIX = "tool-mcp__";
12625
+ var BUILTIN_MCP_TOOLS = {
12626
+ "tool-ListMcpResources": {
12627
+ serverName: "mcp",
12628
+ toolName: "list_resources",
12629
+ displayName: "List Resources",
12630
+ category: "list"
12631
+ },
12632
+ "tool-ListMcpResourcesTool": {
12633
+ serverName: "mcp",
12634
+ toolName: "list_resources",
12635
+ displayName: "List Resources",
12636
+ category: "list"
12637
+ },
12638
+ "tool-ReadMcpResource": {
12639
+ serverName: "mcp",
12640
+ toolName: "read_resource",
12641
+ displayName: "Read Resource",
12642
+ category: "get"
12643
+ },
12644
+ "tool-ReadMcpResourceTool": {
12645
+ serverName: "mcp",
12646
+ toolName: "read_resource",
12647
+ displayName: "Read Resource",
12648
+ category: "get"
12649
+ }
12650
+ };
12651
+ function parseMcpToolType(partType) {
12652
+ const builtin = BUILTIN_MCP_TOOLS[partType];
12653
+ if (builtin) return builtin;
12654
+ if (!partType.startsWith(MCP_TOOL_PREFIX)) return null;
12655
+ const withoutPrefix = partType.slice(10);
12656
+ const separatorIndex = withoutPrefix.indexOf("__");
12657
+ if (separatorIndex === -1) return null;
12658
+ const serverName = withoutPrefix.slice(0, separatorIndex);
12659
+ const toolName2 = withoutPrefix.slice(separatorIndex + 2);
12660
+ return {
12661
+ serverName,
12662
+ toolName: toolName2,
12663
+ displayName: toolName2.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim(),
12664
+ category: "other"
12665
+ };
12666
+ }
12667
+ function formatCount(value, label) {
12668
+ return `${value} ${value === 1 ? label : `${label}s`}`;
12669
+ }
12670
+ function summarizeNestedTools(nestedTools) {
12671
+ if (nestedTools.length === 0) return "";
12672
+ const fileTypes = /* @__PURE__ */ new Set([
12673
+ "tool-Read",
12674
+ "tool-Edit",
12675
+ "tool-Write"
12676
+ ]);
12677
+ const searchTypes = /* @__PURE__ */ new Set([
12678
+ "tool-Search",
12679
+ "tool-Grep",
12680
+ "tool-Glob",
12681
+ "tool-WebSearch"
12682
+ ]);
12683
+ const commandTypes = /* @__PURE__ */ new Set(["tool-Bash"]);
12684
+ let fileCount = 0;
12685
+ let searchCount = 0;
12686
+ let commandCount = 0;
12687
+ for (const tool of nestedTools) if (fileTypes.has(tool.type)) fileCount += 1;
12688
+ else if (searchTypes.has(tool.type)) searchCount += 1;
12689
+ else if (commandTypes.has(tool.type)) commandCount += 1;
12629
12690
  const parts = [];
12630
- for (const [key, value] of sorted) {
12631
- if (parts.length >= 2) break;
12632
- const val = typeof value === "string" ? value : JSON.stringify(value);
12633
- const display = val.length > 30 ? val.slice(0, 27) + "..." : val;
12634
- parts.push(`${key}: ${display}`);
12635
- }
12636
- return parts.join(" ");
12691
+ if (fileCount > 0) parts.push(formatCount(fileCount, "file"));
12692
+ if (searchCount > 0) parts.push(`${searchCount} ${searchCount === 1 ? "search" : "searches"}`);
12693
+ if (commandCount > 0) parts.push(formatCount(commandCount, "command"));
12694
+ if (parts.length === 0) return "";
12695
+ if (parts.length === 1) return parts[0];
12696
+ if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;
12697
+ return `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
12637
12698
  }
12638
- function unwrapMcpOutput(output) {
12639
- if (!output) return output;
12640
- if (Array.isArray(output)) {
12641
- const textParts = [];
12642
- for (const block of output) if (block?.type === "text" && typeof block?.text === "string") textParts.push(block.text);
12643
- if (textParts.length > 0) {
12644
- const combined = textParts.join("");
12645
- try {
12646
- return JSON.parse(combined);
12647
- } catch {
12648
- return combined;
12649
- }
12650
- }
12651
- return output;
12652
- }
12653
- if (output?.type === "text" && typeof output?.text === "string") try {
12654
- return JSON.parse(output.text);
12655
- } catch {
12656
- return output.text;
12657
- }
12658
- if (typeof output === "string") try {
12659
- return JSON.parse(output);
12660
- } catch {
12661
- return output;
12662
- }
12663
- return output;
12699
+ function getNestedCounts(nestedTools) {
12700
+ const fileTypes = /* @__PURE__ */ new Set([
12701
+ "tool-Read",
12702
+ "tool-Edit",
12703
+ "tool-Write"
12704
+ ]);
12705
+ const searchTypes = /* @__PURE__ */ new Set([
12706
+ "tool-Search",
12707
+ "tool-Grep",
12708
+ "tool-Glob",
12709
+ "tool-WebSearch"
12710
+ ]);
12711
+ let fileCount = 0;
12712
+ let searchCount = 0;
12713
+ for (const tool of nestedTools) if (fileTypes.has(tool.type)) fileCount += 1;
12714
+ else if (searchTypes.has(tool.type)) searchCount += 1;
12715
+ return {
12716
+ fileCount,
12717
+ searchCount
12718
+ };
12664
12719
  }
12665
- function formatOutputForDisplay(output) {
12666
- const unwrapped = unwrapMcpOutput(output);
12667
- if (typeof unwrapped === "string") return unwrapped.length > 3e3 ? unwrapped.slice(0, 3e3) + "\n..." : unwrapped;
12668
- const text = JSON.stringify(unwrapped, null, 2);
12669
- return text.length > 3e3 ? text.slice(0, 3e3) + "\n..." : text;
12720
+ function formatStreamCounts(fileCount, searchCount) {
12721
+ const parts = [];
12722
+ if (fileCount > 0) parts.push(formatCount(fileCount, "file"));
12723
+ if (searchCount > 0) parts.push(`${searchCount} ${searchCount === 1 ? "search" : "searches"}`);
12724
+ return parts.join(", ");
12670
12725
  }
12671
- var McpTool = memo(function McpTool2({ part, mcpInfo, chatStatus, defaultOpen }) {
12726
+ var ToolGroup = memo(function ToolGroup2({ part, nestedTools = [], chatStatus, completeLabel, shimmerLabel, interruptedLabel, maxVisibleTools = 5, defaultOpen, showElapsed = true }) {
12672
12727
  const { isPending, isInterrupted } = getToolStatus(part, chatStatus);
12673
- const title = useMemo(() => {
12674
- if (part.state === "input-streaming") return `Preparing ${mcpInfo.displayName}`;
12675
- if (isPending) return getActiveTitle(mcpInfo);
12676
- return getCompletedTitle(mcpInfo);
12728
+ const description = part.input?.description || "";
12729
+ const [expanded, setExpanded] = useState(defaultOpen ?? false);
12730
+ const [visibleCount, setVisibleCount] = useState(0);
12731
+ const startedAt = part.callProviderMetadata?.custom?.startedAt ?? part.startedAt;
12732
+ const hasNestedTools = nestedTools.length > 0;
12733
+ const streamKey = part.toolCallId ?? part.id ?? "";
12734
+ const outputDuration = part.output?.totalDurationMs || part.output?.duration || part.output?.duration_ms;
12735
+ const maskThreshold = 4;
12736
+ const streamHeight = Math.max(1, maxVisibleTools) * 28;
12737
+ const visibleToolCount = isPending ? Math.max(visibleCount, 0) : nestedTools.length;
12738
+ const wasPendingRef = useRef(isPending);
12739
+ const userToggledRef = useRef(false);
12740
+ const openTimerRef = useRef(null);
12741
+ const { fileCount, searchCount } = useMemo(() => {
12742
+ return getNestedCounts(isPending ? nestedTools.slice(0, Math.max(visibleCount, 0)) : nestedTools);
12677
12743
  }, [
12678
- part.state,
12679
12744
  isPending,
12680
- mcpInfo
12745
+ nestedTools,
12746
+ visibleCount
12681
12747
  ]);
12682
- const subtitle = useMemo(() => {
12683
- if (part.state === "input-streaming") return "";
12684
- return formatMcpArgs(part.input);
12685
- }, [part.input, part.state]);
12686
- const displayOutput = useMemo(() => {
12687
- if (!part.output) return null;
12688
- return formatOutputForDisplay(part.output);
12689
- }, [part.output]);
12690
- const codeBlock = useMemo(() => {
12691
- if (!displayOutput) return null;
12692
- const trimmed = displayOutput.trim();
12693
- if (!trimmed) return null;
12694
- return `\`\`\`${trimmed.startsWith("{") || trimmed.startsWith("[") ? "json" : "text"}
12695
- ${displayOutput}
12696
- \`\`\``;
12697
- }, [displayOutput]);
12698
- const hasExpandableContent = !!codeBlock && !isPending;
12699
- if (isInterrupted && !part.output) return /* @__PURE__ */ jsxs("span", {
12700
- className: "text-sm text-an-tool-color-muted",
12701
- children: [mcpInfo.displayName, " interrupted"]
12702
- });
12703
- return /* @__PURE__ */ jsx("div", {
12704
- className: "an-tool-mcp",
12705
- children: /* @__PURE__ */ jsx(ToolRowBase, {
12706
- shimmerLabel: title,
12707
- completeLabel: title,
12708
- isAnimating: isPending,
12709
- detail: subtitle || void 0,
12710
- trailingContent: void 0,
12711
- expandable: hasExpandableContent,
12712
- defaultOpen,
12713
- children: codeBlock && /* @__PURE__ */ jsx(LazyMarkdown, {
12714
- className: "text-[0.75rem]",
12715
- codeControls: false,
12716
- content: codeBlock
12717
- })
12718
- })
12719
- });
12720
- }, areToolPropsEqual);
12721
- function ThinkingCollapsed({ step, state, onComplete, defaultOpen, expanded, onToggleExpand }) {
12722
- useToolComplete(state === "animating", step.duration, onComplete);
12723
- return /* @__PURE__ */ jsx(ToolRowBase, {
12724
- shimmerLabel: "Thinking",
12725
- completeLabel: "Thought",
12726
- isAnimating: state === "animating",
12727
- expandable: !!step.thoughtContent,
12728
- defaultOpen,
12729
- expanded,
12730
- onToggleExpand,
12731
- children: /* @__PURE__ */ jsx("div", {
12732
- className: "max-h-[175px] overflow-y-auto",
12733
- children: /* @__PURE__ */ jsx("p", {
12734
- className: "text-sm whitespace-pre-wrap text-muted-foreground",
12735
- children: step.thoughtContent
12736
- })
12737
- })
12738
- });
12739
- }
12740
- var ThinkingTool = memo(function ThinkingTool2({ part, step: externalStep, state: externalState, onComplete: externalOnComplete, defaultOpen, expanded, onToggleExpand }) {
12741
- let step;
12742
- let stepState;
12743
- let onComplete;
12744
- if (externalStep && externalState && externalOnComplete) {
12745
- step = externalStep;
12746
- stepState = externalState;
12747
- onComplete = externalOnComplete;
12748
- } else if (part) {
12749
- const adapted = adaptToolPart(part, "Thinking");
12750
- step = adapted.step;
12751
- stepState = adapted.stepState;
12752
- onComplete = () => {
12748
+ const streamCounts = formatStreamCounts(fileCount, searchCount);
12749
+ const listRef = useRef(null);
12750
+ const elapsedMs = useElapsedTime(startedAt, isPending);
12751
+ useEffect(() => {
12752
+ const wasPending = wasPendingRef.current;
12753
+ if (openTimerRef.current) {
12754
+ window.clearTimeout(openTimerRef.current);
12755
+ openTimerRef.current = null;
12756
+ }
12757
+ if (isPending && !wasPending) {
12758
+ if (!userToggledRef.current && defaultOpen !== false) {
12759
+ setExpanded(false);
12760
+ openTimerRef.current = window.setTimeout(() => {
12761
+ setExpanded(true);
12762
+ }, 60);
12763
+ }
12764
+ }
12765
+ if (!isPending && wasPending) {
12766
+ setExpanded(false);
12767
+ userToggledRef.current = false;
12768
+ }
12769
+ wasPendingRef.current = isPending;
12770
+ return () => {
12771
+ if (openTimerRef.current) {
12772
+ window.clearTimeout(openTimerRef.current);
12773
+ openTimerRef.current = null;
12774
+ }
12753
12775
  };
12754
- } else return null;
12755
- return /* @__PURE__ */ jsx(ThinkingCollapsed, {
12756
- step,
12757
- state: stepState,
12758
- onComplete,
12759
- defaultOpen,
12760
- expanded,
12761
- onToggleExpand
12776
+ }, [defaultOpen, isPending]);
12777
+ useEffect(() => {
12778
+ if (!isPending || nestedTools.length === 0) {
12779
+ setVisibleCount(nestedTools.length);
12780
+ return;
12781
+ }
12782
+ let index = 1;
12783
+ setVisibleCount(Math.min(index, nestedTools.length));
12784
+ const interval = setInterval(() => {
12785
+ index += 1;
12786
+ setVisibleCount(Math.min(index, nestedTools.length));
12787
+ if (index >= nestedTools.length) clearInterval(interval);
12788
+ }, 450);
12789
+ return () => clearInterval(interval);
12790
+ }, [
12791
+ isPending,
12792
+ nestedTools.length,
12793
+ streamKey
12794
+ ]);
12795
+ useEffect(() => {
12796
+ if (!isPending || !listRef.current) return;
12797
+ listRef.current.scrollTop = listRef.current.scrollHeight;
12798
+ }, [isPending, visibleCount]);
12799
+ const subtitle = (() => {
12800
+ if (isPending && hasNestedTools) return streamCounts;
12801
+ if (!isPending && hasNestedTools) {
12802
+ const summary = summarizeNestedTools(nestedTools);
12803
+ if (summary) return summary;
12804
+ }
12805
+ if (!description) return "";
12806
+ return description.length > 60 ? `${description.slice(0, 57)}...` : description;
12807
+ })();
12808
+ const elapsedTimeDisplay = formatElapsedTime(!isPending && outputDuration ? outputDuration : elapsedMs);
12809
+ if (isInterrupted && !part.output) return /* @__PURE__ */ jsx(ToolRowBase, {
12810
+ completeLabel: interruptedLabel,
12811
+ isAnimating: false
12762
12812
  });
12763
- });
12764
- function SearchGroupRich({ toolSteps, stepStates, onStepComplete, results = [], defaultOpen }) {
12765
- const anyAnimating = toolSteps.some((s) => stepStates[s.id] === "animating");
12766
- const searchQuery = toolSteps.find((s) => s.searchQuery)?.searchQuery ?? "searching...";
12767
- const totalResults = results.length;
12768
- const hasExpandableContent = totalResults > 0;
12769
- function CompleteTracker({ step }) {
12770
- useToolComplete(stepStates[step.id] === "animating", step.duration, () => onStepComplete(step.id));
12771
- return null;
12772
- }
12773
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [toolSteps.map((step) => /* @__PURE__ */ jsx(CompleteTracker, { step }, step.id)), /* @__PURE__ */ jsx(ToolRowBase, {
12774
- shimmerLabel: "Searching...",
12775
- completeLabel: `Found ${totalResults} results`,
12776
- isAnimating: anyAnimating,
12777
- expandable: hasExpandableContent,
12778
- defaultOpen,
12813
+ return /* @__PURE__ */ jsx(ToolRowBase, {
12814
+ completeLabel,
12815
+ shimmerLabel,
12816
+ isAnimating: isPending,
12817
+ detail: subtitle,
12818
+ expandable: hasNestedTools,
12819
+ expanded,
12820
+ onToggleExpand: () => {
12821
+ userToggledRef.current = true;
12822
+ setExpanded((prev) => !prev);
12823
+ },
12824
+ trailingContent: showElapsed && elapsedTimeDisplay ? /* @__PURE__ */ jsx("span", {
12825
+ className: "shrink-0 font-normal text-an-foreground-muted/60 tabular-nums",
12826
+ children: elapsedTimeDisplay
12827
+ }) : void 0,
12779
12828
  children: /* @__PURE__ */ jsxs("div", {
12780
- className: "overflow-hidden rounded-an-tool-border-radius border border-border bg-an-tool-background",
12781
- children: [/* @__PURE__ */ jsxs("div", {
12782
- className: "flex h-7 items-center gap-1 border-b border-an-tool-border-color px-2.5 py-0 text-xs",
12783
- children: [
12784
- /* @__PURE__ */ jsx("span", {
12785
- className: "font-medium text-foreground",
12786
- children: "Searched for"
12787
- }),
12788
- " ",
12789
- /* @__PURE__ */ jsxs("span", {
12790
- className: "truncate text-muted-foreground",
12791
- children: [
12792
- "\u201C",
12793
- searchQuery,
12794
- "\u201D"
12795
- ]
12796
- })
12797
- ]
12798
- }), /* @__PURE__ */ jsx("div", {
12799
- className: "max-h-[200px] overflow-y-auto bg-background",
12800
- children: /* @__PURE__ */ jsx("div", {
12801
- className: "flex flex-col gap-1 p-1",
12802
- children: results.map((result) => /* @__PURE__ */ jsxs("div", {
12803
- className: cn("flex cursor-default items-center gap-2 rounded-[calc(var(--an-tool-border-radius)-4px)] px-2 py-1", "hover:bg-muted/50"),
12804
- children: [
12805
- /* @__PURE__ */ jsx("div", {
12806
- className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground",
12807
- children: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" })
12808
- }),
12809
- /* @__PURE__ */ jsx("span", {
12810
- className: "min-w-0 flex-1 truncate text-sm text-foreground/90",
12811
- children: result.title
12812
- }),
12813
- /* @__PURE__ */ jsx("span", {
12814
- className: "shrink-0 text-xs whitespace-nowrap text-muted-foreground",
12815
- children: result.date || result.source
12816
- })
12817
- ]
12818
- }, `${result.title}-${result.source}-${result.date}`))
12829
+ className: "relative",
12830
+ children: [isPending && expanded && visibleToolCount > maskThreshold && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 top-0 z-10 h-10 bg-linear-to-b from-an-background to-transparent" }), /* @__PURE__ */ jsx("div", {
12831
+ ref: listRef,
12832
+ className: cn(nestedTools.length > 1 ? "flex flex-col gap-2" : void 0, isPending && expanded && visibleToolCount > maskThreshold && "overflow-y-auto"),
12833
+ style: isPending && expanded && visibleToolCount > maskThreshold ? { height: `${streamHeight}px` } : void 0,
12834
+ children: (isPending ? nestedTools.slice(0, Math.max(visibleCount, 0)) : nestedTools).map((nestedPart, idx) => {
12835
+ const derivedPart = isPending ? {
12836
+ ...nestedPart,
12837
+ state: idx === visibleCount - 1 ? "input-streaming" : "output-available"
12838
+ } : nestedPart;
12839
+ const nestedMeta = toolRegistry[derivedPart.type];
12840
+ if (!nestedMeta) return null;
12841
+ const { isPending: nestedIsPending, isError: nestedIsError } = getToolStatus(derivedPart, chatStatus);
12842
+ return /* @__PURE__ */ jsx(GenericTool, {
12843
+ icon: nestedMeta.icon,
12844
+ title: nestedMeta.title(derivedPart),
12845
+ subtitle: nestedMeta.subtitle?.(derivedPart),
12846
+ isPending: nestedIsPending,
12847
+ isError: nestedIsError
12848
+ }, derivedPart.toolCallId ?? derivedPart.id ?? `${derivedPart.type}-${nestedMeta.title(derivedPart)}`);
12819
12849
  })
12820
12850
  })]
12821
12851
  })
12822
- })] });
12823
- }
12824
- function normalizeResults(value) {
12825
- if (!Array.isArray(value)) return void 0;
12826
- const parsed = value.map((item) => {
12827
- if (!item || typeof item !== "object") return null;
12828
- const source = item.source;
12829
- const title = item.title;
12830
- const date = item.date;
12831
- if (typeof source !== "string" || typeof title !== "string" || typeof date !== "string") return null;
12832
- return {
12833
- source,
12834
- title,
12835
- date
12836
- };
12837
- }).filter((item) => Boolean(item));
12838
- return parsed.length > 0 ? parsed : void 0;
12839
- }
12840
- var SearchTool = memo(function SearchTool2({ part, results, defaultOpen }) {
12841
- const toolName2 = part.type?.replace("tool-", "") || "WebSearch";
12842
- const { step, stepState } = adaptToolPart(part, toolName2);
12843
- const stepStates = { [step.id]: stepState };
12844
- const noop = () => {
12845
- };
12846
- return /* @__PURE__ */ jsx(SearchGroupRich, {
12847
- toolSteps: [step],
12848
- stepStates,
12849
- onStepComplete: noop,
12850
- results: results ?? normalizeResults(part.output?.results) ?? normalizeResults(part.result?.results),
12851
- defaultOpen
12852
12852
  });
12853
12853
  });
12854
12854
  function deriveToolStatus(part, chatStatus) {
@@ -12948,6 +12948,83 @@ var ToolRenderer = memo(function ToolRenderer2({ part, nestedTools, chatStatus,
12948
12948
  isError
12949
12949
  });
12950
12950
  });
12951
+ function AgentPlan({ steps, activeIndex, className, ...props }) {
12952
+ const total = steps.length;
12953
+ const completed = progressOf(activeIndex, total);
12954
+ const allDone = completed >= total;
12955
+ const progress = pct(completed, total);
12956
+ return /* @__PURE__ */ jsxs("div", {
12957
+ "data-slot": "agent-plan",
12958
+ className: cn("flex w-full max-w-sm flex-col gap-3", className),
12959
+ ...props,
12960
+ children: [
12961
+ /* @__PURE__ */ jsxs("div", {
12962
+ className: "flex items-center justify-between",
12963
+ children: [/* @__PURE__ */ jsx("span", {
12964
+ className: "text-[0.84375rem] font-medium",
12965
+ children: "Plan"
12966
+ }), /* @__PURE__ */ jsxs("span", {
12967
+ className: cn(mono, "text-foreground/35 tabular-nums"),
12968
+ children: [
12969
+ completed,
12970
+ " of ",
12971
+ total
12972
+ ]
12973
+ })]
12974
+ }),
12975
+ /* @__PURE__ */ jsx("div", {
12976
+ className: "bg-foreground/[0.06] h-[3px] w-full overflow-hidden rounded-full",
12977
+ children: /* @__PURE__ */ jsx("span", {
12978
+ className: "bg-foreground/80 block h-full rounded-full transition-[width] duration-500",
12979
+ style: { width: `${progress}%` }
12980
+ })
12981
+ }),
12982
+ /* @__PURE__ */ jsx("ul", {
12983
+ className: "flex flex-col gap-2.5",
12984
+ children: steps.map((step, i) => {
12985
+ const done = allDone || i < completed;
12986
+ const active = !allDone && i === completed;
12987
+ return /* @__PURE__ */ jsxs("li", {
12988
+ className: "flex items-center gap-2.5 text-[0.84375rem]",
12989
+ children: [/* @__PURE__ */ jsx("span", {
12990
+ className: "flex size-4 shrink-0 items-center justify-center",
12991
+ children: done ? /* @__PURE__ */ jsx(Check, { className: "text-foreground/35 size-3.5" }) : active ? /* @__PURE__ */ jsx(LoaderCircle, { className: "text-foreground/90 size-3.5 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx("span", {
12992
+ "aria-hidden": true,
12993
+ className: "bg-foreground/15 size-1.5 rounded-full"
12994
+ })
12995
+ }), /* @__PURE__ */ jsx("span", {
12996
+ className: cn(done && "text-foreground/40", active && "text-foreground/90", !done && !active && "text-foreground/35"),
12997
+ children: step
12998
+ })]
12999
+ }, step);
13000
+ })
13001
+ })
13002
+ ]
13003
+ });
13004
+ }
13005
+ function fleetAgentPlanPresentation(items) {
13006
+ if (items.length === 0) return void 0;
13007
+ const steps = items.flatMap((item) => {
13008
+ const title = item.title.trim();
13009
+ return title ? [title] : [];
13010
+ });
13011
+ if (steps.length !== items.length) return void 0;
13012
+ let activeIndex = 0;
13013
+ while (activeIndex < items.length && items[activeIndex]?.status === "completed") activeIndex += 1;
13014
+ if (items.slice(activeIndex + 1).some((item) => item.status === "completed")) return void 0;
13015
+ return {
13016
+ steps,
13017
+ activeIndex
13018
+ };
13019
+ }
13020
+ function FleetAgentPlan({ presentation, className }) {
13021
+ return /* @__PURE__ */ jsx(AgentPlan, {
13022
+ steps: presentation.steps,
13023
+ activeIndex: presentation.activeIndex,
13024
+ "aria-label": `Plan progress: ${Math.min(presentation.activeIndex, presentation.steps.length)} of ${presentation.steps.length} steps completed`,
13025
+ className
13026
+ });
13027
+ }
12951
13028
  var STATUS_TEXT = {
12952
13029
  queued: "Waiting to generate",
12953
13030
  generating: "Generating image",
@@ -13567,83 +13644,6 @@ function TodoList({ items, title = "To-dos", open, defaultOpen = true, onOpenCha
13567
13644
  })]
13568
13645
  });
13569
13646
  }
13570
- function AgentPlan({ steps, activeIndex, className, ...props }) {
13571
- const total = steps.length;
13572
- const completed = progressOf(activeIndex, total);
13573
- const allDone = completed >= total;
13574
- const progress = pct(completed, total);
13575
- return /* @__PURE__ */ jsxs("div", {
13576
- "data-slot": "agent-plan",
13577
- className: cn("flex w-full max-w-sm flex-col gap-3", className),
13578
- ...props,
13579
- children: [
13580
- /* @__PURE__ */ jsxs("div", {
13581
- className: "flex items-center justify-between",
13582
- children: [/* @__PURE__ */ jsx("span", {
13583
- className: "text-[0.84375rem] font-medium",
13584
- children: "Plan"
13585
- }), /* @__PURE__ */ jsxs("span", {
13586
- className: cn(mono, "text-foreground/35 tabular-nums"),
13587
- children: [
13588
- completed,
13589
- " of ",
13590
- total
13591
- ]
13592
- })]
13593
- }),
13594
- /* @__PURE__ */ jsx("div", {
13595
- className: "bg-foreground/[0.06] h-[3px] w-full overflow-hidden rounded-full",
13596
- children: /* @__PURE__ */ jsx("span", {
13597
- className: "bg-foreground/80 block h-full rounded-full transition-[width] duration-500",
13598
- style: { width: `${progress}%` }
13599
- })
13600
- }),
13601
- /* @__PURE__ */ jsx("ul", {
13602
- className: "flex flex-col gap-2.5",
13603
- children: steps.map((step, i) => {
13604
- const done = allDone || i < completed;
13605
- const active = !allDone && i === completed;
13606
- return /* @__PURE__ */ jsxs("li", {
13607
- className: "flex items-center gap-2.5 text-[0.84375rem]",
13608
- children: [/* @__PURE__ */ jsx("span", {
13609
- className: "flex size-4 shrink-0 items-center justify-center",
13610
- children: done ? /* @__PURE__ */ jsx(Check, { className: "text-foreground/35 size-3.5" }) : active ? /* @__PURE__ */ jsx(LoaderCircle, { className: "text-foreground/90 size-3.5 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx("span", {
13611
- "aria-hidden": true,
13612
- className: "bg-foreground/15 size-1.5 rounded-full"
13613
- })
13614
- }), /* @__PURE__ */ jsx("span", {
13615
- className: cn(done && "text-foreground/40", active && "text-foreground/90", !done && !active && "text-foreground/35"),
13616
- children: step
13617
- })]
13618
- }, step);
13619
- })
13620
- })
13621
- ]
13622
- });
13623
- }
13624
- function fleetAgentPlanPresentation(items) {
13625
- if (items.length === 0) return void 0;
13626
- const steps = items.flatMap((item) => {
13627
- const title = item.title.trim();
13628
- return title ? [title] : [];
13629
- });
13630
- if (steps.length !== items.length) return void 0;
13631
- let activeIndex = 0;
13632
- while (activeIndex < items.length && items[activeIndex]?.status === "completed") activeIndex += 1;
13633
- if (items.slice(activeIndex + 1).some((item) => item.status === "completed")) return void 0;
13634
- return {
13635
- steps,
13636
- activeIndex
13637
- };
13638
- }
13639
- function FleetAgentPlan({ presentation, className }) {
13640
- return /* @__PURE__ */ jsx(AgentPlan, {
13641
- steps: presentation.steps,
13642
- activeIndex: presentation.activeIndex,
13643
- "aria-label": `Plan progress: ${Math.min(presentation.activeIndex, presentation.steps.length)} of ${presentation.steps.length} steps completed`,
13644
- className
13645
- });
13646
- }
13647
13647
  function getStatusCopy(status) {
13648
13648
  if (status === "approving") return "Approving";
13649
13649
  if (status === "approved") return "Approved";
@@ -14157,7 +14157,7 @@ var BeuiToolRenderer = memo(function BeuiToolRenderer2({ part, chatStatus, fallb
14157
14157
  const planItems = toFleetPlanItems(detail.items);
14158
14158
  const pendingDecision = Boolean(part.input?.pendingDecision);
14159
14159
  if (normalized.lowerName === "planwrite" && pendingDecision) return fallback ?? null;
14160
- const planPresentation = normalized.lowerName === "planwrite" && Boolean(part.input?.executing) ? fleetAgentPlanPresentation(planItems) : void 0;
14160
+ const planPresentation = normalized.lowerName === "planwrite" && part.input?.executing ? fleetAgentPlanPresentation(planItems) : void 0;
14161
14161
  if (planPresentation) return /* @__PURE__ */ jsx(FleetAgentPlan, {
14162
14162
  presentation: planPresentation,
14163
14163
  className: "mb-2"