@apteva/apteva-kit 0.1.69 → 0.1.71

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,13 +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 useState4, useEffect as useEffect4, useRef as useRef5, useMemo as useMemo2, forwardRef, useImperativeHandle } from "react";
7
+ import { useState as useState6, useEffect as useEffect6, useRef as useRef7, useMemo as useMemo2, forwardRef, useImperativeHandle } from "react";
8
8
 
9
9
  // src/components/Chat/MessageList.tsx
10
- import { useEffect as useEffect3, useRef as useRef2 } from "react";
10
+ import { useEffect as useEffect5, useRef as useRef4 } from "react";
11
11
 
12
12
  // src/components/Chat/Message.tsx
13
- import { useEffect as useEffect2, useRef, useMemo } from "react";
13
+ import { useEffect as useEffect4, useRef as useRef3, useMemo } from "react";
14
14
 
15
15
  // src/utils/cn.ts
16
16
  import { clsx } from "clsx";
@@ -502,6 +502,71 @@ function validateFile(file) {
502
502
  }
503
503
 
504
504
  // src/utils/widget-parser.ts
505
+ var STREAMABLE_WIDGET_TYPES = ["list", "table"];
506
+ function parsePartialItemsArray(partialJson) {
507
+ const items = [];
508
+ let isStreaming = false;
509
+ const itemsMatch = partialJson.match(/"items"\s*:\s*\[/);
510
+ if (!itemsMatch) {
511
+ return { items, isStreaming: false };
512
+ }
513
+ const arrayStart = partialJson.indexOf("[", itemsMatch.index);
514
+ if (arrayStart === -1) {
515
+ return { items, isStreaming: true };
516
+ }
517
+ let depth = 0;
518
+ let inString = false;
519
+ let escapeNext = false;
520
+ let objectStart = -1;
521
+ for (let i = arrayStart + 1; i < partialJson.length; i++) {
522
+ const char = partialJson[i];
523
+ if (escapeNext) {
524
+ escapeNext = false;
525
+ continue;
526
+ }
527
+ if (char === "\\" && inString) {
528
+ escapeNext = true;
529
+ continue;
530
+ }
531
+ if (char === '"') {
532
+ inString = !inString;
533
+ continue;
534
+ }
535
+ if (inString) continue;
536
+ if (char === "{") {
537
+ if (depth === 0) {
538
+ objectStart = i;
539
+ }
540
+ depth++;
541
+ } else if (char === "}") {
542
+ depth--;
543
+ if (depth === 0 && objectStart !== -1) {
544
+ const objectJson = partialJson.slice(objectStart, i + 1);
545
+ try {
546
+ const item = JSON.parse(objectJson);
547
+ if (!item.id) {
548
+ item.id = `item-${items.length}-${simpleHash(objectJson)}`;
549
+ }
550
+ items.push(item);
551
+ } catch (e) {
552
+ }
553
+ objectStart = -1;
554
+ }
555
+ } else if (char === "]" && depth === 0) {
556
+ isStreaming = false;
557
+ break;
558
+ }
559
+ }
560
+ if (depth > 0 || objectStart !== -1) {
561
+ isStreaming = true;
562
+ }
563
+ const afterItems = partialJson.slice(arrayStart);
564
+ const closingBracket = findMatchingBracket(afterItems, 0);
565
+ if (closingBracket === -1) {
566
+ isStreaming = true;
567
+ }
568
+ return { items, isStreaming };
569
+ }
505
570
  function simpleHash(str) {
506
571
  let hash = 0;
507
572
  for (let i = 0; i < str.length; i++) {
@@ -563,9 +628,38 @@ function parseWidgetsFromText(text) {
563
628
  const fullBracketStart = lastWidgetStart + bracketOpenIndex;
564
629
  const bracketEnd = findMatchingBracket(text, fullBracketStart);
565
630
  if (bracketEnd === -1) {
566
- processText = text.slice(0, lastWidgetStart);
567
- pendingWidgetType = widgetType;
568
- hasPendingWidget = true;
631
+ if (STREAMABLE_WIDGET_TYPES.includes(widgetType)) {
632
+ const partialContent = text.slice(fullBracketStart + 1);
633
+ const { items, isStreaming } = parsePartialItemsArray(partialContent);
634
+ if (items.length > 0) {
635
+ processText = text.slice(0, lastWidgetStart);
636
+ const widgetId = `widget-${widgetType}-streaming-${simpleHash(partialContent)}`;
637
+ const textBefore = processText.replace(/[\s:;\-–—\.]+$/g, "").trim();
638
+ if (textBefore) {
639
+ segments.push({ type: "text", content: textBefore });
640
+ }
641
+ segments.push({
642
+ type: "widget",
643
+ widget: {
644
+ type: widgetType,
645
+ id: widgetId,
646
+ props: widgetType === "table" ? { rows: items, columns: [] } : { items },
647
+ isStreaming: true
648
+ }
649
+ });
650
+ hasWidgets = true;
651
+ hasPendingWidget = false;
652
+ processText = "";
653
+ } else {
654
+ processText = text.slice(0, lastWidgetStart);
655
+ pendingWidgetType = widgetType;
656
+ hasPendingWidget = true;
657
+ }
658
+ } else {
659
+ processText = text.slice(0, lastWidgetStart);
660
+ pendingWidgetType = widgetType;
661
+ hasPendingWidget = true;
662
+ }
569
663
  }
570
664
  }
571
665
  }
@@ -695,7 +789,7 @@ Widgets: @ui:type[{props}]. Types: ${widgets.join(", ")}. Add "meta" at root (no
695
789
  }
696
790
 
697
791
  // src/components/Widgets/Widgets.tsx
698
- import { useEffect } from "react";
792
+ import { useEffect as useEffect3 } from "react";
699
793
 
700
794
  // src/components/Widgets/widget-library/Card.tsx
701
795
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -728,39 +822,74 @@ function Card({ widget, onAction }) {
728
822
  }
729
823
 
730
824
  // src/components/Widgets/widget-library/List.tsx
825
+ import { useEffect, useRef, useState } from "react";
731
826
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
732
827
  function List({ widget, onAction }) {
733
828
  const { items } = widget.props;
734
- return /* @__PURE__ */ jsx2("div", { className: "border border-neutral-200 dark:border-neutral-700 rounded-xl bg-white dark:bg-neutral-900 overflow-hidden", children: items.map((item, index) => /* @__PURE__ */ jsxs2(
735
- "div",
736
- {
737
- className: `flex items-center p-4 transition-colors ${index !== items.length - 1 ? "border-b border-neutral-200 dark:border-neutral-700" : ""} ${!item.backgroundColor ? "hover:bg-neutral-50 dark:hover:bg-neutral-800" : ""}`,
738
- style: item.backgroundColor ? { backgroundColor: item.backgroundColor } : void 0,
739
- children: [
740
- item.image && /* @__PURE__ */ jsx2("img", { src: item.image, alt: item.title, className: "w-16 h-16 rounded object-cover" }),
741
- /* @__PURE__ */ jsxs2("div", { className: `flex-1 ${item.image ? "ml-4" : ""}`, children: [
742
- /* @__PURE__ */ jsx2("h4", { className: "font-semibold !text-neutral-900 dark:!text-white", children: item.title }),
743
- item.subtitle && /* @__PURE__ */ jsx2("p", { className: "!text-sm !text-neutral-600 dark:!text-neutral-400", children: item.subtitle }),
744
- item.description && /* @__PURE__ */ jsx2("p", { className: "!text-xs !text-neutral-500 dark:!text-neutral-500 mt-1", children: item.description })
745
- ] }),
746
- widget.actions && widget.actions.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: widget.actions.map((action, idx) => /* @__PURE__ */ jsx2(
747
- "button",
748
- {
749
- onClick: () => onAction?.({
750
- type: action.type,
751
- payload: item.metadata || item,
752
- widgetId: widget.id,
753
- timestamp: /* @__PURE__ */ new Date()
754
- }),
755
- className: "px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600",
756
- children: action.label
757
- },
758
- idx
759
- )) })
760
- ]
761
- },
762
- item.id
763
- )) });
829
+ const isStreaming = widget.isStreaming ?? false;
830
+ const seenItemsRef = useRef(/* @__PURE__ */ new Set());
831
+ const [newItemIds, setNewItemIds] = useState(/* @__PURE__ */ new Set());
832
+ useEffect(() => {
833
+ const currentIds = new Set(items.map((item) => item.id));
834
+ const newIds = /* @__PURE__ */ new Set();
835
+ items.forEach((item) => {
836
+ if (!seenItemsRef.current.has(item.id)) {
837
+ newIds.add(item.id);
838
+ }
839
+ });
840
+ items.forEach((item) => seenItemsRef.current.add(item.id));
841
+ if (newIds.size > 0) {
842
+ setNewItemIds(newIds);
843
+ const timer = setTimeout(() => {
844
+ setNewItemIds(/* @__PURE__ */ new Set());
845
+ }, 500);
846
+ return () => clearTimeout(timer);
847
+ }
848
+ }, [items]);
849
+ return /* @__PURE__ */ jsxs2("div", { className: "border border-neutral-200 dark:border-neutral-700 rounded-xl bg-white dark:bg-neutral-900 overflow-hidden", children: [
850
+ items.map((item, index) => {
851
+ const isNew = newItemIds.has(item.id);
852
+ const isLast = index === items.length - 1;
853
+ return /* @__PURE__ */ jsxs2(
854
+ "div",
855
+ {
856
+ className: `apteva-list-item flex items-center p-4 transition-colors ${!isLast || isStreaming ? "border-b border-neutral-200 dark:border-neutral-700" : ""} ${!item.backgroundColor ? "hover:bg-neutral-50 dark:hover:bg-neutral-800" : ""} ${isNew ? "apteva-list-item-new" : ""}`,
857
+ style: item.backgroundColor ? { backgroundColor: item.backgroundColor } : void 0,
858
+ children: [
859
+ item.image && /* @__PURE__ */ jsx2("img", { src: item.image, alt: item.title, className: "w-16 h-16 rounded object-cover" }),
860
+ /* @__PURE__ */ jsxs2("div", { className: `flex-1 ${item.image ? "ml-4" : ""}`, children: [
861
+ /* @__PURE__ */ jsx2("h4", { className: "font-semibold !text-neutral-900 dark:!text-white", children: item.title }),
862
+ item.subtitle && /* @__PURE__ */ jsx2("p", { className: "!text-sm !text-neutral-600 dark:!text-neutral-400", children: item.subtitle }),
863
+ item.description && /* @__PURE__ */ jsx2("p", { className: "!text-xs !text-neutral-500 dark:!text-neutral-500 mt-1", children: item.description })
864
+ ] }),
865
+ widget.actions && widget.actions.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: widget.actions.map((action, idx) => /* @__PURE__ */ jsx2(
866
+ "button",
867
+ {
868
+ onClick: () => onAction?.({
869
+ type: action.type,
870
+ payload: item.metadata || item,
871
+ widgetId: widget.id,
872
+ timestamp: /* @__PURE__ */ new Date()
873
+ }),
874
+ className: "px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600",
875
+ children: action.label
876
+ },
877
+ idx
878
+ )) })
879
+ ]
880
+ },
881
+ item.id
882
+ );
883
+ }),
884
+ isStreaming && /* @__PURE__ */ jsxs2("div", { className: "apteva-list-streaming flex items-center gap-3 p-4 text-neutral-500 dark:text-neutral-400", children: [
885
+ /* @__PURE__ */ jsxs2("div", { className: "apteva-streaming-dots flex gap-1", children: [
886
+ /* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "0ms" } }),
887
+ /* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "150ms" } }),
888
+ /* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "300ms" } })
889
+ ] }),
890
+ /* @__PURE__ */ jsx2("span", { className: "text-sm", children: "Loading more..." })
891
+ ] })
892
+ ] });
764
893
  }
765
894
 
766
895
  // src/components/Widgets/widget-library/Button.tsx
@@ -839,9 +968,33 @@ function ButtonGroup({ widget, onAction }) {
839
968
  }
840
969
 
841
970
  // src/components/Widgets/widget-library/Table.tsx
971
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
842
972
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
843
973
  function Table({ widget, onAction }) {
844
974
  const { columns, rows, caption, compact = false, striped = false } = widget.props;
975
+ const isStreaming = widget.isStreaming ?? false;
976
+ const seenRowsRef = useRef2(/* @__PURE__ */ new Set());
977
+ const [newRowIds, setNewRowIds] = useState2(/* @__PURE__ */ new Set());
978
+ useEffect2(() => {
979
+ const newIds = /* @__PURE__ */ new Set();
980
+ rows.forEach((row, index) => {
981
+ const rowId = row.id || `row-${index}`;
982
+ if (!seenRowsRef.current.has(rowId)) {
983
+ newIds.add(rowId);
984
+ }
985
+ });
986
+ rows.forEach((row, index) => {
987
+ const rowId = row.id || `row-${index}`;
988
+ seenRowsRef.current.add(rowId);
989
+ });
990
+ if (newIds.size > 0) {
991
+ setNewRowIds(newIds);
992
+ const timer = setTimeout(() => {
993
+ setNewRowIds(/* @__PURE__ */ new Set());
994
+ }, 500);
995
+ return () => clearTimeout(timer);
996
+ }
997
+ }, [rows]);
845
998
  const getAlignment = (align) => {
846
999
  switch (align) {
847
1000
  case "center":
@@ -868,58 +1021,78 @@ function Table({ widget, onAction }) {
868
1021
  column.key
869
1022
  )) }) }),
