@apteva/apteva-kit 0.1.18 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,10 +4,13 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
 
6
6
  // src/components/Chat/Chat.tsx
7
- import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useMemo } from "react";
7
+ import { useState as useState3, useEffect as useEffect4, useRef as useRef5, useMemo as useMemo2 } from "react";
8
8
 
9
9
  // src/components/Chat/MessageList.tsx
10
- import { useEffect as useEffect2, useRef } from "react";
10
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
11
+
12
+ // src/components/Chat/Message.tsx
13
+ import { useEffect as useEffect2, useRef, useMemo } from "react";
11
14
 
12
15
  // src/utils/cn.ts
13
16
  import { clsx } from "clsx";
@@ -499,6 +502,15 @@ function validateFile(file) {
499
502
  }
500
503
 
501
504
  // src/utils/widget-parser.ts
505
+ function simpleHash(str) {
506
+ let hash = 0;
507
+ for (let i = 0; i < str.length; i++) {
508
+ const char = str.charCodeAt(i);
509
+ hash = (hash << 5) - hash + char;
510
+ hash = hash & hash;
511
+ }
512
+ return Math.abs(hash).toString(36);
513
+ }
502
514
  function findMatchingBracket(text, startIndex) {
503
515
  let depth = 0;
504
516
  let inString = false;
@@ -583,7 +595,7 @@ function parseWidgetsFromText(text) {
583
595
  try {
584
596
  const trimmedJson = jsonContent.trim();
585
597
  const props = JSON.parse(trimmedJson);
586
- const widgetId = `widget-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
598
+ const widgetId = `widget-${widgetType}-${simpleHash(trimmedJson)}`;
587
599
  segments.push({
588
600
  type: "widget",
589
601
  widget: {
@@ -1079,17 +1091,71 @@ function WidgetSkeleton({ type, className }) {
1079
1091
 
1080
1092
  // src/components/Chat/MarkdownContent.tsx
1081
1093
  import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1094
+ function isImageUrl(url) {
1095
+ const imageExtensions = /\.(jpg|jpeg|png|gif|webp|svg|bmp|ico)(\?.*)?$/i;
1096
+ return imageExtensions.test(url);
1097
+ }
1082
1098
  function parseInlineMarkdown(text, keyPrefix = "") {
1083
1099
  const result = [];
1084
- const boldRegex = /(\*\*|__)(.+?)\1/g;
1100
+ const inlineRegex = /!\[([^\]]*)\]\(([^)]+)\)|\[([^\]]+)\]\(([^)]+)\)|(\*\*|__)(.+?)\5|`([^`]+)`/g;
1085
1101
  let lastIndex = 0;
1086
1102
  let match;
1087
1103
  let key = 0;
1088
- while ((match = boldRegex.exec(text)) !== null) {
1104
+ while ((match = inlineRegex.exec(text)) !== null) {
1089
1105
  if (match.index > lastIndex) {
1090
1106
  result.push(text.slice(lastIndex, match.index));
1091
1107
  }
1092
- result.push(/* @__PURE__ */ jsx9("strong", { children: match[2] }, `${keyPrefix}b${key++}`));
1108
+ if (match[1] !== void 0 || match[2] !== void 0) {
1109
+ const alt = match[1] || "";
1110
+ const src = match[2];
1111
+ result.push(
1112
+ /* @__PURE__ */ jsx9(
1113
+ "img",
1114
+ {
1115
+ src,
1116
+ alt,
1117
+ className: "apteva-md-img"
1118
+ },
1119
+ `${keyPrefix}img${key++}`
1120
+ )
1121
+ );
1122
+ } else if (match[3] !== void 0 || match[4] !== void 0) {
1123
+ const linkText = match[3];
1124
+ const href = match[4];
1125
+ if (isImageUrl(href)) {
1126
+ result.push(
1127
+ /* @__PURE__ */ jsx9(
1128
+ "img",
1129
+ {
1130
+ src: href,
1131
+ alt: linkText,
1132
+ className: "apteva-md-img"
1133
+ },
1134
+ `${keyPrefix}img${key++}`
1135
+ )
1136
+ );
1137
+ } else {
1138
+ result.push(
1139
+ /* @__PURE__ */ jsx9(
1140
+ "a",
1141
+ {
1142
+ href,
1143
+ target: "_blank",
1144
+ rel: "noopener noreferrer",
1145
+ className: "apteva-md-link",
1146
+ children: linkText
1147
+ },
1148
+ `${keyPrefix}a${key++}`
1149
+ )
1150
+ );
1151
+ }
1152
+ } else if (match[5] !== void 0) {
1153
+ result.push(/* @__PURE__ */ jsx9("strong", { children: match[6] }, `${keyPrefix}b${key++}`));
1154
+ } else if (match[7] !== void 0) {
1155
+ result.push(
1156
+ /* @__PURE__ */ jsx9("code", { className: "apteva-md-inline-code", children: match[7] }, `${keyPrefix}code${key++}`)
1157
+ );
1158
+ }
1093
1159
  lastIndex = match.index + match[0].length;
1094
1160
  }
1095
1161
  if (lastIndex < text.length) {
@@ -1163,7 +1229,7 @@ function parseMarkdown(content) {
1163
1229
  const tableMatch = line.match(/^\|(.+)\|$/);
1164
1230
  if (tableMatch && i + 1 < lines.length) {
1165
1231
  const separatorLine = lines[i + 1];
1166
- const separatorMatch = separatorLine.match(/^\|[\s:-]+\|$/);
1232
+ const separatorMatch = separatorLine.match(/^\|([\s:-]+\|)+$/);
1167
1233
  if (separatorMatch) {
1168
1234
  const headerCells = line.split("|").filter((cell) => cell.trim() !== "").map((cell) => cell.trim());
1169
1235
  i += 2;
@@ -1208,22 +1274,72 @@ function MarkdownContent({ content, className = "" }) {
1208
1274
  // src/components/Chat/ToolCall.tsx
1209
1275
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1210
1276
  function ToolCall({ name, status }) {
1211
- return /* @__PURE__ */ jsxs7("div", { className: "apteva-tool-call", children: [
1212
- status === "running" && /* @__PURE__ */ jsx10("div", { className: "apteva-tool-call-dot apteva-tool-call-dot-running" }),
1213
- status === "completed" && /* @__PURE__ */ jsx10("div", { className: "apteva-tool-call-dot apteva-tool-call-dot-completed" }),
1214
- status === "error" && /* @__PURE__ */ jsx10("div", { className: "apteva-tool-call-dot apteva-tool-call-dot-error" }),
1215
- /* @__PURE__ */ jsx10("span", { className: "apteva-tool-call-name", children: name }),
1216
- status === "running" && /* @__PURE__ */ jsx10("span", { className: "apteva-tool-call-status", children: "Running..." }),
1217
- status === "completed" && /* @__PURE__ */ jsx10("span", { className: "apteva-tool-call-status apteva-tool-call-status-completed", children: "Completed" }),
1218
- status === "error" && /* @__PURE__ */ jsx10("span", { className: "apteva-tool-call-status apteva-tool-call-status-error", children: "Error" })
1277
+ if (status === "running") {
1278
+ return /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 !text-blue-700 dark:!text-blue-300 text-sm", children: [
1279
+ /* @__PURE__ */ jsxs7("svg", { className: "w-4 h-4 animate-spin", fill: "none", viewBox: "0 0 24 24", children: [
1280
+ /* @__PURE__ */ jsx10("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1281
+ /* @__PURE__ */ jsx10("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
1282
+ ] }),
1283
+ /* @__PURE__ */ jsxs7("span", { children: [
1284
+ "Calling ",
1285
+ /* @__PURE__ */ jsx10("strong", { children: name }),
1286
+ "..."
1287
+ ] })
1288
+ ] });
1289
+ }
1290
+ if (status === "completed") {
1291
+ return /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 !text-green-700 dark:!text-green-300 text-sm", children: [
1292
+ /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
1293
+ /* @__PURE__ */ jsxs7("span", { children: [
1294
+ "Tool completed: ",
1295
+ /* @__PURE__ */ jsx10("strong", { children: name })
1296
+ ] })
1297
+ ] });
1298
+ }
1299
+ return /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 !text-red-700 dark:!text-red-300 text-sm", children: [
1300
+ /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }),
1301
+ /* @__PURE__ */ jsxs7("span", { children: [
1302
+ "Tool failed: ",
1303
+ /* @__PURE__ */ jsx10("strong", { children: name })
1304
+ ] })
1219
1305
  ] });
1220
1306
  }
1221
1307
 
1222
1308
  // src/components/Chat/Message.tsx
1223
1309
  import { Fragment, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1224
- function Message({ message, onAction, enableWidgets }) {
1310
+ function Message({ message, onAction, enableWidgets, onWidgetRender }) {
1225
1311
  const isUser = message.role === "user";
1226
1312
  const contentSegments = message.metadata?.content_segments;
1313
+ const isStreaming = message.metadata?.isStreaming === true;
1314
+ const hasContent = message.content || contentSegments && contentSegments.length > 0;
1315
+ const reportedWidgetsRef = useRef(/* @__PURE__ */ new Set());
1316
+ const parsedWidgets = useMemo(() => {
1317
+ if (!enableWidgets || isUser || !message.content) {
1318
+ return [];
1319
+ }
1320
+ const parsed = parseWidgetsFromText(message.content);
1321
+ return parsed.segments.filter((seg) => seg.type === "widget" && !!seg.widget).map((seg) => seg.widget);
1322
+ }, [enableWidgets, isUser, message.content]);
1323
+ useEffect2(() => {
1324
+ if (onWidgetRender && message.widgets) {
1325
+ for (const widget of message.widgets) {
1326
+ if (!reportedWidgetsRef.current.has(widget.id)) {
1327
+ reportedWidgetsRef.current.add(widget.id);
1328
+ onWidgetRender(widget);
1329
+ }
1330
+ }
1331
+ }
1332
+ }, [message.widgets, onWidgetRender]);
1333
+ useEffect2(() => {
1334
+ if (onWidgetRender && parsedWidgets.length > 0) {
1335
+ for (const widget of parsedWidgets) {
1336
+ if (!reportedWidgetsRef.current.has(widget.id)) {
1337
+ reportedWidgetsRef.current.add(widget.id);
1338
+ onWidgetRender(widget);
1339
+ }
1340
+ }
1341
+ }
1342
+ }, [parsedWidgets, onWidgetRender]);
1227
1343
  const renderTextContent = (text) => {
1228
1344
  if (!enableWidgets || isUser) {
1229
1345
  return /* @__PURE__ */ jsx11(MarkdownContent, { content: text });
@@ -1249,6 +1365,13 @@ function Message({ message, onAction, enableWidgets }) {
1249
1365
  if (isUser) {
1250
1366
  return /* @__PURE__ */ jsx11("div", { className: "whitespace-pre-wrap !text-sm leading-relaxed", children: message.content });
1251
1367
  }
1368
+ if (isStreaming && !hasContent) {
1369
+ return /* @__PURE__ */ jsxs8("div", { className: "apteva-typing-indicator !text-gray-400", children: [
1370
+ /* @__PURE__ */ jsx11("span", {}),
1371
+ /* @__PURE__ */ jsx11("span", {}),
1372
+ /* @__PURE__ */ jsx11("span", {})
1373
+ ] });
1374
+ }
1252
1375
  if (contentSegments && contentSegments.length > 0) {
1253
1376
  return /* @__PURE__ */ jsx11("div", { children: contentSegments.map((segment, index) => {
1254
1377
  if (segment.type === "text") {
@@ -1271,13 +1394,13 @@ function Message({ message, onAction, enableWidgets }) {
1271
1394
  "div",
1272
1395
  {
1273
1396
  className: cn(
1274
- "max-w-[80%]",
1275
- isUser ? "px-4 py-2.5 rounded-xl bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 !text-gray-900 dark:!text-gray-100 ml-auto" : "!text-gray-900 dark:!text-gray-100"
1397
+ "max-w-[80%] px-4 py-2.5 rounded-2xl",
1398
+ isUser ? "bg-blue-600 !text-white rounded-br-md" : "bg-gray-100 dark:bg-gray-800 !text-gray-900 dark:!text-gray-100 rounded-bl-md"
1276
1399
  ),
1277
1400
  children: [
1278
1401
  renderContent(),
1279
1402
  message.widgets && message.widgets.length > 0 && /* @__PURE__ */ jsx11("div", { className: cn(isUser ? "mt-3" : "mt-2"), children: /* @__PURE__ */ jsx11(Widgets, { widgets: message.widgets, onAction, layout: "stack" }) }),
1280
- /* @__PURE__ */ jsx11("div", { className: cn("!text-xs opacity-70", isUser ? "mt-1.5 !text-gray-500 dark:!text-gray-400" : "mt-1 !text-gray-500 dark:!text-gray-400"), suppressHydrationWarning: true, children: message.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) })
1403
+ /* @__PURE__ */ jsx11("div", { className: cn("!text-xs mt-1.5", isUser ? "!text-blue-200" : "!text-gray-500 dark:!text-gray-400"), suppressHydrationWarning: true, children: message.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) })
1281
1404
  ]
1282
1405
  }
1283
1406
  );
@@ -1435,10 +1558,11 @@ function MessageList({
1435
1558
  suggestedPrompts,
1436
1559
  welcomeVariant,
1437
1560
  onPromptClick,
1438
- enableWidgets
1561
+ enableWidgets,
1562
+ onWidgetRender
1439
1563
  }) {
1440
- const listRef = useRef(null);
1441
- useEffect2(() => {
1564
+ const listRef = useRef2(null);
1565
+ useEffect3(() => {
1442
1566
  if (listRef.current) {
1443
1567
  listRef.current.scrollTop = listRef.current.scrollHeight;
1444
1568
  }
@@ -1454,20 +1578,20 @@ function MessageList({
1454
1578
  onPromptClick: onPromptClick || (() => {
1455
1579
  })
1456
1580
  }
1457
- ) : messages.map((message) => /* @__PURE__ */ jsx13(Message, { message, onAction, enableWidgets }, message.id)) });
1581
+ ) : messages.map((message) => /* @__PURE__ */ jsx13("div", { className: `flex ${message.role === "user" ? "justify-end" : "justify-start"}`, children: /* @__PURE__ */ jsx13(Message, { message, onAction, enableWidgets, onWidgetRender }) }, message.id)) });
1458
1582
  }
1459
1583
 
1460
1584
  // src/components/Chat/Composer.tsx
1461
- import { useState, useRef as useRef2 } from "react";
1585
+ import { useState, useRef as useRef3 } from "react";
1462
1586
  import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1463
1587
  function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false, isLoading = false, onStop, onFileUpload, onSwitchMode }) {
1464
1588
  const [text, setText] = useState("");
1465
1589
  const [showMenu, setShowMenu] = useState(false);
1466
1590
  const [pendingFiles, setPendingFiles] = useState([]);
1467
1591
  const [fileError, setFileError] = useState(null);
1468
- const textareaRef = useRef2(null);
1469
- const fileInputRef = useRef2(null);
1470
- const menuButtonRef = useRef2(null);
1592
+ const textareaRef = useRef3(null);
1593
+ const fileInputRef = useRef3(null);
1594
+ const menuButtonRef = useRef3(null);
1471
1595
  const handleKeyDown = (e) => {
1472
1596
  if (e.key === "Enter" && !e.shiftKey) {
1473
1597
  e.preventDefault();
@@ -1672,7 +1796,7 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
1672
1796
  }
1673
1797
 
1674
1798
  // src/components/Chat/CommandComposer.tsx
1675
- import { useState as useState2, useRef as useRef3 } from "react";
1799
+ import { useState as useState2, useRef as useRef4 } from "react";
1676
1800
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1677
1801
  function CommandComposer({
1678
1802
  onExecute,
@@ -1694,9 +1818,9 @@ function CommandComposer({
1694
1818
  const [pendingFiles, setPendingFiles] = useState2([]);
1695
1819
  const [fileError, setFileError] = useState2(null);
1696
1820
  const [showMenu, setShowMenu] = useState2(false);
1697
- const inputRef = useRef3(null);
1698
- const fileInputRef = useRef3(null);
1699
- const menuButtonRef = useRef3(null);
1821
+ const inputRef = useRef4(null);
1822
+ const fileInputRef = useRef4(null);
1823
+ const menuButtonRef = useRef4(null);
1700
1824
  const handleSubmit = () => {
1701
1825
  const hasText = input.trim();
1702
1826
  const hasFiles = pendingFiles.length > 0;
@@ -2228,6 +2352,7 @@ function Chat({
2228
2352
  const [isLoading, setIsLoading] = useState3(false);
2229
2353
  const [currentThreadId, setCurrentThreadId] = useState3(threadId || null);
2230
2354
  const [mode, setMode] = useState3(initialMode);
2355
+ const [chatToolName, setChatToolName] = useState3(null);
2231
2356
  const [commandState, setCommandState] = useState3("idle");
2232
2357
  const [commandResult, setCommandResult] = useState3(null);
2233
2358
  const [commandError, setCommandError] = useState3(null);
@@ -2240,14 +2365,14 @@ function Chat({
2240
2365
  const [pendingCommand, setPendingCommand] = useState3("");
2241
2366
  const [internalPlanMode, setInternalPlanMode] = useState3(planMode);
2242
2367
  const [showSettingsMenu, setShowSettingsMenu] = useState3(false);
2243
- const fileInputRef = useRef4(null);
2244
- const effectiveContext = useMemo(() => {
2368
+ const fileInputRef = useRef5(null);
2369
+ const effectiveContext = useMemo2(() => {
2245
2370
  if (!enableWidgets) return context;
2246
2371
  const widgetContext = compactWidgetContext ? generateCompactWidgetContext(availableWidgets) : generateWidgetContext(availableWidgets);
2247
2372
  return context ? `${context}
2248
2373
  ${widgetContext}` : widgetContext;
2249
2374
  }, [context, enableWidgets, availableWidgets, compactWidgetContext]);
2250
- useEffect3(() => {
2375
+ useEffect4(() => {
2251
2376
  if (apiUrl || apiKey) {
2252
2377
  aptevaClient.configure({
2253
2378
  ...apiUrl && { apiUrl },
@@ -2255,15 +2380,15 @@ ${widgetContext}` : widgetContext;
2255
2380
  });
2256
2381
  }
2257
2382
  }, [apiUrl, apiKey]);
2258
- useEffect3(() => {
2383
+ useEffect4(() => {
2259
2384
  if (threadId) {
2260
2385
  onThreadChange?.(threadId);
2261
2386
  }
2262
2387
  }, [threadId, onThreadChange]);
2263
- useEffect3(() => {
2388
+ useEffect4(() => {
2264
2389
  setInternalPlanMode(planMode);
2265
2390
  }, [planMode]);
2266
- useEffect3(() => {
2391
+ useEffect4(() => {
2267
2392
  const handleClickOutside = (event) => {
2268
2393
  const target = event.target;
2269
2394
  if (showSettingsMenu && !target.closest(".settings-menu-container")) {
@@ -2308,6 +2433,7 @@ ${widgetContext}` : widgetContext;
2308
2433
  let accumulatedWidgets = [];
2309
2434
  let responseThreadId = currentThreadId;
2310
2435
  let toolInputBuffer = "";
2436
+ const streamingMessageId = `msg-${Date.now()}`;
2311
2437
  const updateMessage = () => {
2312
2438
  const segments = [...contentSegments];
2313
2439
  if (currentTextBuffer) {
@@ -2327,19 +2453,19 @@ ${widgetContext}` : widgetContext;
2327
2453
  ...lastMessage,
2328
2454
  content: currentTextBuffer,
2329
2455
  widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : void 0,
2330
- metadata: { ...lastMessage.metadata, content_segments: segments }
2456
+ metadata: { ...lastMessage.metadata, content_segments: segments, isStreaming: true }
2331
2457
  }
2332
2458
  ];
2333
2459
  } else {
2334
2460
  return [
2335
2461
  ...prev,
2336
2462
  {
2337
- id: `msg-${Date.now()}-streaming`,
2463
+ id: streamingMessageId,
2338
2464
  role: "assistant",
2339
2465
  content: currentTextBuffer,
2340
2466
  widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : void 0,
2341
2467
  timestamp: /* @__PURE__ */ new Date(),
2342
- metadata: { content_segments: segments }
2468
+ metadata: { content_segments: segments, isStreaming: true }
2343
2469
  }
2344
2470
  ];
2345
2471
  }
@@ -2384,6 +2510,7 @@ ${widgetContext}` : widgetContext;
2384
2510
  }
2385
2511
  contentSegments.push({ type: "tool", id: chunk.tool_id, name: chunk.tool_name });
2386
2512
  toolInputBuffer = "";
2513
+ setChatToolName(chunk.tool_name);
2387
2514
  updateMessage();
2388
2515
  }
2389
2516
  break;
@@ -2399,6 +2526,7 @@ ${widgetContext}` : widgetContext;
2399
2526
  toolSegment.result = chunk.content;
2400
2527
  onToolResult?.(toolSegment.name, chunk.content);
2401
2528
  }
2529
+ setChatToolName(null);
2402
2530
  updateMessage();
2403
2531
  }
2404
2532
  break;
@@ -2428,10 +2556,10 @@ ${widgetContext}` : widgetContext;
2428
2556
  ...prev.slice(0, -1),
2429
2557
  {
2430
2558
  ...lastMessage,
2431
- id: `msg-${Date.now()}`,
2559
+ // Keep the same ID to avoid React remounting the component
2432
2560
  content: currentTextBuffer || "Response received",
2433
2561
  widgets: accumulatedWidgets.length > 0 ? accumulatedWidgets : void 0,
2434
- metadata: { thread_id: threadId2, content_segments: contentSegments }
2562
+ metadata: { thread_id: threadId2, content_segments: contentSegments, isStreaming: false }
2435
2563
  }
2436
2564
  ];
2437
2565
  }
@@ -2443,6 +2571,7 @@ ${widgetContext}` : widgetContext;
2443
2571
  }
2444
2572
  setIsLoading(false);
2445
2573
  setCurrentRequestId(null);
2574
+ setChatToolName(null);
2446
2575
  },
2447
2576
  (error) => {
2448
2577
  const errorMessage = {
@@ -2461,6 +2590,7 @@ ${widgetContext}` : widgetContext;
2461
2590
  });
2462
2591
  setIsLoading(false);
2463
2592
  setCurrentRequestId(null);
2593
+ setChatToolName(null);
2464
2594
  onError?.(error);
2465
2595
  }
2466
2596
  );
@@ -2704,7 +2834,13 @@ ${planToExecute}`;
2704
2834
  };
2705
2835
  const isCompact = commandVariant === "compact";
2706
2836
  return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-col h-full", className), children: [
2707
- showHeader && mode === "chat" && /* @__PURE__ */ jsx16("div", { className: "px-4 py-3 flex items-center justify-between", children: /* @__PURE__ */ jsx16("h2", { className: "!text-lg font-semibold !text-gray-900 dark:!text-white", children: headerTitle }) }),
2837
+ showHeader && mode === "chat" && /* @__PURE__ */ jsx16("div", { className: "apteva-chat-header px-4 py-3 flex items-center justify-between", children: /* @__PURE__ */ jsxs12("div", { children: [
2838
+ /* @__PURE__ */ jsx16("div", { className: "apteva-chat-title", children: headerTitle }),
2839
+ /* @__PURE__ */ jsx16("div", { className: cn(
2840
+ "apteva-chat-status",
2841
+ isLoading ? chatToolName ? "apteva-chat-status-tool" : "apteva-chat-status-thinking" : "apteva-chat-status-ready"
2842
+ ), children: isLoading ? chatToolName ? `Using ${chatToolName}...` : "Thinking..." : "Ready" })
2843
+ ] }) }),
2708
2844
  mode === "chat" && /* @__PURE__ */ jsxs12(Fragment4, { children: [
2709
2845
  /* @__PURE__ */ jsx16(
2710
2846
  MessageList,
@@ -2717,10 +2853,10 @@ ${planToExecute}`;
2717
2853
  suggestedPrompts,
2718
2854
  welcomeVariant,
2719
2855
  onPromptClick: (prompt) => handleSendMessage(prompt),
2720
- enableWidgets
2856
+ enableWidgets,
2857
+ onWidgetRender
2721
2858
  }
2722
2859
  ),
2723
- isLoading && /* @__PURE__ */ jsx16("div", { className: "px-4 py-2 !text-sm !text-gray-500 dark:!text-gray-400 italic", children: "AI is thinking..." }),
2724
2860
  /* @__PURE__ */ jsx16(
2725
2861
  Composer,
2726
2862
  {
@@ -2777,7 +2913,7 @@ import { useState as useState4 } from "react";
2777
2913
  import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
2778
2914
 
2779
2915
  // src/components/Command/Command.tsx
2780
- import React, { useState as useState5, useEffect as useEffect4 } from "react";
2916
+ import React, { useState as useState5, useEffect as useEffect5 } from "react";
2781
2917
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
2782
2918
  function Command({
2783
2919
  agentId,
@@ -2818,15 +2954,15 @@ function Command({
2818
2954
  const [showSettingsMenu, setShowSettingsMenu] = useState5(false);
2819
2955
  const [internalPlanMode, setInternalPlanMode] = useState5(planMode);
2820
2956
  const fileInputRef = React.useRef(null);
2821
- useEffect4(() => {
2957
+ useEffect5(() => {
2822
2958
  if (autoExecute && state === "idle" && command) {
2823
2959
  executeCommand();
2824
2960
  }
2825
2961
  }, [autoExecute]);
2826
- useEffect4(() => {
2962
+ useEffect5(() => {
2827
2963
  setInternalPlanMode(planMode);
2828
2964
  }, [planMode]);
2829
- useEffect4(() => {
2965
+ useEffect5(() => {
2830
2966
  const handleClickOutside = (event) => {
2831
2967
  const target = event.target;
2832
2968
  if (showSettingsMenu && !target.closest(".settings-menu-container")) {
@@ -3859,7 +3995,7 @@ function Prompt({
3859
3995
  }
3860
3996
 
3861
3997
  // src/components/Stream/Stream.tsx
3862
- import { useState as useState7, useEffect as useEffect5 } from "react";
3998
+ import { useState as useState7, useEffect as useEffect6 } from "react";
3863
3999
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
3864
4000
  function Stream({
3865
4001
  agentId,
@@ -3879,7 +4015,7 @@ function Stream({
3879
4015
  const [text, setText] = useState7("");
3880
4016
  const [isStreaming, setIsStreaming] = useState7(false);
3881
4017
  const [isComplete, setIsComplete] = useState7(false);
3882
- useEffect5(() => {
4018
+ useEffect6(() => {
3883
4019
  if (autoStart && !isStreaming && !isComplete) {
3884
4020
  startStreaming();
3885
4021
  }