@yieldfabric/terminal 1.0.0 → 1.1.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.
- package/LICENSE.md +293 -0
- package/NOTICE.md +28 -0
- package/README.md +78 -9
- package/dist/index.cjs +1391 -775
- package/dist/index.d.cts +244 -4
- package/dist/index.d.ts +244 -4
- package/dist/index.js +959 -350
- package/package.json +18 -8
package/dist/index.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) 2026 YieldFabric Technologies Ltd, DIFC, UAE.
|
|
4
|
+
* All rights reserved. Proprietary and confidential.
|
|
5
|
+
* Source review requires written authorization; see package LICENSE.md and NOTICE.md.
|
|
6
|
+
* Runtime use requires a separate express license.
|
|
7
|
+
*/
|
|
8
|
+
import React15, { createContext, memo, useMemo, useRef, useEffect, useCallback, useContext, useState, useReducer } from 'react';
|
|
3
9
|
import { X, Check, Plus, FileText, MessageCircle, ChevronRight, Paperclip, FolderOpen, Brain, XCircle, Loader2, Minimize2, Maximize2, AlertTriangle, HelpCircle, ChevronLeft, Pencil, ChevronDown, ExternalLink, Search, Network, Boxes, Settings, Terminal, CheckCircle, ArrowRight, Users, Eye, AlertCircle, CheckCircle2, Copy, Zap, Download, Trash2, Link2 } from 'lucide-react';
|
|
4
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
11
|
import ReactMarkdown from 'react-markdown';
|
|
12
|
+
import remarkGfm from 'remark-gfm';
|
|
6
13
|
import { createAvatar } from '@dicebear/core';
|
|
7
14
|
import { avataaars } from '@dicebear/collection';
|
|
8
15
|
import { motion } from 'framer-motion';
|
|
@@ -68,6 +75,7 @@ var BUILT_IN_COMMANDS = [
|
|
|
68
75
|
{ id: "files", label: "/files", description: "List uploaded files for this page working group", category: "built-in" },
|
|
69
76
|
{ id: "ask", label: "/ask", description: "Ask the AI assistant for analysis (streaming)", category: "built-in" },
|
|
70
77
|
{ id: "note", label: "/note", description: "Save a free-form note in this workspace. Type @name to link an entity.", category: "built-in" },
|
|
78
|
+
{ id: "log", label: "/log", description: "Capture what you did or decided as a work item on this workspace\u2019s board.", category: "built-in" },
|
|
71
79
|
{ id: "personal", label: "/personal", description: "Save a free-form note in your personal notebook (visible only to you, even from a team workspace).", category: "built-in" }
|
|
72
80
|
];
|
|
73
81
|
function getBuiltInCommands() {
|
|
@@ -89,23 +97,45 @@ function processStreamLines(buffer, onJsonLine) {
|
|
|
89
97
|
for (const line of lines) {
|
|
90
98
|
const trimmed = line.trim();
|
|
91
99
|
if (!trimmed) continue;
|
|
92
|
-
if (trimmed.startsWith("data:
|
|
93
|
-
const jsonStr = trimmed.substring(
|
|
100
|
+
if (trimmed.startsWith("data:")) {
|
|
101
|
+
const jsonStr = trimmed.substring(5).trimStart();
|
|
102
|
+
let parsed2;
|
|
94
103
|
try {
|
|
95
|
-
|
|
104
|
+
parsed2 = JSON.parse(jsonStr);
|
|
96
105
|
} catch {
|
|
106
|
+
continue;
|
|
97
107
|
}
|
|
108
|
+
onJsonLine(parsed2);
|
|
98
109
|
continue;
|
|
99
110
|
}
|
|
100
111
|
if (trimmed.startsWith(":")) continue;
|
|
112
|
+
let parsed;
|
|
101
113
|
try {
|
|
102
|
-
|
|
114
|
+
parsed = JSON.parse(trimmed);
|
|
103
115
|
} catch {
|
|
116
|
+
continue;
|
|
104
117
|
}
|
|
118
|
+
onJsonLine(parsed);
|
|
105
119
|
}
|
|
106
120
|
return remainder;
|
|
107
121
|
}
|
|
108
122
|
|
|
123
|
+
// src/utils/streamStall.ts
|
|
124
|
+
var SSE_KEEPALIVE_MS = 15e3;
|
|
125
|
+
var SSE_STALL_MS = SSE_KEEPALIVE_MS * 3;
|
|
126
|
+
async function withStallTimeout(work, ms = SSE_STALL_MS, sleep = (d) => new Promise((wake) => setTimeout(wake, d))) {
|
|
127
|
+
let done = false;
|
|
128
|
+
const settled = work.then((value) => {
|
|
129
|
+
done = true;
|
|
130
|
+
return value;
|
|
131
|
+
});
|
|
132
|
+
const stalled = sleep(ms).then(() => {
|
|
133
|
+
if (!done) throw new Error("the connection went quiet");
|
|
134
|
+
return void 0;
|
|
135
|
+
});
|
|
136
|
+
return Promise.race([settled, stalled]);
|
|
137
|
+
}
|
|
138
|
+
|
|
109
139
|
// src/utils/streamingHandler.ts
|
|
110
140
|
async function handleStreamingResponse(url, requestBody, onChunk, onComplete, onError) {
|
|
111
141
|
try {
|
|
@@ -147,6 +177,14 @@ async function handleStreamingResponse(url, requestBody, onChunk, onComplete, on
|
|
|
147
177
|
var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) => {
|
|
148
178
|
const signal = options?.signal;
|
|
149
179
|
const method = options?.method || "POST";
|
|
180
|
+
const stallMs = options?.stallMs ?? SSE_STALL_MS;
|
|
181
|
+
const stallAbort = new AbortController();
|
|
182
|
+
const abortFromCaller = () => stallAbort.abort();
|
|
183
|
+
let reader;
|
|
184
|
+
if (signal) {
|
|
185
|
+
if (signal.aborted) stallAbort.abort();
|
|
186
|
+
else signal.addEventListener("abort", abortFromCaller, { once: true });
|
|
187
|
+
}
|
|
150
188
|
try {
|
|
151
189
|
const requestHeaders = {
|
|
152
190
|
Accept: "text/event-stream",
|
|
@@ -154,12 +192,12 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
|
|
|
154
192
|
...method !== "GET" && method !== "HEAD" ? { "Content-Type": "application/json" } : {},
|
|
155
193
|
...options?.headers
|
|
156
194
|
};
|
|
157
|
-
const response = await fetch(url, {
|
|
195
|
+
const response = await (options?.fetcher ?? fetch)(url, {
|
|
158
196
|
method,
|
|
159
197
|
headers: requestHeaders,
|
|
160
198
|
body: method === "GET" || method === "HEAD" ? void 0 : JSON.stringify(body),
|
|
161
199
|
cache: "no-store",
|
|
162
|
-
signal
|
|
200
|
+
signal: stallAbort.signal
|
|
163
201
|
});
|
|
164
202
|
if (response.status === 410 && options?.onGone) {
|
|
165
203
|
options.onGone(await response.text());
|
|
@@ -169,19 +207,32 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
|
|
|
169
207
|
const errorText = await response.text();
|
|
170
208
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
171
209
|
}
|
|
172
|
-
|
|
210
|
+
reader = response.body?.getReader();
|
|
173
211
|
if (!reader) {
|
|
174
212
|
throw new Error("No response body reader available");
|
|
175
213
|
}
|
|
176
214
|
const decoder = new TextDecoder();
|
|
177
215
|
let buffer = "";
|
|
178
216
|
let receivedData = false;
|
|
217
|
+
let finalSeen = false;
|
|
218
|
+
let failed = false;
|
|
219
|
+
const dispatch = (chunk) => {
|
|
220
|
+
if (failed) return;
|
|
221
|
+
if (chunk.error) {
|
|
222
|
+
failed = true;
|
|
223
|
+
onError(typeof chunk.error === "string" ? chunk.error : "The assistant could not finish this answer.");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (chunk.is_final === true) finalSeen = true;
|
|
227
|
+
onChunk(chunk);
|
|
228
|
+
};
|
|
179
229
|
while (true) {
|
|
180
230
|
let readResult;
|
|
181
231
|
try {
|
|
182
|
-
readResult = await reader.read();
|
|
232
|
+
readResult = stallMs > 0 ? await withStallTimeout(reader.read(), stallMs) : await reader.read();
|
|
183
233
|
} catch (readError) {
|
|
184
234
|
if (signal?.aborted) return;
|
|
235
|
+
stallAbort.abort();
|
|
185
236
|
console.warn(
|
|
186
237
|
"SSE reader error (connection may have been interrupted):",
|
|
187
238
|
readError.message
|
|
@@ -195,16 +246,31 @@ var handleSSEStream = async (url, body, onChunk, onComplete, onError, options) =
|
|
|
195
246
|
}
|
|
196
247
|
const { done, value } = readResult;
|
|
197
248
|
if (done) {
|
|
198
|
-
|
|
249
|
+
buffer += decoder.decode();
|
|
250
|
+
if (buffer.trim()) processStreamLines(buffer + "\n", dispatch);
|
|
251
|
+
if (failed) return;
|
|
252
|
+
if ((options?.requireFinal ?? true) && !finalSeen) {
|
|
253
|
+
onError("Connection interrupted before the answer was complete. The assistant may still be working.");
|
|
254
|
+
} else onComplete();
|
|
199
255
|
break;
|
|
200
256
|
}
|
|
201
257
|
buffer += decoder.decode(value, { stream: true });
|
|
202
258
|
receivedData = true;
|
|
203
|
-
buffer = processStreamLines(buffer,
|
|
259
|
+
buffer = processStreamLines(buffer, dispatch);
|
|
260
|
+
if (failed) return;
|
|
204
261
|
}
|
|
205
262
|
} catch (error) {
|
|
206
263
|
if (signal?.aborted) return;
|
|
207
264
|
onError(error.message || "Streaming error");
|
|
265
|
+
} finally {
|
|
266
|
+
signal?.removeEventListener("abort", abortFromCaller);
|
|
267
|
+
if (reader) {
|
|
268
|
+
try {
|
|
269
|
+
await reader.cancel();
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
reader.releaseLock();
|
|
273
|
+
}
|
|
208
274
|
}
|
|
209
275
|
};
|
|
210
276
|
|
|
@@ -850,7 +916,7 @@ function ScopedReasoningProvider({
|
|
|
850
916
|
() => ({ hasOwnedKgId }),
|
|
851
917
|
[hasOwnedKgId]
|
|
852
918
|
);
|
|
853
|
-
return
|
|
919
|
+
return React15.createElement(
|
|
854
920
|
ScopedReasoningContext.Provider,
|
|
855
921
|
{ value },
|
|
856
922
|
children
|
|
@@ -1079,12 +1145,13 @@ function ShareButton({ content, title }) {
|
|
|
1079
1145
|
"button",
|
|
1080
1146
|
{
|
|
1081
1147
|
onClick: handleShare,
|
|
1082
|
-
className: "
|
|
1148
|
+
className: "inline-flex h-6 w-6 items-center justify-center rounded-md transition-all duration-200 hover:scale-110",
|
|
1083
1149
|
style: {
|
|
1084
1150
|
backgroundColor: done ? "rgba(74,222,128,0.15)" : t.bgRaisedHover,
|
|
1085
1151
|
color: done ? t.success : t.textMuted
|
|
1086
1152
|
},
|
|
1087
1153
|
title: state === "copied" ? "Copied!" : state === "shared" ? "Shared!" : "Share",
|
|
1154
|
+
"aria-label": state === "copied" ? "Link copied" : state === "shared" ? "Shared" : "Share message",
|
|
1088
1155
|
children: done ? /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M5 12l5 5L20 7" }) }) : /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1089
1156
|
/* @__PURE__ */ jsx("path", { d: "M4 12v7a2 2 0 002 2h12a2 2 0 002-2v-7" }),
|
|
1090
1157
|
/* @__PURE__ */ jsx("polyline", { points: "16 6 12 2 8 6" }),
|
|
@@ -1093,11 +1160,30 @@ function ShareButton({ content, title }) {
|
|
|
1093
1160
|
}
|
|
1094
1161
|
);
|
|
1095
1162
|
}
|
|
1163
|
+
|
|
1164
|
+
// src/utils/stripInternalIds.ts
|
|
1165
|
+
var UUID = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
|
|
1166
|
+
var PREFIXED = `(?:KG|DOC|FRAME|SET|NODE|CHUNK):${UUID}`;
|
|
1167
|
+
var WRAP = "[*_`]*";
|
|
1168
|
+
var PAREN_PREFIXED = new RegExp(`\\s*\\(\\s*${WRAP}${PREFIXED}${WRAP}\\s*\\)`, "g");
|
|
1169
|
+
var PAREN_BARE = new RegExp(`\\s*\\(\\s*${WRAP}${UUID}${WRAP}\\s*\\)`, "g");
|
|
1170
|
+
var BARE_PREFIXED = new RegExp(`${WRAP}${PREFIXED}${WRAP}`, "g");
|
|
1171
|
+
var ID_PHRASE = new RegExp(
|
|
1172
|
+
`\\s*(?:\\(\\s*)?(?:for\\s+|with\\s+)?(?:suggestion|proposal|item|thread|entity|message|document)\\s+id[:\\s]+${WRAP}${UUID}${WRAP}(?:\\s*\\))?`,
|
|
1173
|
+
"gi"
|
|
1174
|
+
);
|
|
1175
|
+
var BARE_UUID = new RegExp(`${WRAP}${UUID}${WRAP}`, "g");
|
|
1176
|
+
function stripInternalIds(text) {
|
|
1177
|
+
if (!text || !/(?:KG|DOC|FRAME|SET|NODE|CHUNK):|-[0-9a-fA-F]{4}-/.test(text)) return text;
|
|
1178
|
+
return text.split(/(```[\s\S]*?```)/g).map(
|
|
1179
|
+
(part) => part.startsWith("```") ? part : part.replace(PAREN_PREFIXED, "").replace(PAREN_BARE, "").replace(BARE_PREFIXED, "").replace(ID_PHRASE, "").replace(BARE_UUID, "").replace(/[ \t]+([,.;:)])/g, "$1").replace(/([^\n ]) {2,}(?=\S)/g, "$1 ")
|
|
1180
|
+
).join("");
|
|
1181
|
+
}
|
|
1096
1182
|
function TimestampRenderer({ timestamp }) {
|
|
1097
1183
|
const t = useTheme();
|
|
1098
1184
|
const [timeString, setTimeString] = useState("");
|
|
1099
1185
|
useEffect(() => {
|
|
1100
|
-
setTimeString(timestamp.toLocaleTimeString());
|
|
1186
|
+
setTimeString(timestamp.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }));
|
|
1101
1187
|
}, [timestamp]);
|
|
1102
1188
|
return /* @__PURE__ */ jsx("div", { className: "text-xs ml-6 mt-1", style: { color: t.textMuted }, children: timeString });
|
|
1103
1189
|
}
|
|
@@ -1118,20 +1204,20 @@ async function gql(url, token, query, variables) {
|
|
|
1118
1204
|
return res.json();
|
|
1119
1205
|
}
|
|
1120
1206
|
function InteractiveActionCard({
|
|
1121
|
-
action,
|
|
1207
|
+
action: action2,
|
|
1122
1208
|
onExecute,
|
|
1123
1209
|
graphqlUrl = "",
|
|
1124
1210
|
authToken = ""
|
|
1125
1211
|
}) {
|
|
1126
1212
|
const t = useTheme();
|
|
1127
1213
|
const initialValues = useMemo(() => {
|
|
1128
|
-
const amount2 =
|
|
1129
|
-
const assetId =
|
|
1130
|
-
const entityId =
|
|
1131
|
-
const walletId =
|
|
1214
|
+
const amount2 = action2.metadata?.formatted_amount || (action2.payload?.arguments?.amount && action2.payload.arguments.amount !== "0" ? action2.payload.arguments.amount : "") || "";
|
|
1215
|
+
const assetId = action2.payload?.arguments?.asset_id || "";
|
|
1216
|
+
const entityId = action2.payload?.arguments?.destination_id || "";
|
|
1217
|
+
const walletId = action2.payload?.arguments?.destination_wallet_id || "";
|
|
1132
1218
|
return { amount: amount2, assetId, entityId, walletId };
|
|
1133
|
-
}, [
|
|
1134
|
-
const [editedAction, setEditedAction] = useState(
|
|
1219
|
+
}, [action2]);
|
|
1220
|
+
const [editedAction, setEditedAction] = useState(action2);
|
|
1135
1221
|
const [entities, setEntities] = useState([]);
|
|
1136
1222
|
const [wallets, setWallets] = useState([]);
|
|
1137
1223
|
const [assets, setAssets] = useState([]);
|
|
@@ -1245,14 +1331,14 @@ function InteractiveActionCard({
|
|
|
1245
1331
|
[assets, entities, wallets]
|
|
1246
1332
|
);
|
|
1247
1333
|
useEffect(() => {
|
|
1248
|
-
if (
|
|
1334
|
+
if (action2.payload?.tool_name === "yieldfabric/send_instant_payment") {
|
|
1249
1335
|
fetchEntities();
|
|
1250
1336
|
fetchAssets();
|
|
1251
1337
|
if (initialValues.entityId) fetchWallets(initialValues.entityId);
|
|
1252
1338
|
}
|
|
1253
1339
|
}, []);
|
|
1254
1340
|
useEffect(() => {
|
|
1255
|
-
if (selectedEntityId &&
|
|
1341
|
+
if (selectedEntityId && action2.payload?.tool_name === "yieldfabric/send_instant_payment") {
|
|
1256
1342
|
const shouldFetch = selectedEntityId !== initialValues.entityId || wallets.length === 0;
|
|
1257
1343
|
if (shouldFetch) fetchWallets(selectedEntityId);
|
|
1258
1344
|
if (selectedEntityId !== initialValues.entityId) {
|
|
@@ -1262,14 +1348,14 @@ function InteractiveActionCard({
|
|
|
1262
1348
|
}
|
|
1263
1349
|
}, [selectedEntityId]);
|
|
1264
1350
|
useEffect(() => {
|
|
1265
|
-
if (
|
|
1351
|
+
if (action2.payload?.tool_name !== "yieldfabric/send_instant_payment") return;
|
|
1266
1352
|
if (initialValues.assetId && assets.length > 0) {
|
|
1267
1353
|
const match = assets.find((a) => a.id === initialValues.assetId) || assets.find(
|
|
1268
1354
|
(a) => a.id.toUpperCase() === initialValues.assetId.toUpperCase()
|
|
1269
1355
|
) || assets.find(
|
|
1270
1356
|
(a) => initialValues.assetId.toUpperCase() === "CBDC" && a.name?.toUpperCase().includes("CBDC")
|
|
1271
|
-
) ||
|
|
1272
|
-
(a) => a.id ===
|
|
1357
|
+
) || action2.metadata?.asset_id && assets.find(
|
|
1358
|
+
(a) => a.id === action2.metadata.asset_id || a.id.toUpperCase() === action2.metadata.asset_id.toUpperCase()
|
|
1273
1359
|
);
|
|
1274
1360
|
if (match && selectedAssetId !== match.id) {
|
|
1275
1361
|
setSelectedAssetId(match.id);
|
|
@@ -1293,11 +1379,11 @@ function InteractiveActionCard({
|
|
|
1293
1379
|
updateActionField("amount", initialValues.amount);
|
|
1294
1380
|
}
|
|
1295
1381
|
}, [assets, entities, wallets]);
|
|
1296
|
-
if (
|
|
1382
|
+
if (action2.payload?.tool_name === "yieldfabric/swap_credit_for_cash") {
|
|
1297
1383
|
return /* @__PURE__ */ jsx(
|
|
1298
1384
|
RedeemCreditCard,
|
|
1299
1385
|
{
|
|
1300
|
-
action,
|
|
1386
|
+
action: action2,
|
|
1301
1387
|
onExecute,
|
|
1302
1388
|
graphqlUrl,
|
|
1303
1389
|
authToken,
|
|
@@ -1308,20 +1394,20 @@ function InteractiveActionCard({
|
|
|
1308
1394
|
}
|
|
1309
1395
|
);
|
|
1310
1396
|
}
|
|
1311
|
-
if (
|
|
1312
|
-
return /* @__PURE__ */ jsx(CompleteSwapCard, { action, onExecute });
|
|
1397
|
+
if (action2.payload?.tool_name === "yieldfabric/complete_swap") {
|
|
1398
|
+
return /* @__PURE__ */ jsx(CompleteSwapCard, { action: action2, onExecute });
|
|
1313
1399
|
}
|
|
1314
|
-
if (
|
|
1315
|
-
return /* @__PURE__ */ jsx(AcceptPaymentCard, { action, onExecute });
|
|
1400
|
+
if (action2.payload?.tool_name === "yieldfabric/accept_payment") {
|
|
1401
|
+
return /* @__PURE__ */ jsx(AcceptPaymentCard, { action: action2, onExecute });
|
|
1316
1402
|
}
|
|
1317
|
-
if (
|
|
1318
|
-
return /* @__PURE__ */ jsx(FileControlsCard, { action, onExecute });
|
|
1403
|
+
if (action2.action_type === "file_controls") {
|
|
1404
|
+
return /* @__PURE__ */ jsx(FileControlsCard, { action: action2, onExecute });
|
|
1319
1405
|
}
|
|
1320
|
-
if (
|
|
1321
|
-
return /* @__PURE__ */ jsx(DownloadSourceCard, { action, onExecute });
|
|
1406
|
+
if (action2.action_type === "download_source") {
|
|
1407
|
+
return /* @__PURE__ */ jsx(DownloadSourceCard, { action: action2, onExecute });
|
|
1322
1408
|
}
|
|
1323
|
-
if (
|
|
1324
|
-
return /* @__PURE__ */ jsx(GenericActionCard, { action, onExecute });
|
|
1409
|
+
if (action2.payload?.tool_name !== "yieldfabric/send_instant_payment") {
|
|
1410
|
+
return /* @__PURE__ */ jsx(GenericActionCard, { action: action2, onExecute });
|
|
1325
1411
|
}
|
|
1326
1412
|
return /* @__PURE__ */ jsxs(
|
|
1327
1413
|
"div",
|
|
@@ -1468,7 +1554,7 @@ function InteractiveActionCard({
|
|
|
1468
1554
|
);
|
|
1469
1555
|
}
|
|
1470
1556
|
function RedeemCreditCard({
|
|
1471
|
-
action,
|
|
1557
|
+
action: action2,
|
|
1472
1558
|
onExecute,
|
|
1473
1559
|
graphqlUrl,
|
|
1474
1560
|
authToken,
|
|
@@ -1478,14 +1564,14 @@ function RedeemCreditCard({
|
|
|
1478
1564
|
setLoadingObligor
|
|
1479
1565
|
}) {
|
|
1480
1566
|
const t = useTheme();
|
|
1481
|
-
const metadata =
|
|
1567
|
+
const metadata = action2.metadata || {};
|
|
1482
1568
|
const formattedAmount = metadata.formatted_amount || metadata.amount || "0.00";
|
|
1483
1569
|
const currency = metadata.currency || "Unknown";
|
|
1484
1570
|
const obligor = metadata.obligor || metadata.obligor_id || "Unknown";
|
|
1485
1571
|
const obligorId = metadata.obligor_id || obligor;
|
|
1486
1572
|
const assetDisplay = formatAssetDisplay(metadata, currency);
|
|
1487
1573
|
useEffect(() => {
|
|
1488
|
-
if (
|
|
1574
|
+
if (action2.payload?.tool_name !== "yieldfabric/swap_credit_for_cash") return;
|
|
1489
1575
|
if (obligorId === "Unknown" || obligor.includes("@")) return;
|
|
1490
1576
|
if (metadata.obligor_name && metadata.obligor_name !== obligorId && !obligorId.includes("-"))
|
|
1491
1577
|
return;
|
|
@@ -1516,7 +1602,7 @@ function RedeemCreditCard({
|
|
|
1516
1602
|
setLoadingObligor(false);
|
|
1517
1603
|
}
|
|
1518
1604
|
})();
|
|
1519
|
-
}, [obligorId,
|
|
1605
|
+
}, [obligorId, action2.payload?.tool_name]);
|
|
1520
1606
|
const obligorDisplay = (() => {
|
|
1521
1607
|
if (obligorEntity?.name) return obligorEntity.name;
|
|
1522
1608
|
if (metadata.obligor_name && metadata.obligor_name !== obligorId && metadata.obligor_name !== obligor)
|
|
@@ -1568,7 +1654,7 @@ function RedeemCreditCard({
|
|
|
1568
1654
|
onClick: (e) => {
|
|
1569
1655
|
e.preventDefault();
|
|
1570
1656
|
e.stopPropagation();
|
|
1571
|
-
onExecute(
|
|
1657
|
+
onExecute(action2);
|
|
1572
1658
|
},
|
|
1573
1659
|
className: "w-full py-2 px-4 text-sm font-medium rounded transition-colors flex items-center justify-center gap-2",
|
|
1574
1660
|
style: { backgroundColor: t.success, color: t.textInverse },
|
|
@@ -1583,12 +1669,12 @@ function RedeemCreditCard({
|
|
|
1583
1669
|
);
|
|
1584
1670
|
}
|
|
1585
1671
|
function CompleteSwapCard({
|
|
1586
|
-
action,
|
|
1672
|
+
action: action2,
|
|
1587
1673
|
onExecute
|
|
1588
1674
|
}) {
|
|
1589
1675
|
const t = useTheme();
|
|
1590
|
-
const metadata =
|
|
1591
|
-
const swapId = metadata.swap_id ||
|
|
1676
|
+
const metadata = action2.metadata || {};
|
|
1677
|
+
const swapId = metadata.swap_id || action2.payload?.arguments?.swap_id || "Unknown";
|
|
1592
1678
|
const initiator = metadata.initiator || "Unknown";
|
|
1593
1679
|
const status = metadata.status || "PENDING";
|
|
1594
1680
|
const deadline = metadata.deadline ? new Date(metadata.deadline).toLocaleString() : "N/A";
|
|
@@ -1650,7 +1736,7 @@ function CompleteSwapCard({
|
|
|
1650
1736
|
onClick: (e) => {
|
|
1651
1737
|
e.preventDefault();
|
|
1652
1738
|
e.stopPropagation();
|
|
1653
|
-
onExecute(
|
|
1739
|
+
onExecute(action2);
|
|
1654
1740
|
},
|
|
1655
1741
|
className: "w-full py-2 px-4 text-sm font-medium rounded transition-colors flex items-center justify-center gap-2",
|
|
1656
1742
|
style: { backgroundColor: t.success, color: t.textInverse },
|
|
@@ -1692,11 +1778,11 @@ function PaymentLeg({
|
|
|
1692
1778
|
] });
|
|
1693
1779
|
}
|
|
1694
1780
|
function AcceptPaymentCard({
|
|
1695
|
-
action,
|
|
1781
|
+
action: action2,
|
|
1696
1782
|
onExecute
|
|
1697
1783
|
}) {
|
|
1698
1784
|
const t = useTheme();
|
|
1699
|
-
const metadata =
|
|
1785
|
+
const metadata = action2.metadata || {};
|
|
1700
1786
|
const formattedAmount = metadata.formatted_amount || metadata.amount || "0.00";
|
|
1701
1787
|
const currency = metadata.currency || "Unknown";
|
|
1702
1788
|
const from = metadata.from || "Unknown";
|
|
@@ -1756,7 +1842,7 @@ function AcceptPaymentCard({
|
|
|
1756
1842
|
onClick: (e) => {
|
|
1757
1843
|
e.preventDefault();
|
|
1758
1844
|
e.stopPropagation();
|
|
1759
|
-
onExecute(
|
|
1845
|
+
onExecute(action2);
|
|
1760
1846
|
},
|
|
1761
1847
|
className: "w-full py-1.5 px-3 text-xs font-medium rounded transition-colors flex items-center justify-center gap-1.5 mt-auto",
|
|
1762
1848
|
style: { backgroundColor: t.success, color: t.textInverse },
|
|
@@ -1771,12 +1857,12 @@ function AcceptPaymentCard({
|
|
|
1771
1857
|
);
|
|
1772
1858
|
}
|
|
1773
1859
|
function FileControlsCard({
|
|
1774
|
-
action,
|
|
1860
|
+
action: action2,
|
|
1775
1861
|
onExecute
|
|
1776
1862
|
}) {
|
|
1777
1863
|
const t = useTheme();
|
|
1778
|
-
const title =
|
|
1779
|
-
const documentId =
|
|
1864
|
+
const title = action2.payload?.title || "Document";
|
|
1865
|
+
const documentId = action2.payload?.document_id;
|
|
1780
1866
|
const doDownload = (e) => {
|
|
1781
1867
|
e.preventDefault();
|
|
1782
1868
|
e.stopPropagation();
|
|
@@ -1835,18 +1921,18 @@ function FileControlsCard({
|
|
|
1835
1921
|
);
|
|
1836
1922
|
}
|
|
1837
1923
|
function DownloadSourceCard({
|
|
1838
|
-
action,
|
|
1924
|
+
action: action2,
|
|
1839
1925
|
onExecute
|
|
1840
1926
|
}) {
|
|
1841
1927
|
const t = useTheme();
|
|
1842
|
-
const title =
|
|
1928
|
+
const title = action2.payload?.title || action2.metadata?.display_text || action2.description || "Document";
|
|
1843
1929
|
return /* @__PURE__ */ jsx(
|
|
1844
1930
|
"button",
|
|
1845
1931
|
{
|
|
1846
1932
|
onClick: (e) => {
|
|
1847
1933
|
e.preventDefault();
|
|
1848
1934
|
e.stopPropagation();
|
|
1849
|
-
onExecute(
|
|
1935
|
+
onExecute(action2);
|
|
1850
1936
|
},
|
|
1851
1937
|
className: "relative overflow-hidden w-full p-3 rounded-lg transition-all duration-200 text-left group",
|
|
1852
1938
|
style: { backgroundColor: t.buttonBg, border: `1px solid ${t.border}` },
|
|
@@ -1866,7 +1952,7 @@ function DownloadSourceCard({
|
|
|
1866
1952
|
);
|
|
1867
1953
|
}
|
|
1868
1954
|
function GenericActionCard({
|
|
1869
|
-
action,
|
|
1955
|
+
action: action2,
|
|
1870
1956
|
onExecute
|
|
1871
1957
|
}) {
|
|
1872
1958
|
const t = useTheme();
|
|
@@ -1876,14 +1962,14 @@ function GenericActionCard({
|
|
|
1876
1962
|
onClick: (e) => {
|
|
1877
1963
|
e.preventDefault();
|
|
1878
1964
|
e.stopPropagation();
|
|
1879
|
-
onExecute(
|
|
1965
|
+
onExecute(action2);
|
|
1880
1966
|
},
|
|
1881
1967
|
className: "flex items-center space-x-3 p-3 rounded-lg transition-colors text-left group",
|
|
1882
1968
|
style: { backgroundColor: GREEN_ACTION.bg, border: GREEN_ACTION.borderStyle },
|
|
1883
1969
|
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = GREEN_ACTION.bgHover,
|
|
1884
1970
|
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = GREEN_ACTION.bg,
|
|
1885
1971
|
children: [
|
|
1886
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "font-medium text-sm mb-1.5", style: { color: t.success }, children:
|
|
1972
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "font-medium text-sm mb-1.5", style: { color: t.success }, children: action2.metadata?.display_text || action2.description || `Execute ${action2.action_type}` }) }),
|
|
1887
1973
|
/* @__PURE__ */ jsx(ArrowRight, { className: "w-5 h-5 transition-colors flex-shrink-0 ml-2", style: { color: t.success } })
|
|
1888
1974
|
]
|
|
1889
1975
|
}
|
|
@@ -2131,13 +2217,29 @@ function CopyButton({ content }) {
|
|
|
2131
2217
|
"button",
|
|
2132
2218
|
{
|
|
2133
2219
|
onClick: handleCopy,
|
|
2134
|
-
className: "
|
|
2220
|
+
className: "inline-flex h-6 w-6 items-center justify-center rounded transition-colors hover:scale-110",
|
|
2135
2221
|
style: { backgroundColor: t.bgRaisedHover, color: t.textSecondary },
|
|
2136
2222
|
title: "Copy",
|
|
2223
|
+
"aria-label": copied ? "Copied" : "Copy message",
|
|
2137
2224
|
children: copied ? /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5", style: { color: t.success } }) : /* @__PURE__ */ jsx(Copy, { className: "w-3.5 h-3.5" })
|
|
2138
2225
|
}
|
|
2139
2226
|
);
|
|
2140
2227
|
}
|
|
2228
|
+
function AgentCompletionNotice({ completion }) {
|
|
2229
|
+
const t = useTheme();
|
|
2230
|
+
if (!completion || completion.stop_reason === "answered") return null;
|
|
2231
|
+
const message = {
|
|
2232
|
+
rounds_exhausted: "Partial answer \u2014 I reached the step limit. Ask a narrower follow-up to continue.",
|
|
2233
|
+
budget_exhausted: "Partial answer \u2014 this question needs more context than fits in one answer. Try narrowing the question.",
|
|
2234
|
+
awaiting_tool_results: "This answer paused before its next step. Ask again to review a fresh answer.",
|
|
2235
|
+
empty: "No answer was returned. Please try again.",
|
|
2236
|
+
failed: "The answer could not be completed. What arrived so far is kept here.",
|
|
2237
|
+
interrupted: "Connection interrupted. The assistant may still be working; check the conversation before sending again.",
|
|
2238
|
+
cancelled: "Stopped. You can change your question and ask again."
|
|
2239
|
+
}[completion.stop_reason];
|
|
2240
|
+
if (!message) return null;
|
|
2241
|
+
return /* @__PURE__ */ jsx("p", { role: "status", className: "mt-2 rounded-md px-3 py-2 text-xs", style: { color: t.textSecondary, backgroundColor: t.bgRaisedAlt, border: `1px solid ${t.border}` }, children: message });
|
|
2242
|
+
}
|
|
2141
2243
|
var AGENT_PALETTE = [
|
|
2142
2244
|
"a78bfa",
|
|
2143
2245
|
// violet-400
|
|
@@ -2213,7 +2315,7 @@ function TimeLabel({ timestamp }) {
|
|
|
2213
2315
|
const t = useTheme();
|
|
2214
2316
|
const [timeStr, setTimeStr] = useState("");
|
|
2215
2317
|
useEffect(() => {
|
|
2216
|
-
setTimeStr(timestamp.toLocaleTimeString());
|
|
2318
|
+
setTimeStr(timestamp.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }));
|
|
2217
2319
|
}, [timestamp]);
|
|
2218
2320
|
return /* @__PURE__ */ jsx("span", { className: "text-[10px] mt-0.5", style: { color: t.textSecondary }, children: timeStr });
|
|
2219
2321
|
}
|
|
@@ -2531,7 +2633,10 @@ function hashTypeColor(type) {
|
|
|
2531
2633
|
for (let i = 0; i < type.length; i++) h = (h << 5) - h + type.charCodeAt(i) | 0;
|
|
2532
2634
|
return SOURCE_TYPE_PALETTE[Math.abs(h) % SOURCE_TYPE_PALETTE.length];
|
|
2533
2635
|
}
|
|
2534
|
-
function SourceCard({
|
|
2636
|
+
function SourceCard({
|
|
2637
|
+
source,
|
|
2638
|
+
onActivate
|
|
2639
|
+
}) {
|
|
2535
2640
|
const t = useTheme();
|
|
2536
2641
|
const [expanded, setExpanded] = useState(false);
|
|
2537
2642
|
const showType = source.type && source.type.toLowerCase() !== "unknown";
|
|
@@ -2539,13 +2644,25 @@ function SourceCard({ source }) {
|
|
|
2539
2644
|
const displayLabel = formatSourceLabel(source.label);
|
|
2540
2645
|
return /* @__PURE__ */ jsxs("div", { className: "rounded", style: { border: `1px solid ${t.border}`, backgroundColor: t.bgRaisedAlt }, children: [
|
|
2541
2646
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-1.5", children: [
|
|
2542
|
-
source.description ? /* @__PURE__ */ jsx(
|
|
2543
|
-
|
|
2647
|
+
source.description ? /* @__PURE__ */ jsx(
|
|
2648
|
+
"button",
|
|
2544
2649
|
{
|
|
2545
|
-
|
|
2546
|
-
|
|
2650
|
+
type: "button",
|
|
2651
|
+
onClick: (event) => {
|
|
2652
|
+
event.stopPropagation();
|
|
2653
|
+
setExpanded(!expanded);
|
|
2654
|
+
},
|
|
2655
|
+
className: "flex-shrink-0 rounded-sm focus:outline-none focus-visible:ring-2",
|
|
2656
|
+
"aria-label": expanded ? `Collapse ${displayLabel} details` : `Expand ${displayLabel} details`,
|
|
2657
|
+
children: /* @__PURE__ */ jsx(
|
|
2658
|
+
ChevronRight,
|
|
2659
|
+
{
|
|
2660
|
+
className: "w-3 h-3 transition-transform",
|
|
2661
|
+
style: { color: t.textMuted, transform: expanded ? "rotate(90deg)" : "none" }
|
|
2662
|
+
}
|
|
2663
|
+
)
|
|
2547
2664
|
}
|
|
2548
|
-
)
|
|
2665
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-3 h-3 flex-shrink-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 rounded-full", style: { backgroundColor: badgeColor } }) }),
|
|
2549
2666
|
showType && /* @__PURE__ */ jsx(
|
|
2550
2667
|
"span",
|
|
2551
2668
|
{
|
|
@@ -2554,11 +2671,28 @@ function SourceCard({ source }) {
|
|
|
2554
2671
|
children: source.type
|
|
2555
2672
|
}
|
|
2556
2673
|
),
|
|
2557
|
-
/* @__PURE__ */ jsx(
|
|
2674
|
+
onActivate ? /* @__PURE__ */ jsx(
|
|
2675
|
+
"button",
|
|
2676
|
+
{
|
|
2677
|
+
type: "button",
|
|
2678
|
+
className: "text-[11px] truncate flex-1 cursor-pointer text-left rounded-sm hover:underline focus:outline-none focus-visible:ring-2",
|
|
2679
|
+
style: { color: t.text },
|
|
2680
|
+
onClick: (event) => {
|
|
2681
|
+
event.stopPropagation();
|
|
2682
|
+
onActivate(source);
|
|
2683
|
+
},
|
|
2684
|
+
"aria-label": `Open ${displayLabel}`,
|
|
2685
|
+
children: displayLabel
|
|
2686
|
+
}
|
|
2687
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-[11px] truncate flex-1", style: { color: t.text }, children: displayLabel })
|
|
2558
2688
|
] }),
|
|
2559
2689
|
expanded && source.description && /* @__PURE__ */ jsx("div", { className: "px-2.5 pb-2 text-[10px] leading-relaxed", style: { color: t.textSecondary, borderTop: `1px solid ${t.border}` }, children: source.description })
|
|
2560
2690
|
] });
|
|
2561
2691
|
}
|
|
2692
|
+
var REMARK_PLUGINS = [remarkGfm];
|
|
2693
|
+
function isBlockCode(className, text) {
|
|
2694
|
+
return /language-/.test(typeof className === "string" ? className : "") || text.includes("\n");
|
|
2695
|
+
}
|
|
2562
2696
|
function getMarkdownComponents(t) {
|
|
2563
2697
|
return {
|
|
2564
2698
|
h1: ({ node, ...props }) => /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold mt-4 mb-2", style: { color: t.headingText }, ...props }),
|
|
@@ -2570,10 +2704,38 @@ function getMarkdownComponents(t) {
|
|
|
2570
2704
|
li: ({ node, ...props }) => /* @__PURE__ */ jsx("li", { className: "ml-2", ...props }),
|
|
2571
2705
|
strong: ({ node, ...props }) => /* @__PURE__ */ jsx("strong", { className: "font-bold", style: { color: t.text }, ...props }),
|
|
2572
2706
|
em: ({ node, ...props }) => /* @__PURE__ */ jsx("em", { className: "italic", style: { color: t.textSecondary }, ...props }),
|
|
2573
|
-
code: ({ node, inline, children, ...props }) =>
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2707
|
+
code: ({ node, inline, children, ...props }) => {
|
|
2708
|
+
const text = String(children ?? "");
|
|
2709
|
+
const isInline = inline ?? !isBlockCode(props.className, text);
|
|
2710
|
+
return isInline ? /* @__PURE__ */ jsx("code", { className: "px-1 py-0.5 rounded font-mono text-xs", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children }) : /* @__PURE__ */ jsxs("div", { className: "relative group/code", children: [
|
|
2711
|
+
/* @__PURE__ */ jsx(CopyButton, { content: text }),
|
|
2712
|
+
/* @__PURE__ */ jsx("code", { className: "block p-2 rounded my-2 font-mono text-xs overflow-x-auto", style: { backgroundColor: t.codeBg, color: t.codeText }, ...props, children })
|
|
2713
|
+
] });
|
|
2714
|
+
},
|
|
2715
|
+
// Tables are why remark-gfm is here. The wrapper is not decoration:
|
|
2716
|
+
// this renders inside a chat rail the user can drag down to ~360px,
|
|
2717
|
+
// and a table holding a term plus a few numbers will exceed that. It
|
|
2718
|
+
// has to scroll INSIDE its own box — without the wrapper the reply
|
|
2719
|
+
// column itself widens and every other line in the conversation
|
|
2720
|
+
// starts scrolling sideways along with it.
|
|
2721
|
+
table: ({ node, ...p }) => /* @__PURE__ */ jsx(
|
|
2722
|
+
"div",
|
|
2723
|
+
{
|
|
2724
|
+
className: "my-2 max-w-full overflow-x-auto rounded",
|
|
2725
|
+
style: { border: `1px solid ${t.codeBg}` },
|
|
2726
|
+
children: /* @__PURE__ */ jsx("table", { className: "w-full border-collapse text-xs", ...p })
|
|
2727
|
+
}
|
|
2728
|
+
),
|
|
2729
|
+
thead: ({ node, ...p }) => /* @__PURE__ */ jsx("thead", { style: { backgroundColor: t.codeBg }, ...p }),
|
|
2730
|
+
th: ({ node, ...p }) => /* @__PURE__ */ jsx(
|
|
2731
|
+
"th",
|
|
2732
|
+
{
|
|
2733
|
+
className: "px-2.5 py-1.5 text-left font-semibold whitespace-nowrap",
|
|
2734
|
+
style: { color: t.headingText, borderBottom: `1px solid ${t.codeBg}` },
|
|
2735
|
+
...p
|
|
2736
|
+
}
|
|
2737
|
+
),
|
|
2738
|
+
td: ({ node, ...p }) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top", style: { borderBottom: `1px solid ${t.codeBg}` }, ...p })
|
|
2577
2739
|
};
|
|
2578
2740
|
}
|
|
2579
2741
|
function TerminalEntryRenderer({
|
|
@@ -2588,6 +2750,7 @@ function TerminalEntryRenderer({
|
|
|
2588
2750
|
authToken,
|
|
2589
2751
|
onPageNavigation,
|
|
2590
2752
|
onSourcesActivate,
|
|
2753
|
+
onSourceActivate,
|
|
2591
2754
|
renderEntryExtra,
|
|
2592
2755
|
renderEntry,
|
|
2593
2756
|
widgets,
|
|
@@ -2605,7 +2768,7 @@ function TerminalEntryRenderer({
|
|
|
2605
2768
|
const isError = entry.type === "error";
|
|
2606
2769
|
const isSuccess = entry.type === "success";
|
|
2607
2770
|
const isEmpty = !entry.content || entry.content.trim() === "";
|
|
2608
|
-
const useAttribution = isCollaborative && entry.sender && !isSystem && !isEmpty;
|
|
2771
|
+
const useAttribution = (isCollaborative || entry.sender?.type === "agent") && entry.sender && !isSystem && !isEmpty;
|
|
2609
2772
|
const isGrouped = useAttribution && !!prevEntry?.sender && !!entry.sender && prevEntry.sender.entity_id === entry.sender.entity_id && prevEntry.sender.type === entry.sender.type && !(!prevEntry.content || prevEntry.content.trim() === "") && entry.timestamp.getTime() - prevEntry.timestamp.getTime() < 5 * 60 * 1e3 && prevEntry.type !== "system";
|
|
2610
2773
|
const beforeWidgets = widgets?.filter((w) => w.position === "before" && w.match(entry)) || [];
|
|
2611
2774
|
const afterWidgets = widgets?.filter((w) => (!w.position || w.position === "after") && w.match(entry)) || [];
|
|
@@ -2618,12 +2781,12 @@ function TerminalEntryRenderer({
|
|
|
2618
2781
|
timestamp: entry.timestamp,
|
|
2619
2782
|
isOwnMessage: entry.sender.entity_id === currentUser?.entity_id,
|
|
2620
2783
|
grouped: isGrouped,
|
|
2621
|
-
children: entry.sender?.type === "agent" ? /* @__PURE__ */ jsxs("div", { className: "text-sm prose prose-invert prose-sm max-w-
|
|
2784
|
+
children: entry.sender?.type === "agent" ? /* @__PURE__ */ jsxs("div", { className: "text-sm prose prose-invert prose-sm max-w-[72ch] group relative", style: { color: t.text }, children: [
|
|
2622
2785
|
/* @__PURE__ */ jsxs("div", { className: "absolute -top-9 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
|
|
2623
2786
|
/* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
|
|
2624
2787
|
/* @__PURE__ */ jsx(ShareButton, { content: entry.content })
|
|
2625
2788
|
] }),
|
|
2626
|
-
/* @__PURE__ */ jsx(ReactMarkdown, { components: markdownComponents, children: entry.content })
|
|
2789
|
+
/* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: REMARK_PLUGINS, components: markdownComponents, children: stripInternalIds(entry.content) })
|
|
2627
2790
|
] }) : /* @__PURE__ */ jsxs("div", { className: "text-sm whitespace-pre-wrap group relative", style: { color: isError ? t.error : t.text }, children: [
|
|
2628
2791
|
/* @__PURE__ */ jsxs("div", { className: "absolute -top-9 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
|
|
2629
2792
|
/* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
|
|
@@ -2634,7 +2797,6 @@ function TerminalEntryRenderer({
|
|
|
2634
2797
|
}
|
|
2635
2798
|
) : /* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-2", children: [
|
|
2636
2799
|
isSystem && !isEmpty && /* @__PURE__ */ jsx(Terminal, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.textSystem } }),
|
|
2637
|
-
isCommand && !isEmpty && /* @__PURE__ */ jsx(Brain, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.info } }),
|
|
2638
2800
|
isInfo && !isEmpty && /* @__PURE__ */ jsx(CheckCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.info } }),
|
|
2639
2801
|
isSuccess && !isEmpty && /* @__PURE__ */ jsx(CheckCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.success } }),
|
|
2640
2802
|
isError && !isEmpty && /* @__PURE__ */ jsx(XCircle, { className: "w-4 h-4 mt-0.5 flex-shrink-0", style: { color: t.error } }),
|
|
@@ -2647,12 +2809,30 @@ function TerminalEntryRenderer({
|
|
|
2647
2809
|
/* @__PURE__ */ jsx(
|
|
2648
2810
|
ReactMarkdown,
|
|
2649
2811
|
{
|
|
2812
|
+
remarkPlugins: REMARK_PLUGINS,
|
|
2650
2813
|
components: markdownComponents,
|
|
2651
|
-
children: entry.content
|
|
2814
|
+
children: stripInternalIds(entry.content)
|
|
2652
2815
|
},
|
|
2653
2816
|
`${entry.id || index}-${entry.content.length}`
|
|
2654
2817
|
)
|
|
2655
|
-
] }) :
|
|
2818
|
+
] }) : isCommand && !isSystem ? (
|
|
2819
|
+
// What the person typed: a quiet bubble on the right, the way the
|
|
2820
|
+
// console shows it — not a monospace line that reads as a log.
|
|
2821
|
+
/* @__PURE__ */ jsxs("div", { className: "group relative flex w-full flex-1 justify-end", children: [
|
|
2822
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute -top-5 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
|
|
2823
|
+
/* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
|
|
2824
|
+
/* @__PURE__ */ jsx(ShareButton, { content: entry.content })
|
|
2825
|
+
] }),
|
|
2826
|
+
/* @__PURE__ */ jsx(
|
|
2827
|
+
"p",
|
|
2828
|
+
{
|
|
2829
|
+
className: "max-w-[80%] whitespace-pre-wrap rounded-lg border px-4 py-2.5 text-sm leading-relaxed",
|
|
2830
|
+
style: { color: t.text, borderColor: t.borderStrong, backgroundColor: "rgba(255,255,255,0.05)" },
|
|
2831
|
+
children: entry.content
|
|
2832
|
+
}
|
|
2833
|
+
)
|
|
2834
|
+
] })
|
|
2835
|
+
) : /* @__PURE__ */ jsxs("div", { className: "group relative", children: [
|
|
2656
2836
|
/* @__PURE__ */ jsxs("div", { className: "absolute -top-5 right-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity z-10", children: [
|
|
2657
2837
|
/* @__PURE__ */ jsx(CopyButton, { content: entry.content }),
|
|
2658
2838
|
/* @__PURE__ */ jsx(ShareButton, { content: entry.content })
|
|
@@ -2660,9 +2840,9 @@ function TerminalEntryRenderer({
|
|
|
2660
2840
|
/* @__PURE__ */ jsx(
|
|
2661
2841
|
"pre",
|
|
2662
2842
|
{
|
|
2663
|
-
className: "font-mono text-sm whitespace-pre-wrap",
|
|
2843
|
+
className: "font-mono text-sm whitespace-pre-wrap max-w-[72ch]",
|
|
2664
2844
|
style: {
|
|
2665
|
-
color: isSystem ? t.textSystem :
|
|
2845
|
+
color: isSystem ? t.textSystem : isSuccess ? t.success : isError ? t.error : t.text
|
|
2666
2846
|
},
|
|
2667
2847
|
children: entry.content
|
|
2668
2848
|
}
|
|
@@ -2793,7 +2973,14 @@ function TerminalEntryRenderer({
|
|
|
2793
2973
|
{
|
|
2794
2974
|
summary: `${entry.sources.length} source${entry.sources.length !== 1 ? "s" : ""}`,
|
|
2795
2975
|
defaultExpanded: false,
|
|
2796
|
-
children: /* @__PURE__ */ jsx("div", { className: "space-y-1 py-1", children: entry.sources.map((src) => /* @__PURE__ */ jsx(
|
|
2976
|
+
children: /* @__PURE__ */ jsx("div", { className: "space-y-1 py-1", children: entry.sources.map((src) => /* @__PURE__ */ jsx(
|
|
2977
|
+
SourceCard,
|
|
2978
|
+
{
|
|
2979
|
+
source: src,
|
|
2980
|
+
onActivate: onSourceActivate ? () => onSourceActivate(src, entry) : void 0
|
|
2981
|
+
},
|
|
2982
|
+
src.id
|
|
2983
|
+
)) })
|
|
2797
2984
|
}
|
|
2798
2985
|
)
|
|
2799
2986
|
}
|
|
@@ -2813,11 +3000,11 @@ function TerminalEntryRenderer({
|
|
|
2813
3000
|
/* @__PURE__ */ jsx("span", { className: "font-medium text-sm", style: { color: t.success }, children: "Actions" }),
|
|
2814
3001
|
/* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: t.textMuted }, children: "click to execute" })
|
|
2815
3002
|
] }),
|
|
2816
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2", children: entry.suggested_actions.map((
|
|
3003
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2", children: entry.suggested_actions.map((action2, idx) => /* @__PURE__ */ jsxs("div", { children: [
|
|
2817
3004
|
/* @__PURE__ */ jsx(
|
|
2818
3005
|
InteractiveActionCard,
|
|
2819
3006
|
{
|
|
2820
|
-
action,
|
|
3007
|
+
action: action2,
|
|
2821
3008
|
graphqlUrl: config.graphqlUrl,
|
|
2822
3009
|
authToken: authToken || "",
|
|
2823
3010
|
onExecute: (updatedAction) => {
|
|
@@ -2826,15 +3013,15 @@ function TerminalEntryRenderer({
|
|
|
2826
3013
|
}
|
|
2827
3014
|
}
|
|
2828
3015
|
),
|
|
2829
|
-
|
|
3016
|
+
action2.approval && /* @__PURE__ */ jsx(
|
|
2830
3017
|
ApprovalTracker,
|
|
2831
3018
|
{
|
|
2832
|
-
approval:
|
|
3019
|
+
approval: action2.approval,
|
|
2833
3020
|
currentUserId: currentUser?.entity_id,
|
|
2834
3021
|
onApprove: () => {
|
|
2835
3022
|
window.dispatchEvent(
|
|
2836
3023
|
new CustomEvent("terminal-approval-decision", {
|
|
2837
|
-
detail: { action, decision: "approved", entity_id: currentUser?.entity_id },
|
|
3024
|
+
detail: { action: action2, decision: "approved", entity_id: currentUser?.entity_id },
|
|
2838
3025
|
bubbles: true
|
|
2839
3026
|
})
|
|
2840
3027
|
);
|
|
@@ -2842,7 +3029,7 @@ function TerminalEntryRenderer({
|
|
|
2842
3029
|
onReject: () => {
|
|
2843
3030
|
window.dispatchEvent(
|
|
2844
3031
|
new CustomEvent("terminal-approval-decision", {
|
|
2845
|
-
detail: { action, decision: "rejected", entity_id: currentUser?.entity_id },
|
|
3032
|
+
detail: { action: action2, decision: "rejected", entity_id: currentUser?.entity_id },
|
|
2846
3033
|
bubbles: true
|
|
2847
3034
|
})
|
|
2848
3035
|
);
|
|
@@ -2890,9 +3077,10 @@ function TerminalEntryRenderer({
|
|
|
2890
3077
|
] });
|
|
2891
3078
|
const isTurnStart = !!prevEntry && isCommand && prevEntry.type !== "system";
|
|
2892
3079
|
const defaultRender = () => /* @__PURE__ */ jsxs("div", { className: `${isGrouped ? "" : "mb-5"} ${isTurnStart ? "mt-6" : ""}`, children: [
|
|
2893
|
-
beforeWidgets.map((w) => /* @__PURE__ */ jsx(
|
|
2894
|
-
replaceWidget ? /* @__PURE__ */ jsx(
|
|
2895
|
-
afterWidgets.map((w) => /* @__PURE__ */ jsx(
|
|
3080
|
+
beforeWidgets.map((w) => /* @__PURE__ */ jsx(React15.Fragment, { children: w.render({ entry, index }) }, w.name)),
|
|
3081
|
+
replaceWidget ? /* @__PURE__ */ jsx(React15.Fragment, { children: replaceWidget.render({ entry, index }) }, replaceWidget.name) : builtInContent,
|
|
3082
|
+
afterWidgets.map((w) => /* @__PURE__ */ jsx(React15.Fragment, { children: w.render({ entry, index }) }, w.name)),
|
|
3083
|
+
/* @__PURE__ */ jsx(AgentCompletionNotice, { completion: entry.metadata?.completion }),
|
|
2896
3084
|
renderEntryExtra?.(entry, index)
|
|
2897
3085
|
] });
|
|
2898
3086
|
if (renderEntry) {
|
|
@@ -2901,6 +3089,9 @@ function TerminalEntryRenderer({
|
|
|
2901
3089
|
}
|
|
2902
3090
|
return defaultRender();
|
|
2903
3091
|
}
|
|
3092
|
+
|
|
3093
|
+
// src/types/terminal.types.ts
|
|
3094
|
+
var DEFAULT_AGENT_LABEL = "YieldFabric Agent";
|
|
2904
3095
|
function LiveKGBridge({ progressState, onLiveKGUpdate }) {
|
|
2905
3096
|
const onUpdateRef = useRef(onLiveKGUpdate);
|
|
2906
3097
|
onUpdateRef.current = onLiveKGUpdate;
|
|
@@ -2929,14 +3120,17 @@ function TerminalShell({
|
|
|
2929
3120
|
className = "",
|
|
2930
3121
|
style,
|
|
2931
3122
|
showHeader = true,
|
|
3123
|
+
agentLabel = DEFAULT_AGENT_LABEL,
|
|
2932
3124
|
focusInput,
|
|
2933
3125
|
setTerminalHistory,
|
|
2934
3126
|
terminalBodyRef,
|
|
2935
3127
|
workingGroupContext,
|
|
3128
|
+
showWorkingGroupBanner = true,
|
|
2936
3129
|
progressState,
|
|
2937
3130
|
streamTransparency,
|
|
2938
3131
|
streamNowMs,
|
|
2939
3132
|
isExecuting,
|
|
3133
|
+
showBusyIndicator,
|
|
2940
3134
|
handleCancelReasoning,
|
|
2941
3135
|
onViewKnowledgeGraph,
|
|
2942
3136
|
onLiveKGUpdate,
|
|
@@ -2954,6 +3148,9 @@ function TerminalShell({
|
|
|
2954
3148
|
className: `border-0 flex flex-col ${className}`,
|
|
2955
3149
|
style: { minHeight: "300px", borderRadius: "12px", backgroundColor: "transparent", ...style },
|
|
2956
3150
|
onClick: () => {
|
|
3151
|
+
if (typeof window !== "undefined" && window.matchMedia?.("(pointer: coarse)").matches) {
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
2957
3154
|
const sel = window.getSelection();
|
|
2958
3155
|
if (!sel || sel.toString().length === 0) focusInput();
|
|
2959
3156
|
},
|
|
@@ -2972,7 +3169,7 @@ function TerminalShell({
|
|
|
2972
3169
|
"button",
|
|
2973
3170
|
{
|
|
2974
3171
|
onClick: () => setTerminalHistory([
|
|
2975
|
-
{ type: "system", content:
|
|
3172
|
+
{ type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
|
|
2976
3173
|
{ type: "system", content: "Terminal cleared.", timestamp: /* @__PURE__ */ new Date() }
|
|
2977
3174
|
]),
|
|
2978
3175
|
className: "hover:opacity-80",
|
|
@@ -2990,7 +3187,7 @@ function TerminalShell({
|
|
|
2990
3187
|
className: "p-6 flex-1 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-700 scrollbar-track-transparent",
|
|
2991
3188
|
style: { minHeight: "200px", display: "flex", flexDirection: "column", backgroundColor: "transparent" },
|
|
2992
3189
|
children: [
|
|
2993
|
-
workingGroupContext && /* @__PURE__ */ jsxs(
|
|
3190
|
+
workingGroupContext && showWorkingGroupBanner && /* @__PURE__ */ jsxs(
|
|
2994
3191
|
"div",
|
|
2995
3192
|
{
|
|
2996
3193
|
className: "mb-3 ml-1 mr-1 px-3 py-2 rounded-md text-xs flex items-center justify-between",
|
|
@@ -3015,7 +3212,7 @@ function TerminalShell({
|
|
|
3015
3212
|
}
|
|
3016
3213
|
),
|
|
3017
3214
|
/* @__PURE__ */ jsx(LiveKGBridge, { progressState, onLiveKGUpdate }),
|
|
3018
|
-
isExecuting && !progressState && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 px-6 py-2 flex-shrink-0 border-t", style: { color: t.text, borderColor: t.border }, children: [
|
|
3215
|
+
isExecuting && !progressState && showBusyIndicator !== false && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 px-6 py-2 flex-shrink-0 border-t", style: { color: t.text, borderColor: t.border }, children: [
|
|
3019
3216
|
/* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
|
|
3020
3217
|
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full animate-pulse", style: { backgroundColor: t.info } }),
|
|
3021
3218
|
/* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full animate-pulse", style: { backgroundColor: t.info, animationDelay: "150ms" } }),
|
|
@@ -3090,7 +3287,7 @@ function KGScopeDropdown({ items, onSelect, compact = false }) {
|
|
|
3090
3287
|
}
|
|
3091
3288
|
function ReasoningModeSelector({ current, onChange, compact = false }) {
|
|
3092
3289
|
const t = useTheme();
|
|
3093
|
-
const isLight = t.bgRaised === "#ffffff";
|
|
3290
|
+
const isLight = t.mode ? t.mode === "light" : t.bgRaised === "#ffffff";
|
|
3094
3291
|
const isReason = current === "reason";
|
|
3095
3292
|
const label = isReason ? "Reason" : "Auto";
|
|
3096
3293
|
const title = isReason ? "Force deep reasoning \u2014 click to let the AI decide" : "AI decides \u2014 click to force deep reasoning";
|
|
@@ -3145,11 +3342,24 @@ function splitInputByMentions(command, knownMentionNames) {
|
|
|
3145
3342
|
segments.push({ kind: "text", value: command.slice(cursor) });
|
|
3146
3343
|
return segments;
|
|
3147
3344
|
}
|
|
3345
|
+
var INPUT_MAX_HEIGHT = 120;
|
|
3346
|
+
function fitToContent(input) {
|
|
3347
|
+
resetHeight(input);
|
|
3348
|
+
if (!input.value.trim()) return;
|
|
3349
|
+
const needed = input.scrollHeight;
|
|
3350
|
+
input.style.height = `${Math.min(needed, INPUT_MAX_HEIGHT)}px`;
|
|
3351
|
+
if (needed > INPUT_MAX_HEIGHT) input.style.overflowY = "auto";
|
|
3352
|
+
}
|
|
3353
|
+
function resetHeight(input) {
|
|
3354
|
+
input.style.height = "auto";
|
|
3355
|
+
input.style.overflowY = "";
|
|
3356
|
+
}
|
|
3148
3357
|
function TerminalInputBar({
|
|
3149
3358
|
inputRef,
|
|
3150
3359
|
fileInputRef,
|
|
3151
3360
|
currentCommand,
|
|
3152
3361
|
isExecuting,
|
|
3362
|
+
disabled = false,
|
|
3153
3363
|
placeholder = "Ask anything...",
|
|
3154
3364
|
onInputChange,
|
|
3155
3365
|
onKeyDown,
|
|
@@ -3172,20 +3382,28 @@ function TerminalInputBar({
|
|
|
3172
3382
|
inputBarExtra,
|
|
3173
3383
|
modeSelector,
|
|
3174
3384
|
compactToolbar = false,
|
|
3175
|
-
submitTitle = "Send"
|
|
3385
|
+
submitTitle = "Send",
|
|
3386
|
+
autoFocus = true
|
|
3176
3387
|
}) {
|
|
3177
3388
|
const t = useTheme();
|
|
3178
|
-
|
|
3389
|
+
useEffect(() => {
|
|
3390
|
+
if (!autoFocus) return;
|
|
3391
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
3392
|
+
}, []);
|
|
3393
|
+
const [focused, setFocused] = React15.useState(false);
|
|
3394
|
+
const chipsVisible = focused || currentCommand.trim().length > 0;
|
|
3395
|
+
const isTouch = typeof window !== "undefined" && "ontouchstart" in window;
|
|
3396
|
+
const isLight = t.mode ? t.mode === "light" : t.bgRaised === "#ffffff";
|
|
3179
3397
|
const hasCommand = Boolean(currentCommand.trim());
|
|
3180
|
-
const placeholderColor = isLight ?
|
|
3181
|
-
const panelBorder = isLight ?
|
|
3182
|
-
const panelBg =
|
|
3183
|
-
const toolbarButtonBg = isLight ? "rgba(
|
|
3184
|
-
const toolbarButtonHover = isLight ?
|
|
3185
|
-
const toolbarButtonText = isLight ?
|
|
3398
|
+
const placeholderColor = isLight ? t.textMuted : "rgba(255,255,255,0.52)";
|
|
3399
|
+
const panelBorder = isLight ? t.border : "rgba(255,255,255,0.10)";
|
|
3400
|
+
const panelBg = t.bgInput;
|
|
3401
|
+
const toolbarButtonBg = isLight ? "rgba(255,255,255,0.72)" : "rgba(255,255,255,0.05)";
|
|
3402
|
+
const toolbarButtonHover = isLight ? t.bgRaised : "rgba(255,255,255,0.14)";
|
|
3403
|
+
const toolbarButtonText = isLight ? t.textSecondary : "rgba(255,255,255,0.52)";
|
|
3186
3404
|
const toolbarButtonStyle = {
|
|
3187
3405
|
backgroundColor: toolbarButtonBg,
|
|
3188
|
-
border: `1px solid ${isLight ?
|
|
3406
|
+
border: `1px solid ${isLight ? t.border : "rgba(255,255,255,0.08)"}`,
|
|
3189
3407
|
boxShadow: "none",
|
|
3190
3408
|
color: toolbarButtonText
|
|
3191
3409
|
};
|
|
@@ -3198,8 +3416,11 @@ function TerminalInputBar({
|
|
|
3198
3416
|
}
|
|
3199
3417
|
const el = toolbarRef.current;
|
|
3200
3418
|
if (!el || typeof ResizeObserver === "undefined") return;
|
|
3419
|
+
let lastWidth = -1;
|
|
3201
3420
|
const ro = new ResizeObserver((entries) => {
|
|
3202
|
-
const w = entries[0]?.contentRect.width ?? 0;
|
|
3421
|
+
const w = Math.round(entries[0]?.contentRect.width ?? 0);
|
|
3422
|
+
if (w === lastWidth) return;
|
|
3423
|
+
lastWidth = w;
|
|
3203
3424
|
setCompact((prev) => prev ? w < 520 : w < 480);
|
|
3204
3425
|
});
|
|
3205
3426
|
ro.observe(el);
|
|
@@ -3209,13 +3430,10 @@ function TerminalInputBar({
|
|
|
3209
3430
|
useEffect(() => {
|
|
3210
3431
|
const input = inputRef.current;
|
|
3211
3432
|
if (!input) return;
|
|
3212
|
-
input
|
|
3213
|
-
if (currentCommand.trim()) {
|
|
3214
|
-
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
3215
|
-
}
|
|
3433
|
+
fitToContent(input);
|
|
3216
3434
|
}, [currentCommand, inputRef]);
|
|
3217
3435
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3218
|
-
/* @__PURE__ */ jsx("style", { children: `.yf-input-bar::placeholder { color: ${placeholderColor}; }` }),
|
|
3436
|
+
/* @__PURE__ */ jsx("style", { children: `.yf-input-bar::placeholder { color: ${placeholderColor}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }` }),
|
|
3219
3437
|
commandPaletteItems.length > 0 && /* @__PURE__ */ jsxs(
|
|
3220
3438
|
"div",
|
|
3221
3439
|
{
|
|
@@ -3254,17 +3472,24 @@ function TerminalInputBar({
|
|
|
3254
3472
|
/* @__PURE__ */ jsx(
|
|
3255
3473
|
"div",
|
|
3256
3474
|
{
|
|
3257
|
-
className: `relative z-20 flex-shrink-0 px-3 pb-3 pt-2 transition-opacity duration-300 sm:px-4 ${isExecuting ? "opacity-40 pointer-events-none" : ""}`,
|
|
3475
|
+
className: `relative z-20 flex-shrink-0 px-3 pb-3 pt-2 transition-opacity duration-300 sm:px-4 ${isExecuting || disabled ? "opacity-40 pointer-events-none" : ""}`,
|
|
3258
3476
|
children: /* @__PURE__ */ jsxs(
|
|
3259
3477
|
"div",
|
|
3260
3478
|
{
|
|
3261
|
-
className:
|
|
3479
|
+
className: `rounded-xl border px-3 transition-[box-shadow,border-color] sm:px-4 ${focused ? "yf-input-focused" : ""}`,
|
|
3262
3480
|
style: {
|
|
3263
3481
|
backgroundColor: panelBg,
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3482
|
+
// No backdrop blur on a touch screen. It is the one compositing
|
|
3483
|
+
// layer between the textarea and the page, and on iPhone the
|
|
3484
|
+
// caret was drawn a line below and a character right of where
|
|
3485
|
+
// typing lands — the caret rect resolved against the wrong
|
|
3486
|
+
// layer — while WebKit's own layout (checked in WebKit 26) puts
|
|
3487
|
+
// it on the line. The box keeps its colour; only the frosted
|
|
3488
|
+
// fabric behind it goes, which at this size is barely a change.
|
|
3489
|
+
backdropFilter: isTouch ? void 0 : "blur(18px)",
|
|
3490
|
+
borderColor: focused ? t.primary : panelBorder,
|
|
3491
|
+
boxShadow: focused ? `0 0 0 3px ${t.primaryMuted || "rgba(5,78,146,0.18)"}` : isLight ? "0 18px 70px -38px rgba(30,30,58,0.45)" : "0 18px 70px -38px rgba(0,0,0,0.95)",
|
|
3492
|
+
WebkitBackdropFilter: isTouch ? void 0 : "blur(18px)"
|
|
3268
3493
|
},
|
|
3269
3494
|
children: [
|
|
3270
3495
|
/* @__PURE__ */ jsx(
|
|
@@ -3333,8 +3558,7 @@ function TerminalInputBar({
|
|
|
3333
3558
|
onInputChange(`${prefixRaw}${e.target.value}`);
|
|
3334
3559
|
onCaretChange?.(prefixRaw.length + (e.target.selectionStart ?? e.target.value.length));
|
|
3335
3560
|
onTyping?.();
|
|
3336
|
-
e.target
|
|
3337
|
-
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
3561
|
+
fitToContent(e.target);
|
|
3338
3562
|
},
|
|
3339
3563
|
onSelect: (e) => {
|
|
3340
3564
|
const ta = e.currentTarget;
|
|
@@ -3361,17 +3585,34 @@ function TerminalInputBar({
|
|
|
3361
3585
|
if (e.key === "Enter" && !e.shiftKey && !e.defaultPrevented) {
|
|
3362
3586
|
e.preventDefault();
|
|
3363
3587
|
onSubmit();
|
|
3364
|
-
if (inputRef.current) inputRef.current
|
|
3588
|
+
if (inputRef.current) resetHeight(inputRef.current);
|
|
3365
3589
|
}
|
|
3366
3590
|
},
|
|
3367
|
-
disabled: isExecuting,
|
|
3591
|
+
disabled: isExecuting || disabled,
|
|
3592
|
+
"aria-label": placeholder ?? "Message",
|
|
3368
3593
|
placeholder: isExecuting ? "Processing..." : placeholder,
|
|
3369
3594
|
rows: 1,
|
|
3370
|
-
className: "yf-input-bar flex-1 min-w-[100px] bg-transparent focus:outline-none text-[16px] leading-6 resize-none overflow-hidden sm:text-
|
|
3595
|
+
className: "yf-input-bar flex-1 min-w-[100px] bg-transparent focus:outline-none text-[16px] leading-6 resize-none overflow-hidden sm:text-sm sm:leading-5",
|
|
3596
|
+
onFocus: () => {
|
|
3597
|
+
setFocused(true);
|
|
3598
|
+
if (!("ontouchstart" in window)) return;
|
|
3599
|
+
window.setTimeout(() => {
|
|
3600
|
+
const ta = inputRef.current;
|
|
3601
|
+
if (!ta || document.activeElement !== ta) return;
|
|
3602
|
+
let scroller = ta.parentElement;
|
|
3603
|
+
while (scroller && !/(auto|scroll)/.test(getComputedStyle(scroller).overflowY)) scroller = scroller.parentElement;
|
|
3604
|
+
window.scrollBy(0, 1);
|
|
3605
|
+
if (scroller) scroller.scrollTop += 1;
|
|
3606
|
+
window.requestAnimationFrame(() => {
|
|
3607
|
+
window.scrollBy(0, -1);
|
|
3608
|
+
if (scroller) scroller.scrollTop -= 1;
|
|
3609
|
+
});
|
|
3610
|
+
}, 400);
|
|
3611
|
+
},
|
|
3612
|
+
onBlur: () => setFocused(false),
|
|
3371
3613
|
style: { color: t.text, caretColor: t.cursor },
|
|
3372
3614
|
spellCheck: false,
|
|
3373
3615
|
autoComplete: "off",
|
|
3374
|
-
autoFocus: true,
|
|
3375
3616
|
tabIndex: 0
|
|
3376
3617
|
}
|
|
3377
3618
|
)
|
|
@@ -3380,67 +3621,85 @@ function TerminalInputBar({
|
|
|
3380
3621
|
"button",
|
|
3381
3622
|
{
|
|
3382
3623
|
type: "submit",
|
|
3383
|
-
disabled: !hasCommand || isExecuting,
|
|
3384
|
-
className: "h-10 w-10 rounded-xl disabled:opacity-
|
|
3624
|
+
disabled: !hasCommand || isExecuting || disabled,
|
|
3625
|
+
className: "h-10 w-10 rounded-xl disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200 shrink-0 sm:h-8 sm:w-8",
|
|
3385
3626
|
style: {
|
|
3386
|
-
backgroundColor:
|
|
3387
|
-
|
|
3627
|
+
backgroundColor: isLight ? t.primary : hasCommand ? t.primary : "rgba(255,255,255,0.08)",
|
|
3628
|
+
// `textInverse` is the theme's "text on a filled button".
|
|
3629
|
+
// `bgBase` was used here before and is `transparent` in
|
|
3630
|
+
// every app theme — so the chevron vanished the moment
|
|
3631
|
+
// there was something to send.
|
|
3632
|
+
// In LIGHT mode this is always a solid accent fill with white
|
|
3633
|
+
// on it (6.1:1). It is the app's primary verb and the single
|
|
3634
|
+
// most-pressed control; a pale disc — grey, or a 10% tint —
|
|
3635
|
+
// read as disabled even when it was not. The empty state is
|
|
3636
|
+
// already expressed by `disabled:opacity-60`, so the fill does
|
|
3637
|
+
// not also have to whisper. Dark keeps its white-alpha rest,
|
|
3638
|
+
// where a solid orange disc would shout on near-black.
|
|
3639
|
+
color: isLight ? t.textInverse : hasCommand ? t.textInverse : "rgba(255,255,255,0.72)"
|
|
3388
3640
|
},
|
|
3389
3641
|
onMouseEnter: (e) => {
|
|
3390
|
-
|
|
3642
|
+
if (hasCommand) {
|
|
3643
|
+
e.currentTarget.style.filter = "brightness(1.15)";
|
|
3644
|
+
} else {
|
|
3645
|
+
e.currentTarget.style.backgroundColor = toolbarButtonHover;
|
|
3646
|
+
}
|
|
3391
3647
|
},
|
|
3392
3648
|
onMouseLeave: (e) => {
|
|
3393
|
-
e.currentTarget.style.
|
|
3649
|
+
e.currentTarget.style.filter = "";
|
|
3650
|
+
e.currentTarget.style.backgroundColor = isLight ? t.primary : hasCommand ? t.primary : "rgba(255,255,255,0.08)";
|
|
3394
3651
|
},
|
|
3395
3652
|
title: submitTitle,
|
|
3396
3653
|
"aria-label": submitTitle,
|
|
3397
|
-
children: isExecuting ? /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full animate-spin", style: { border: `1.5px solid ${hasCommand ?
|
|
3654
|
+
children: isExecuting ? /* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full animate-spin", style: { border: `1.5px solid ${hasCommand ? t.textInverse : t.textMuted}`, borderTopColor: "transparent" } }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 sm:h-4 sm:w-4" })
|
|
3398
3655
|
}
|
|
3399
3656
|
)
|
|
3400
3657
|
] });
|
|
3401
3658
|
})(),
|
|
3402
3659
|
/* @__PURE__ */ jsxs("div", { ref: toolbarRef, className: "flex items-center justify-between pt-2.5 gap-2", children: [
|
|
3403
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[
|
|
3404
|
-
/* @__PURE__ */
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
e
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
e
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
e
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
e
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3660
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[11px] min-w-0 flex-wrap", children: [
|
|
3661
|
+
chipsVisible && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3662
|
+
/* @__PURE__ */ jsx(
|
|
3663
|
+
"button",
|
|
3664
|
+
{
|
|
3665
|
+
type: "button",
|
|
3666
|
+
onClick: () => {
|
|
3667
|
+
onInputChange("@");
|
|
3668
|
+
inputRef.current?.focus();
|
|
3669
|
+
},
|
|
3670
|
+
title: "Insert @ mention",
|
|
3671
|
+
className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 min-h-[40px] sm:min-h-0 inline-flex items-center rounded-lg transition-colors font-semibold flex-shrink-0`,
|
|
3672
|
+
style: toolbarButtonStyle,
|
|
3673
|
+
onMouseEnter: (e) => {
|
|
3674
|
+
e.currentTarget.style.backgroundColor = toolbarButtonHover;
|
|
3675
|
+
},
|
|
3676
|
+
onMouseLeave: (e) => {
|
|
3677
|
+
e.currentTarget.style.backgroundColor = toolbarButtonBg;
|
|
3678
|
+
},
|
|
3679
|
+
children: toolbarIsCompact ? "@" : "@ mention"
|
|
3680
|
+
}
|
|
3681
|
+
),
|
|
3682
|
+
/* @__PURE__ */ jsx(
|
|
3683
|
+
"button",
|
|
3684
|
+
{
|
|
3685
|
+
type: "button",
|
|
3686
|
+
onClick: () => {
|
|
3687
|
+
onInputChange("/");
|
|
3688
|
+
inputRef.current?.focus();
|
|
3689
|
+
},
|
|
3690
|
+
title: "Insert / command",
|
|
3691
|
+
className: `${toolbarIsCompact ? "px-2" : "px-2.5"} py-1 min-h-[40px] sm:min-h-0 inline-flex items-center rounded-lg transition-colors font-semibold flex-shrink-0`,
|
|
3692
|
+
style: toolbarButtonStyle,
|
|
3693
|
+
onMouseEnter: (e) => {
|
|
3694
|
+
e.currentTarget.style.backgroundColor = toolbarButtonHover;
|
|
3695
|
+
},
|
|
3696
|
+
onMouseLeave: (e) => {
|
|
3697
|
+
e.currentTarget.style.backgroundColor = toolbarButtonBg;
|
|
3698
|
+
},
|
|
3699
|
+
children: toolbarIsCompact ? "/" : "/ commands"
|
|
3700
|
+
}
|
|
3701
|
+
)
|
|
3702
|
+
] }),
|
|
3444
3703
|
availableKGs && availableKGs.length > 0 && /* @__PURE__ */ jsx(Fragment, { children: activeKGScope ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md text-[10px] min-w-0", title: activeKGScope.label, style: { backgroundColor: "rgba(255,140,66,0.08)", border: "1px solid rgba(255,140,66,0.15)", color: "rgba(255,140,66,0.8)" }, children: [
|
|
3445
3704
|
/* @__PURE__ */ jsxs("svg", { className: "w-3 h-3 opacity-60 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
|
|
3446
3705
|
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101" }),
|
|
@@ -3454,7 +3713,7 @@ function TerminalInputBar({
|
|
|
3454
3713
|
] }),
|
|
3455
3714
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => onKGScopeChange?.(null), className: "ml-0.5 opacity-40 hover:opacity-100 transition-opacity", children: "\u2715" })
|
|
3456
3715
|
] }) : /* @__PURE__ */ jsx(KGScopeDropdown, { items: availableKGs, onSelect: (scope) => onKGScopeChange?.(scope), compact: toolbarIsCompact }) }),
|
|
3457
|
-
modeSelector ?? (onReasoningModeChange && /* @__PURE__ */ jsx(ReasoningModeSelector, { current: reasoningMode || null, onChange: onReasoningModeChange, compact: toolbarIsCompact }))
|
|
3716
|
+
chipsVisible && (modeSelector ?? (onReasoningModeChange && /* @__PURE__ */ jsx(ReasoningModeSelector, { current: reasoningMode || null, onChange: onReasoningModeChange, compact: toolbarIsCompact })))
|
|
3458
3717
|
] }),
|
|
3459
3718
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [
|
|
3460
3719
|
inputBarExtra,
|
|
@@ -3462,8 +3721,8 @@ function TerminalInputBar({
|
|
|
3462
3721
|
"button",
|
|
3463
3722
|
{
|
|
3464
3723
|
type: "button",
|
|
3465
|
-
disabled: isExecuting,
|
|
3466
|
-
className: "h-8 w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
|
|
3724
|
+
disabled: isExecuting || disabled,
|
|
3725
|
+
className: "h-10 w-10 sm:h-8 sm:w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
|
|
3467
3726
|
style: toolbarButtonStyle,
|
|
3468
3727
|
title: "Upload files",
|
|
3469
3728
|
onClick: () => fileInputRef.current?.click(),
|
|
@@ -3480,8 +3739,8 @@ function TerminalInputBar({
|
|
|
3480
3739
|
"button",
|
|
3481
3740
|
{
|
|
3482
3741
|
type: "button",
|
|
3483
|
-
disabled: isExecuting,
|
|
3484
|
-
className: "h-8 w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
|
|
3742
|
+
disabled: isExecuting || disabled,
|
|
3743
|
+
className: "h-10 w-10 sm:h-8 sm:w-8 rounded-xl disabled:opacity-30 disabled:cursor-not-allowed flex items-center justify-center transition-all duration-200",
|
|
3485
3744
|
style: toolbarButtonStyle,
|
|
3486
3745
|
title: "List files",
|
|
3487
3746
|
onClick: () => onListFilesCommand(),
|
|
@@ -3512,7 +3771,7 @@ var KIND_DOT = {
|
|
|
3512
3771
|
};
|
|
3513
3772
|
function SlashMentionPicker({ candidates, selectedIndex, onPick }) {
|
|
3514
3773
|
const t = useTheme();
|
|
3515
|
-
const isLight = t.bgRaised === "#ffffff";
|
|
3774
|
+
const isLight = t.mode ? t.mode === "light" : t.bgRaised === "#ffffff";
|
|
3516
3775
|
if (candidates.length === 0) return null;
|
|
3517
3776
|
return /* @__PURE__ */ jsxs(
|
|
3518
3777
|
"div",
|
|
@@ -3601,16 +3860,15 @@ function useCommandHistory() {
|
|
|
3601
3860
|
}, []);
|
|
3602
3861
|
return { commandHistory, historyIndex, pushCommand, navigateUp, navigateDown, resetIndex };
|
|
3603
3862
|
}
|
|
3604
|
-
function useFocusManagement() {
|
|
3863
|
+
function useFocusManagement(autoFocus = true) {
|
|
3605
3864
|
const inputRef = useRef(null);
|
|
3606
3865
|
const focusInput = useCallback(() => {
|
|
3607
3866
|
const selection = window.getSelection();
|
|
3608
3867
|
if (selection && selection.toString().length > 0) return;
|
|
3609
|
-
|
|
3610
|
-
inputRef.current.focus();
|
|
3611
|
-
}
|
|
3868
|
+
inputRef.current?.focus({ preventScroll: true });
|
|
3612
3869
|
}, []);
|
|
3613
3870
|
useEffect(() => {
|
|
3871
|
+
if (!autoFocus) return;
|
|
3614
3872
|
const timer = setTimeout(focusInput, 100);
|
|
3615
3873
|
const handleVisibilityChange = () => {
|
|
3616
3874
|
if (!document.hidden) {
|
|
@@ -3622,11 +3880,12 @@ function useFocusManagement() {
|
|
|
3622
3880
|
clearTimeout(timer);
|
|
3623
3881
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
3624
3882
|
};
|
|
3625
|
-
}, [focusInput]);
|
|
3883
|
+
}, [focusInput, autoFocus]);
|
|
3626
3884
|
return { inputRef, focusInput };
|
|
3627
3885
|
}
|
|
3628
3886
|
function useStreamingChat({
|
|
3629
3887
|
config,
|
|
3888
|
+
authToken,
|
|
3630
3889
|
onStreamRequest,
|
|
3631
3890
|
reasoningMode,
|
|
3632
3891
|
setTerminalHistory,
|
|
@@ -3635,11 +3894,14 @@ function useStreamingChat({
|
|
|
3635
3894
|
currentUser,
|
|
3636
3895
|
sourceKGNodes
|
|
3637
3896
|
}) {
|
|
3897
|
+
const authTokenRef = useRef(authToken);
|
|
3898
|
+
authTokenRef.current = authToken;
|
|
3638
3899
|
const sourceKGNodesRef = useRef(sourceKGNodes);
|
|
3639
3900
|
sourceKGNodesRef.current = sourceKGNodes;
|
|
3640
3901
|
const reasoningModeRef = useRef(reasoningMode);
|
|
3641
3902
|
reasoningModeRef.current = reasoningMode;
|
|
3642
3903
|
const [isExecuting, setIsExecuting] = useState(false);
|
|
3904
|
+
const turnSequence = useRef(0);
|
|
3643
3905
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
3644
3906
|
const [progressState, setProgressState] = useState(null);
|
|
3645
3907
|
const [activityEvents, setActivityEvents] = useState([]);
|
|
@@ -3655,6 +3917,15 @@ function useStreamingChat({
|
|
|
3655
3917
|
const currentStreamingLineId = useRef(null);
|
|
3656
3918
|
const liveRunIdRef = useRef(null);
|
|
3657
3919
|
liveRunIdRef.current = liveRunId;
|
|
3920
|
+
const mountEpoch = useRef(0);
|
|
3921
|
+
useEffect(() => {
|
|
3922
|
+
const epoch = ++mountEpoch.current;
|
|
3923
|
+
return () => {
|
|
3924
|
+
void Promise.resolve().then(() => {
|
|
3925
|
+
if (mountEpoch.current === epoch) currentStreamingLineId.current = null;
|
|
3926
|
+
});
|
|
3927
|
+
};
|
|
3928
|
+
}, []);
|
|
3658
3929
|
useEffect(() => {
|
|
3659
3930
|
progressStateRef.current = progressState;
|
|
3660
3931
|
}, [progressState]);
|
|
@@ -3707,45 +3978,54 @@ function useStreamingChat({
|
|
|
3707
3978
|
currentStreamingLineId.current = null;
|
|
3708
3979
|
setTimeout(() => focusInput(), 50);
|
|
3709
3980
|
}, [focusInput]);
|
|
3710
|
-
const
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
console.error("Failed to send pipeline input:", e);
|
|
3730
|
-
}
|
|
3731
|
-
},
|
|
3732
|
-
[config.agentsApiUrl]
|
|
3733
|
-
);
|
|
3981
|
+
const postPipelineAction = useCallback(async (runId, action2, body) => {
|
|
3982
|
+
const headers = config.getAuthHeaders?.() ?? (authTokenRef.current ? { Authorization: `Bearer ${authTokenRef.current}` } : {});
|
|
3983
|
+
const response = await fetch(`${config.agentsApiUrl || "http://localhost:3001"}/pipelines/${runId}/${action2}`, {
|
|
3984
|
+
method: "POST",
|
|
3985
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
3986
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
3987
|
+
});
|
|
3988
|
+
if (!response.ok) throw new Error(`The request was not accepted (${response.status}). Please try again.`);
|
|
3989
|
+
}, [config]);
|
|
3990
|
+
const handleHilSubmit = useCallback(async (message) => {
|
|
3991
|
+
const runId = liveRunIdRef.current;
|
|
3992
|
+
if (!runId) return;
|
|
3993
|
+
try {
|
|
3994
|
+
if (message.trim()) await postPipelineAction(runId, "input", { kind: "guidance", content: message });
|
|
3995
|
+
await postPipelineAction(runId, "input", { kind: "proceed" });
|
|
3996
|
+
} catch (error) {
|
|
3997
|
+
addTerminalLine("error", `Your input was not sent. ${error.message}`);
|
|
3998
|
+
}
|
|
3999
|
+
}, [postPipelineAction, addTerminalLine]);
|
|
3734
4000
|
const handleCancelReasoning = useCallback(async () => {
|
|
3735
4001
|
const runId = liveRunIdRef.current;
|
|
3736
4002
|
if (!runId) return;
|
|
3737
|
-
const apiUrl = config.agentsApiUrl || "http://localhost:3001";
|
|
3738
|
-
setProgressState(null);
|
|
3739
|
-
resetStreamState();
|
|
3740
4003
|
try {
|
|
3741
|
-
await
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
} catch (
|
|
3746
|
-
|
|
4004
|
+
await postPipelineAction(runId, "cancel");
|
|
4005
|
+
setProgressState(null);
|
|
4006
|
+
resetStreamState();
|
|
4007
|
+
addTerminalLine("info", "Stopped the analysis.");
|
|
4008
|
+
} catch (error) {
|
|
4009
|
+
addTerminalLine("error", `The analysis is still running. ${error.message}`);
|
|
3747
4010
|
}
|
|
3748
|
-
}, [
|
|
4011
|
+
}, [postPipelineAction, resetStreamState, addTerminalLine]);
|
|
4012
|
+
const settleAgentSteps = useCallback(
|
|
4013
|
+
(lineId) => {
|
|
4014
|
+
setTerminalHistory((prev) => {
|
|
4015
|
+
const idx = prev.findIndex((line) => line.id === lineId);
|
|
4016
|
+
if (idx === -1) return prev;
|
|
4017
|
+
const meta = prev[idx].metadata;
|
|
4018
|
+
if (!meta?.agentStepsLive) return prev;
|
|
4019
|
+
const updated = [...prev];
|
|
4020
|
+
updated[idx] = {
|
|
4021
|
+
...updated[idx],
|
|
4022
|
+
metadata: { ...updated[idx].metadata || {}, agentStepsLive: false }
|
|
4023
|
+
};
|
|
4024
|
+
return updated;
|
|
4025
|
+
});
|
|
4026
|
+
},
|
|
4027
|
+
[setTerminalHistory]
|
|
4028
|
+
);
|
|
3749
4029
|
const handleStreamingChat = useCallback(
|
|
3750
4030
|
async (cmd) => {
|
|
3751
4031
|
if (isProcessingRef.current || !onStreamRequest) return;
|
|
@@ -3757,8 +4037,9 @@ function useStreamingChat({
|
|
|
3757
4037
|
const startMs = Date.now();
|
|
3758
4038
|
setStreamTransparency({ startedAtMs: startMs, lastEventAtMs: startMs });
|
|
3759
4039
|
setActivityEvents([]);
|
|
3760
|
-
const
|
|
3761
|
-
const
|
|
4040
|
+
const turnKey = `${Date.now()}-${++turnSequence.current}`;
|
|
4041
|
+
const userCommandId = `${turnKey}:question`;
|
|
4042
|
+
const streamingLineId = `${turnKey}:answer`;
|
|
3762
4043
|
currentStreamingLineId.current = streamingLineId;
|
|
3763
4044
|
const userCommandEntry = {
|
|
3764
4045
|
id: userCommandId,
|
|
@@ -3784,14 +4065,14 @@ function useStreamingChat({
|
|
|
3784
4065
|
setTerminalHistory((prev) => [
|
|
3785
4066
|
...prev,
|
|
3786
4067
|
{
|
|
3787
|
-
id:
|
|
4068
|
+
id: `${turnKey}:before-question`,
|
|
3788
4069
|
type: "info",
|
|
3789
4070
|
content: "",
|
|
3790
4071
|
timestamp: /* @__PURE__ */ new Date()
|
|
3791
4072
|
},
|
|
3792
4073
|
userCommandEntry,
|
|
3793
4074
|
{
|
|
3794
|
-
id:
|
|
4075
|
+
id: `${turnKey}:before-answer`,
|
|
3795
4076
|
type: "info",
|
|
3796
4077
|
content: "",
|
|
3797
4078
|
timestamp: /* @__PURE__ */ new Date()
|
|
@@ -3805,10 +4086,37 @@ function useStreamingChat({
|
|
|
3805
4086
|
let sources;
|
|
3806
4087
|
let kgId;
|
|
3807
4088
|
let runId;
|
|
4089
|
+
const steps = /* @__PURE__ */ new Map();
|
|
4090
|
+
const fail = (error) => {
|
|
4091
|
+
if (currentStreamingLineId.current !== streamingLineId) return;
|
|
4092
|
+
settleAgentSteps(streamingLineId);
|
|
4093
|
+
updateStreamingLine(
|
|
4094
|
+
streamingLineId,
|
|
4095
|
+
fullResponse,
|
|
4096
|
+
pageSuggestions,
|
|
4097
|
+
suggestedActions,
|
|
4098
|
+
progressStateRef.current ? captureReasoningSnapshot(progressStateRef.current, true) : void 0,
|
|
4099
|
+
pipelineDraft,
|
|
4100
|
+
sources,
|
|
4101
|
+
kgId,
|
|
4102
|
+
runId
|
|
4103
|
+
);
|
|
4104
|
+
setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, completion: { stop_reason: /connection|interrupt/i.test(error) ? "interrupted" : "failed" } } } : entry));
|
|
4105
|
+
addTerminalLine("error", error);
|
|
4106
|
+
setProgressState(null);
|
|
4107
|
+
resetStreamState();
|
|
4108
|
+
};
|
|
3808
4109
|
try {
|
|
3809
4110
|
await onStreamRequest(cmd, {
|
|
3810
4111
|
onChunk: (chunk) => {
|
|
4112
|
+
if (currentStreamingLineId.current !== streamingLineId) return;
|
|
4113
|
+
if (chunk.entryMetadata) {
|
|
4114
|
+
setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, ...chunk.entryMetadata } } : entry));
|
|
4115
|
+
}
|
|
3811
4116
|
const eventMs = Date.now();
|
|
4117
|
+
if (chunk.completion) {
|
|
4118
|
+
setTerminalHistory((prev) => prev.map((entry) => entry.id === streamingLineId ? { ...entry, metadata: { ...entry.metadata, completion: chunk.completion } } : entry));
|
|
4119
|
+
}
|
|
3812
4120
|
if (chunk.sender) {
|
|
3813
4121
|
setStreamingLineSender(streamingLineId, chunk.sender);
|
|
3814
4122
|
if (currentUser) {
|
|
@@ -3821,6 +4129,28 @@ function useStreamingChat({
|
|
|
3821
4129
|
if (chunk.collaboration) {
|
|
3822
4130
|
setCollaborationState(chunk.collaboration);
|
|
3823
4131
|
}
|
|
4132
|
+
if (chunk.step) {
|
|
4133
|
+
steps.set(chunk.step.seq, chunk.step);
|
|
4134
|
+
const ordered = Array.from(steps.values()).sort((a, b) => a.seq - b.seq);
|
|
4135
|
+
setTerminalHistory((prev) => {
|
|
4136
|
+
const idx = prev.findIndex((line) => line.id === streamingLineId);
|
|
4137
|
+
if (idx === -1) return prev;
|
|
4138
|
+
const updated = [...prev];
|
|
4139
|
+
updated[idx] = {
|
|
4140
|
+
...updated[idx],
|
|
4141
|
+
metadata: {
|
|
4142
|
+
...updated[idx].metadata || {},
|
|
4143
|
+
agentSteps: ordered,
|
|
4144
|
+
// Explicit rather than inferred from the streaming cursor:
|
|
4145
|
+
// a tool loop runs to completion BEFORE the first answer
|
|
4146
|
+
// token, so during the whole loop the entry's content is
|
|
4147
|
+
// empty and carries no cursor to read.
|
|
4148
|
+
agentStepsLive: true
|
|
4149
|
+
}
|
|
4150
|
+
};
|
|
4151
|
+
return updated;
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
3824
4154
|
const ckgId = extractKgId(chunk, chunk.progress);
|
|
3825
4155
|
const cRunId = chunk.run_id || chunk.progress?.run_id;
|
|
3826
4156
|
const ctId = chunk.thread_id || chunk.progress?.thread_id || chunk.reasoning_thread_id || chunk.progress?.reasoning_thread_id;
|
|
@@ -3964,49 +4294,14 @@ function useStreamingChat({
|
|
|
3964
4294
|
kgId,
|
|
3965
4295
|
runId
|
|
3966
4296
|
);
|
|
4297
|
+
settleAgentSteps(streamingLineId);
|
|
3967
4298
|
resetStreamState();
|
|
3968
4299
|
}
|
|
3969
4300
|
},
|
|
3970
|
-
onError:
|
|
3971
|
-
if (currentStreamingLineId.current === streamingLineId) {
|
|
3972
|
-
if (progressStateRef.current) {
|
|
3973
|
-
const snap = captureReasoningSnapshot(
|
|
3974
|
-
progressStateRef.current,
|
|
3975
|
-
true
|
|
3976
|
-
);
|
|
3977
|
-
updateStreamingLine(
|
|
3978
|
-
streamingLineId,
|
|
3979
|
-
fullResponse || "",
|
|
3980
|
-
void 0,
|
|
3981
|
-
void 0,
|
|
3982
|
-
snap
|
|
3983
|
-
);
|
|
3984
|
-
setProgressState(null);
|
|
3985
|
-
} else {
|
|
3986
|
-
addTerminalLine("error", `STREAMING ERROR: ${error}`);
|
|
3987
|
-
setProgressState(null);
|
|
3988
|
-
}
|
|
3989
|
-
resetStreamState();
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
4301
|
+
onError: fail
|
|
3992
4302
|
}, reasoningModeRef.current ? { reasoningMode: reasoningModeRef.current } : void 0);
|
|
3993
4303
|
} catch (error) {
|
|
3994
|
-
|
|
3995
|
-
const snap = captureReasoningSnapshot(
|
|
3996
|
-
progressStateRef.current,
|
|
3997
|
-
true
|
|
3998
|
-
);
|
|
3999
|
-
updateStreamingLine(
|
|
4000
|
-
currentStreamingLineId.current,
|
|
4001
|
-
fullResponse || "",
|
|
4002
|
-
void 0,
|
|
4003
|
-
void 0,
|
|
4004
|
-
snap
|
|
4005
|
-
);
|
|
4006
|
-
}
|
|
4007
|
-
addTerminalLine("error", `STREAMING EXCEPTION: ${error.message}`);
|
|
4008
|
-
setProgressState(null);
|
|
4009
|
-
resetStreamState();
|
|
4304
|
+
fail(error?.message || "The answer could not be completed.");
|
|
4010
4305
|
}
|
|
4011
4306
|
},
|
|
4012
4307
|
[
|
|
@@ -4015,7 +4310,9 @@ function useStreamingChat({
|
|
|
4015
4310
|
updateStreamingLine,
|
|
4016
4311
|
setStreamingLineSender,
|
|
4017
4312
|
resetStreamState,
|
|
4018
|
-
addTerminalLine
|
|
4313
|
+
addTerminalLine,
|
|
4314
|
+
settleAgentSteps,
|
|
4315
|
+
currentUser
|
|
4019
4316
|
]
|
|
4020
4317
|
);
|
|
4021
4318
|
const clearReasoningSession = useCallback(() => {
|
|
@@ -4108,6 +4405,7 @@ function useTerminalCore({
|
|
|
4108
4405
|
onReasoningModeChangeProp,
|
|
4109
4406
|
reasoningRef,
|
|
4110
4407
|
workingGroupContextProp = null,
|
|
4408
|
+
autoFocusInput = true,
|
|
4111
4409
|
onResolveWorkingGroup,
|
|
4112
4410
|
onRagFileUpload,
|
|
4113
4411
|
onListRagFiles,
|
|
@@ -4125,12 +4423,13 @@ function useTerminalCore({
|
|
|
4125
4423
|
pollIntervalMs,
|
|
4126
4424
|
authToken
|
|
4127
4425
|
}) {
|
|
4426
|
+
const agentLabel = config.agentLabel?.trim() || DEFAULT_AGENT_LABEL;
|
|
4128
4427
|
const [internalReasoningMode, setInternalReasoningMode] = useState(null);
|
|
4129
4428
|
const reasoningMode = reasoningModeProp !== void 0 ? reasoningModeProp : internalReasoningMode;
|
|
4130
4429
|
const onReasoningModeChange = onReasoningModeChangeProp || setInternalReasoningMode;
|
|
4131
4430
|
const [terminalHistory, setTerminalHistory] = useState(() => {
|
|
4132
4431
|
if (initialHistory && initialHistory.length > 0) return initialHistory;
|
|
4133
|
-
return [{ type: "system", content:
|
|
4432
|
+
return [{ type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() }];
|
|
4134
4433
|
});
|
|
4135
4434
|
useEffect(() => {
|
|
4136
4435
|
if (historyRef) {
|
|
@@ -4143,7 +4442,7 @@ function useTerminalCore({
|
|
|
4143
4442
|
const enrichedHistory = useMemo(() => {
|
|
4144
4443
|
if (!sourceKGNodes?.length) return terminalHistory;
|
|
4145
4444
|
let changed = false;
|
|
4146
|
-
const
|
|
4445
|
+
const result2 = terminalHistory.map((entry) => {
|
|
4147
4446
|
if ((entry.type === "response" || entry.type === "success") && entry.content && entry.content.length > 20 && !entry.sources?.length) {
|
|
4148
4447
|
const sources = extractKGSources(entry.content, sourceKGNodes);
|
|
4149
4448
|
if (sources.length > 0) {
|
|
@@ -4153,7 +4452,7 @@ function useTerminalCore({
|
|
|
4153
4452
|
}
|
|
4154
4453
|
return entry;
|
|
4155
4454
|
});
|
|
4156
|
-
return changed ?
|
|
4455
|
+
return changed ? result2 : terminalHistory;
|
|
4157
4456
|
}, [terminalHistory, sourceKGNodes]);
|
|
4158
4457
|
useEffect(() => {
|
|
4159
4458
|
if (initialHistory && initialHistory.length > 0) {
|
|
@@ -4173,6 +4472,7 @@ function useTerminalCore({
|
|
|
4173
4472
|
setTerminalHistory((prev) => [...prev, { id: Date.now().toString(), type: "response", content, timestamp: /* @__PURE__ */ new Date(), suggested_actions: actions }]);
|
|
4174
4473
|
}, []);
|
|
4175
4474
|
const [currentCommand, setCurrentCommand] = useState("");
|
|
4475
|
+
const [pendingSubmit, setPendingSubmit] = useState(null);
|
|
4176
4476
|
const [workingGroupContext, setWorkingGroupContext] = useState(workingGroupContextProp);
|
|
4177
4477
|
const [hasShownWelcome, setHasShownWelcome] = useState(false);
|
|
4178
4478
|
const [isInputFocused, setIsInputFocused] = useState(true);
|
|
@@ -4185,13 +4485,16 @@ function useTerminalCore({
|
|
|
4185
4485
|
for (const ctrl of uploadAbortsRef.current) ctrl.abort();
|
|
4186
4486
|
uploadAbortsRef.current = [];
|
|
4187
4487
|
}, []);
|
|
4188
|
-
const { inputRef, focusInput } = useFocusManagement();
|
|
4488
|
+
const { inputRef, focusInput } = useFocusManagement(autoFocusInput);
|
|
4189
4489
|
useEffect(() => {
|
|
4190
4490
|
function onPrefill(e) {
|
|
4191
4491
|
const detail = e.detail;
|
|
4192
4492
|
if (!detail || typeof detail.value !== "string") return;
|
|
4193
4493
|
const value = detail.value;
|
|
4194
4494
|
setCurrentCommand(value);
|
|
4495
|
+
if (e.detail?.submit) {
|
|
4496
|
+
setPendingSubmit(value);
|
|
4497
|
+
}
|
|
4195
4498
|
requestAnimationFrame(() => {
|
|
4196
4499
|
focusInput();
|
|
4197
4500
|
const el = inputRef.current;
|
|
@@ -4205,6 +4508,9 @@ function useTerminalCore({
|
|
|
4205
4508
|
window.removeEventListener("yieldfabric:terminal:prefill", onPrefill);
|
|
4206
4509
|
};
|
|
4207
4510
|
}, [focusInput, inputRef]);
|
|
4511
|
+
const restoreInputFocus = useCallback(() => {
|
|
4512
|
+
if (autoFocusInput) focusInput();
|
|
4513
|
+
}, [autoFocusInput, focusInput]);
|
|
4208
4514
|
const {
|
|
4209
4515
|
isExecuting,
|
|
4210
4516
|
setIsExecuting,
|
|
@@ -4224,11 +4530,12 @@ function useTerminalCore({
|
|
|
4224
4530
|
activityEvents
|
|
4225
4531
|
} = useStreamingChat({
|
|
4226
4532
|
config,
|
|
4533
|
+
authToken,
|
|
4227
4534
|
onStreamRequest,
|
|
4228
4535
|
reasoningMode,
|
|
4229
4536
|
setTerminalHistory,
|
|
4230
4537
|
addTerminalLine,
|
|
4231
|
-
focusInput,
|
|
4538
|
+
focusInput: restoreInputFocus,
|
|
4232
4539
|
currentUser,
|
|
4233
4540
|
sourceKGNodes
|
|
4234
4541
|
});
|
|
@@ -4291,12 +4598,12 @@ function useTerminalCore({
|
|
|
4291
4598
|
}, [onResolveWorkingGroup]);
|
|
4292
4599
|
useEffect(() => {
|
|
4293
4600
|
const handleActionResult = (event) => {
|
|
4294
|
-
const
|
|
4295
|
-
if (
|
|
4601
|
+
const result2 = event.detail;
|
|
4602
|
+
if (result2.success) {
|
|
4296
4603
|
addTerminalLine("success", "Action executed successfully!");
|
|
4297
|
-
if (
|
|
4604
|
+
if (result2.data) addTerminalLine("response", JSON.stringify(result2.data, null, 2));
|
|
4298
4605
|
} else {
|
|
4299
|
-
addTerminalLine("error", `Action failed: ${
|
|
4606
|
+
addTerminalLine("error", `Action failed: ${result2.error || "Unknown error"}`);
|
|
4300
4607
|
}
|
|
4301
4608
|
};
|
|
4302
4609
|
window.addEventListener("terminal-action-result", handleActionResult);
|
|
@@ -4308,7 +4615,7 @@ function useTerminalCore({
|
|
|
4308
4615
|
const fullMessage = config.welcomeMessage;
|
|
4309
4616
|
const typingLineId = Date.now().toString();
|
|
4310
4617
|
setTerminalHistory([
|
|
4311
|
-
{ type: "system", content:
|
|
4618
|
+
{ type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
|
|
4312
4619
|
{ id: typingLineId, type: "info", content: "", timestamp: /* @__PURE__ */ new Date() }
|
|
4313
4620
|
]);
|
|
4314
4621
|
let i = 0;
|
|
@@ -4364,7 +4671,7 @@ function useTerminalCore({
|
|
|
4364
4671
|
}, [commandPaletteItems, selectedPaletteItem]);
|
|
4365
4672
|
const handleClearCommand = useCallback(() => {
|
|
4366
4673
|
setTerminalHistory([
|
|
4367
|
-
{ type: "system", content:
|
|
4674
|
+
{ type: "system", content: agentLabel, timestamp: /* @__PURE__ */ new Date() },
|
|
4368
4675
|
{ type: "system", content: "Terminal cleared.", timestamp: /* @__PURE__ */ new Date() }
|
|
4369
4676
|
]);
|
|
4370
4677
|
setCurrentCommand("");
|
|
@@ -4387,11 +4694,11 @@ function useTerminalCore({
|
|
|
4387
4694
|
addTerminalLine("info", `Uploading ${files.length} file(s)...`);
|
|
4388
4695
|
setIsExecuting(true);
|
|
4389
4696
|
try {
|
|
4390
|
-
const
|
|
4391
|
-
if (
|
|
4392
|
-
addTerminalLine("success", `Started ${
|
|
4393
|
-
if (
|
|
4394
|
-
const runs =
|
|
4697
|
+
const result2 = await onRagFileUpload(files, workingGroupContext);
|
|
4698
|
+
if (result2.success) {
|
|
4699
|
+
addTerminalLine("success", `Started ${result2.pipelineRuns?.length ?? result2.documentsIngested ?? files.length} ingestion pipeline(s)`);
|
|
4700
|
+
if (result2.message) addTerminalLine("response", result2.message);
|
|
4701
|
+
const runs = result2.pipelineRuns ?? [];
|
|
4395
4702
|
if (runs.length > 0) {
|
|
4396
4703
|
const apiUrl = config.agentsApiUrl || "http://localhost:3001";
|
|
4397
4704
|
const remaining = new Set(runs.map((r) => r.run_id));
|
|
@@ -4478,7 +4785,7 @@ function useTerminalCore({
|
|
|
4478
4785
|
await handleListFilesCommand();
|
|
4479
4786
|
}
|
|
4480
4787
|
} else {
|
|
4481
|
-
addTerminalLine("error", `Upload failed${
|
|
4788
|
+
addTerminalLine("error", `Upload failed${result2.message ? `: ${result2.message}` : ""}`);
|
|
4482
4789
|
}
|
|
4483
4790
|
} catch (error) {
|
|
4484
4791
|
addTerminalLine("error", `Upload exception: ${error?.message || "Unknown error"}`);
|
|
@@ -4487,7 +4794,7 @@ function useTerminalCore({
|
|
|
4487
4794
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
4488
4795
|
setTimeout(() => focusInput(), 50);
|
|
4489
4796
|
}
|
|
4490
|
-
}, [onRagFileUpload, onListRagFiles, workingGroupContext, addTerminalLine, setIsExecuting, focusInput, config.agentsApiUrl]);
|
|
4797
|
+
}, [onRagFileUpload, onListRagFiles, workingGroupContext, addTerminalLine, setIsExecuting, focusInput, config.agentsApiUrl, authToken]);
|
|
4491
4798
|
const handleListFilesCommand = useCallback(async () => {
|
|
4492
4799
|
addTerminalLine("info", "");
|
|
4493
4800
|
addTerminalLine("command", "files");
|
|
@@ -4497,12 +4804,12 @@ function useTerminalCore({
|
|
|
4497
4804
|
}
|
|
4498
4805
|
setIsExecuting(true);
|
|
4499
4806
|
try {
|
|
4500
|
-
const
|
|
4501
|
-
if (!
|
|
4502
|
-
addTerminalLine("error", `Could not load files${
|
|
4807
|
+
const result2 = await onListRagFiles(workingGroupContext);
|
|
4808
|
+
if (!result2.success) {
|
|
4809
|
+
addTerminalLine("error", `Could not load files${result2.message ? `: ${result2.message}` : ""}`);
|
|
4503
4810
|
return;
|
|
4504
4811
|
}
|
|
4505
|
-
const files =
|
|
4812
|
+
const files = result2.files || [];
|
|
4506
4813
|
if (files.length === 0) {
|
|
4507
4814
|
addTerminalLine("info", "No files uploaded yet for this page working group.");
|
|
4508
4815
|
return;
|
|
@@ -4531,12 +4838,12 @@ function useTerminalCore({
|
|
|
4531
4838
|
return;
|
|
4532
4839
|
}
|
|
4533
4840
|
const title = payload.title || payload.document_id;
|
|
4534
|
-
const
|
|
4535
|
-
if (
|
|
4841
|
+
const result2 = await onDeleteRagFile(String(payload.document_id), workingGroupContext);
|
|
4842
|
+
if (result2.success) {
|
|
4536
4843
|
addTerminalLine("success", `Removed ${title}`);
|
|
4537
4844
|
await handleListFilesCommand();
|
|
4538
4845
|
} else {
|
|
4539
|
-
addTerminalLine("error", `Failed to remove ${title}${
|
|
4846
|
+
addTerminalLine("error", `Failed to remove ${title}${result2.message ? `: ${result2.message}` : ""}`);
|
|
4540
4847
|
}
|
|
4541
4848
|
return;
|
|
4542
4849
|
}
|
|
@@ -4546,9 +4853,9 @@ function useTerminalCore({
|
|
|
4546
4853
|
return;
|
|
4547
4854
|
}
|
|
4548
4855
|
const title = payload.title || payload.document_id;
|
|
4549
|
-
const
|
|
4550
|
-
if (
|
|
4551
|
-
else addTerminalLine("error", `Download failed for ${title}${
|
|
4856
|
+
const result2 = await onDownloadRagFile(String(payload.document_id), title, workingGroupContext);
|
|
4857
|
+
if (result2.success) addTerminalLine("success", `Download started: ${title}`);
|
|
4858
|
+
else addTerminalLine("error", `Download failed for ${title}${result2.message ? `: ${result2.message}` : ""}`);
|
|
4552
4859
|
return;
|
|
4553
4860
|
}
|
|
4554
4861
|
if (actionType === "resume_pipeline_run") {
|
|
@@ -4587,6 +4894,8 @@ function useTerminalCore({
|
|
|
4587
4894
|
window.dispatchEvent(new CustomEvent("terminal-action-execute", { detail: updatedAction, bubbles: true }));
|
|
4588
4895
|
}, [onDeleteRagFile, onDownloadRagFile, workingGroupContext, addTerminalLine, handleListFilesCommand, config.agentsApiUrl]);
|
|
4589
4896
|
return {
|
|
4897
|
+
// Identity
|
|
4898
|
+
agentLabel,
|
|
4590
4899
|
// History
|
|
4591
4900
|
terminalHistory,
|
|
4592
4901
|
setTerminalHistory,
|
|
@@ -4615,6 +4924,8 @@ function useTerminalCore({
|
|
|
4615
4924
|
// Command input
|
|
4616
4925
|
currentCommand,
|
|
4617
4926
|
setCurrentCommand,
|
|
4927
|
+
pendingSubmit,
|
|
4928
|
+
setPendingSubmit,
|
|
4618
4929
|
commandPaletteItems,
|
|
4619
4930
|
setCommandPaletteItems,
|
|
4620
4931
|
selectedPaletteItem,
|
|
@@ -4737,6 +5048,7 @@ function extractQuery(input, caret, enabledCommands, requireSlashCommand) {
|
|
|
4737
5048
|
return { query: tail, command: cmd };
|
|
4738
5049
|
}
|
|
4739
5050
|
function StandardTerminal({
|
|
5051
|
+
showBusyIndicator,
|
|
4740
5052
|
theme: themeOverrides,
|
|
4741
5053
|
config,
|
|
4742
5054
|
onCommandExecute,
|
|
@@ -4756,9 +5068,15 @@ function StandardTerminal({
|
|
|
4756
5068
|
onDeleteRagFile,
|
|
4757
5069
|
onDownloadRagFile,
|
|
4758
5070
|
workingGroupContext: workingGroupContextProp = null,
|
|
5071
|
+
showWorkingGroupBanner = true,
|
|
5072
|
+
autoFocusInput = true,
|
|
5073
|
+
inputPlaceholder,
|
|
5074
|
+
submitRequest,
|
|
5075
|
+
onSubmitRequest,
|
|
4759
5076
|
onPipelineDraftEdit,
|
|
4760
5077
|
onPipelineDraftReject,
|
|
4761
5078
|
onSubmitNote,
|
|
5079
|
+
onSubmitLog,
|
|
4762
5080
|
onMentionResolve,
|
|
4763
5081
|
onMentionPicked,
|
|
4764
5082
|
availableKGs,
|
|
@@ -4779,6 +5097,7 @@ function StandardTerminal({
|
|
|
4779
5097
|
widgets,
|
|
4780
5098
|
slots,
|
|
4781
5099
|
onSourcesActivate,
|
|
5100
|
+
onSourceActivate,
|
|
4782
5101
|
onPollMessages,
|
|
4783
5102
|
pollIntervalMs,
|
|
4784
5103
|
historyRef
|
|
@@ -4794,6 +5113,7 @@ function StandardTerminal({
|
|
|
4794
5113
|
reasoningRef,
|
|
4795
5114
|
workingGroupContextProp,
|
|
4796
5115
|
onResolveWorkingGroup,
|
|
5116
|
+
autoFocusInput,
|
|
4797
5117
|
onRagFileUpload,
|
|
4798
5118
|
onListRagFiles,
|
|
4799
5119
|
onDeleteRagFile,
|
|
@@ -4809,17 +5129,32 @@ function StandardTerminal({
|
|
|
4809
5129
|
showWelcomeMessage
|
|
4810
5130
|
});
|
|
4811
5131
|
const { pushCommand, navigateUp, navigateDown, resetIndex } = useCommandHistory();
|
|
5132
|
+
const consumedRequest = useRef(null);
|
|
5133
|
+
React15.useEffect(() => {
|
|
5134
|
+
if (!submitRequest || consumedRequest.current === submitRequest.id || !submitRequest.value.trim() || !onStreamRequest || core.isExecuting || core.isStreaming || core.currentStreamingLineId.current) return;
|
|
5135
|
+
consumedRequest.current = submitRequest.id;
|
|
5136
|
+
onSubmitRequest?.(submitRequest.id);
|
|
5137
|
+
void core.handleStreamingChat(submitRequest.value.trim());
|
|
5138
|
+
}, [
|
|
5139
|
+
submitRequest,
|
|
5140
|
+
onSubmitRequest,
|
|
5141
|
+
onStreamRequest,
|
|
5142
|
+
core.isExecuting,
|
|
5143
|
+
core.isStreaming,
|
|
5144
|
+
core.currentStreamingLineId,
|
|
5145
|
+
core.handleStreamingChat
|
|
5146
|
+
]);
|
|
4812
5147
|
const [suggestions, setSuggestions] = useState([]);
|
|
4813
5148
|
const [selectedSuggestion, setSelectedSuggestion] = useState(0);
|
|
4814
5149
|
const [internalAuthToken, setInternalAuthToken] = useState(authToken);
|
|
4815
5150
|
const authTokenRef = useRef(internalAuthToken);
|
|
4816
5151
|
authTokenRef.current = internalAuthToken;
|
|
4817
|
-
|
|
5152
|
+
React15.useEffect(() => {
|
|
4818
5153
|
if (authToken !== internalAuthToken) setInternalAuthToken(authToken);
|
|
4819
5154
|
}, [authToken]);
|
|
4820
5155
|
const [caretIndex, setCaretIndex] = useState(0);
|
|
4821
5156
|
const [slashPickedNames, setSlashPickedNames] = useState([]);
|
|
4822
|
-
const liveSlashPickedNames =
|
|
5157
|
+
const liveSlashPickedNames = React15.useMemo(
|
|
4823
5158
|
() => slashPickedNames.filter(
|
|
4824
5159
|
(n) => core.currentCommand.toLowerCase().includes(`@${n.toLowerCase()}`)
|
|
4825
5160
|
),
|
|
@@ -4906,6 +5241,11 @@ function StandardTerminal({
|
|
|
4906
5241
|
setSuggestions([]);
|
|
4907
5242
|
}
|
|
4908
5243
|
};
|
|
5244
|
+
React15.useEffect(() => {
|
|
5245
|
+
if (!core.pendingSubmit) return;
|
|
5246
|
+
core.setPendingSubmit(null);
|
|
5247
|
+
void handleSubmit();
|
|
5248
|
+
}, [core.pendingSubmit]);
|
|
4909
5249
|
const handleSubmit = async () => {
|
|
4910
5250
|
if (!core.currentCommand.trim() || core.isExecuting || core.isStreaming || core.currentStreamingLineId.current) return;
|
|
4911
5251
|
const rawCmd = core.currentCommand.trim();
|
|
@@ -4953,6 +5293,21 @@ function StandardTerminal({
|
|
|
4953
5293
|
setTimeout(() => core.focusInput(), 50);
|
|
4954
5294
|
return;
|
|
4955
5295
|
}
|
|
5296
|
+
if (command === "log") {
|
|
5297
|
+
const prose = args.join(" ");
|
|
5298
|
+
core.addTerminalLine("command", prose.trim() ? `log ${prose}` : "log");
|
|
5299
|
+
if (!onSubmitLog) {
|
|
5300
|
+
core.addTerminalLine("error", "Work capture is not available in this context.");
|
|
5301
|
+
} else if (!prose.trim()) {
|
|
5302
|
+
core.addTerminalLine("info", "Usage: /log <what you did or decided>");
|
|
5303
|
+
} else {
|
|
5304
|
+
const result2 = await onSubmitLog(prose);
|
|
5305
|
+
core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
|
|
5306
|
+
}
|
|
5307
|
+
core.setCurrentCommand("");
|
|
5308
|
+
setTimeout(() => core.focusInput(), 50);
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
4956
5311
|
if (isNaturalLanguage(cmd, config.endpoints) && onStreamRequest) {
|
|
4957
5312
|
await core.handleStreamingChat(cmd);
|
|
4958
5313
|
core.setCurrentCommand("");
|
|
@@ -5008,8 +5363,8 @@ function StandardTerminal({
|
|
|
5008
5363
|
);
|
|
5009
5364
|
return;
|
|
5010
5365
|
}
|
|
5011
|
-
const
|
|
5012
|
-
core.addTerminalLine(
|
|
5366
|
+
const result2 = await onSubmitNote(prose, scope);
|
|
5367
|
+
core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
|
|
5013
5368
|
};
|
|
5014
5369
|
const handleTokenCommand = (args) => {
|
|
5015
5370
|
core.addTerminalLine("command", `token ${args.join(" ")}`);
|
|
@@ -5037,18 +5392,18 @@ Method: ${parsed.endpoint.method}
|
|
|
5037
5392
|
Path: ${parsed.endpoint.path}`);
|
|
5038
5393
|
core.addTerminalLine("info", "");
|
|
5039
5394
|
try {
|
|
5040
|
-
const
|
|
5041
|
-
if (
|
|
5042
|
-
core.addTerminalLine("success",
|
|
5043
|
-
if (
|
|
5044
|
-
if (parsed.endpoint.id.includes("login") &&
|
|
5045
|
-
setInternalAuthToken(
|
|
5046
|
-
onAuthTokenChange?.(
|
|
5395
|
+
const result2 = await onCommandExecute(cmd, parsed.endpoint, parsed.args);
|
|
5396
|
+
if (result2.success) {
|
|
5397
|
+
core.addTerminalLine("success", result2.message || "RESPONSE: SUCCESS");
|
|
5398
|
+
if (result2.data) core.addTerminalLine("response", JSON.stringify(result2.data, null, 2));
|
|
5399
|
+
if (parsed.endpoint.id.includes("login") && result2.data?.token) {
|
|
5400
|
+
setInternalAuthToken(result2.data.token);
|
|
5401
|
+
onAuthTokenChange?.(result2.data.token);
|
|
5047
5402
|
core.addTerminalLine("success", "AUTH TOKEN AUTO-SAVED");
|
|
5048
5403
|
}
|
|
5049
5404
|
} else {
|
|
5050
|
-
core.addTerminalLine("error", `ERROR: ${
|
|
5051
|
-
if (
|
|
5405
|
+
core.addTerminalLine("error", `ERROR: ${result2.error || "Request failed"}`);
|
|
5406
|
+
if (result2.data) core.addTerminalLine("response", JSON.stringify(result2.data, null, 2));
|
|
5052
5407
|
}
|
|
5053
5408
|
} catch (error) {
|
|
5054
5409
|
core.addTerminalLine("error", `SYSTEM ERROR: ${error.message}`);
|
|
@@ -5071,14 +5426,17 @@ Path: ${parsed.endpoint.path}`);
|
|
|
5071
5426
|
className,
|
|
5072
5427
|
style,
|
|
5073
5428
|
showHeader,
|
|
5429
|
+
agentLabel: core.agentLabel,
|
|
5074
5430
|
focusInput: core.focusInput,
|
|
5075
5431
|
setTerminalHistory: core.setTerminalHistory,
|
|
5076
5432
|
terminalBodyRef: core.terminalBodyRef,
|
|
5077
5433
|
workingGroupContext: core.workingGroupContext,
|
|
5434
|
+
showWorkingGroupBanner,
|
|
5078
5435
|
progressState: core.progressState,
|
|
5079
5436
|
streamTransparency: core.streamTransparency,
|
|
5080
5437
|
streamNowMs: core.streamNowMs,
|
|
5081
5438
|
isExecuting: core.isExecuting,
|
|
5439
|
+
showBusyIndicator,
|
|
5082
5440
|
handleCancelReasoning: core.handleCancelReasoning,
|
|
5083
5441
|
onViewKnowledgeGraph,
|
|
5084
5442
|
onLiveKGUpdate,
|
|
@@ -5153,11 +5511,12 @@ Path: ${parsed.endpoint.path}`);
|
|
|
5153
5511
|
inputBar: /* @__PURE__ */ jsx(
|
|
5154
5512
|
TerminalInputBar,
|
|
5155
5513
|
{
|
|
5514
|
+
autoFocus: autoFocusInput,
|
|
5156
5515
|
inputRef: core.inputRef,
|
|
5157
5516
|
fileInputRef: core.fileInputRef,
|
|
5158
5517
|
currentCommand: core.currentCommand,
|
|
5159
5518
|
isExecuting: core.isExecuting,
|
|
5160
|
-
placeholder: activeKGScope ? `Ask about ${activeKGScope.label}...` : "Ask anything...",
|
|
5519
|
+
placeholder: activeKGScope ? `Ask about ${activeKGScope.label}...` : inputPlaceholder ?? "Ask anything...",
|
|
5161
5520
|
onInputChange: handleInputChange,
|
|
5162
5521
|
onKeyDown: handleKeyDown,
|
|
5163
5522
|
onSubmit: handleSubmit,
|
|
@@ -5194,6 +5553,7 @@ Path: ${parsed.endpoint.path}`);
|
|
|
5194
5553
|
authToken: authTokenRef.current,
|
|
5195
5554
|
onPageNavigation,
|
|
5196
5555
|
onSourcesActivate,
|
|
5556
|
+
onSourceActivate,
|
|
5197
5557
|
renderEntryExtra,
|
|
5198
5558
|
renderEntry,
|
|
5199
5559
|
widgets,
|
|
@@ -5484,6 +5844,7 @@ function useMentions(currentCommand, participants, mentionTargets) {
|
|
|
5484
5844
|
};
|
|
5485
5845
|
}
|
|
5486
5846
|
function ChatTerminal({
|
|
5847
|
+
showBusyIndicator,
|
|
5487
5848
|
theme: themeOverrides,
|
|
5488
5849
|
config,
|
|
5489
5850
|
className = "",
|
|
@@ -5499,6 +5860,8 @@ function ChatTerminal({
|
|
|
5499
5860
|
onDeleteRagFile,
|
|
5500
5861
|
onDownloadRagFile,
|
|
5501
5862
|
workingGroupContext: workingGroupContextProp = null,
|
|
5863
|
+
showWorkingGroupBanner = true,
|
|
5864
|
+
autoFocusInput = true,
|
|
5502
5865
|
onPipelineDraftEdit,
|
|
5503
5866
|
onPipelineDraftReject,
|
|
5504
5867
|
onPageNavigation,
|
|
@@ -5521,6 +5884,7 @@ function ChatTerminal({
|
|
|
5521
5884
|
widgets,
|
|
5522
5885
|
slots,
|
|
5523
5886
|
onSourcesActivate,
|
|
5887
|
+
onSourceActivate,
|
|
5524
5888
|
historyRef,
|
|
5525
5889
|
currentUser,
|
|
5526
5890
|
onSendMessage,
|
|
@@ -5530,8 +5894,10 @@ function ChatTerminal({
|
|
|
5530
5894
|
typingUsers,
|
|
5531
5895
|
onTyping,
|
|
5532
5896
|
onSubmitNote,
|
|
5897
|
+
onSubmitLog,
|
|
5533
5898
|
onMentionResolve,
|
|
5534
|
-
onMentionPicked
|
|
5899
|
+
onMentionPicked,
|
|
5900
|
+
authToken
|
|
5535
5901
|
}) {
|
|
5536
5902
|
const core = useTerminalCore({
|
|
5537
5903
|
config,
|
|
@@ -5544,6 +5910,7 @@ function ChatTerminal({
|
|
|
5544
5910
|
reasoningRef,
|
|
5545
5911
|
workingGroupContextProp,
|
|
5546
5912
|
onResolveWorkingGroup,
|
|
5913
|
+
autoFocusInput,
|
|
5547
5914
|
onRagFileUpload,
|
|
5548
5915
|
onListRagFiles,
|
|
5549
5916
|
onDeleteRagFile,
|
|
@@ -5557,7 +5924,8 @@ function ChatTerminal({
|
|
|
5557
5924
|
showWelcomeMessage,
|
|
5558
5925
|
currentUser,
|
|
5559
5926
|
onPollMessages,
|
|
5560
|
-
pollIntervalMs
|
|
5927
|
+
pollIntervalMs,
|
|
5928
|
+
authToken
|
|
5561
5929
|
});
|
|
5562
5930
|
useEffect(() => {
|
|
5563
5931
|
onActivityEventsChange?.(core.activityEvents);
|
|
@@ -5701,11 +6069,26 @@ function ChatTerminal({
|
|
|
5701
6069
|
`Usage: /${command} <prose>. Use @name to link an entity.`
|
|
5702
6070
|
);
|
|
5703
6071
|
} else {
|
|
5704
|
-
const
|
|
6072
|
+
const result2 = await onSubmitNote(
|
|
5705
6073
|
prose,
|
|
5706
6074
|
command === "personal" ? "personal" : "workspace"
|
|
5707
6075
|
);
|
|
5708
|
-
core.addTerminalLine(
|
|
6076
|
+
core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
|
|
6077
|
+
}
|
|
6078
|
+
core.setCurrentCommand("");
|
|
6079
|
+
setTimeout(() => core.focusInput(), 50);
|
|
6080
|
+
return;
|
|
6081
|
+
}
|
|
6082
|
+
if (command === "log") {
|
|
6083
|
+
const prose = args.join(" ");
|
|
6084
|
+
core.addTerminalLine("command", prose.trim() ? `log ${prose}` : "log");
|
|
6085
|
+
if (!onSubmitLog) {
|
|
6086
|
+
core.addTerminalLine("error", "Work capture is not available in this context.");
|
|
6087
|
+
} else if (!prose.trim()) {
|
|
6088
|
+
core.addTerminalLine("info", "Usage: /log <what you did or decided>");
|
|
6089
|
+
} else {
|
|
6090
|
+
const result2 = await onSubmitLog(prose);
|
|
6091
|
+
core.addTerminalLine(result2.ok ? "success" : "error", result2.message);
|
|
5709
6092
|
}
|
|
5710
6093
|
core.setCurrentCommand("");
|
|
5711
6094
|
setTimeout(() => core.focusInput(), 50);
|
|
@@ -5752,14 +6135,17 @@ function ChatTerminal({
|
|
|
5752
6135
|
className,
|
|
5753
6136
|
style,
|
|
5754
6137
|
showHeader,
|
|
6138
|
+
agentLabel: core.agentLabel,
|
|
5755
6139
|
focusInput: core.focusInput,
|
|
5756
6140
|
setTerminalHistory: core.setTerminalHistory,
|
|
5757
6141
|
terminalBodyRef: core.terminalBodyRef,
|
|
5758
6142
|
workingGroupContext: core.workingGroupContext,
|
|
6143
|
+
showWorkingGroupBanner,
|
|
5759
6144
|
progressState: core.progressState,
|
|
5760
6145
|
streamTransparency: core.streamTransparency,
|
|
5761
6146
|
streamNowMs: core.streamNowMs,
|
|
5762
6147
|
isExecuting: core.isExecuting,
|
|
6148
|
+
showBusyIndicator,
|
|
5763
6149
|
handleCancelReasoning: core.handleCancelReasoning,
|
|
5764
6150
|
onViewKnowledgeGraph,
|
|
5765
6151
|
onLiveKGUpdate,
|
|
@@ -5796,6 +6182,7 @@ function ChatTerminal({
|
|
|
5796
6182
|
inputBar: /* @__PURE__ */ jsx(
|
|
5797
6183
|
TerminalInputBar,
|
|
5798
6184
|
{
|
|
6185
|
+
autoFocus: autoFocusInput,
|
|
5799
6186
|
inputRef: core.inputRef,
|
|
5800
6187
|
fileInputRef: core.fileInputRef,
|
|
5801
6188
|
currentCommand: core.currentCommand,
|
|
@@ -5848,6 +6235,7 @@ function ChatTerminal({
|
|
|
5848
6235
|
config,
|
|
5849
6236
|
onPageNavigation,
|
|
5850
6237
|
onSourcesActivate,
|
|
6238
|
+
onSourceActivate,
|
|
5851
6239
|
renderEntryExtra,
|
|
5852
6240
|
renderEntry,
|
|
5853
6241
|
widgets,
|
|
@@ -7004,6 +7392,227 @@ function ReasoningHistoryCard({
|
|
|
7004
7392
|
}
|
|
7005
7393
|
);
|
|
7006
7394
|
}
|
|
7395
|
+
function subject(step) {
|
|
7396
|
+
const idx = step.detail.indexOf(": ");
|
|
7397
|
+
const s = idx > -1 ? step.detail.slice(idx + 2).trim() : "";
|
|
7398
|
+
return s.length ? s : null;
|
|
7399
|
+
}
|
|
7400
|
+
function bare(tool) {
|
|
7401
|
+
return tool.replace(/^yf_kg_/, "").replace(/^yf_/, "");
|
|
7402
|
+
}
|
|
7403
|
+
function action(step) {
|
|
7404
|
+
const subj = subject(step);
|
|
7405
|
+
const quoted = subj ? `\u201C${subj}\u201D` : null;
|
|
7406
|
+
switch (bare(step.tool)) {
|
|
7407
|
+
case "graphs":
|
|
7408
|
+
return "Listed knowledge collections";
|
|
7409
|
+
case "search":
|
|
7410
|
+
return quoted ? `Searched for ${quoted}` : "Searched the documents";
|
|
7411
|
+
case "count":
|
|
7412
|
+
return quoted ? `Counted mentions of ${quoted}` : "Counted mentions";
|
|
7413
|
+
case "enumerate":
|
|
7414
|
+
return quoted ? `Listed every match for ${quoted}` : "Listed every match";
|
|
7415
|
+
case "fetch":
|
|
7416
|
+
return "Read a document";
|
|
7417
|
+
case "entities":
|
|
7418
|
+
return "Listed the people and things found";
|
|
7419
|
+
case "explore":
|
|
7420
|
+
return quoted ? `Followed connections from ${quoted}` : "Followed connections";
|
|
7421
|
+
case "sets":
|
|
7422
|
+
return "Listed frozen document sets";
|
|
7423
|
+
case "get_set":
|
|
7424
|
+
return "Read a frozen document set";
|
|
7425
|
+
case "count_in_set":
|
|
7426
|
+
return quoted ? `Counted ${quoted} inside a set` : "Counted inside a set";
|
|
7427
|
+
case "think":
|
|
7428
|
+
return "Thought it through";
|
|
7429
|
+
default:
|
|
7430
|
+
return subj ? `${bare(step.tool).replace(/_/g, " ")} ${subj}` : bare(step.tool).replace(/_/g, " ");
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
function took(step) {
|
|
7434
|
+
if (step.status === "running") return null;
|
|
7435
|
+
const ms = Number(step.ms);
|
|
7436
|
+
if (!Number.isFinite(ms) || ms < 1e3) return null;
|
|
7437
|
+
return ms < 1e4 ? `${(ms / 1e3).toFixed(1)}s` : `${Math.round(ms / 1e3)}s`;
|
|
7438
|
+
}
|
|
7439
|
+
function groupTook(g) {
|
|
7440
|
+
const slowest = g.steps.reduce(
|
|
7441
|
+
(worst, s) => Number(s.ms) > Number(worst.ms) ? s : worst,
|
|
7442
|
+
g.steps[0]
|
|
7443
|
+
);
|
|
7444
|
+
return took(slowest);
|
|
7445
|
+
}
|
|
7446
|
+
function result(step) {
|
|
7447
|
+
if (step.status === "running") return null;
|
|
7448
|
+
if (step.status === "error") return "unavailable";
|
|
7449
|
+
const n = Number(step.outcome);
|
|
7450
|
+
if (!Number.isFinite(n)) return null;
|
|
7451
|
+
const [one, many] = {
|
|
7452
|
+
graphs: ["collection", "collections"],
|
|
7453
|
+
search: ["result", "results"],
|
|
7454
|
+
count: ["document", "documents"],
|
|
7455
|
+
enumerate: ["match", "matches"],
|
|
7456
|
+
entities: ["entity", "entities"],
|
|
7457
|
+
explore: ["connection", "connections"],
|
|
7458
|
+
sets: ["set", "sets"]
|
|
7459
|
+
}[bare(step.tool)] ?? ["result", "results"];
|
|
7460
|
+
if (n === 0) return "nothing found";
|
|
7461
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
7462
|
+
}
|
|
7463
|
+
function group(steps) {
|
|
7464
|
+
const out = [];
|
|
7465
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
7466
|
+
for (const step of steps) {
|
|
7467
|
+
const label = action(step);
|
|
7468
|
+
const key = `${step.round ?? ""}\0${label}`;
|
|
7469
|
+
const existing = byKey.get(key);
|
|
7470
|
+
if (existing) {
|
|
7471
|
+
existing.steps.push(step);
|
|
7472
|
+
continue;
|
|
7473
|
+
}
|
|
7474
|
+
const g = { key: step.seq, label, round: step.round, steps: [step] };
|
|
7475
|
+
byKey.set(key, g);
|
|
7476
|
+
out.push(g);
|
|
7477
|
+
}
|
|
7478
|
+
return out;
|
|
7479
|
+
}
|
|
7480
|
+
function groupResult(g) {
|
|
7481
|
+
if (g.steps.length === 1) return result(g.steps[0]);
|
|
7482
|
+
const done = g.steps.filter((s) => s.status !== "running");
|
|
7483
|
+
if (!done.length) return null;
|
|
7484
|
+
const hits = done.filter((s) => Number(s.outcome) > 0).length;
|
|
7485
|
+
if (hits === 0) return "nothing found";
|
|
7486
|
+
return `found in ${hits} of ${done.length}`;
|
|
7487
|
+
}
|
|
7488
|
+
function roundCount(steps) {
|
|
7489
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7490
|
+
for (const s of steps) if (typeof s.round === "number") seen.add(s.round);
|
|
7491
|
+
return seen.size ? seen.size : null;
|
|
7492
|
+
}
|
|
7493
|
+
function AgentStepTrace({ steps, working }) {
|
|
7494
|
+
const t = useTheme();
|
|
7495
|
+
const failed = steps.some((s) => s.status === "error");
|
|
7496
|
+
const prominent = working || failed;
|
|
7497
|
+
const [open, setOpen] = useState(prominent);
|
|
7498
|
+
const [touched, setTouched] = useState(false);
|
|
7499
|
+
const [hover, setHover] = useState(false);
|
|
7500
|
+
useEffect(() => {
|
|
7501
|
+
if (!touched) setOpen(prominent);
|
|
7502
|
+
}, [prominent, touched]);
|
|
7503
|
+
if (!steps.length) return null;
|
|
7504
|
+
const groups = group(steps);
|
|
7505
|
+
const rounds = roundCount(steps);
|
|
7506
|
+
const n = rounds ?? groups.length;
|
|
7507
|
+
const count = `${n} ${rounds ? "round" : "step"}${n === 1 ? "" : "s"}`;
|
|
7508
|
+
const only = groups.length === 1 ? groups[0] : null;
|
|
7509
|
+
const summary = working ? `${action(steps[steps.length - 1])}\u2026` : failed ? `${count}, some unavailable` : only ? [
|
|
7510
|
+
only.label + (only.steps.length > 1 ? ` \xD7${only.steps.length}` : ""),
|
|
7511
|
+
groupResult(only)
|
|
7512
|
+
].filter(Boolean).join(" \u2014 ") : count;
|
|
7513
|
+
const toggle = /* @__PURE__ */ jsxs(
|
|
7514
|
+
"button",
|
|
7515
|
+
{
|
|
7516
|
+
type: "button",
|
|
7517
|
+
onClick: () => {
|
|
7518
|
+
setTouched(true);
|
|
7519
|
+
setOpen((o) => !o);
|
|
7520
|
+
},
|
|
7521
|
+
onMouseEnter: () => setHover(true),
|
|
7522
|
+
onMouseLeave: () => setHover(false),
|
|
7523
|
+
"aria-expanded": open,
|
|
7524
|
+
className: "flex w-full items-center gap-2 text-left text-xs",
|
|
7525
|
+
style: { color: failed ? t.error : hover ? t.text : t.textMuted },
|
|
7526
|
+
children: [
|
|
7527
|
+
working && /* @__PURE__ */ jsx(
|
|
7528
|
+
"span",
|
|
7529
|
+
{
|
|
7530
|
+
"aria-hidden": true,
|
|
7531
|
+
className: "inline-block h-1.5 w-1.5 shrink-0 rounded-full motion-safe:animate-pulse",
|
|
7532
|
+
style: { backgroundColor: t.primary }
|
|
7533
|
+
}
|
|
7534
|
+
),
|
|
7535
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: summary }),
|
|
7536
|
+
!(only && !working && !failed) && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "shrink-0", children: open ? "\u2212" : "+" })
|
|
7537
|
+
]
|
|
7538
|
+
}
|
|
7539
|
+
);
|
|
7540
|
+
const rows = /* @__PURE__ */ jsx("ol", { className: "mt-2 space-y-1", children: groups.map((g, i) => {
|
|
7541
|
+
const res = groupResult(g);
|
|
7542
|
+
const slow = groupTook(g);
|
|
7543
|
+
const anyError = g.steps.some((s) => s.status === "error");
|
|
7544
|
+
const running = g.steps.some((s) => s.status === "running");
|
|
7545
|
+
const startsRound = g.round !== void 0 && g.round !== groups[i - 1]?.round;
|
|
7546
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-baseline gap-2 text-xs", children: [
|
|
7547
|
+
rounds !== null && /* @__PURE__ */ jsx(
|
|
7548
|
+
"span",
|
|
7549
|
+
{
|
|
7550
|
+
className: "w-3 shrink-0 text-right tabular-nums",
|
|
7551
|
+
style: { color: t.textMuted },
|
|
7552
|
+
"aria-hidden": !startsRound,
|
|
7553
|
+
children: startsRound ? g.round : ""
|
|
7554
|
+
}
|
|
7555
|
+
),
|
|
7556
|
+
/* @__PURE__ */ jsx(
|
|
7557
|
+
"span",
|
|
7558
|
+
{
|
|
7559
|
+
"aria-hidden": true,
|
|
7560
|
+
className: "w-3 shrink-0 text-[10px]",
|
|
7561
|
+
style: { color: anyError ? t.error : t.textMuted },
|
|
7562
|
+
children: running ? "\xB7" : anyError ? "!" : "\u2713"
|
|
7563
|
+
}
|
|
7564
|
+
),
|
|
7565
|
+
/* @__PURE__ */ jsxs(
|
|
7566
|
+
"span",
|
|
7567
|
+
{
|
|
7568
|
+
className: "min-w-0 flex-1 truncate",
|
|
7569
|
+
style: { color: t.textSecondary },
|
|
7570
|
+
title: g.label,
|
|
7571
|
+
children: [
|
|
7572
|
+
g.label,
|
|
7573
|
+
g.steps.length > 1 && /* @__PURE__ */ jsxs("span", { style: { color: t.textMuted }, children: [
|
|
7574
|
+
" \xD7",
|
|
7575
|
+
g.steps.length
|
|
7576
|
+
] })
|
|
7577
|
+
]
|
|
7578
|
+
}
|
|
7579
|
+
),
|
|
7580
|
+
slow && /* @__PURE__ */ jsx(
|
|
7581
|
+
"span",
|
|
7582
|
+
{
|
|
7583
|
+
className: "shrink-0 tabular-nums",
|
|
7584
|
+
style: { color: t.textMuted },
|
|
7585
|
+
children: slow
|
|
7586
|
+
}
|
|
7587
|
+
),
|
|
7588
|
+
res && /* @__PURE__ */ jsx("span", { className: "shrink-0", style: { color: anyError ? t.error : t.textMuted }, children: res })
|
|
7589
|
+
] }, g.key);
|
|
7590
|
+
}) });
|
|
7591
|
+
if (!prominent) {
|
|
7592
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
|
|
7593
|
+
toggle,
|
|
7594
|
+
open && !only && rows
|
|
7595
|
+
] });
|
|
7596
|
+
}
|
|
7597
|
+
return /* @__PURE__ */ jsxs(
|
|
7598
|
+
"div",
|
|
7599
|
+
{
|
|
7600
|
+
className: "mt-2 rounded-lg p-3",
|
|
7601
|
+
style: { backgroundColor: t.bgRaisedAlt, border: `1px solid ${t.border}` },
|
|
7602
|
+
children: [
|
|
7603
|
+
toggle,
|
|
7604
|
+
open && rows
|
|
7605
|
+
]
|
|
7606
|
+
}
|
|
7607
|
+
);
|
|
7608
|
+
}
|
|
7609
|
+
function agentStepTraceExtra(entry) {
|
|
7610
|
+
const meta = entry.metadata;
|
|
7611
|
+
const steps = meta?.agentSteps;
|
|
7612
|
+
if (!steps?.length) return null;
|
|
7613
|
+
const working = meta?.agentStepsLive ?? entry.content.endsWith("\u258B");
|
|
7614
|
+
return /* @__PURE__ */ jsx(AgentStepTrace, { steps, working });
|
|
7615
|
+
}
|
|
7007
7616
|
|
|
7008
7617
|
// src/knowledge/graphTheme.ts
|
|
7009
7618
|
var NODE_TYPE_COLORS = {
|
|
@@ -7479,7 +8088,7 @@ var MarkdownContent = memo(function MarkdownContent2({
|
|
|
7479
8088
|
if (!entities || entities.length === 0) return MARKDOWN_COMPONENTS;
|
|
7480
8089
|
return { ...MARKDOWN_COMPONENTS, ...buildHighlightOverrides(entities, onEntityClick) };
|
|
7481
8090
|
}, [entities, onEntityClick]);
|
|
7482
|
-
return /* @__PURE__ */ jsx("div", { className: `text-xs leading-relaxed text-gray-300 break-words ${className}`, children: /* @__PURE__ */ jsx(ReactMarkdown, { components, children }) });
|
|
8091
|
+
return /* @__PURE__ */ jsx("div", { className: `text-xs leading-relaxed text-gray-300 break-words ${className}`, children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children }) });
|
|
7483
8092
|
});
|
|
7484
8093
|
function escapeRegex(s) {
|
|
7485
8094
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -7545,13 +8154,13 @@ function highlightText(text, regex, entityMap, onEntityClick) {
|
|
|
7545
8154
|
return parts;
|
|
7546
8155
|
}
|
|
7547
8156
|
function highlightChildren(children, regex, entityMap, onEntityClick) {
|
|
7548
|
-
return
|
|
8157
|
+
return React15.Children.map(children, (child) => {
|
|
7549
8158
|
if (typeof child === "string") {
|
|
7550
8159
|
const highlighted = highlightText(child, regex, entityMap, onEntityClick);
|
|
7551
8160
|
return highlighted.length === 1 && typeof highlighted[0] === "string" ? child : /* @__PURE__ */ jsx(Fragment, { children: highlighted });
|
|
7552
8161
|
}
|
|
7553
|
-
if (
|
|
7554
|
-
return
|
|
8162
|
+
if (React15.isValidElement(child) && child.props.children) {
|
|
8163
|
+
return React15.cloneElement(child, {
|
|
7555
8164
|
...child.props,
|
|
7556
8165
|
children: highlightChildren(child.props.children, regex, entityMap, onEntityClick)
|
|
7557
8166
|
});
|
|
@@ -8022,10 +8631,10 @@ var SAVE_STAGE_MESSAGES = {
|
|
|
8022
8631
|
extracting: "re-analyzing entities with AI\u2026",
|
|
8023
8632
|
finishing: "almost done \xB7 finalizing graph\u2026"
|
|
8024
8633
|
};
|
|
8025
|
-
function summarizeSaveResult(
|
|
8026
|
-
if (!
|
|
8027
|
-
const added =
|
|
8028
|
-
const removed =
|
|
8634
|
+
function summarizeSaveResult(result2) {
|
|
8635
|
+
if (!result2?.diff) return "Saved";
|
|
8636
|
+
const added = result2.diff.added_node_keys?.length ?? 0;
|
|
8637
|
+
const removed = result2.diff.removed_node_keys?.length ?? 0;
|
|
8029
8638
|
if (added === 0 && removed === 0) return "Saved \xB7 graph unchanged";
|
|
8030
8639
|
const parts = [];
|
|
8031
8640
|
if (added > 0) parts.push(`+${added}`);
|
|
@@ -8104,11 +8713,11 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
|
|
|
8104
8713
|
setIsSaving(true);
|
|
8105
8714
|
try {
|
|
8106
8715
|
const rawResult = await onSaveDescription(draftAtSaveTime);
|
|
8107
|
-
const
|
|
8716
|
+
const result2 = rawResult ?? null;
|
|
8108
8717
|
if (currentNodeIdRef.current === savingForNodeId) {
|
|
8109
8718
|
setLocalDescription(draftAtSaveTime);
|
|
8110
8719
|
setIsEditing(false);
|
|
8111
|
-
setLastSaveResult(
|
|
8720
|
+
setLastSaveResult(result2);
|
|
8112
8721
|
if (savedPillTimerRef.current) clearTimeout(savedPillTimerRef.current);
|
|
8113
8722
|
savedPillTimerRef.current = setTimeout(() => {
|
|
8114
8723
|
setLastSaveResult(null);
|
|
@@ -8644,11 +9253,11 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
|
|
|
8644
9253
|
renderedClaims.length,
|
|
8645
9254
|
")"
|
|
8646
9255
|
] }),
|
|
8647
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: claimGroups.map((
|
|
8648
|
-
const isRelated =
|
|
9256
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: claimGroups.map((group2) => {
|
|
9257
|
+
const isRelated = group2.predicate === "(related)";
|
|
8649
9258
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
8650
|
-
|
|
8651
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children:
|
|
9259
|
+
group2.items.length > 1 && /* @__PURE__ */ jsx("div", { className: "text-[10px] text-gray-500 italic mb-0.5 px-2", children: group2.predicate }),
|
|
9260
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: group2.items.map((claim) => {
|
|
8652
9261
|
const cnColors = getNodeColors(claim.targetType);
|
|
8653
9262
|
return /* @__PURE__ */ jsxs(
|
|
8654
9263
|
"button",
|
|
@@ -8686,7 +9295,7 @@ function NodeDetailDrawer({ node, connectedNodes, chunks = [], annotations, onCl
|
|
|
8686
9295
|
claim.key
|
|
8687
9296
|
);
|
|
8688
9297
|
}) })
|
|
8689
|
-
] },
|
|
9298
|
+
] }, group2.predicate);
|
|
8690
9299
|
}) })
|
|
8691
9300
|
] }),
|
|
8692
9301
|
Object.keys(visibleProperties).length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -9301,7 +9910,7 @@ var RECRUITING_LINES = [
|
|
|
9301
9910
|
];
|
|
9302
9911
|
function RecruitingHint() {
|
|
9303
9912
|
const [idx, setIdx] = useState(0);
|
|
9304
|
-
|
|
9913
|
+
React15.useEffect(() => {
|
|
9305
9914
|
const t = setInterval(() => setIdx((i) => (i + 1) % RECRUITING_LINES.length), 2500);
|
|
9306
9915
|
return () => clearInterval(t);
|
|
9307
9916
|
}, []);
|
|
@@ -9404,7 +10013,7 @@ function RelationshipSentence({ rel }) {
|
|
|
9404
10013
|
const hasRange = rel.range.length > 0;
|
|
9405
10014
|
return /* @__PURE__ */ jsxs("div", { style: { lineHeight: 2, color: "#888", fontSize: 13, wordBreak: "break-word" }, children: [
|
|
9406
10015
|
hasDomain && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9407
|
-
rel.domain.map((d, i) => /* @__PURE__ */ jsxs(
|
|
10016
|
+
rel.domain.map((d, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
|
|
9408
10017
|
i > 0 && /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: " or " }),
|
|
9409
10018
|
/* @__PURE__ */ jsx(TypeChip, { name: d })
|
|
9410
10019
|
] }, d)),
|
|
@@ -9413,7 +10022,7 @@ function RelationshipSentence({ rel }) {
|
|
|
9413
10022
|
/* @__PURE__ */ jsx("span", { style: { color: "#ddd", fontStyle: "italic", fontWeight: 500 }, children: verb }),
|
|
9414
10023
|
hasRange && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9415
10024
|
" ",
|
|
9416
|
-
rel.range.map((r, i) => /* @__PURE__ */ jsxs(
|
|
10025
|
+
rel.range.map((r, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
|
|
9417
10026
|
i > 0 && /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: " and " }),
|
|
9418
10027
|
/* @__PURE__ */ jsx(TypeChip, { name: r })
|
|
9419
10028
|
] }, r))
|
|
@@ -9933,7 +10542,7 @@ function DocumentProcessingProgress() {
|
|
|
9933
10542
|
if (!state) return null;
|
|
9934
10543
|
const currentIdx = DOCUMENT_PIPELINE_STEPS.findIndex((s) => s.key === state.step);
|
|
9935
10544
|
return /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex flex-col gap-1", style: { borderBottom: "1px solid #282828", backgroundColor: "#1a1a1a" }, children: [
|
|
9936
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-0", children: DOCUMENT_PIPELINE_STEPS.map((step, i) => /* @__PURE__ */ jsxs(
|
|
10545
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-0", children: DOCUMENT_PIPELINE_STEPS.map((step, i) => /* @__PURE__ */ jsxs(React15.Fragment, { children: [
|
|
9937
10546
|
i > 0 && /* @__PURE__ */ jsx("div", { className: "w-2 h-px mx-0.5", style: { backgroundColor: i <= currentIdx ? "#10b981" : "#333" } }),
|
|
9938
10547
|
/* @__PURE__ */ jsx(
|
|
9939
10548
|
"span",
|
|
@@ -10217,10 +10826,10 @@ function hydrateAgentIds(ids) {
|
|
|
10217
10826
|
};
|
|
10218
10827
|
});
|
|
10219
10828
|
}
|
|
10220
|
-
function stageReducer(state,
|
|
10221
|
-
switch (
|
|
10829
|
+
function stageReducer(state, action2) {
|
|
10830
|
+
switch (action2.type) {
|
|
10222
10831
|
case "TEAM_SETUP": {
|
|
10223
|
-
const incomingIds = new Set(
|
|
10832
|
+
const incomingIds = new Set(action2.agents.map((a) => a.id));
|
|
10224
10833
|
let isWholesaleReplace = state.lastBackendTeamIds.size > 0;
|
|
10225
10834
|
if (isWholesaleReplace) {
|
|
10226
10835
|
state.lastBackendTeamIds.forEach((id) => {
|
|
@@ -10238,48 +10847,48 @@ function stageReducer(state, action) {
|
|
|
10238
10847
|
return {
|
|
10239
10848
|
...state,
|
|
10240
10849
|
stage: "team_formation",
|
|
10241
|
-
team: [...
|
|
10850
|
+
team: [...action2.agents, ...surviving],
|
|
10242
10851
|
localOnlyAgentIds: nextLocalOnly,
|
|
10243
10852
|
lastBackendTeamIds: incomingIds
|
|
10244
10853
|
};
|
|
10245
10854
|
}
|
|
10246
10855
|
case "PHASE_ADVANCED": {
|
|
10247
|
-
const to =
|
|
10856
|
+
const to = action2.to;
|
|
10248
10857
|
if (to === "team_formation") return { ...state, stage: "team_formation" };
|
|
10249
10858
|
if (to === "schema_seeding") return { ...state, stage: "schema_seeding" };
|
|
10250
10859
|
if (to === "construction" || to === "synthesis" || to === "done") return { ...state, stage: "graph" };
|
|
10251
10860
|
return state;
|
|
10252
10861
|
}
|
|
10253
10862
|
case "UPDATE_AGENT":
|
|
10254
|
-
return { ...state, team: state.team.map((a) => a.id ===
|
|
10863
|
+
return { ...state, team: state.team.map((a) => a.id === action2.id ? { ...a, ...action2.updates } : a) };
|
|
10255
10864
|
case "REMOVE_AGENT": {
|
|
10256
10865
|
const nextLocalOnly = new Set(state.localOnlyAgentIds);
|
|
10257
|
-
nextLocalOnly.delete(
|
|
10866
|
+
nextLocalOnly.delete(action2.id);
|
|
10258
10867
|
return {
|
|
10259
10868
|
...state,
|
|
10260
|
-
team: state.team.filter((a) => a.id !==
|
|
10869
|
+
team: state.team.filter((a) => a.id !== action2.id),
|
|
10261
10870
|
localOnlyAgentIds: nextLocalOnly
|
|
10262
10871
|
};
|
|
10263
10872
|
}
|
|
10264
10873
|
case "ADD_AGENT": {
|
|
10265
10874
|
const nextLocalOnly = new Set(state.localOnlyAgentIds);
|
|
10266
|
-
nextLocalOnly.add(
|
|
10875
|
+
nextLocalOnly.add(action2.agent.id);
|
|
10267
10876
|
return {
|
|
10268
10877
|
...state,
|
|
10269
|
-
team: [...state.team,
|
|
10878
|
+
team: [...state.team, action2.agent],
|
|
10270
10879
|
localOnlyAgentIds: nextLocalOnly
|
|
10271
10880
|
};
|
|
10272
10881
|
}
|
|
10273
10882
|
case "SCHEMA_SEEDED":
|
|
10274
|
-
return { ...state, schemaNodeTypeCount:
|
|
10883
|
+
return { ...state, schemaNodeTypeCount: action2.nodeTypeCount, schemaEdgeTypeCount: action2.edgeTypeCount };
|
|
10275
10884
|
case "SCHEMA_TYPE_ADDED":
|
|
10276
|
-
return { ...state, schemaNodeTypes: state.schemaNodeTypes.includes(
|
|
10885
|
+
return { ...state, schemaNodeTypes: state.schemaNodeTypes.includes(action2.typeName) ? state.schemaNodeTypes : [...state.schemaNodeTypes, action2.typeName] };
|
|
10277
10886
|
case "SCHEMA_TEXT": {
|
|
10278
10887
|
const rels = [];
|
|
10279
10888
|
const nodeTypes2 = new Set(state.schemaNodeTypes);
|
|
10280
10889
|
const relPattern = /(\w+)\s*:\s*\[([^\]]*)\]\s*→\s*\[([^\]]*)\]/g;
|
|
10281
10890
|
let m;
|
|
10282
|
-
while ((m = relPattern.exec(
|
|
10891
|
+
while ((m = relPattern.exec(action2.text)) !== null) {
|
|
10283
10892
|
const name = m[1];
|
|
10284
10893
|
const domain = m[2].split(",").map((s) => s.replace(/"/g, "").trim()).filter(Boolean);
|
|
10285
10894
|
const range = m[3].split(",").map((s) => s.replace(/"/g, "").trim()).filter(Boolean);
|
|
@@ -10294,7 +10903,7 @@ function stageReducer(state, action) {
|
|
|
10294
10903
|
};
|
|
10295
10904
|
}
|
|
10296
10905
|
case "DOC_STEP": {
|
|
10297
|
-
const step =
|
|
10906
|
+
const step = action2.step;
|
|
10298
10907
|
if (step === "complete") return { ...state, stage: "graph" };
|
|
10299
10908
|
if (step === "processing" || step === "vocabulary") return { ...state, stage: "doc_preparing" };
|
|
10300
10909
|
if (step === "extracting") return { ...state, stage: "doc_extracting" };
|
|
@@ -10303,7 +10912,7 @@ function stageReducer(state, action) {
|
|
|
10303
10912
|
return state;
|
|
10304
10913
|
}
|
|
10305
10914
|
case "DOC_ACTIVITY":
|
|
10306
|
-
return { ...state, docActivity: [...state.docActivity,
|
|
10915
|
+
return { ...state, docActivity: [...state.docActivity, action2.item] };
|
|
10307
10916
|
case "FORCE_GRAPH":
|
|
10308
10917
|
return { ...state, stage: "graph" };
|
|
10309
10918
|
default:
|
|
@@ -11169,7 +11778,7 @@ function PipelineProgressBar({ listenForEvents = true, currentPhase: currentPhas
|
|
|
11169
11778
|
PIPELINE_STEPS.map((step, i) => {
|
|
11170
11779
|
const isCompleted = completed.has(step.key) || i < currentIdx;
|
|
11171
11780
|
const isCurrent = step.key === currentPhase;
|
|
11172
|
-
return /* @__PURE__ */ jsxs(
|
|
11781
|
+
return /* @__PURE__ */ jsxs(React15.Fragment, { children: [
|
|
11173
11782
|
i > 0 && /* @__PURE__ */ jsx(
|
|
11174
11783
|
"div",
|
|
11175
11784
|
{
|
|
@@ -12957,19 +13566,19 @@ function KnowledgeGraphView({
|
|
|
12957
13566
|
setSearching(true);
|
|
12958
13567
|
searchTimerRef.current = setTimeout(async () => {
|
|
12959
13568
|
try {
|
|
12960
|
-
const
|
|
12961
|
-
setSearchResult(
|
|
12962
|
-
if (
|
|
13569
|
+
const result2 = data.onSearchNodes ? await data.onSearchNodes(groupId, kgId, q, 10, 2) : { hits: [], traversal: [] };
|
|
13570
|
+
setSearchResult(result2);
|
|
13571
|
+
if (result2.hits.length === 0 && localMatchIds.size === 0) {
|
|
12963
13572
|
restoreFullGraph();
|
|
12964
13573
|
setSearching(false);
|
|
12965
13574
|
return;
|
|
12966
13575
|
}
|
|
12967
|
-
if (
|
|
13576
|
+
if (result2.hits.length === 0) {
|
|
12968
13577
|
setSearching(false);
|
|
12969
13578
|
return;
|
|
12970
13579
|
}
|
|
12971
13580
|
const scoreMap = /* @__PURE__ */ new Map();
|
|
12972
|
-
|
|
13581
|
+
result2.hits.forEach((h) => {
|
|
12973
13582
|
const existing = scoreMap.get(h.node_key) ?? 0;
|
|
12974
13583
|
if ((h.score ?? 0) > existing) scoreMap.set(h.node_key, h.score ?? 0);
|
|
12975
13584
|
});
|
|
@@ -12977,9 +13586,9 @@ function KnowledgeGraphView({
|
|
|
12977
13586
|
if (!scoreMap.has(id)) scoreMap.set(id, 0.5);
|
|
12978
13587
|
});
|
|
12979
13588
|
const traversalIds = /* @__PURE__ */ new Set();
|
|
12980
|
-
|
|
13589
|
+
result2.traversal.forEach((t) => traversalIds.add(t.node_key));
|
|
12981
13590
|
const neighborIds = /* @__PURE__ */ new Set();
|
|
12982
|
-
|
|
13591
|
+
result2.hits.forEach((h) => {
|
|
12983
13592
|
h.neighbors?.forEach((nk) => {
|
|
12984
13593
|
if (!scoreMap.has(nk)) neighborIds.add(nk);
|
|
12985
13594
|
});
|
|
@@ -13468,9 +14077,9 @@ function KnowledgeGraphView({
|
|
|
13468
14077
|
if (!data.onCreateNote || !draftNote || !draftNote.trim()) return;
|
|
13469
14078
|
setSavingDraft(true);
|
|
13470
14079
|
try {
|
|
13471
|
-
const
|
|
14080
|
+
const result2 = await data.onCreateNote(groupId, kgId, draftNote);
|
|
13472
14081
|
setDraftNote(null);
|
|
13473
|
-
setSelectedNodeId(`chunk:${
|
|
14082
|
+
setSelectedNodeId(`chunk:${result2.chunk_id}`);
|
|
13474
14083
|
if (data.onLoadAllChunks) {
|
|
13475
14084
|
try {
|
|
13476
14085
|
const fresh = await data.onLoadAllChunks(groupId, kgId);
|
|
@@ -13479,10 +14088,10 @@ function KnowledgeGraphView({
|
|
|
13479
14088
|
console.warn("[KGV] post-create chunk refetch failed", err);
|
|
13480
14089
|
}
|
|
13481
14090
|
}
|
|
13482
|
-
if (
|
|
14091
|
+
if (result2.run_id && config?.agentsApiUrl) {
|
|
13483
14092
|
setNoteRuns((prev) => [
|
|
13484
14093
|
...prev,
|
|
13485
|
-
{ run_id:
|
|
14094
|
+
{ run_id: result2.run_id, kg_id: kgId }
|
|
13486
14095
|
]);
|
|
13487
14096
|
}
|
|
13488
14097
|
} catch (err) {
|
|
@@ -14037,4 +14646,4 @@ var terminalClassNames = {
|
|
|
14037
14646
|
promptSymbol: "terminal-prompt-symbol"
|
|
14038
14647
|
};
|
|
14039
14648
|
|
|
14040
|
-
export { ADVANCE_PHASE_SIGNAL, AGENT_PALETTE, AgentAvatar, AgentPresenceBar, AnnotationThread, CLAIM_STATUS_COLORS, ChatTerminal, CheckpointCard, ClaimNode, ConstructionProgress, CoreTerminal, DOCUMENT_PIPELINE_STEPS, DocumentProcessingProgress, EDGE_TYPE_COLORS, EdgeDetailDrawer, EdgeMarkerDefs, CoreTerminal as EmbeddedTerminal, ExpandableTerminal, GraphChatPanel, GraphEdge, GraphNode, InlineTerminal, KnowledgeGraphView, LIVE_KG_ID, LiveActivityTicker, MarkdownContent, MarkdownEditor, NODE_TYPE_COLORS, NODE_TYPE_LABELS, NodeDetailDrawer, PROGRESS_EVENT_NAME, PipelineProgressBar, ReasoningHistoryCard, ReasoningOverlay, ReasoningView, SYNTHESIS_DONE_SIGNAL, ScopedReasoningProvider, SettlementBar, SlashMentionPicker, StageCanvas, StandardTerminal, TerminalInputBar, TerminalThemeProvider, agentSeed, avatarColor, blueScope, buildClaimsGraph, buildTerminalCommand, buttonShadow, captureReasoningSnapshot, defaultTheme, dispatchProgressEvent, documentEventToActivity, emeraldCollab, emeraldRevised, eventToActivity, extractKGSources, extractKgId, filterCommands, formatAssetDisplay, formatPaymentAmount, formatTokenAssetId, getAgentColor, getBuiltInCommands, getClaimStatusColors, getEdgeColor, getEdgeTypeLabel, getNodeColors, getNodeTypeLabel, getVocabTypeColors, getVocabTypeLabel, greenAction, handleSSEStream, handleStreamingResponse, hostApp, initials, isFixedKgId, isNaturalLanguage, layoutGraph, mergeTheme, openPipelineEventStream, orangeRebuttal, parseTerminalCommand, pipelineBg, processStreamLines, purple, reduceProgress, renderMarkdownBlock, resolvePaymentAssetDisplay, snapshotToSubgraph, terminalClassNames, terminalColors, useScopedProgressEvent, useSlashMentionPicker, useTheme, warmBg };
|
|
14649
|
+
export { ADVANCE_PHASE_SIGNAL, AGENT_PALETTE, AgentAvatar, AgentPresenceBar, AgentStepTrace, AnnotationThread, CLAIM_STATUS_COLORS, ChatTerminal, CheckpointCard, ClaimNode, ConstructionProgress, CoreTerminal, DEFAULT_AGENT_LABEL, DOCUMENT_PIPELINE_STEPS, DocumentProcessingProgress, EDGE_TYPE_COLORS, EdgeDetailDrawer, EdgeMarkerDefs, CoreTerminal as EmbeddedTerminal, ExpandableTerminal, GraphChatPanel, GraphEdge, GraphNode, InlineTerminal, KnowledgeGraphView, LIVE_KG_ID, LiveActivityTicker, MarkdownContent, MarkdownEditor, NODE_TYPE_COLORS, NODE_TYPE_LABELS, NodeDetailDrawer, PROGRESS_EVENT_NAME, PipelineProgressBar, ReasoningHistoryCard, ReasoningOverlay, ReasoningView, SSE_KEEPALIVE_MS, SSE_STALL_MS, SYNTHESIS_DONE_SIGNAL, ScopedReasoningProvider, SettlementBar, SlashMentionPicker, StageCanvas, StandardTerminal, TerminalInputBar, TerminalThemeProvider, agentSeed, agentStepTraceExtra, avatarColor, blueScope, buildClaimsGraph, buildTerminalCommand, buttonShadow, captureReasoningSnapshot, defaultTheme, dispatchProgressEvent, documentEventToActivity, emeraldCollab, emeraldRevised, eventToActivity, extractKGSources, extractKgId, filterCommands, formatAssetDisplay, formatPaymentAmount, formatTokenAssetId, getAgentColor, getBuiltInCommands, getClaimStatusColors, getEdgeColor, getEdgeTypeLabel, getNodeColors, getNodeTypeLabel, getVocabTypeColors, getVocabTypeLabel, greenAction, handleSSEStream, handleStreamingResponse, hostApp, initials, isFixedKgId, isNaturalLanguage, layoutGraph, mergeTheme, openPipelineEventStream, orangeRebuttal, parseTerminalCommand, pipelineBg, processStreamLines, purple, reduceProgress, renderMarkdownBlock, resolvePaymentAssetDisplay, snapshotToSubgraph, terminalClassNames, terminalColors, useScopedProgressEvent, useSlashMentionPicker, useTheme, warmBg, withStallTimeout };
|