870
1023
  /* @__PURE__ */ jsxs3("tbody", { children: [
871
- rows.map((row, rowIndex) => /* @__PURE__ */ jsx5(
872
- "tr",
873
- {
874
- className: cn(
875
- "border-b border-neutral-200 dark:border-neutral-700 last:border-b-0",
876
- "transition-colors hover:bg-neutral-50 dark:hover:bg-neutral-800",
877
- striped && rowIndex % 2 === 1 && "bg-neutral-50/50 dark:bg-neutral-800/50"
878
- ),
879
- onClick: () => {
880
- if (widget.actions && widget.actions.length > 0) {
881
- onAction?.({
882
- type: widget.actions[0].type,
883
- payload: row,
884
- widgetId: widget.id,
885
- timestamp: /* @__PURE__ */ new Date()
886
- });
887
- }
888
- },
889
- style: { cursor: widget.actions?.length ? "pointer" : "default" },
890
- children: columns.map((column) => /* @__PURE__ */ jsx5(
891
- "td",
892
- {
893
- className: cn(
894
- "text-neutral-700 dark:text-neutral-300",
895
- compact ? "px-3 py-2 text-xs" : "px-4 py-3 text-sm",
896
- getAlignment(column.align)
897
- ),
898
- children: row[column.key] ?? "\u2014"
1024
+ rows.map((row, rowIndex) => {
1025
+ const rowId = row.id || `row-${rowIndex}`;
1026
+ const isNew = newRowIds.has(rowId);
1027
+ return /* @__PURE__ */ jsx5(
1028
+ "tr",
1029
+ {
1030
+ className: cn(
1031
+ "apteva-table-row border-b border-neutral-200 dark:border-neutral-700 last:border-b-0",
1032
+ "transition-colors hover:bg-neutral-50 dark:hover:bg-neutral-800",
1033
+ striped && rowIndex % 2 === 1 && "bg-neutral-50/50 dark:bg-neutral-800/50",
1034
+ isNew && "apteva-table-row-new"
1035
+ ),
1036
+ onClick: () => {
1037
+ if (widget.actions && widget.actions.length > 0) {
1038
+ onAction?.({
1039
+ type: widget.actions[0].type,
1040
+ payload: row,
1041
+ widgetId: widget.id,
1042
+ timestamp: /* @__PURE__ */ new Date()
1043
+ });
1044
+ }
899
1045
  },
900
- column.key
901
- ))
902
- },
903
- row.id || rowIndex
904
- )),
905
- rows.length === 0 && /* @__PURE__ */ jsx5("tr", { children: /* @__PURE__ */ jsx5(
1046
+ style: { cursor: widget.actions?.length ? "pointer" : "default" },
1047
+ children: columns.map((column) => /* @__PURE__ */ jsx5(
1048
+ "td",
1049
+ {
1050
+ className: cn(
1051
+ "text-neutral-700 dark:text-neutral-300",
1052
+ compact ? "px-3 py-2 text-xs" : "px-4 py-3 text-sm",
1053
+ getAlignment(column.align)
1054
+ ),
1055
+ children: row[column.key] ?? "\u2014"
1056
+ },
1057
+ column.key
1058
+ ))
1059
+ },
1060
+ rowId
1061
+ );
1062
+ }),
1063
+ rows.length === 0 && !isStreaming && /* @__PURE__ */ jsx5("tr", { children: /* @__PURE__ */ jsx5(
906
1064
  "td",
907
1065
  {
908
- colSpan: columns.length,
1066
+ colSpan: columns.length || 1,
909
1067
  className: "px-4 py-8 text-center text-sm text-neutral-500 dark:text-neutral-400",
910
1068
  children: "No data available"
911
1069
  }
1070
+ ) }),
1071
+ isStreaming && /* @__PURE__ */ jsx5("tr", { className: "apteva-table-streaming", children: /* @__PURE__ */ jsx5(
1072
+ "td",
1073
+ {
1074
+ colSpan: columns.length || 1,
1075
+ className: "px-4 py-3 text-center",
1076
+ children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-center gap-3 text-neutral-500 dark:text-neutral-400", children: [
1077
+ /* @__PURE__ */ jsxs3("div", { className: "flex gap-1", children: [
1078
+ /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "0ms" } }),
1079
+ /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "150ms" } }),
1080
+ /* @__PURE__ */ jsx5("span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "300ms" } })
1081
+ ] }),
1082
+ /* @__PURE__ */ jsx5("span", { className: "text-sm", children: "Loading more..." })
1083
+ ] })
1084
+ }
912
1085
  ) })
