@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.js +237 -101
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +187 -51
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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-${
|
|
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
|
|
1100
|
+
const inlineRegex = /!\[([^\]]*)\]\(([^)]+)\)|\[([^\]]+)\]\(([^)]+)\)|(\*\*|__)(.+?)\5|`([^`]+)`/g;
|
|
1085
1101
|
let lastIndex = 0;
|
|
1086
1102
|
let match;
|
|
1087
1103
|
let key = 0;
|
|
1088
|
-
while ((match =
|
|
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
|
-
|
|
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
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
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 ? "
|
|
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
|
|
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 =
|
|
1441
|
-
|
|
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
|
|
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 =
|
|
1469
|
-
const fileInputRef =
|
|
1470
|
-
const menuButtonRef =
|
|
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
|
|
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 =
|
|
1698
|
-
const fileInputRef =
|
|
1699
|
-
const menuButtonRef =
|
|
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 =
|
|
2244
|
-
const effectiveContext =
|
|
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
|
-
|
|
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
|
-
|
|
2383
|
+
useEffect4(() => {
|
|
2259
2384
|
if (threadId) {
|
|
2260
2385
|
onThreadChange?.(threadId);
|
|
2261
2386
|
}
|
|
2262
2387
|
}, [threadId, onThreadChange]);
|
|
2263
|
-
|
|
2388
|
+
useEffect4(() => {
|
|
2264
2389
|
setInternalPlanMode(planMode);
|
|
2265
2390
|
}, [planMode]);
|
|
2266
|
-
|
|
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:
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
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
|
-
|
|
2957
|
+
useEffect5(() => {
|
|
2822
2958
|
if (autoExecute && state === "idle" && command) {
|
|
2823
2959
|
executeCommand();
|
|
2824
2960
|
}
|
|
2825
2961
|
}, [autoExecute]);
|
|
2826
|
-
|
|
2962
|
+
useEffect5(() => {
|
|
2827
2963
|
setInternalPlanMode(planMode);
|
|
2828
2964
|
}, [planMode]);
|
|
2829
|
-
|
|
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
|
|
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
|
-
|
|
4018
|
+
useEffect6(() => {
|
|
3883
4019
|
if (autoStart && !isStreaming && !isComplete) {
|
|
3884
4020
|
startStreaming();
|
|
3885
4021
|
}
|