913
1086
  ] })
914
1087
  ] }) }) });
915
1088
  }
916
1089
 
917
1090
  // src/components/Widgets/widget-library/Form.tsx
918
- import { useState } from "react";
1091
+ import { useState as useState3 } from "react";
919
1092
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
920
1093
  function Form({ widget, onAction }) {
921
1094
  const { title, fields } = widget.props;
922
- const [formData, setFormData] = useState(() => {
1095
+ const [formData, setFormData] = useState3(() => {
923
1096
  const initial = {};
924
1097
  fields.forEach((field) => {
925
1098
  initial[field.name] = field.defaultValue ?? (field.type === "checkbox" ? false : "");
@@ -1069,7 +1242,7 @@ function Widgets({
1069
1242
  columns = 3,
1070
1243
  className
1071
1244
  }) {
1072
- useEffect(() => {
1245
+ useEffect3(() => {
1073
1246
  widgets.forEach((widget) => {
1074
1247
  onWidgetMount?.(widget.id);
1075
1248
  });
@@ -1345,14 +1518,39 @@ function MarkdownContent({ content, className = "" }) {
1345
1518
 
1346
1519
  // src/components/Chat/ToolCall.tsx
1347
1520
  import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1348
- function ToolCall({ name, status }) {
1521
+ function ToolCall({ name, status, isReceiving = false }) {
1522
+ if (status === "preparing") {
1523
+ return /* @__PURE__ */ jsxs8("div", { className: `apteva-tool-card apteva-tool-card-preparing ${isReceiving ? "apteva-tool-receiving" : ""}`, children: [
1524
+ /* @__PURE__ */ jsxs8("svg", { className: "apteva-tool-icon apteva-tool-icon-spin", fill: "none", viewBox: "0 0 24 24", children: [
1525
+ /* @__PURE__ */ jsx11("circle", { className: "apteva-tool-spinner-track", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1526
+ /* @__PURE__ */ jsx11("path", { className: "apteva-tool-spinner-fill", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
1527
+ ] }),
1528
+ /* @__PURE__ */ jsxs8("span", { className: "apteva-tool-label", children: [
1529
+ /* @__PURE__ */ jsx11("strong", { children: name }),
1530
+ /* @__PURE__ */ jsx11("span", { className: "apteva-tool-status-text", children: " preparing" }),
1531
+ /* @__PURE__ */ jsxs8("span", { className: "apteva-tool-dots", children: [
1532
+ /* @__PURE__ */ jsx11("span", { children: "." }),
1533
+ /* @__PURE__ */ jsx11("span", { children: "." }),
1534
+ /* @__PURE__ */ jsx11("span", { children: "." })
1535
+ ] })
1536
+ ] })
1537
+ ] });
1538
+ }
1349
1539
  if (status === "running") {
1350
1540
  return /* @__PURE__ */ jsxs8("div", { className: "apteva-tool-card apteva-tool-card-running", children: [
1351
1541
  /* @__PURE__ */ jsxs8("svg", { className: "apteva-tool-icon apteva-tool-icon-spin", fill: "none", viewBox: "0 0 24 24", children: [
1352
1542
  /* @__PURE__ */ jsx11("circle", { className: "apteva-tool-spinner-track", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1353
1543
  /* @__PURE__ */ jsx11("path", { className: "apteva-tool-spinner-fill", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
1354
1544
  ] }),
1355
- /* @__PURE__ */ jsx11("span", { className: "apteva-tool-label", children: name })
1545
+ /* @__PURE__ */ jsxs8("span", { className: "apteva-tool-label", children: [
1546
+ /* @__PURE__ */ jsx11("strong", { children: name }),
1547
+ /* @__PURE__ */ jsx11("span", { className: "apteva-tool-status-text", children: " running" }),
1548
+ /* @__PURE__ */ jsxs8("span", { className: "apteva-tool-dots", children: [
1549
+ /* @__PURE__ */ jsx11("span", { children: "." }),
1550
+ /* @__PURE__ */ jsx11("span", { children: "." }),
1551
+ /* @__PURE__ */ jsx11("span", { children: "." })
1552
+ ] })
1553
+ ] })
1356
1554
  ] });
1357
1555
  }
1358
1556
  if (status === "completed") {
@@ -1377,7 +1575,7 @@ function Message({ message, onAction, enableWidgets, onWidgetRender }) {
1377
1575
  const contentSegments = message.metadata?.content_segments;
1378
1576
  const isStreaming = message.metadata?.isStreaming === true;
1379
1577
  const hasContent = message.content || contentSegments && contentSegments.length > 0;
1380
- const reportedWidgetsRef = useRef(/* @__PURE__ */ new Set());
1578
+ const reportedWidgetsRef = useRef3(/* @__PURE__ */ new Set());
1381
1579
  const parsedWidgets = useMemo(() => {
1382
1580
  if (!enableWidgets || isUser || !message.content) {
1383
1581
  return [];
@@ -1385,7 +1583,7 @@ function Message({ message, onAction, enableWidgets, onWidgetRender }) {
1385
1583
  const parsed = parseWidgetsFromText(message.content);
1386
1584
  return parsed.segments.filter((seg) => seg.type === "widget" && !!seg.widget).map((seg) => seg.widget);
1387
1585
  }, [enableWidgets, isUser, message.content]);
1388
- useEffect2(() => {
1586
+ useEffect4(() => {
1389
1587
  if (onWidgetRender && message.widgets) {
1390
1588
  for (const widget of message.widgets) {
1391
1589
  if (!reportedWidgetsRef.current.has(widget.id)) {
@@ -1395,7 +1593,7 @@ function Message({ message, onAction, enableWidgets, onWidgetRender }) {
1395
1593
  }
1396
1594
  }
1397
1595
  }, [message.widgets, onWidgetRender]);
1398
- useEffect2(() => {
1596
+ useEffect4(() => {
1399
1597
  if (onWidgetRender && parsedWidgets.length > 0) {
1400
1598
  for (const widget of parsedWidgets) {
1401
1599
  if (!reportedWidgetsRef.current.has(widget.id)) {
@@ -1566,7 +1764,8 @@ function Message({ message, onAction, enableWidgets, onWidgetRender }) {
1566
1764
  ToolCall,
1567
1765
  {
1568
1766
  name: segment.name,
1569
- status: segment.result !== void 0 ? "completed" : "running"
1767
+ status: segment.status || (segment.result !== void 0 ? "completed" : "running"),
1768
+ isReceiving: segment.isReceiving
1570
1769
  }
1571
1770
  ) }, segment.id)
1572
1771
  );
@@ -1767,16 +1966,16 @@ function MessageList({
1767
1966
  enableWidgets,
1768
1967
  onWidgetRender
1769
1968
  }) {
1770
- const listRef = useRef2(null);
1771
- const isNearBottomRef = useRef2(true);
1772
- const lastScrollHeightRef = useRef2(0);
1969
+ const listRef = useRef4(null);
1970
+ const isNearBottomRef = useRef4(true);
1971
+ const lastScrollHeightRef = useRef4(0);
1773
1972
  const handleScroll = () => {
1774
1973
  if (listRef.current) {
1775
1974
  const { scrollTop, scrollHeight, clientHeight } = listRef.current;
1776
1975
  isNearBottomRef.current = scrollHeight - scrollTop - clientHeight < 100;
1777
1976
  }
1778
1977
  };
1779
- useEffect3(() => {
1978
+ useEffect5(() => {
1780
1979
  if (listRef.current && isNearBottomRef.current) {
1781
1980
  const currentScrollHeight = listRef.current.scrollHeight;
1782
1981
  if (currentScrollHeight !== lastScrollHeightRef.current) {
@@ -1800,16 +1999,16 @@ function MessageList({
1800
1999
  }
1801
2000
 
1802
2001
  // src/components/Chat/Composer.tsx
1803
- import { useState as useState2, useRef as useRef3 } from "react";
2002
+ import { useState as useState4, useRef as useRef5 } from "react";
1804
2003
  import { Fragment, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1805
2004
  function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false, isLoading = false, onStop, onFileUpload, onSwitchMode }) {
1806
- const [text, setText] = useState2("");
1807
- const [showMenu, setShowMenu] = useState2(false);
1808
- const [pendingFiles, setPendingFiles] = useState2([]);
1809
- const [fileError, setFileError] = useState2(null);
1810
- const textareaRef = useRef3(null);
1811
- const fileInputRef = useRef3(null);
1812
- const menuButtonRef = useRef3(null);
2005
+ const [text, setText] = useState4("");
2006
+ const [showMenu, setShowMenu] = useState4(false);
2007
+ const [pendingFiles, setPendingFiles] = useState4([]);
2008
+ const [fileError, setFileError] = useState4(null);
2009
+ const textareaRef = useRef5(null);
2010
+ const fileInputRef = useRef5(null);
2011
+ const menuButtonRef = useRef5(null);
1813
2012
  const handleKeyDown = (e) => {
1814
2013
  if (e.key === "Enter" && !e.shiftKey) {
1815
2014
  e.preventDefault();
@@ -2013,7 +2212,7 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
2013
2212
  }
2014
2213
 
2015
2214
  // src/components/Chat/CommandComposer.tsx
2016
- import { useState as useState3, useRef as useRef4 } from "react";
2215
+ import { useState as useState5, useRef as useRef6 } from "react";
2017
2216
  import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
2018
2217
  function CommandComposer({
2019
2218
  onExecute,
@@ -2031,13 +2230,13 @@ function CommandComposer({
2031
2230
  placeholder = "Enter your command...",
2032
2231
  disabled = false
2033
2232
  }) {
2034
- const [input, setInput] = useState3("");
2035
- const [pendingFiles, setPendingFiles] = useState3([]);
2036
- const [fileError, setFileError] = useState3(null);
2037
- const [showMenu, setShowMenu] = useState3(false);
2038
- const inputRef = useRef4(null);
2039
- const fileInputRef = useRef4(null);
2040
- const menuButtonRef = useRef4(null);
2233
+ const [input, setInput] = useState5("");
2234
+ const [pendingFiles, setPendingFiles] = useState5([]);
2235
+ const [fileError, setFileError] = useState5(null);
2236
+ const [showMenu, setShowMenu] = useState5(false);
2237
+ const inputRef = useRef6(null);
2238
+ const fileInputRef = useRef6(null);
2239
+ const menuButtonRef = useRef6(null);
2041
2240
  const handleSubmit = () => {
2042
2241
  const hasText = input.trim();
2043
2242
  const hasFiles = pendingFiles.length > 0;
@@ -2566,25 +2765,25 @@ var Chat = forwardRef(function Chat2({
2566
2765
  onWidgetRender,
2567
2766
  className
2568
2767
  }, ref) {
2569
- const [messages, setMessages] = useState4(initialMessages);
2570
- const [isLoading, setIsLoading] = useState4(false);
2571
- const [currentThreadId, setCurrentThreadId] = useState4(threadId || null);
2572
- const [mode, setMode] = useState4(initialMode);
2573
- const [chatToolName, setChatToolName] = useState4(null);
2574
- const [commandState, setCommandState] = useState4("idle");
2575
- const [commandResult, setCommandResult] = useState4(null);
2576
- const [commandError, setCommandError] = useState4(null);
2577
- const [progress, setProgress] = useState4(0);
2578
- const [commandInput, setCommandInput] = useState4("");
2579
- const [streamedContent, setStreamedContent] = useState4("");
2580
- const [currentToolName, setCurrentToolName] = useState4(null);
2581
- const [currentRequestId, setCurrentRequestId] = useState4(null);
2582
- const [plan, setPlan] = useState4("");
2583
- const [pendingCommand, setPendingCommand] = useState4("");
2584
- const [internalPlanMode, setInternalPlanMode] = useState4(planMode);
2585
- const [showSettingsMenu, setShowSettingsMenu] = useState4(false);
2586
- const fileInputRef = useRef5(null);
2587
- const handleSendMessageRef = useRef5(null);
2768
+ const [messages, setMessages] = useState6(initialMessages);
2769
+ const [isLoading, setIsLoading] = useState6(false);
2770
+ const [currentThreadId, setCurrentThreadId] = useState6(threadId || null);
2771
+ const [mode, setMode] = useState6(initialMode);
2772
+ const [chatToolName, setChatToolName] = useState6(null);
2773
+ const [commandState, setCommandState] = useState6("idle");
2774
+ const [commandResult, setCommandResult] = useState6(null);
2775
+ const [commandError, setCommandError] = useState6(null);
2776
+ const [progress, setProgress] = useState6(0);
2777
+ const [commandInput, setCommandInput] = useState6("");
2778
+ const [streamedContent, setStreamedContent] = useState6("");
2779
+ const [currentToolName, setCurrentToolName] = useState6(null);
2780
+ const [currentRequestId, setCurrentRequestId] = useState6(null);
2781
+ const [plan, setPlan] = useState6("");
2782
+ const [pendingCommand, setPendingCommand] = useState6("");
2783
+ const [internalPlanMode, setInternalPlanMode] = useState6(planMode);
2784
+ const [showSettingsMenu, setShowSettingsMenu] = useState6(false);
2785
+ const fileInputRef = useRef7(null);
2786
+ const handleSendMessageRef = useRef7(null);
2588
2787
  useImperativeHandle(ref, () => ({
2589
2788
  sendMessage: async (text) => {
2590
2789
  if (handleSendMessageRef.current) {
@@ -2605,7 +2804,7 @@ var Chat = forwardRef(function Chat2({
2605
2804
  return context ? `${context}
2606
2805
  ${widgetContext}` : widgetContext;
2607
2806
  }, [context, enableWidgets, availableWidgets, compactWidgetContext]);
2608
- useEffect4(() => {
2807
+ useEffect6(() => {
2609
2808
  if (apiUrl || apiKey) {
2610
2809
  aptevaClient.configure({
2611
2810
  ...apiUrl && { apiUrl },
@@ -2613,15 +2812,15 @@ ${widgetContext}` : widgetContext;
2613
2812
  });
2614
2813
  }
2615
2814
  }, [apiUrl, apiKey]);
2616
- useEffect4(() => {
2815
+ useEffect6(() => {
2617
2816
  if (threadId) {
2618
2817
  onThreadChange?.(threadId);
2619
2818
  }
2620
2819
  }, [threadId, onThreadChange]);
2621
- useEffect4(() => {
2820
+ useEffect6(() => {
2622
2821
  setInternalPlanMode(planMode);
2623
2822
  }, [planMode]);
2624
- useEffect4(() => {
2823
+ useEffect6(() => {
2625
2824
  const handleClickOutside = (event) => {
2626
2825
  const target = event.target;
2627
2826
  if (showSettingsMenu && !target.closest(".settings-menu-container")) {
@@ -2672,6 +2871,7 @@ ${widgetContext}` : widgetContext;
2672
2871
  let accumulatedWidgets = [];
2673
2872
  let responseThreadId = currentThreadId;
2674
2873
  let toolInputBuffer = "";
2874
+ let receivingTimeout = null;
2675
2875
  const streamingMessageId = `msg-${Date.now()}`;
2676
2876
  const updateMessage = () => {
2677
2877
  const segments = [...contentSegments];
@@ -2748,7 +2948,7 @@ ${widgetContext}` : widgetContext;
2748
2948
  contentSegments.push({ type: "text", content: currentTextBuffer });
2749
2949
  currentTextBuffer = "";
2750
2950
  }
2751
- contentSegments.push({ type: "tool", id: chunk.tool_id, name: displayName });
2951
+ contentSegments.push({ type: "tool", id: chunk.tool_id, name: displayName, status: "preparing" });
2752
2952
  toolInputBuffer = "";
2753
2953
  setChatToolName(displayName);
2754
2954
  onToolCall?.(chunk.tool_name, chunk.tool_id);
@@ -2758,6 +2958,28 @@ ${widgetContext}` : widgetContext;
2758
2958
  case "tool_input_delta":
2759
2959
  if (chunk.tool_id && chunk.content) {
2760
2960
  toolInputBuffer += chunk.content;
2961
+ const toolSegment = contentSegments.find((s) => s.type === "tool" && s.id === chunk.tool_id);
2962
+ if (toolSegment) {
2963
+ toolSegment.isReceiving = true;
2964
+ updateMessage();
2965
+ if (receivingTimeout) clearTimeout(receivingTimeout);
2966
+ receivingTimeout = setTimeout(() => {
2967
+ if (toolSegment.status === "preparing") {
2968
+ toolSegment.isReceiving = false;
2969
+ updateMessage();
2970
+ }
2971
+ }, 150);
2972
+ }
2973
+ }
2974
+ break;
2975
+ case "tool_use":
2976
+ if (chunk.tool_id) {
2977
+ const toolSegment = contentSegments.find((s) => s.type === "tool" && s.id === chunk.tool_id);
2978
+ if (toolSegment && toolSegment.status === "preparing") {
2979
+ toolSegment.status = "running";
2980
+ toolSegment.isReceiving = false;
2981
+ updateMessage();
2982
+ }
2761
2983
  }
2762
2984
  break;
2763
2985
  case "tool_result":
@@ -2765,6 +2987,8 @@ ${widgetContext}` : widgetContext;
2765
2987
  const toolSegment = contentSegments.find((s) => s.type === "tool" && s.id === chunk.tool_id);
2766
2988
  if (toolSegment) {
2767
2989
  toolSegment.result = chunk.content;
2990
+ toolSegment.status = "completed";
2991
+ toolSegment.isReceiving = false;
2768
2992
  onToolResult?.(toolSegment.name, chunk.content);
2769
2993
  }
2770
2994
  setChatToolName(null);
@@ -3153,11 +3377,11 @@ ${planToExecute}`;
3153
3377
  });
3154
3378
 
3155
3379
  // src/components/Chat/CommandOutput.tsx
3156
- import { useState as useState5 } from "react";
3380
+ import { useState as useState7 } from "react";
3157
3381
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
3158
3382
 
3159
3383
  // src/components/Command/Command.tsx
3160
- import React, { useState as useState6, useEffect as useEffect5 } from "react";
3384
+ import React, { useState as useState8, useEffect as useEffect7 } from "react";
3161
3385
  import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
3162
3386
  function Command({
3163
3387
  agentId,
@@ -3185,28 +3409,28 @@ function Command({
3185
3409
  resultRenderer,
3186
3410
  className
3187
3411
  }) {
3188
- const [state, setState] = useState6("idle");
3189
- const [result, setResult] = useState6(null);
3190
- const [error, setError] = useState6(null);
3191
- const [progress, setProgress] = useState6(0);
3192
- const [command, setCommand] = useState6(initialCommand || "");
3193
- const [streamedContent, setStreamedContent] = useState6("");
3194
- const [plan, setPlan] = useState6("");
3195
- const [pendingCommand, setPendingCommand] = useState6("");
3196
- const [showPlanDetails, setShowPlanDetails] = useState6(false);
3197
- const [uploadedFiles, setUploadedFiles] = useState6([]);
3198
- const [showSettingsMenu, setShowSettingsMenu] = useState6(false);
3199
- const [internalPlanMode, setInternalPlanMode] = useState6(planMode);
3412
+ const [state, setState] = useState8("idle");
3413
+ const [result, setResult] = useState8(null);
3414
+ const [error, setError] = useState8(null);
3415
+ const [progress, setProgress] = useState8(0);
3416
+ const [command, setCommand] = useState8(initialCommand || "");
3417
+ const [streamedContent, setStreamedContent] = useState8("");
3418
+ const [plan, setPlan] = useState8("");
3419
+ const [pendingCommand, setPendingCommand] = useState8("");
3420
+ const [showPlanDetails, setShowPlanDetails] = useState8(false);
3421
+ const [uploadedFiles, setUploadedFiles] = useState8([]);
3422
+ const [showSettingsMenu, setShowSettingsMenu] = useState8(false);
3423
+ const [internalPlanMode, setInternalPlanMode] = useState8(planMode);
3200
3424
  const fileInputRef = React.useRef(null);
3201
- useEffect5(() => {
3425
+ useEffect7(() => {
3202
3426
  if (autoExecute && state === "idle" && command) {
3203
3427
  executeCommand();
3204
3428
  }
3205
3429
  }, [autoExecute]);
3206
- useEffect5(() => {
3430
+ useEffect7(() => {
3207
3431
  setInternalPlanMode(planMode);
3208
3432
  }, [planMode]);
3209
- useEffect5(() => {
3433
+ useEffect7(() => {
3210
3434
  const handleClickOutside = (event) => {
3211
3435
  const target = event.target;
3212
3436
  if (showSettingsMenu && !target.closest(".settings-menu-container")) {
@@ -4128,7 +4352,7 @@ ${planToExecute}`;
4128
4352
  }
4129
4353
 
4130
4354
  // src/components/Prompt/Prompt.tsx
4131
- import { useState as useState7 } from "react";
4355
+ import { useState as useState9 } from "react";
4132
4356
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
4133
4357
  function Prompt({
4134
4358
  agentId,
@@ -4146,9 +4370,9 @@ function Prompt({
4146
4370
  showSuggestions = false,
4147
4371
  className
4148
4372
  }) {
4149
- const [value, setValue] = useState7(initialValue);
4150
- const [isLoading, setIsLoading] = useState7(false);
4151
- const [suggestions] = useState7(["Plan a trip", "Write a description", "Analyze data"]);
4373
+ const [value, setValue] = useState9(initialValue);
4374
+ const [isLoading, setIsLoading] = useState9(false);
4375
+ const [suggestions] = useState9(["Plan a trip", "Write a description", "Analyze data"]);
4152
4376
  const handleChange = (e) => {
4153
4377
  const newValue = e.target.value;
4154
4378
  if (!maxLength || newValue.length <= maxLength) {
@@ -4239,7 +4463,7 @@ function Prompt({
4239
4463
  }
4240
4464
 
4241
4465
  // src/components/Stream/Stream.tsx
4242
- import { useState as useState8, useEffect as useEffect6 } from "react";
4466
+ import { useState as useState10, useEffect as useEffect8 } from "react";
4243
4467
  import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
4244
4468
  function Stream({
4245
4469
  agentId,
@@ -4256,10 +4480,10 @@ function Stream({
4256
4480
  typingSpeed = 30,
4257
4481
  className
4258
4482
  }) {
4259
- const [text, setText] = useState8("");
4260
- const [isStreaming, setIsStreaming] = useState8(false);
4261
- const [isComplete, setIsComplete] = useState8(false);
4262
- useEffect6(() => {
4483
+ const [text, setText] = useState10("");
4484
+ const [isStreaming, setIsStreaming] = useState10(false);
4485
+ const [isComplete, setIsComplete] = useState10(false);
4486
+ useEffect8(() => {
4263
4487
  if (autoStart && !isStreaming && !isComplete) {
4264
4488
  startStreaming();
4265
4489
  }
@@ -4336,7 +4560,7 @@ function Stream({
4336
4560
  }
4337
4561
 
4338
4562
  // src/components/Threads/ThreadList.tsx
4339
- import { useState as useState9 } from "react";
4563
+ import { useState as useState11 } from "react";
4340
4564
 
4341
4565
  // src/components/Threads/ThreadItem.tsx
4342
4566
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
@@ -4400,7 +4624,7 @@ function ThreadList({
4400
4624
  showSearch = false,
4401
4625
  groupBy = "none"
4402
4626
  }) {
4403
- const [searchQuery, setSearchQuery] = useState9("");
4627
+ const [searchQuery, setSearchQuery] = useState11("");
4404
4628
  const filteredThreads = threads.filter(
4405
4629
  (thread) => thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || thread.preview?.toLowerCase().includes(searchQuery.toLowerCase())
4406
4630
  );