@blade-hq/agent-react 2610.0.0-beta.31 → 2610.0.0-beta.33
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/README.md +28 -1
- package/dist/components/AssistantTurnBlock.d.ts +3 -1
- package/dist/components/ChatSurface.d.ts +5 -1
- package/dist/components/MessageList.d.ts +2 -1
- package/dist/components/PlanUpdateBlock.d.ts +31 -0
- package/dist/components/SessionMemoryToggle.d.ts +19 -0
- package/dist/context.d.ts +1 -0
- package/dist/hooks/use-agent-session.d.ts +5 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +932 -534
- package/dist/index.js.map +1 -1
- package/dist/style.css +4 -1
- package/dist/style.full.css +5 -2
- package/package.json +2 -2
- package/public-api.md +92 -3
package/dist/index.js
CHANGED
|
@@ -17,6 +17,9 @@ function useBladeClient() {
|
|
|
17
17
|
}
|
|
18
18
|
return client;
|
|
19
19
|
}
|
|
20
|
+
function useOptionalBladeClient() {
|
|
21
|
+
return useContext(BladeClientContext);
|
|
22
|
+
}
|
|
20
23
|
|
|
21
24
|
// src/hooks/use-agent-session.ts
|
|
22
25
|
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
@@ -30,11 +33,14 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
30
33
|
const connRef = useRef({
|
|
31
34
|
id: null,
|
|
32
35
|
session: null,
|
|
36
|
+
cleanup: null,
|
|
33
37
|
gen: 0
|
|
34
38
|
});
|
|
35
39
|
const createdIdPromiseRef = useRef(null);
|
|
36
40
|
const onCreatedRef = useRef(options.onSessionCreated);
|
|
37
41
|
onCreatedRef.current = options.onSessionCreated;
|
|
42
|
+
const onConnectedRef = useRef(options.onSessionConnected);
|
|
43
|
+
onConnectedRef.current = options.onSessionConnected;
|
|
38
44
|
const createOptionsRef = useRef(options.createOptions);
|
|
39
45
|
createOptionsRef.current = options.createOptions;
|
|
40
46
|
const sessionIdRef = useRef(sessionId);
|
|
@@ -42,6 +48,7 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
42
48
|
const connect = useMemo(() => {
|
|
43
49
|
return (targetId) => {
|
|
44
50
|
const gen = ++connRef.current.gen;
|
|
51
|
+
let pendingCleanup = null;
|
|
45
52
|
const idPromise = targetId ? Promise.resolve(targetId) : (
|
|
46
53
|
// biome-ignore lint/suspicious/noAssignInExpressions: ??= 挂 ref 是 StrictMode 下"只创建一次"的关键
|
|
47
54
|
createdIdPromiseRef.current ??= client.sessions.create(createOptionsRef.current ?? {}).then((created) => {
|
|
@@ -51,16 +58,25 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
51
58
|
return id;
|
|
52
59
|
})
|
|
53
60
|
);
|
|
54
|
-
idPromise.then(
|
|
61
|
+
idPromise.then(
|
|
62
|
+
(id) => client.hub.connect(id, {
|
|
63
|
+
setup: (next) => {
|
|
64
|
+
pendingCleanup = onConnectedRef.current?.(next) ?? null;
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
).then((next) => {
|
|
55
68
|
if (connRef.current.gen !== gen) {
|
|
69
|
+
pendingCleanup?.();
|
|
56
70
|
next.dispose();
|
|
57
71
|
return;
|
|
58
72
|
}
|
|
59
73
|
connRef.current.id = next.sessionId;
|
|
60
74
|
connRef.current.session = next;
|
|
75
|
+
connRef.current.cleanup = pendingCleanup;
|
|
61
76
|
setSession(next);
|
|
62
77
|
setError(null);
|
|
63
78
|
}).catch((err) => {
|
|
79
|
+
pendingCleanup?.();
|
|
64
80
|
if (connRef.current.gen !== gen) return;
|
|
65
81
|
createdIdPromiseRef.current = null;
|
|
66
82
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -72,8 +88,11 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
72
88
|
return () => {
|
|
73
89
|
connRef.current.gen++;
|
|
74
90
|
const toRelease = connRef.current.session;
|
|
91
|
+
const cleanup = connRef.current.cleanup;
|
|
75
92
|
connRef.current.id = null;
|
|
76
93
|
connRef.current.session = null;
|
|
94
|
+
connRef.current.cleanup = null;
|
|
95
|
+
cleanup?.();
|
|
77
96
|
setSession(null);
|
|
78
97
|
if (toRelease) setTimeout(() => toRelease.dispose(), DISPOSE_DELAY_MS);
|
|
79
98
|
};
|
|
@@ -83,8 +102,11 @@ function useAgentSession(sessionId, options = {}) {
|
|
|
83
102
|
if (connRef.current.id === null) return;
|
|
84
103
|
if (sessionId === connRef.current.id) return;
|
|
85
104
|
const previous = connRef.current.session;
|
|
105
|
+
const cleanup = connRef.current.cleanup;
|
|
86
106
|
connRef.current.id = null;
|
|
87
107
|
connRef.current.session = null;
|
|
108
|
+
connRef.current.cleanup = null;
|
|
109
|
+
cleanup?.();
|
|
88
110
|
if (previous) setTimeout(() => previous.dispose(), DISPOSE_DELAY_MS);
|
|
89
111
|
connect(sessionId);
|
|
90
112
|
}, [sessionId, connect]);
|
|
@@ -900,6 +922,17 @@ var CircleAlert = createLucideIcon("CircleAlert", [
|
|
|
900
922
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
901
923
|
]);
|
|
902
924
|
|
|
925
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/circle-dot.js
|
|
926
|
+
var CircleDot = createLucideIcon("CircleDot", [
|
|
927
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
928
|
+
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
|
|
929
|
+
]);
|
|
930
|
+
|
|
931
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
932
|
+
var Circle = createLucideIcon("Circle", [
|
|
933
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
|
|
934
|
+
]);
|
|
935
|
+
|
|
903
936
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/copy.js
|
|
904
937
|
var Copy = createLucideIcon("Copy", [
|
|
905
938
|
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
@@ -993,6 +1026,15 @@ var Lightbulb = createLucideIcon("Lightbulb", [
|
|
|
993
1026
|
["path", { d: "M10 22h4", key: "ceow96" }]
|
|
994
1027
|
]);
|
|
995
1028
|
|
|
1029
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/list-checks.js
|
|
1030
|
+
var ListChecks = createLucideIcon("ListChecks", [
|
|
1031
|
+
["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
|
|
1032
|
+
["path", { d: "m3 7 2 2 4-4", key: "1obspn" }],
|
|
1033
|
+
["path", { d: "M13 6h8", key: "15sg57" }],
|
|
1034
|
+
["path", { d: "M13 12h8", key: "h98zly" }],
|
|
1035
|
+
["path", { d: "M13 18h8", key: "oe0vm4" }]
|
|
1036
|
+
]);
|
|
1037
|
+
|
|
996
1038
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/loader-circle.js
|
|
997
1039
|
var LoaderCircle = createLucideIcon("LoaderCircle", [
|
|
998
1040
|
["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
|
|
@@ -1102,7 +1144,7 @@ var X = createLucideIcon("X", [
|
|
|
1102
1144
|
]);
|
|
1103
1145
|
|
|
1104
1146
|
// src/components/AgentChat.tsx
|
|
1105
|
-
import { useCallback as useCallback8, useEffect as
|
|
1147
|
+
import { useCallback as useCallback8, useEffect as useEffect12, useMemo as useMemo8, useState as useState14 } from "react";
|
|
1106
1148
|
|
|
1107
1149
|
// src/lib/utils.ts
|
|
1108
1150
|
function cn(...inputs) {
|
|
@@ -1229,11 +1271,349 @@ function ReplayMismatchPrompt({ mismatch, className }) {
|
|
|
1229
1271
|
);
|
|
1230
1272
|
}
|
|
1231
1273
|
|
|
1274
|
+
// src/components/PlanUpdateBlock.tsx
|
|
1275
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
1276
|
+
|
|
1277
|
+
// src/components/display-utils.ts
|
|
1278
|
+
var TOOL_NAME_ALIASES = {
|
|
1279
|
+
agent: "Agent",
|
|
1280
|
+
ask_user_question: "AskUserQuestion",
|
|
1281
|
+
bash: "Bash",
|
|
1282
|
+
bg_bash: "BgBash",
|
|
1283
|
+
edit: "Edit",
|
|
1284
|
+
exit_plan_mode: "ExitPlanMode",
|
|
1285
|
+
file_edit: "Edit",
|
|
1286
|
+
file_read: "Read",
|
|
1287
|
+
file_write: "Write",
|
|
1288
|
+
finish_task: "FinishTask",
|
|
1289
|
+
glob: "Glob",
|
|
1290
|
+
grep: "Grep",
|
|
1291
|
+
kb_search: "KbSearch",
|
|
1292
|
+
ls: "Ls",
|
|
1293
|
+
multi_edit: "MultiEdit",
|
|
1294
|
+
read: "Read",
|
|
1295
|
+
read_skill: "ReadSkill",
|
|
1296
|
+
update_plan: "UpdatePlan",
|
|
1297
|
+
web_fetch: "WebFetch",
|
|
1298
|
+
web_search: "WebSearch",
|
|
1299
|
+
write: "Write"
|
|
1300
|
+
};
|
|
1301
|
+
var TOOL_DISPLAY_LABELS = {
|
|
1302
|
+
Bash: "\u6267\u884C\u547D\u4EE4",
|
|
1303
|
+
BgBash: "\u540E\u53F0\u6267\u884C\u547D\u4EE4",
|
|
1304
|
+
Read: "\u8BFB\u53D6\u6587\u4EF6",
|
|
1305
|
+
Write: "\u5199\u5165\u6587\u4EF6",
|
|
1306
|
+
Edit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1307
|
+
MultiEdit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1308
|
+
Ls: "\u5217\u51FA\u76EE\u5F55",
|
|
1309
|
+
Glob: "\u5339\u914D\u6587\u4EF6",
|
|
1310
|
+
Grep: "\u641C\u7D22\u6587\u672C",
|
|
1311
|
+
KbSearch: "\u68C0\u7D22\u77E5\u8BC6\u5E93",
|
|
1312
|
+
WebSearch: "\u641C\u7D22\u7F51\u9875",
|
|
1313
|
+
WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
|
|
1314
|
+
Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
|
|
1315
|
+
AskUserQuestion: "\u5411\u7528\u6237\u63D0\u95EE",
|
|
1316
|
+
ReadSkill: "\u8BFB\u53D6\u6280\u80FD",
|
|
1317
|
+
FinishTask: "\u4EFB\u52A1\u5B8C\u6210",
|
|
1318
|
+
ExitPlanMode: "\u63D0\u4EA4\u8BA1\u5212",
|
|
1319
|
+
ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
|
|
1320
|
+
GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
|
|
1321
|
+
};
|
|
1322
|
+
function safeParseJson(value) {
|
|
1323
|
+
if (!value) return null;
|
|
1324
|
+
try {
|
|
1325
|
+
return JSON.parse(value);
|
|
1326
|
+
} catch {
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
function getStringArgValue(args, key) {
|
|
1331
|
+
const value = args?.[key];
|
|
1332
|
+
return typeof value === "string" ? value.trim() : "";
|
|
1333
|
+
}
|
|
1334
|
+
var SKILL_ENTRY_FILE_NAMES = /* @__PURE__ */ new Set(["skill.md", "command.md"]);
|
|
1335
|
+
var NON_SKILL_DIR_NAMES = /* @__PURE__ */ new Set([".", "..", ".agent", ".agents", ".claude", "skill_data", "skills"]);
|
|
1336
|
+
function getSkillNameFromFilePath(filePath) {
|
|
1337
|
+
if (!filePath) return null;
|
|
1338
|
+
const segments = filePath.split(/[\\/]+/).filter(Boolean);
|
|
1339
|
+
const fileName = segments.pop();
|
|
1340
|
+
if (!fileName || !SKILL_ENTRY_FILE_NAMES.has(fileName.toLowerCase())) return null;
|
|
1341
|
+
const dirName = segments.pop();
|
|
1342
|
+
if (!dirName || NON_SKILL_DIR_NAMES.has(dirName.toLowerCase())) return null;
|
|
1343
|
+
return dirName;
|
|
1344
|
+
}
|
|
1345
|
+
function formatToolName(name) {
|
|
1346
|
+
const trimmed = name.trim();
|
|
1347
|
+
if (!trimmed) return name;
|
|
1348
|
+
const stripped = trimmed.split(":").pop()?.split("/").pop()?.split(".").pop()?.trim() || trimmed;
|
|
1349
|
+
const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
1350
|
+
return TOOL_NAME_ALIASES[normalized] ?? stripped;
|
|
1351
|
+
}
|
|
1352
|
+
function getToolDisplayLabel(toolCall) {
|
|
1353
|
+
const normalized = formatToolName(toolCall.name);
|
|
1354
|
+
const args = safeParseJson(toolCall.arguments);
|
|
1355
|
+
const displayName = toolCall.display_name?.trim() ?? "";
|
|
1356
|
+
const baseLabel = displayName || TOOL_DISPLAY_LABELS[normalized] || normalized;
|
|
1357
|
+
const metaDisplayName = getStringArgValue(args, "_meta_display_name");
|
|
1358
|
+
if (metaDisplayName) {
|
|
1359
|
+
return metaDisplayName;
|
|
1360
|
+
}
|
|
1361
|
+
const description = getStringArgValue(args, "description");
|
|
1362
|
+
if (normalized === "BgBash") {
|
|
1363
|
+
return description ? `\u540E\u53F0\u6267\u884C\uFF1A${description}` : "\u540E\u53F0\u6267\u884C\u547D\u4EE4";
|
|
1364
|
+
}
|
|
1365
|
+
if (normalized === "ReadSkill") {
|
|
1366
|
+
const skillName = getStringArgValue(args, "skill") || getStringArgValue(args, "skill_name");
|
|
1367
|
+
return skillName ? `${baseLabel}\u300C${skillName}\u300D` : baseLabel;
|
|
1368
|
+
}
|
|
1369
|
+
if (normalized === "Read") {
|
|
1370
|
+
const skillName = getSkillNameFromFilePath(
|
|
1371
|
+
getStringArgValue(args, "file_path") || getStringArgValue(args, "path")
|
|
1372
|
+
);
|
|
1373
|
+
if (skillName) return `\u8BFB\u53D6\u6280\u80FD\u300C${skillName}\u300D`;
|
|
1374
|
+
}
|
|
1375
|
+
if (normalized === "FinishTask") {
|
|
1376
|
+
const title = getStringArgValue(args, "title");
|
|
1377
|
+
return title ? `${baseLabel}\uFF1A${title}` : baseLabel;
|
|
1378
|
+
}
|
|
1379
|
+
return description || baseLabel;
|
|
1380
|
+
}
|
|
1381
|
+
function getToolTone(status) {
|
|
1382
|
+
if (status === "error" || status === "cancelled") return "red";
|
|
1383
|
+
if (status === "awaiting_answer") return "amber";
|
|
1384
|
+
if (status === "pending") return "blue";
|
|
1385
|
+
return "emerald";
|
|
1386
|
+
}
|
|
1387
|
+
function getToolStatusLabel(status) {
|
|
1388
|
+
if (status === "pending") return "\u8FD0\u884C\u4E2D";
|
|
1389
|
+
if (status === "awaiting_answer") return "\u7B49\u5F85\u56DE\u7B54";
|
|
1390
|
+
if (status === "error") return "\u9519\u8BEF";
|
|
1391
|
+
if (status === "cancelled") return "\u5DF2\u53D6\u6D88";
|
|
1392
|
+
return "\u5B8C\u6210";
|
|
1393
|
+
}
|
|
1394
|
+
function formatToolDuration(ms) {
|
|
1395
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
1396
|
+
const seconds = ms / 1e3;
|
|
1397
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
1398
|
+
const minutes = Math.floor(seconds / 60);
|
|
1399
|
+
const remainingSeconds = Math.round(seconds % 60);
|
|
1400
|
+
return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
|
|
1401
|
+
}
|
|
1402
|
+
function formatToolArgs(args) {
|
|
1403
|
+
try {
|
|
1404
|
+
return JSON.stringify(JSON.parse(args), null, 2);
|
|
1405
|
+
} catch {
|
|
1406
|
+
return args;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
var RESULT_PREVIEW_LIMIT = 4e3;
|
|
1410
|
+
function formatToolResult(result) {
|
|
1411
|
+
const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1412
|
+
if (text == null) return "";
|
|
1413
|
+
if (text.length <= RESULT_PREVIEW_LIMIT) return text;
|
|
1414
|
+
return `${text.slice(0, RESULT_PREVIEW_LIMIT)}
|
|
1415
|
+
\u2026\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// src/components/PlanUpdateBlock.tsx
|
|
1419
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1420
|
+
var PLAN_STEP_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
1421
|
+
var PLAN_AUTO_COLLAPSE_MS = 5e3;
|
|
1422
|
+
function isPlanUpdateTool(toolCall) {
|
|
1423
|
+
return formatToolName(toolCall.name) === "UpdatePlan";
|
|
1424
|
+
}
|
|
1425
|
+
function getPlanUpdateDisplayState(messages) {
|
|
1426
|
+
let current = null;
|
|
1427
|
+
let latestAttempt = null;
|
|
1428
|
+
let latestAttemptStreaming = false;
|
|
1429
|
+
for (const message of messages) {
|
|
1430
|
+
if ((message.loop_name ?? "root") !== "root") continue;
|
|
1431
|
+
for (const toolCall of message.tool_calls ?? []) {
|
|
1432
|
+
if (!isPlanUpdateTool(toolCall)) continue;
|
|
1433
|
+
latestAttempt = toolCall;
|
|
1434
|
+
latestAttemptStreaming = message.status === "streaming";
|
|
1435
|
+
if (toolCall.status === "done" && parsePlanUpdate(toolCall.arguments)) current = toolCall;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return {
|
|
1439
|
+
current,
|
|
1440
|
+
updating: latestAttempt?.status === "pending" && latestAttemptStreaming
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
function parsePlanUpdate(argumentsJson) {
|
|
1444
|
+
try {
|
|
1445
|
+
const raw = JSON.parse(argumentsJson);
|
|
1446
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1447
|
+
const candidate = raw;
|
|
1448
|
+
if (!Array.isArray(candidate.plan)) return null;
|
|
1449
|
+
const plan = candidate.plan.map((item) => {
|
|
1450
|
+
if (!item || typeof item !== "object") return null;
|
|
1451
|
+
const step = item.step;
|
|
1452
|
+
const status = item.status;
|
|
1453
|
+
if (typeof step !== "string" || !step.trim() || typeof status !== "string" || !PLAN_STEP_STATUSES.has(status)) {
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
return { step: step.trim(), status };
|
|
1457
|
+
});
|
|
1458
|
+
if (plan.some((item) => item === null)) return null;
|
|
1459
|
+
if (plan.filter((item) => item?.status === "in_progress").length > 1) return null;
|
|
1460
|
+
return { plan };
|
|
1461
|
+
} catch {
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
function pickCurrentPlanStep(plan) {
|
|
1466
|
+
return plan.find((item) => item.status === "in_progress") ?? plan.find((item) => item.status === "pending") ?? plan[plan.length - 1] ?? null;
|
|
1467
|
+
}
|
|
1468
|
+
function PlanStepIcon({
|
|
1469
|
+
status,
|
|
1470
|
+
size = 17,
|
|
1471
|
+
running = false
|
|
1472
|
+
}) {
|
|
1473
|
+
if (status === "completed") {
|
|
1474
|
+
return /* @__PURE__ */ jsx4(Check, { size, strokeWidth: 2, className: "shrink-0 text-emerald-500" });
|
|
1475
|
+
}
|
|
1476
|
+
if (status === "in_progress") {
|
|
1477
|
+
return running ? /* @__PURE__ */ jsx4(LoaderCircle, { size, className: "shrink-0 animate-spin text-[hsl(var(--muted-foreground))]" }) : /* @__PURE__ */ jsx4(CircleDot, { size, className: "shrink-0 text-amber-500" });
|
|
1478
|
+
}
|
|
1479
|
+
return /* @__PURE__ */ jsx4(Circle, { size, className: "shrink-0 text-[hsl(var(--muted-foreground))]/60" });
|
|
1480
|
+
}
|
|
1481
|
+
function PlanUpdateBlock({
|
|
1482
|
+
toolCall,
|
|
1483
|
+
running = false,
|
|
1484
|
+
autoReveal = false
|
|
1485
|
+
}) {
|
|
1486
|
+
const updateKey = `${toolCall.id}:${toolCall.arguments}`;
|
|
1487
|
+
const revealKey = autoReveal ? updateKey : null;
|
|
1488
|
+
const [collapsed, setCollapsed] = useState4(!autoReveal);
|
|
1489
|
+
const collapseTimerRef = useRef4(null);
|
|
1490
|
+
const data = parsePlanUpdate(toolCall.arguments);
|
|
1491
|
+
useEffect4(() => {
|
|
1492
|
+
if (!revealKey) return;
|
|
1493
|
+
if (collapseTimerRef.current) clearTimeout(collapseTimerRef.current);
|
|
1494
|
+
setCollapsed(false);
|
|
1495
|
+
collapseTimerRef.current = setTimeout(() => {
|
|
1496
|
+
setCollapsed(true);
|
|
1497
|
+
collapseTimerRef.current = null;
|
|
1498
|
+
}, PLAN_AUTO_COLLAPSE_MS);
|
|
1499
|
+
}, [revealKey]);
|
|
1500
|
+
useEffect4(
|
|
1501
|
+
() => () => {
|
|
1502
|
+
if (collapseTimerRef.current) clearTimeout(collapseTimerRef.current);
|
|
1503
|
+
},
|
|
1504
|
+
[]
|
|
1505
|
+
);
|
|
1506
|
+
if (!data) return null;
|
|
1507
|
+
const completed = data.plan.filter((item) => item.status === "completed").length;
|
|
1508
|
+
const currentStep = pickCurrentPlanStep(data.plan);
|
|
1509
|
+
const pausedAtCurrentStep = !running && currentStep?.status === "in_progress";
|
|
1510
|
+
return /* @__PURE__ */ jsxs3("section", { className: "overflow-hidden", children: [
|
|
1511
|
+
/* @__PURE__ */ jsxs3(
|
|
1512
|
+
"button",
|
|
1513
|
+
{
|
|
1514
|
+
type: "button",
|
|
1515
|
+
"aria-expanded": !collapsed,
|
|
1516
|
+
onClick: () => {
|
|
1517
|
+
if (collapseTimerRef.current) {
|
|
1518
|
+
clearTimeout(collapseTimerRef.current);
|
|
1519
|
+
collapseTimerRef.current = null;
|
|
1520
|
+
}
|
|
1521
|
+
setCollapsed((value) => !value);
|
|
1522
|
+
},
|
|
1523
|
+
className: cn(
|
|
1524
|
+
"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--muted)/0.3)]",
|
|
1525
|
+
!collapsed && "border-b border-[hsl(var(--border))]"
|
|
1526
|
+
),
|
|
1527
|
+
children: [
|
|
1528
|
+
collapsed && currentStep ? /* @__PURE__ */ jsxs3("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-xs text-[hsl(var(--foreground))]", children: [
|
|
1529
|
+
/* @__PURE__ */ jsx4(PlanStepIcon, { status: currentStep.status, size: 14, running }),
|
|
1530
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate", children: currentStep.step }),
|
|
1531
|
+
pausedAtCurrentStep ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-[11px] text-amber-500", children: "\u5DF2\u6682\u505C" }) : null
|
|
1532
|
+
] }) : /* @__PURE__ */ jsxs3("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
|
|
1533
|
+
/* @__PURE__ */ jsx4(ListChecks, { size: 14, className: "shrink-0", "aria-hidden": "true" }),
|
|
1534
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate", children: "\u4EFB\u52A1\u8FDB\u5EA6" }),
|
|
1535
|
+
pausedAtCurrentStep ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-amber-500", children: "\u5DF2\u6682\u505C" }) : null
|
|
1536
|
+
] }),
|
|
1537
|
+
/* @__PURE__ */ jsxs3("span", { className: "shrink-0 text-[11px] tabular-nums text-[hsl(var(--muted-foreground))]", children: [
|
|
1538
|
+
completed,
|
|
1539
|
+
"/",
|
|
1540
|
+
data.plan.length
|
|
1541
|
+
] }),
|
|
1542
|
+
/* @__PURE__ */ jsx4(
|
|
1543
|
+
ChevronDown,
|
|
1544
|
+
{
|
|
1545
|
+
size: 14,
|
|
1546
|
+
className: cn(
|
|
1547
|
+
"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform duration-300 ease-out motion-reduce:transition-none",
|
|
1548
|
+
!collapsed && "rotate-180"
|
|
1549
|
+
)
|
|
1550
|
+
}
|
|
1551
|
+
)
|
|
1552
|
+
]
|
|
1553
|
+
}
|
|
1554
|
+
),
|
|
1555
|
+
/* @__PURE__ */ jsx4(
|
|
1556
|
+
"div",
|
|
1557
|
+
{
|
|
1558
|
+
"aria-hidden": collapsed,
|
|
1559
|
+
className: cn(
|
|
1560
|
+
"grid transition-[grid-template-rows,opacity] duration-300 ease-out motion-reduce:transition-none",
|
|
1561
|
+
collapsed ? "grid-rows-[0fr] opacity-0" : "grid-rows-[1fr] opacity-100"
|
|
1562
|
+
),
|
|
1563
|
+
children: /* @__PURE__ */ jsx4("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx4("div", { className: "flex max-h-40 flex-col gap-0.5 overflow-y-auto px-3 py-2", children: data.plan.length === 0 ? /* @__PURE__ */ jsx4("span", { className: "text-xs text-[hsl(var(--muted-foreground))]", children: "\u6682\u65E0\u4EFB\u52A1\u6B65\u9AA4" }) : data.plan.map((item, index) => /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-2 py-0.5", children: [
|
|
1564
|
+
/* @__PURE__ */ jsx4("span", { className: "mt-[3px] flex shrink-0", children: /* @__PURE__ */ jsx4(PlanStepIcon, { status: item.status, size: 14, running }) }),
|
|
1565
|
+
/* @__PURE__ */ jsx4(
|
|
1566
|
+
"span",
|
|
1567
|
+
{
|
|
1568
|
+
className: cn(
|
|
1569
|
+
"min-w-0 flex-1 break-words text-[13px] leading-5",
|
|
1570
|
+
item.status === "completed" ? "text-[hsl(var(--muted-foreground))]" : item.status === "in_progress" ? "font-medium text-[hsl(var(--foreground))]" : "text-[hsl(var(--muted-foreground))]"
|
|
1571
|
+
),
|
|
1572
|
+
children: item.step
|
|
1573
|
+
}
|
|
1574
|
+
)
|
|
1575
|
+
] }, `${index}-${item.step}`)) }) })
|
|
1576
|
+
}
|
|
1577
|
+
)
|
|
1578
|
+
] });
|
|
1579
|
+
}
|
|
1580
|
+
function CurrentPlanPanel({
|
|
1581
|
+
messages,
|
|
1582
|
+
running = false,
|
|
1583
|
+
revealRevision = 0,
|
|
1584
|
+
sessionId,
|
|
1585
|
+
className
|
|
1586
|
+
}) {
|
|
1587
|
+
const { current, updating } = getPlanUpdateDisplayState(messages);
|
|
1588
|
+
const revealBaselinesRef = useRef4(/* @__PURE__ */ new Map([[sessionId, revealRevision]]));
|
|
1589
|
+
const autoReveal = (revealBaselinesRef.current.get(sessionId) ?? 0) !== revealRevision;
|
|
1590
|
+
useEffect4(() => {
|
|
1591
|
+
if (!current) return;
|
|
1592
|
+
revealBaselinesRef.current.set(sessionId, revealRevision);
|
|
1593
|
+
}, [current, revealRevision, sessionId]);
|
|
1594
|
+
if (!current && !updating) return null;
|
|
1595
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("blade-chat-plan mx-auto w-full max-w-[748px] px-4", className), children: [
|
|
1596
|
+
updating ? /* @__PURE__ */ jsxs3("div", { className: "mb-2 flex items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
1597
|
+
/* @__PURE__ */ jsx4(LoaderCircle, { size: 14, className: "shrink-0 animate-spin" }),
|
|
1598
|
+
/* @__PURE__ */ jsx4("span", { children: "\u6B63\u5728\u66F4\u65B0\u4EFB\u52A1\u8FDB\u5EA6\u2026" })
|
|
1599
|
+
] }) : null,
|
|
1600
|
+
current ? /* @__PURE__ */ jsx4(
|
|
1601
|
+
PlanUpdateBlock,
|
|
1602
|
+
{
|
|
1603
|
+
toolCall: current,
|
|
1604
|
+
running,
|
|
1605
|
+
autoReveal
|
|
1606
|
+
},
|
|
1607
|
+
sessionId ?? "current-session"
|
|
1608
|
+
) : null
|
|
1609
|
+
] });
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1232
1612
|
// src/components/ChatSurface.tsx
|
|
1233
1613
|
import { chatErrorForDisplay as chatErrorForDisplay2 } from "@blade-hq/agent-client";
|
|
1234
1614
|
|
|
1235
1615
|
// src/components/ChatInput.tsx
|
|
1236
|
-
import { jsx as
|
|
1616
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1237
1617
|
function isImeCompositionKey(event) {
|
|
1238
1618
|
return event.isComposing || event.keyCode === 229;
|
|
1239
1619
|
}
|
|
@@ -1269,8 +1649,8 @@ function ChatInput({
|
|
|
1269
1649
|
void handleSend();
|
|
1270
1650
|
}
|
|
1271
1651
|
};
|
|
1272
|
-
return /* @__PURE__ */
|
|
1273
|
-
/* @__PURE__ */
|
|
1652
|
+
return /* @__PURE__ */ jsx5("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: /* @__PURE__ */ jsxs4("div", { className: "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2", children: [
|
|
1653
|
+
/* @__PURE__ */ jsx5(
|
|
1274
1654
|
"textarea",
|
|
1275
1655
|
{
|
|
1276
1656
|
value,
|
|
@@ -1287,7 +1667,7 @@ function ChatInput({
|
|
|
1287
1667
|
className: "blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]"
|
|
1288
1668
|
}
|
|
1289
1669
|
),
|
|
1290
|
-
isStreaming ? /* @__PURE__ */
|
|
1670
|
+
isStreaming ? /* @__PURE__ */ jsx5(
|
|
1291
1671
|
"button",
|
|
1292
1672
|
{
|
|
1293
1673
|
type: "button",
|
|
@@ -1296,9 +1676,9 @@ function ChatInput({
|
|
|
1296
1676
|
"aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1297
1677
|
title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1298
1678
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60",
|
|
1299
|
-
children: isStopping ? /* @__PURE__ */
|
|
1679
|
+
children: isStopping ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Square, { size: 12, fill: "currentColor" })
|
|
1300
1680
|
}
|
|
1301
|
-
) : /* @__PURE__ */
|
|
1681
|
+
) : /* @__PURE__ */ jsx5(
|
|
1302
1682
|
"button",
|
|
1303
1683
|
{
|
|
1304
1684
|
type: "button",
|
|
@@ -1307,23 +1687,23 @@ function ChatInput({
|
|
|
1307
1687
|
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1308
1688
|
title: "\u53D1\u9001\u6D88\u606F",
|
|
1309
1689
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40",
|
|
1310
|
-
children: /* @__PURE__ */
|
|
1690
|
+
children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 })
|
|
1311
1691
|
}
|
|
1312
1692
|
)
|
|
1313
1693
|
] }) });
|
|
1314
1694
|
}
|
|
1315
1695
|
|
|
1316
1696
|
// src/components/ConnectionBanner.tsx
|
|
1317
|
-
import { useEffect as
|
|
1318
|
-
import { jsx as
|
|
1697
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState5 } from "react";
|
|
1698
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1319
1699
|
var CONNECTION_NOTICE_DELAY_MS = 3e3;
|
|
1320
1700
|
var CONNECTION_ERROR_DELAY_MS = 15e3;
|
|
1321
1701
|
function useConnectionNoticePhase(connected) {
|
|
1322
|
-
const [phase, setPhase] =
|
|
1323
|
-
const connectedRef =
|
|
1324
|
-
const timersRef =
|
|
1702
|
+
const [phase, setPhase] = useState5("hidden");
|
|
1703
|
+
const connectedRef = useRef5(connected);
|
|
1704
|
+
const timersRef = useRef5([]);
|
|
1325
1705
|
connectedRef.current = connected;
|
|
1326
|
-
|
|
1706
|
+
useEffect5(() => {
|
|
1327
1707
|
const clearTimers = () => {
|
|
1328
1708
|
for (const timer of timersRef.current) clearTimeout(timer);
|
|
1329
1709
|
timersRef.current = [];
|
|
@@ -1363,14 +1743,14 @@ function useConnectionNoticePhase(connected) {
|
|
|
1363
1743
|
return phase;
|
|
1364
1744
|
}
|
|
1365
1745
|
function ConnectionBanner({ connection, className }) {
|
|
1366
|
-
const hasConnectedRef =
|
|
1746
|
+
const hasConnectedRef = useRef5(connection === "connected" || connection === "reconnecting");
|
|
1367
1747
|
if (connection === "connected") hasConnectedRef.current = true;
|
|
1368
1748
|
const connected = connection === "connected";
|
|
1369
1749
|
const phase = useConnectionNoticePhase(connected);
|
|
1370
1750
|
if (connected || phase === "hidden") return null;
|
|
1371
1751
|
const recovering = phase === "recovering";
|
|
1372
1752
|
const firstConnection = !hasConnectedRef.current;
|
|
1373
|
-
return /* @__PURE__ */
|
|
1753
|
+
return /* @__PURE__ */ jsx6("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs5(
|
|
1374
1754
|
"div",
|
|
1375
1755
|
{
|
|
1376
1756
|
className: cn(
|
|
@@ -1378,10 +1758,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1378
1758
|
recovering ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
|
|
1379
1759
|
),
|
|
1380
1760
|
children: [
|
|
1381
|
-
/* @__PURE__ */
|
|
1382
|
-
/* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1384
|
-
/* @__PURE__ */
|
|
1761
|
+
/* @__PURE__ */ jsx6("span", { className: "mt-0.5 shrink-0", children: recovering ? /* @__PURE__ */ jsx6(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx6(TriangleAlert, { size: 14 }) }),
|
|
1762
|
+
/* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
|
|
1763
|
+
/* @__PURE__ */ jsx6("div", { className: "text-sm font-medium", children: recovering ? firstConnection ? "\u6B63\u5728\u8FDE\u63A5\u2026" : "\u6B63\u5728\u6062\u590D\u8FDE\u63A5\u2026" : "\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5" }),
|
|
1764
|
+
/* @__PURE__ */ jsx6("div", { className: "text-xs opacity-80", children: recovering ? "\u6062\u590D\u540E\u4F1A\u81EA\u52A8\u540C\u6B65\u6700\u65B0\u6D88\u606F\uFF0C\u8BF7\u7A0D\u5019" : "\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u670D\u52A1\u72B6\u6001\uFF0C\u7CFB\u7EDF\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5" })
|
|
1385
1765
|
] })
|
|
1386
1766
|
]
|
|
1387
1767
|
}
|
|
@@ -1390,10 +1770,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1390
1770
|
|
|
1391
1771
|
// src/components/MessageList.tsx
|
|
1392
1772
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1393
|
-
import { useCallback as useCallback7, useEffect as
|
|
1773
|
+
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo7, useRef as useRef12, useState as useState13 } from "react";
|
|
1394
1774
|
|
|
1395
1775
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
1396
|
-
import { useCallback as useCallback4, useMemo as useMemo3, useRef as
|
|
1776
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef6, useState as useState6 } from "react";
|
|
1397
1777
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1398
1778
|
/**
|
|
1399
1779
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1430,10 +1810,10 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1430
1810
|
mouseDown = false;
|
|
1431
1811
|
});
|
|
1432
1812
|
var useStickToBottom = (options = {}) => {
|
|
1433
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1434
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1435
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1436
|
-
const optionsRef =
|
|
1813
|
+
const [escapedFromLock, updateEscapedFromLock] = useState6(false);
|
|
1814
|
+
const [isAtBottom, updateIsAtBottom] = useState6(options.initial !== false);
|
|
1815
|
+
const [isNearBottom, setIsNearBottom] = useState6(false);
|
|
1816
|
+
const optionsRef = useRef6(null);
|
|
1437
1817
|
optionsRef.current = options;
|
|
1438
1818
|
const isSelecting = useCallback4(() => {
|
|
1439
1819
|
if (!mouseDown) {
|
|
@@ -1737,11 +2117,11 @@ function mergeAnimations(...animations) {
|
|
|
1737
2117
|
|
|
1738
2118
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
1739
2119
|
import * as React from "react";
|
|
1740
|
-
import { createContext as createContext2, useContext as useContext2, useEffect as
|
|
2120
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect6, useImperativeHandle, useLayoutEffect, useMemo as useMemo4, useRef as useRef7 } from "react";
|
|
1741
2121
|
var StickToBottomContext = createContext2(null);
|
|
1742
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
2122
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect6;
|
|
1743
2123
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
1744
|
-
const customTargetScrollTop =
|
|
2124
|
+
const customTargetScrollTop = useRef7(null);
|
|
1745
2125
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
1746
2126
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
1747
2127
|
return get?.(target, elements) ?? target;
|
|
@@ -1823,153 +2203,11 @@ import {
|
|
|
1823
2203
|
getTextContent,
|
|
1824
2204
|
normalizeMessageContent
|
|
1825
2205
|
} from "@blade-hq/agent-client";
|
|
1826
|
-
import { useEffect as
|
|
2206
|
+
import { useEffect as useEffect9, useRef as useRef10, useState as useState11 } from "react";
|
|
1827
2207
|
|
|
1828
2208
|
// src/components/AgentLoopBlock.tsx
|
|
1829
|
-
import { useState as
|
|
1830
|
-
|
|
1831
|
-
// src/components/display-utils.ts
|
|
1832
|
-
var TOOL_NAME_ALIASES = {
|
|
1833
|
-
agent: "Agent",
|
|
1834
|
-
ask_user_question: "AskUserQuestion",
|
|
1835
|
-
bash: "Bash",
|
|
1836
|
-
bg_bash: "BgBash",
|
|
1837
|
-
edit: "Edit",
|
|
1838
|
-
exit_plan_mode: "ExitPlanMode",
|
|
1839
|
-
file_edit: "Edit",
|
|
1840
|
-
file_read: "Read",
|
|
1841
|
-
file_write: "Write",
|
|
1842
|
-
finish_task: "FinishTask",
|
|
1843
|
-
glob: "Glob",
|
|
1844
|
-
grep: "Grep",
|
|
1845
|
-
kb_search: "KbSearch",
|
|
1846
|
-
ls: "Ls",
|
|
1847
|
-
multi_edit: "MultiEdit",
|
|
1848
|
-
read: "Read",
|
|
1849
|
-
read_skill: "ReadSkill",
|
|
1850
|
-
web_fetch: "WebFetch",
|
|
1851
|
-
web_search: "WebSearch",
|
|
1852
|
-
write: "Write"
|
|
1853
|
-
};
|
|
1854
|
-
var TOOL_DISPLAY_LABELS = {
|
|
1855
|
-
Bash: "\u6267\u884C\u547D\u4EE4",
|
|
1856
|
-
BgBash: "\u540E\u53F0\u6267\u884C\u547D\u4EE4",
|
|
1857
|
-
Read: "\u8BFB\u53D6\u6587\u4EF6",
|
|
1858
|
-
Write: "\u5199\u5165\u6587\u4EF6",
|
|
1859
|
-
Edit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1860
|
-
MultiEdit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1861
|
-
Ls: "\u5217\u51FA\u76EE\u5F55",
|
|
1862
|
-
Glob: "\u5339\u914D\u6587\u4EF6",
|
|
1863
|
-
Grep: "\u641C\u7D22\u6587\u672C",
|
|
1864
|
-
KbSearch: "\u68C0\u7D22\u77E5\u8BC6\u5E93",
|
|
1865
|
-
WebSearch: "\u641C\u7D22\u7F51\u9875",
|
|
1866
|
-
WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
|
|
1867
|
-
Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
|
|
1868
|
-
AskUserQuestion: "\u5411\u7528\u6237\u63D0\u95EE",
|
|
1869
|
-
ReadSkill: "\u8BFB\u53D6\u6280\u80FD",
|
|
1870
|
-
FinishTask: "\u4EFB\u52A1\u5B8C\u6210",
|
|
1871
|
-
ExitPlanMode: "\u63D0\u4EA4\u8BA1\u5212",
|
|
1872
|
-
ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
|
|
1873
|
-
GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
|
|
1874
|
-
};
|
|
1875
|
-
function safeParseJson(value) {
|
|
1876
|
-
if (!value) return null;
|
|
1877
|
-
try {
|
|
1878
|
-
return JSON.parse(value);
|
|
1879
|
-
} catch {
|
|
1880
|
-
return null;
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
function getStringArgValue(args, key) {
|
|
1884
|
-
const value = args?.[key];
|
|
1885
|
-
return typeof value === "string" ? value.trim() : "";
|
|
1886
|
-
}
|
|
1887
|
-
var SKILL_ENTRY_FILE_NAMES = /* @__PURE__ */ new Set(["skill.md", "command.md"]);
|
|
1888
|
-
var NON_SKILL_DIR_NAMES = /* @__PURE__ */ new Set([".", "..", ".agent", ".agents", ".claude", "skill_data", "skills"]);
|
|
1889
|
-
function getSkillNameFromFilePath(filePath) {
|
|
1890
|
-
if (!filePath) return null;
|
|
1891
|
-
const segments = filePath.split(/[\\/]+/).filter(Boolean);
|
|
1892
|
-
const fileName = segments.pop();
|
|
1893
|
-
if (!fileName || !SKILL_ENTRY_FILE_NAMES.has(fileName.toLowerCase())) return null;
|
|
1894
|
-
const dirName = segments.pop();
|
|
1895
|
-
if (!dirName || NON_SKILL_DIR_NAMES.has(dirName.toLowerCase())) return null;
|
|
1896
|
-
return dirName;
|
|
1897
|
-
}
|
|
1898
|
-
function formatToolName(name) {
|
|
1899
|
-
const trimmed = name.trim();
|
|
1900
|
-
if (!trimmed) return name;
|
|
1901
|
-
const stripped = trimmed.split(":").pop()?.split("/").pop()?.split(".").pop()?.trim() || trimmed;
|
|
1902
|
-
const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
1903
|
-
return TOOL_NAME_ALIASES[normalized] ?? stripped;
|
|
1904
|
-
}
|
|
1905
|
-
function getToolDisplayLabel(toolCall) {
|
|
1906
|
-
const normalized = formatToolName(toolCall.name);
|
|
1907
|
-
const args = safeParseJson(toolCall.arguments);
|
|
1908
|
-
const displayName = toolCall.display_name?.trim() ?? "";
|
|
1909
|
-
const baseLabel = displayName || TOOL_DISPLAY_LABELS[normalized] || normalized;
|
|
1910
|
-
const metaDisplayName = getStringArgValue(args, "_meta_display_name");
|
|
1911
|
-
if (metaDisplayName) {
|
|
1912
|
-
return metaDisplayName;
|
|
1913
|
-
}
|
|
1914
|
-
const description = getStringArgValue(args, "description");
|
|
1915
|
-
if (normalized === "BgBash") {
|
|
1916
|
-
return description ? `\u540E\u53F0\u6267\u884C\uFF1A${description}` : "\u540E\u53F0\u6267\u884C\u547D\u4EE4";
|
|
1917
|
-
}
|
|
1918
|
-
if (normalized === "ReadSkill") {
|
|
1919
|
-
const skillName = getStringArgValue(args, "skill") || getStringArgValue(args, "skill_name");
|
|
1920
|
-
return skillName ? `${baseLabel}\u300C${skillName}\u300D` : baseLabel;
|
|
1921
|
-
}
|
|
1922
|
-
if (normalized === "Read") {
|
|
1923
|
-
const skillName = getSkillNameFromFilePath(
|
|
1924
|
-
getStringArgValue(args, "file_path") || getStringArgValue(args, "path")
|
|
1925
|
-
);
|
|
1926
|
-
if (skillName) return `\u8BFB\u53D6\u6280\u80FD\u300C${skillName}\u300D`;
|
|
1927
|
-
}
|
|
1928
|
-
if (normalized === "FinishTask") {
|
|
1929
|
-
const title = getStringArgValue(args, "title");
|
|
1930
|
-
return title ? `${baseLabel}\uFF1A${title}` : baseLabel;
|
|
1931
|
-
}
|
|
1932
|
-
return description || baseLabel;
|
|
1933
|
-
}
|
|
1934
|
-
function getToolTone(status) {
|
|
1935
|
-
if (status === "error" || status === "cancelled") return "red";
|
|
1936
|
-
if (status === "awaiting_answer") return "amber";
|
|
1937
|
-
if (status === "pending") return "blue";
|
|
1938
|
-
return "emerald";
|
|
1939
|
-
}
|
|
1940
|
-
function getToolStatusLabel(status) {
|
|
1941
|
-
if (status === "pending") return "\u8FD0\u884C\u4E2D";
|
|
1942
|
-
if (status === "awaiting_answer") return "\u7B49\u5F85\u56DE\u7B54";
|
|
1943
|
-
if (status === "error") return "\u9519\u8BEF";
|
|
1944
|
-
if (status === "cancelled") return "\u5DF2\u53D6\u6D88";
|
|
1945
|
-
return "\u5B8C\u6210";
|
|
1946
|
-
}
|
|
1947
|
-
function formatToolDuration(ms) {
|
|
1948
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
1949
|
-
const seconds = ms / 1e3;
|
|
1950
|
-
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
1951
|
-
const minutes = Math.floor(seconds / 60);
|
|
1952
|
-
const remainingSeconds = Math.round(seconds % 60);
|
|
1953
|
-
return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
|
|
1954
|
-
}
|
|
1955
|
-
function formatToolArgs(args) {
|
|
1956
|
-
try {
|
|
1957
|
-
return JSON.stringify(JSON.parse(args), null, 2);
|
|
1958
|
-
} catch {
|
|
1959
|
-
return args;
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
var RESULT_PREVIEW_LIMIT = 4e3;
|
|
1963
|
-
function formatToolResult(result) {
|
|
1964
|
-
const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1965
|
-
if (text == null) return "";
|
|
1966
|
-
if (text.length <= RESULT_PREVIEW_LIMIT) return text;
|
|
1967
|
-
return `${text.slice(0, RESULT_PREVIEW_LIMIT)}
|
|
1968
|
-
\u2026\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
// src/components/AgentLoopBlock.tsx
|
|
1972
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2209
|
+
import { useState as useState7 } from "react";
|
|
2210
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1973
2211
|
function parseAgentDescription(argumentsJson) {
|
|
1974
2212
|
try {
|
|
1975
2213
|
const parsed = JSON.parse(argumentsJson);
|
|
@@ -1979,7 +2217,7 @@ function parseAgentDescription(argumentsJson) {
|
|
|
1979
2217
|
}
|
|
1980
2218
|
}
|
|
1981
2219
|
function AgentLoopBlock({ toolCall }) {
|
|
1982
|
-
const [expanded, setExpanded] =
|
|
2220
|
+
const [expanded, setExpanded] = useState7(false);
|
|
1983
2221
|
const description = parseAgentDescription(toolCall.arguments);
|
|
1984
2222
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
1985
2223
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
@@ -1988,8 +2226,8 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1988
2226
|
"size-3.5 shrink-0",
|
|
1989
2227
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
1990
2228
|
);
|
|
1991
|
-
return /* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
2229
|
+
return /* @__PURE__ */ jsxs6("div", { className: "blade-chat-agent-loop text-xs leading-[22px]", children: [
|
|
2230
|
+
/* @__PURE__ */ jsxs6(
|
|
1993
2231
|
"button",
|
|
1994
2232
|
{
|
|
1995
2233
|
type: "button",
|
|
@@ -2004,17 +2242,18 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
2004
2242
|
),
|
|
2005
2243
|
title: `\u5B50\u4EFB\u52A1\uFF1A${description}`,
|
|
2006
2244
|
children: [
|
|
2007
|
-
running ? /* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2245
|
+
running ? /* @__PURE__ */ jsx7(LoaderCircle, { className: cn(iconClass, "animate-spin"), "aria-hidden": "true" }) : toolCall.status === "error" ? /* @__PURE__ */ jsx7(CircleAlert, { className: iconClass, "aria-hidden": "true" }) : toolCall.status === "cancelled" ? /* @__PURE__ */ jsx7(X, { className: iconClass, "aria-hidden": "true" }) : /* @__PURE__ */ jsx7(Bot, { className: iconClass, "aria-hidden": "true" }),
|
|
2246
|
+
/* @__PURE__ */ jsxs6("span", { className: "min-w-0 truncate", children: [
|
|
2009
2247
|
"\u5B50\u4EFB\u52A1\uFF1A",
|
|
2010
2248
|
description
|
|
2011
2249
|
] }),
|
|
2012
|
-
hasResult ? /* @__PURE__ */
|
|
2250
|
+
hasResult ? /* @__PURE__ */ jsx7(
|
|
2013
2251
|
ChevronRight,
|
|
2014
2252
|
{
|
|
2015
2253
|
size: 14,
|
|
2254
|
+
style: { transitionDuration: "260ms", transitionTimingFunction: "cubic-bezier(0.25, 0.1, 0.25, 1)" },
|
|
2016
2255
|
className: cn(
|
|
2017
|
-
"shrink-0 transition-transform
|
|
2256
|
+
"shrink-0 transition-transform",
|
|
2018
2257
|
expanded && "rotate-90"
|
|
2019
2258
|
),
|
|
2020
2259
|
"aria-hidden": "true"
|
|
@@ -2023,18 +2262,18 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
2023
2262
|
]
|
|
2024
2263
|
}
|
|
2025
2264
|
),
|
|
2026
|
-
expanded && hasResult ? /* @__PURE__ */
|
|
2265
|
+
expanded && hasResult ? /* @__PURE__ */ jsx7("div", { className: "ml-[18px] mt-1.5 max-h-[400px] overflow-auto whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: formatToolResult(toolCall.result) }) : null
|
|
2027
2266
|
] });
|
|
2028
2267
|
}
|
|
2029
2268
|
|
|
2030
2269
|
// src/components/MarkdownContent.tsx
|
|
2031
2270
|
import {
|
|
2032
|
-
useEffect as
|
|
2271
|
+
useEffect as useEffect7,
|
|
2033
2272
|
useMemo as useMemo5,
|
|
2034
|
-
useRef as
|
|
2035
|
-
useState as
|
|
2273
|
+
useRef as useRef8,
|
|
2274
|
+
useState as useState8
|
|
2036
2275
|
} from "react";
|
|
2037
|
-
import { jsx as
|
|
2276
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2038
2277
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
2039
2278
|
function normalizeAdjacentUrlFormatting(value) {
|
|
2040
2279
|
const protectedSegments = [];
|
|
@@ -2049,10 +2288,10 @@ function normalizeAdjacentUrlFormatting(value) {
|
|
|
2049
2288
|
return normalized.replace(/blade-url-protected-(\d+)-marker/g, (_, index) => protectedSegments[Number(index)]);
|
|
2050
2289
|
}
|
|
2051
2290
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
2052
|
-
const preRef =
|
|
2053
|
-
const [copied, setCopied] =
|
|
2054
|
-
const [language, setLanguage] =
|
|
2055
|
-
|
|
2291
|
+
const preRef = useRef8(null);
|
|
2292
|
+
const [copied, setCopied] = useState8(false);
|
|
2293
|
+
const [language, setLanguage] = useState8("");
|
|
2294
|
+
useEffect7(() => {
|
|
2056
2295
|
const codeEl = preRef.current?.querySelector("code");
|
|
2057
2296
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
2058
2297
|
}, []);
|
|
@@ -2063,10 +2302,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2063
2302
|
setTimeout(() => setCopied(false), 2e3);
|
|
2064
2303
|
}
|
|
2065
2304
|
};
|
|
2066
|
-
return /* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
2305
|
+
return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
|
|
2306
|
+
/* @__PURE__ */ jsxs7("div", { className: "blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5", children: [
|
|
2307
|
+
/* @__PURE__ */ jsx8("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
|
|
2308
|
+
/* @__PURE__ */ jsxs7(
|
|
2070
2309
|
"button",
|
|
2071
2310
|
{
|
|
2072
2311
|
type: "button",
|
|
@@ -2076,13 +2315,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2076
2315
|
copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
|
|
2077
2316
|
),
|
|
2078
2317
|
children: [
|
|
2079
|
-
copied ? /* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */
|
|
2318
|
+
copied ? /* @__PURE__ */ jsx8(Check, { size: 12 }) : /* @__PURE__ */ jsx8(Copy, { size: 12 }),
|
|
2319
|
+
/* @__PURE__ */ jsx8("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
|
|
2081
2320
|
]
|
|
2082
2321
|
}
|
|
2083
2322
|
)
|
|
2084
2323
|
] }),
|
|
2085
|
-
/* @__PURE__ */
|
|
2324
|
+
/* @__PURE__ */ jsx8(
|
|
2086
2325
|
"pre",
|
|
2087
2326
|
{
|
|
2088
2327
|
ref: preRef,
|
|
@@ -2094,7 +2333,7 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2094
2333
|
] });
|
|
2095
2334
|
}
|
|
2096
2335
|
function ExternalAnchor({ node: _node, children, ...props }) {
|
|
2097
|
-
return /* @__PURE__ */
|
|
2336
|
+
return /* @__PURE__ */ jsx8("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
2098
2337
|
}
|
|
2099
2338
|
var MARKDOWN_COMPONENTS = {
|
|
2100
2339
|
pre: CodeBlockPre,
|
|
@@ -2104,7 +2343,7 @@ function MarkdownContent({ children, className, mode, sessionId }) {
|
|
|
2104
2343
|
const resolvedChildren = useMemo5(() => {
|
|
2105
2344
|
return normalizeAdjacentUrlFormatting(children.replace(SYSTEM_REMINDER_RE, ""));
|
|
2106
2345
|
}, [children]);
|
|
2107
|
-
return /* @__PURE__ */
|
|
2346
|
+
return /* @__PURE__ */ jsx8(
|
|
2108
2347
|
_r,
|
|
2109
2348
|
{
|
|
2110
2349
|
className: cn("blade-chat-markdown break-words", className),
|
|
@@ -2117,17 +2356,17 @@ function MarkdownContent({ children, className, mode, sessionId }) {
|
|
|
2117
2356
|
}
|
|
2118
2357
|
|
|
2119
2358
|
// src/components/Shimmer.tsx
|
|
2120
|
-
import { jsx as
|
|
2359
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2121
2360
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
2122
|
-
return /* @__PURE__ */
|
|
2361
|
+
return /* @__PURE__ */ jsx9("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
|
|
2123
2362
|
}
|
|
2124
2363
|
|
|
2125
2364
|
// src/components/ToolCallBlock.tsx
|
|
2126
|
-
import { useState as
|
|
2365
|
+
import { useState as useState10 } from "react";
|
|
2127
2366
|
|
|
2128
2367
|
// src/components/AskUserQuestionBlock.tsx
|
|
2129
|
-
import { useEffect as
|
|
2130
|
-
import { jsx as
|
|
2368
|
+
import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef9, useState as useState9 } from "react";
|
|
2369
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2131
2370
|
var CUSTOM_TEXTAREA_MAX_HEIGHT = 160;
|
|
2132
2371
|
function resizeCustomTextarea(textarea) {
|
|
2133
2372
|
textarea.style.height = "auto";
|
|
@@ -2135,12 +2374,12 @@ function resizeCustomTextarea(textarea) {
|
|
|
2135
2374
|
textarea.style.overflowY = textarea.scrollHeight > CUSTOM_TEXTAREA_MAX_HEIGHT ? "auto" : "hidden";
|
|
2136
2375
|
}
|
|
2137
2376
|
function useAutoResizeTextarea(value) {
|
|
2138
|
-
const textareaRef =
|
|
2139
|
-
|
|
2377
|
+
const textareaRef = useRef9(null);
|
|
2378
|
+
useEffect8(() => {
|
|
2140
2379
|
const textarea = textareaRef.current;
|
|
2141
2380
|
if (textarea?.value === value) resizeCustomTextarea(textarea);
|
|
2142
2381
|
}, [value]);
|
|
2143
|
-
|
|
2382
|
+
useEffect8(() => {
|
|
2144
2383
|
const textarea = textareaRef.current;
|
|
2145
2384
|
if (!textarea || typeof ResizeObserver === "undefined") return;
|
|
2146
2385
|
let previousWidth = textarea.clientWidth;
|
|
@@ -2165,12 +2404,12 @@ function AskUserQuestionBlock({
|
|
|
2165
2404
|
answerData,
|
|
2166
2405
|
onAnswer
|
|
2167
2406
|
}) {
|
|
2168
|
-
const [selections, setSelections] =
|
|
2169
|
-
const [customTexts, setCustomTexts] =
|
|
2170
|
-
const [usingCustom, setUsingCustom] =
|
|
2171
|
-
const [note, setNote] =
|
|
2172
|
-
const [submitted, setSubmitted] =
|
|
2173
|
-
|
|
2407
|
+
const [selections, setSelections] = useState9(/* @__PURE__ */ new Map());
|
|
2408
|
+
const [customTexts, setCustomTexts] = useState9(/* @__PURE__ */ new Map());
|
|
2409
|
+
const [usingCustom, setUsingCustom] = useState9(/* @__PURE__ */ new Set());
|
|
2410
|
+
const [note, setNote] = useState9("");
|
|
2411
|
+
const [submitted, setSubmitted] = useState9(false);
|
|
2412
|
+
useEffect8(() => {
|
|
2174
2413
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
2175
2414
|
setSubmitted(false);
|
|
2176
2415
|
}
|
|
@@ -2268,7 +2507,7 @@ ${parts.join("\n")}`,
|
|
|
2268
2507
|
setSubmitted(true);
|
|
2269
2508
|
onAnswer(text, toolCallId, nextAnswerData);
|
|
2270
2509
|
};
|
|
2271
|
-
return /* @__PURE__ */
|
|
2510
|
+
return /* @__PURE__ */ jsxs8(
|
|
2272
2511
|
"div",
|
|
2273
2512
|
{
|
|
2274
2513
|
className: cn(
|
|
@@ -2276,12 +2515,12 @@ ${parts.join("\n")}`,
|
|
|
2276
2515
|
answered ? "max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80" : "max-w-lg space-y-5 p-4 text-sm"
|
|
2277
2516
|
),
|
|
2278
2517
|
children: [
|
|
2279
|
-
data.source_loop?.description && /* @__PURE__ */
|
|
2518
|
+
data.source_loop?.description && /* @__PURE__ */ jsxs8("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
2280
2519
|
"\u5B50\u667A\u80FD\u4F53\u300C",
|
|
2281
2520
|
data.source_loop.description,
|
|
2282
2521
|
"\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
|
|
2283
2522
|
] }),
|
|
2284
|
-
data.questions.map((q, qIdx) => /* @__PURE__ */
|
|
2523
|
+
data.questions.map((q, qIdx) => /* @__PURE__ */ jsx10(
|
|
2285
2524
|
QuestionCard,
|
|
2286
2525
|
{
|
|
2287
2526
|
question: q,
|
|
@@ -2296,7 +2535,7 @@ ${parts.join("\n")}`,
|
|
|
2296
2535
|
},
|
|
2297
2536
|
q.question
|
|
2298
2537
|
)),
|
|
2299
|
-
/* @__PURE__ */
|
|
2538
|
+
/* @__PURE__ */ jsx10(
|
|
2300
2539
|
NoteField,
|
|
2301
2540
|
{
|
|
2302
2541
|
answered,
|
|
@@ -2305,7 +2544,7 @@ ${parts.join("\n")}`,
|
|
|
2305
2544
|
onChange: setNote
|
|
2306
2545
|
}
|
|
2307
2546
|
),
|
|
2308
|
-
!answered && !submitted && onAnswer && /* @__PURE__ */
|
|
2547
|
+
!answered && !submitted && onAnswer && /* @__PURE__ */ jsx10(
|
|
2309
2548
|
"button",
|
|
2310
2549
|
{
|
|
2311
2550
|
type: "button",
|
|
@@ -2315,14 +2554,14 @@ ${parts.join("\n")}`,
|
|
|
2315
2554
|
children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
|
|
2316
2555
|
}
|
|
2317
2556
|
),
|
|
2318
|
-
submitted && !answered && /* @__PURE__ */
|
|
2557
|
+
submitted && !answered && /* @__PURE__ */ jsxs8(
|
|
2319
2558
|
"button",
|
|
2320
2559
|
{
|
|
2321
2560
|
type: "button",
|
|
2322
2561
|
disabled: true,
|
|
2323
2562
|
className: "flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80",
|
|
2324
2563
|
children: [
|
|
2325
|
-
/* @__PURE__ */
|
|
2564
|
+
/* @__PURE__ */ jsx10(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
2326
2565
|
"\u786E\u8BA4\u4E2D"
|
|
2327
2566
|
]
|
|
2328
2567
|
}
|
|
@@ -2344,30 +2583,30 @@ function QuestionCard({
|
|
|
2344
2583
|
}) {
|
|
2345
2584
|
const multi = question.multiSelect ?? false;
|
|
2346
2585
|
const customTextareaRef = useAutoResizeTextarea(customText);
|
|
2347
|
-
return /* @__PURE__ */
|
|
2348
|
-
/* @__PURE__ */
|
|
2349
|
-
/* @__PURE__ */
|
|
2586
|
+
return /* @__PURE__ */ jsxs8("div", { children: [
|
|
2587
|
+
/* @__PURE__ */ jsxs8("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
|
|
2588
|
+
/* @__PURE__ */ jsx10(
|
|
2350
2589
|
MessageSquareMore,
|
|
2351
2590
|
{
|
|
2352
2591
|
size: answered ? 12 : 13,
|
|
2353
2592
|
className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
|
|
2354
2593
|
}
|
|
2355
2594
|
),
|
|
2356
|
-
/* @__PURE__ */
|
|
2595
|
+
/* @__PURE__ */ jsx10(
|
|
2357
2596
|
"div",
|
|
2358
2597
|
{
|
|
2359
2598
|
className: cn(
|
|
2360
2599
|
"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
|
|
2361
2600
|
answered ? "text-xs" : "text-sm"
|
|
2362
2601
|
),
|
|
2363
|
-
children: /* @__PURE__ */
|
|
2602
|
+
children: /* @__PURE__ */ jsx10(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
2364
2603
|
}
|
|
2365
2604
|
)
|
|
2366
2605
|
] }),
|
|
2367
|
-
/* @__PURE__ */
|
|
2606
|
+
/* @__PURE__ */ jsxs8("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
|
|
2368
2607
|
question.options.map((opt, optIdx) => {
|
|
2369
2608
|
const isSel = selected.has(optIdx);
|
|
2370
|
-
return /* @__PURE__ */
|
|
2609
|
+
return /* @__PURE__ */ jsxs8(
|
|
2371
2610
|
"button",
|
|
2372
2611
|
{
|
|
2373
2612
|
type: "button",
|
|
@@ -2381,14 +2620,14 @@ function QuestionCard({
|
|
|
2381
2620
|
answered && "cursor-default opacity-70"
|
|
2382
2621
|
),
|
|
2383
2622
|
children: [
|
|
2384
|
-
multi && /* @__PURE__ */
|
|
2623
|
+
multi && /* @__PURE__ */ jsx10(
|
|
2385
2624
|
"div",
|
|
2386
2625
|
{
|
|
2387
2626
|
className: cn(
|
|
2388
2627
|
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
2389
2628
|
isSel && !answered ? "border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]" : "border-[hsl(var(--border))]"
|
|
2390
2629
|
),
|
|
2391
|
-
children: isSel && /* @__PURE__ */
|
|
2630
|
+
children: isSel && /* @__PURE__ */ jsx10(
|
|
2392
2631
|
Check,
|
|
2393
2632
|
{
|
|
2394
2633
|
size: 9,
|
|
@@ -2397,9 +2636,9 @@ function QuestionCard({
|
|
|
2397
2636
|
)
|
|
2398
2637
|
}
|
|
2399
2638
|
),
|
|
2400
|
-
/* @__PURE__ */
|
|
2401
|
-
/* @__PURE__ */
|
|
2402
|
-
opt.description && /* @__PURE__ */
|
|
2639
|
+
/* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
|
|
2640
|
+
/* @__PURE__ */ jsx10("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
|
|
2641
|
+
opt.description && /* @__PURE__ */ jsx10(
|
|
2403
2642
|
"div",
|
|
2404
2643
|
{
|
|
2405
2644
|
className: cn(
|
|
@@ -2416,7 +2655,7 @@ function QuestionCard({
|
|
|
2416
2655
|
opt.label
|
|
2417
2656
|
);
|
|
2418
2657
|
}),
|
|
2419
|
-
answered && !isCustom ? null : /* @__PURE__ */
|
|
2658
|
+
answered && !isCustom ? null : /* @__PURE__ */ jsxs8(
|
|
2420
2659
|
"div",
|
|
2421
2660
|
{
|
|
2422
2661
|
className: cn(
|
|
@@ -2426,8 +2665,8 @@ function QuestionCard({
|
|
|
2426
2665
|
answered && "cursor-default opacity-70"
|
|
2427
2666
|
),
|
|
2428
2667
|
children: [
|
|
2429
|
-
/* @__PURE__ */
|
|
2430
|
-
/* @__PURE__ */
|
|
2668
|
+
/* @__PURE__ */ jsx10("span", { className: "shrink-0 pt-1 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
|
|
2669
|
+
/* @__PURE__ */ jsx10(
|
|
2431
2670
|
"textarea",
|
|
2432
2671
|
{
|
|
2433
2672
|
ref: customTextareaRef,
|
|
@@ -2459,7 +2698,7 @@ function NoteField({
|
|
|
2459
2698
|
const textareaRef = useAutoResizeTextarea(note);
|
|
2460
2699
|
const readOnly = answered || submitted;
|
|
2461
2700
|
if (answered && !note.trim()) return null;
|
|
2462
|
-
return /* @__PURE__ */
|
|
2701
|
+
return /* @__PURE__ */ jsxs8(
|
|
2463
2702
|
"label",
|
|
2464
2703
|
{
|
|
2465
2704
|
className: cn(
|
|
@@ -2469,8 +2708,8 @@ function NoteField({
|
|
|
2469
2708
|
readOnly && "cursor-default opacity-70"
|
|
2470
2709
|
),
|
|
2471
2710
|
children: [
|
|
2472
|
-
/* @__PURE__ */
|
|
2473
|
-
/* @__PURE__ */
|
|
2711
|
+
/* @__PURE__ */ jsx10("span", { className: "mb-1.5 block text-xs text-[hsl(var(--muted-foreground))]", children: "\u8865\u5145\u8BF4\u660E\uFF08\u53EF\u9009\uFF09" }),
|
|
2712
|
+
/* @__PURE__ */ jsx10(
|
|
2474
2713
|
"textarea",
|
|
2475
2714
|
{
|
|
2476
2715
|
ref: textareaRef,
|
|
@@ -2559,7 +2798,7 @@ function normalizeOptionItem(value) {
|
|
|
2559
2798
|
}
|
|
2560
2799
|
|
|
2561
2800
|
// src/components/ToolCallBlock.tsx
|
|
2562
|
-
import { Fragment, jsx as
|
|
2801
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2563
2802
|
function resolveAskQuestionState({
|
|
2564
2803
|
toolStatus,
|
|
2565
2804
|
hasAnswerData,
|
|
@@ -2581,12 +2820,12 @@ function ToolCallBlock({
|
|
|
2581
2820
|
isActiveQuestion,
|
|
2582
2821
|
renderer
|
|
2583
2822
|
}) {
|
|
2584
|
-
const [expanded, setExpanded] =
|
|
2823
|
+
const [expanded, setExpanded] = useState10(false);
|
|
2585
2824
|
const normalizedName = formatToolName(toolCall.name);
|
|
2586
2825
|
if (renderer) {
|
|
2587
2826
|
const custom = renderer(toolCall);
|
|
2588
2827
|
if (custom !== null && custom !== void 0) {
|
|
2589
|
-
return /* @__PURE__ */
|
|
2828
|
+
return /* @__PURE__ */ jsx11(Fragment, { children: custom });
|
|
2590
2829
|
}
|
|
2591
2830
|
}
|
|
2592
2831
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2599,7 +2838,7 @@ function ToolCallBlock({
|
|
|
2599
2838
|
});
|
|
2600
2839
|
const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
|
|
2601
2840
|
if (askData) {
|
|
2602
|
-
return /* @__PURE__ */
|
|
2841
|
+
return /* @__PURE__ */ jsx11(
|
|
2603
2842
|
AskUserQuestionBlock,
|
|
2604
2843
|
{
|
|
2605
2844
|
data: askData,
|
|
@@ -2612,31 +2851,31 @@ function ToolCallBlock({
|
|
|
2612
2851
|
);
|
|
2613
2852
|
}
|
|
2614
2853
|
if (toolCall.status === "pending") {
|
|
2615
|
-
return /* @__PURE__ */
|
|
2616
|
-
/* @__PURE__ */
|
|
2617
|
-
/* @__PURE__ */
|
|
2854
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]", children: [
|
|
2855
|
+
/* @__PURE__ */ jsx11(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
2856
|
+
/* @__PURE__ */ jsx11("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
|
|
2618
2857
|
] });
|
|
2619
2858
|
}
|
|
2620
2859
|
const errorDetail = parseAskUserQuestionError(
|
|
2621
2860
|
typeof toolCall.result === "string" ? toolCall.result : null
|
|
2622
2861
|
);
|
|
2623
|
-
return /* @__PURE__ */
|
|
2624
|
-
/* @__PURE__ */
|
|
2625
|
-
/* @__PURE__ */
|
|
2626
|
-
errorDetail?.detail ? /* @__PURE__ */
|
|
2627
|
-
/* @__PURE__ */
|
|
2628
|
-
/* @__PURE__ */
|
|
2862
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]", children: [
|
|
2863
|
+
/* @__PURE__ */ jsx11("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
|
|
2864
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: errorDetail?.message ?? "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" }),
|
|
2865
|
+
errorDetail?.detail ? /* @__PURE__ */ jsxs9("details", { className: "mt-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
|
|
2866
|
+
/* @__PURE__ */ jsx11("summary", { className: "cursor-pointer", children: "\u67E5\u770B\u5177\u4F53\u539F\u56E0" }),
|
|
2867
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-words font-mono", children: errorDetail.detail })
|
|
2629
2868
|
] }) : null
|
|
2630
2869
|
] });
|
|
2631
2870
|
}
|
|
2632
2871
|
const tone = getToolTone(toolCall.status);
|
|
2633
2872
|
const displayName = getToolDisplayLabel(toolCall);
|
|
2634
2873
|
const toneClass = tone === "red" ? "border-l-[hsl(var(--muted-foreground)/0.5)]" : tone === "amber" ? "border-l-amber-400" : tone === "blue" ? "border-l-blue-500" : "border-l-[hsl(var(--primary))]";
|
|
2635
|
-
const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */
|
|
2874
|
+
const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx11(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx11(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx11(X, { size: 11 }) : /* @__PURE__ */ jsx11(Check, { size: 11 });
|
|
2636
2875
|
const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
|
|
2637
|
-
return /* @__PURE__ */
|
|
2638
|
-
/* @__PURE__ */
|
|
2639
|
-
/* @__PURE__ */
|
|
2876
|
+
return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-tool ml-4 text-xs", children: [
|
|
2877
|
+
/* @__PURE__ */ jsxs9("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
|
|
2878
|
+
/* @__PURE__ */ jsxs9(
|
|
2640
2879
|
"button",
|
|
2641
2880
|
{
|
|
2642
2881
|
type: "button",
|
|
@@ -2644,7 +2883,7 @@ function ToolCallBlock({
|
|
|
2644
2883
|
className: "flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
|
|
2645
2884
|
"aria-expanded": expanded,
|
|
2646
2885
|
children: [
|
|
2647
|
-
/* @__PURE__ */
|
|
2886
|
+
/* @__PURE__ */ jsx11(
|
|
2648
2887
|
ChevronRight,
|
|
2649
2888
|
{
|
|
2650
2889
|
size: 11,
|
|
@@ -2654,24 +2893,24 @@ function ToolCallBlock({
|
|
|
2654
2893
|
)
|
|
2655
2894
|
}
|
|
2656
2895
|
),
|
|
2657
|
-
/* @__PURE__ */
|
|
2896
|
+
/* @__PURE__ */ jsxs9("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
2658
2897
|
statusIcon,
|
|
2659
|
-
/* @__PURE__ */
|
|
2898
|
+
/* @__PURE__ */ jsx11("span", { children: getToolStatusLabel(toolCall.status) })
|
|
2660
2899
|
] }),
|
|
2661
|
-
/* @__PURE__ */
|
|
2900
|
+
/* @__PURE__ */ jsx11("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
|
|
2662
2901
|
]
|
|
2663
2902
|
}
|
|
2664
2903
|
),
|
|
2665
|
-
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */
|
|
2904
|
+
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx11("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
|
|
2666
2905
|
] }),
|
|
2667
|
-
expanded && /* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
2671
|
-
/* @__PURE__ */
|
|
2672
|
-
toolCall.result != null && /* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2674
|
-
/* @__PURE__ */
|
|
2906
|
+
expanded && /* @__PURE__ */ jsxs9("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
|
|
2907
|
+
/* @__PURE__ */ jsx11("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
|
|
2908
|
+
/* @__PURE__ */ jsx11("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
|
|
2909
|
+
/* @__PURE__ */ jsx11("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
|
|
2910
|
+
/* @__PURE__ */ jsx11("pre", { className: "overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolArgs(toolCall.arguments) }),
|
|
2911
|
+
toolCall.result != null && /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2912
|
+
/* @__PURE__ */ jsx11("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
2913
|
+
/* @__PURE__ */ jsx11("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
|
|
2675
2914
|
] })
|
|
2676
2915
|
] })
|
|
2677
2916
|
] });
|
|
@@ -2689,12 +2928,12 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2689
2928
|
}
|
|
2690
2929
|
|
|
2691
2930
|
// src/components/AssistantTurnBlock.tsx
|
|
2692
|
-
import { jsx as
|
|
2931
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2693
2932
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2694
|
-
const [open, setOpen] =
|
|
2933
|
+
const [open, setOpen] = useState11(false);
|
|
2695
2934
|
if (!isStreaming) return null;
|
|
2696
|
-
return /* @__PURE__ */
|
|
2697
|
-
/* @__PURE__ */
|
|
2935
|
+
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-thinking text-xs", children: [
|
|
2936
|
+
/* @__PURE__ */ jsxs10(
|
|
2698
2937
|
"button",
|
|
2699
2938
|
{
|
|
2700
2939
|
type: "button",
|
|
@@ -2702,8 +2941,8 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2702
2941
|
"aria-expanded": open,
|
|
2703
2942
|
className: "group/thinking inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
2704
2943
|
children: [
|
|
2705
|
-
/* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2944
|
+
/* @__PURE__ */ jsx12(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }),
|
|
2945
|
+
/* @__PURE__ */ jsx12(
|
|
2707
2946
|
ChevronRight,
|
|
2708
2947
|
{
|
|
2709
2948
|
size: 14,
|
|
@@ -2716,7 +2955,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2716
2955
|
]
|
|
2717
2956
|
}
|
|
2718
2957
|
),
|
|
2719
|
-
open ? /* @__PURE__ */
|
|
2958
|
+
open ? /* @__PURE__ */ jsx12("div", { className: "mt-1.5 whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: reasoning }) : null
|
|
2720
2959
|
] });
|
|
2721
2960
|
}
|
|
2722
2961
|
function getMessageText(message) {
|
|
@@ -2908,14 +3147,14 @@ function ExecutionToolRow({ toolCall }) {
|
|
|
2908
3147
|
"size-3.5 shrink-0",
|
|
2909
3148
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
2910
3149
|
);
|
|
2911
|
-
const icon = toolCall.status === "pending" ? /* @__PURE__ */
|
|
3150
|
+
const icon = toolCall.status === "pending" ? /* @__PURE__ */ jsx12(LoaderCircle, { className: cn(iconClass, "animate-spin"), "aria-hidden": "true" }) : toolCall.status === "error" ? /* @__PURE__ */ jsx12(CircleAlert, { className: iconClass, "aria-hidden": "true" }) : toolCall.status === "cancelled" ? /* @__PURE__ */ jsx12(X, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "WebSearch" || normalizedName === "WebFetch" ? /* @__PURE__ */ jsx12(Earth, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Bash" || normalizedName === "BgBash" ? /* @__PURE__ */ jsx12(Terminal, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Write" || normalizedName === "Edit" || normalizedName === "MultiEdit" ? /* @__PURE__ */ jsx12(FilePenLine, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Read" || normalizedName === "ReadSkill" || normalizedName === "get_skill_content" ? /* @__PURE__ */ jsx12(BookOpen, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Grep" || normalizedName === "Glob" || normalizedName === "search_skills" ? /* @__PURE__ */ jsx12(Search, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Agent" ? /* @__PURE__ */ jsx12(Bot, { className: iconClass, "aria-hidden": "true" }) : /* @__PURE__ */ jsx12(Wrench, { className: iconClass, "aria-hidden": "true" });
|
|
2912
3151
|
const rowClassName = cn(
|
|
2913
3152
|
"flex min-w-0 items-center gap-1 py-1.5 text-xs leading-[22px]",
|
|
2914
3153
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
2915
3154
|
);
|
|
2916
|
-
return /* @__PURE__ */
|
|
3155
|
+
return /* @__PURE__ */ jsxs10("div", { "data-testid": "execution-tool-intent", className: rowClassName, title: label, children: [
|
|
2917
3156
|
icon,
|
|
2918
|
-
/* @__PURE__ */
|
|
3157
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 truncate", children: label })
|
|
2919
3158
|
] });
|
|
2920
3159
|
}
|
|
2921
3160
|
function AssistantTurnBlock({
|
|
@@ -2925,8 +3164,15 @@ function AssistantTurnBlock({
|
|
|
2925
3164
|
onAnswer,
|
|
2926
3165
|
sessionStatus,
|
|
2927
3166
|
toolCallRenderer,
|
|
3167
|
+
hidePlanUpdateTools = false,
|
|
2928
3168
|
sessionId
|
|
2929
3169
|
}) {
|
|
3170
|
+
const shouldHideToolCall = (message, toolCall) => {
|
|
3171
|
+
if (!hidePlanUpdateTools || !isPlanUpdateTool(toolCall) || parsePlanUpdate(toolCall.arguments) === null) {
|
|
3172
|
+
return false;
|
|
3173
|
+
}
|
|
3174
|
+
return toolCall.status === "done" || toolCall.status === "pending" && message.status === "streaming";
|
|
3175
|
+
};
|
|
2930
3176
|
const hasInterrupted = messages.some((message) => message.status === "interrupted");
|
|
2931
3177
|
const hasFailedWithoutContent = messages.some(
|
|
2932
3178
|
(message) => message.status === "failed" && !hasRenderableMessageContent(message)
|
|
@@ -2936,16 +3182,16 @@ function AssistantTurnBlock({
|
|
|
2936
3182
|
const finalOrderedParts = finalMessage ? getOrderedMessageParts(
|
|
2937
3183
|
finalMessage,
|
|
2938
3184
|
(finalMessage.tool_calls ?? []).filter(
|
|
2939
|
-
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
3185
|
+
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !shouldHideToolCall(finalMessage, toolCall)
|
|
2940
3186
|
)
|
|
2941
3187
|
) : [];
|
|
2942
3188
|
const hasExecutionProcess = messages.some(
|
|
2943
|
-
(message) => message.reasoning || (message.tool_calls
|
|
3189
|
+
(message) => message.reasoning || (message.tool_calls ?? []).some((toolCall) => !shouldHideToolCall(message, toolCall))
|
|
2944
3190
|
);
|
|
2945
3191
|
const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
|
|
2946
3192
|
const hasActionableToolCall = messages.some(
|
|
2947
3193
|
(message) => message.status === "failed" || message.status === "interrupted" || (message.tool_calls ?? []).some(
|
|
2948
|
-
(toolCall) => toolCall.status === "error" || toolCall.status === "cancelled"
|
|
3194
|
+
(toolCall) => !shouldHideToolCall(message, toolCall) && (toolCall.status === "error" || toolCall.status === "cancelled")
|
|
2949
3195
|
)
|
|
2950
3196
|
);
|
|
2951
3197
|
const questionToolCalls = messages.flatMap(
|
|
@@ -2954,12 +3200,12 @@ function AssistantTurnBlock({
|
|
|
2954
3200
|
)
|
|
2955
3201
|
);
|
|
2956
3202
|
const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
|
|
2957
|
-
const [displayMode, setDisplayMode] =
|
|
3203
|
+
const [displayMode, setDisplayMode] = useState11(
|
|
2958
3204
|
() => isStreaming || hasActionableToolCall ? "detail" : "compact"
|
|
2959
3205
|
);
|
|
2960
|
-
const userSelectedDisplayModeRef =
|
|
2961
|
-
const wasStreamingRef =
|
|
2962
|
-
|
|
3206
|
+
const userSelectedDisplayModeRef = useRef10(false);
|
|
3207
|
+
const wasStreamingRef = useRef10(isStreaming);
|
|
3208
|
+
useEffect9(() => {
|
|
2963
3209
|
if (wasStreamingRef.current && !isStreaming && !userSelectedDisplayModeRef.current) {
|
|
2964
3210
|
setDisplayMode(hasActionableToolCall ? "detail" : "compact");
|
|
2965
3211
|
}
|
|
@@ -2967,11 +3213,11 @@ function AssistantTurnBlock({
|
|
|
2967
3213
|
}, [hasActionableToolCall, isStreaming]);
|
|
2968
3214
|
const effectiveMode = resolveTurnDisplayMode({ isStreaming, displayMode });
|
|
2969
3215
|
const executionDurationMs = getExecutionDurationMs({ messages, isStreaming });
|
|
2970
|
-
const [clock, setClock] =
|
|
3216
|
+
const [clock, setClock] = useState11(() => Date.now());
|
|
2971
3217
|
const hasLiveStartTime = messages.some(
|
|
2972
3218
|
(message) => message.timestamp != null && Number.isFinite(Date.parse(message.timestamp))
|
|
2973
3219
|
);
|
|
2974
|
-
|
|
3220
|
+
useEffect9(() => {
|
|
2975
3221
|
if (!isStreaming || !hasLiveStartTime) return;
|
|
2976
3222
|
const timer = window.setInterval(() => setClock(Date.now()), 1e3);
|
|
2977
3223
|
return () => window.clearInterval(timer);
|
|
@@ -2979,21 +3225,21 @@ function AssistantTurnBlock({
|
|
|
2979
3225
|
const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({ messages, isStreaming, now: clock }) : executionDurationMs;
|
|
2980
3226
|
const memoryRefs = collectMemoryRefs(messages);
|
|
2981
3227
|
if (!hasExecutionProcess) {
|
|
2982
|
-
return /* @__PURE__ */
|
|
3228
|
+
return /* @__PURE__ */ jsxs10(
|
|
2983
3229
|
"div",
|
|
2984
3230
|
{
|
|
2985
3231
|
"aria-busy": isStreaming || void 0,
|
|
2986
3232
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
2987
3233
|
children: [
|
|
2988
|
-
memoryRefs.length > 0 ? /* @__PURE__ */
|
|
2989
|
-
hasInterrupted && /* @__PURE__ */
|
|
2990
|
-
hasFailedWithoutContent && /* @__PURE__ */
|
|
3234
|
+
memoryRefs.length > 0 ? /* @__PURE__ */ jsx12(MemoryRefsHint, { refs: memoryRefs }) : null,
|
|
3235
|
+
hasInterrupted && /* @__PURE__ */ jsx12("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
|
|
3236
|
+
hasFailedWithoutContent && /* @__PURE__ */ jsx12("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
|
|
2991
3237
|
messages.map((message, index) => {
|
|
2992
|
-
return hasRenderableMessageContent(message) ? /* @__PURE__ */
|
|
3238
|
+
return hasRenderableMessageContent(message) ? /* @__PURE__ */ jsx12(
|
|
2993
3239
|
"div",
|
|
2994
3240
|
{
|
|
2995
3241
|
className: "flex flex-col gap-3",
|
|
2996
|
-
children: /* @__PURE__ */
|
|
3242
|
+
children: /* @__PURE__ */ jsx12(
|
|
2997
3243
|
AssistantMessageContent,
|
|
2998
3244
|
{
|
|
2999
3245
|
message,
|
|
@@ -3009,26 +3255,26 @@ function AssistantTurnBlock({
|
|
|
3009
3255
|
}
|
|
3010
3256
|
);
|
|
3011
3257
|
}
|
|
3012
|
-
return /* @__PURE__ */
|
|
3258
|
+
return /* @__PURE__ */ jsxs10(
|
|
3013
3259
|
"div",
|
|
3014
3260
|
{
|
|
3015
3261
|
"aria-busy": isStreaming || void 0,
|
|
3016
3262
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
3017
3263
|
children: [
|
|
3018
|
-
memoryRefs.length > 0 ? /* @__PURE__ */
|
|
3019
|
-
hasInterrupted && /* @__PURE__ */
|
|
3020
|
-
hasFailedWithoutContent && /* @__PURE__ */
|
|
3021
|
-
/* @__PURE__ */
|
|
3022
|
-
/* @__PURE__ */
|
|
3264
|
+
memoryRefs.length > 0 ? /* @__PURE__ */ jsx12(MemoryRefsHint, { refs: memoryRefs }) : null,
|
|
3265
|
+
hasInterrupted && /* @__PURE__ */ jsx12("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
|
|
3266
|
+
hasFailedWithoutContent && /* @__PURE__ */ jsx12("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
|
|
3267
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex w-full items-start gap-2.5", children: [
|
|
3268
|
+
/* @__PURE__ */ jsx12(
|
|
3023
3269
|
"span",
|
|
3024
3270
|
{
|
|
3025
3271
|
className: "grid size-[30px] shrink-0 place-items-center rounded-full bg-[hsl(var(--muted)/0.55)] text-[hsl(var(--foreground))]",
|
|
3026
3272
|
"aria-hidden": "true",
|
|
3027
|
-
children: /* @__PURE__ */
|
|
3273
|
+
children: /* @__PURE__ */ jsx12(Bot, { size: 16 })
|
|
3028
3274
|
}
|
|
3029
3275
|
),
|
|
3030
|
-
/* @__PURE__ */
|
|
3031
|
-
/* @__PURE__ */
|
|
3276
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
3277
|
+
/* @__PURE__ */ jsxs10(
|
|
3032
3278
|
"button",
|
|
3033
3279
|
{
|
|
3034
3280
|
type: "button",
|
|
@@ -3041,19 +3287,20 @@ function AssistantTurnBlock({
|
|
|
3041
3287
|
"data-testid": "assistant-execution-summary",
|
|
3042
3288
|
className: "inline-flex min-w-0 max-w-full select-none items-center gap-1 bg-transparent p-0 text-left text-xs leading-[22px] text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
|
|
3043
3289
|
children: [
|
|
3044
|
-
/* @__PURE__ */
|
|
3290
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 truncate", children: executionSummaryLabel({
|
|
3045
3291
|
messages,
|
|
3046
3292
|
isStreaming,
|
|
3047
3293
|
durationMs: liveExecutionDurationMs,
|
|
3048
3294
|
sessionStatus,
|
|
3049
3295
|
askAnswers
|
|
3050
3296
|
}) }),
|
|
3051
|
-
/* @__PURE__ */
|
|
3297
|
+
/* @__PURE__ */ jsx12(
|
|
3052
3298
|
ChevronRight,
|
|
3053
3299
|
{
|
|
3054
3300
|
size: 14,
|
|
3301
|
+
style: { transitionDuration: "260ms", transitionTimingFunction: "cubic-bezier(0.25, 0.1, 0.25, 1)" },
|
|
3055
3302
|
className: cn(
|
|
3056
|
-
"shrink-0 transition-transform
|
|
3303
|
+
"shrink-0 transition-transform",
|
|
3057
3304
|
effectiveMode === "detail" && "rotate-90"
|
|
3058
3305
|
),
|
|
3059
3306
|
"aria-hidden": "true"
|
|
@@ -3062,26 +3309,26 @@ function AssistantTurnBlock({
|
|
|
3062
3309
|
]
|
|
3063
3310
|
}
|
|
3064
3311
|
),
|
|
3065
|
-
/* @__PURE__ */
|
|
3312
|
+
/* @__PURE__ */ jsx12("div", { className: "mt-3 h-px w-full bg-[hsl(var(--border)/0.75)]" })
|
|
3066
3313
|
] })
|
|
3067
3314
|
] }),
|
|
3068
|
-
effectiveMode === "detail" ? /* @__PURE__ */
|
|
3315
|
+
effectiveMode === "detail" ? /* @__PURE__ */ jsx12("div", { className: "ml-10 flex flex-col gap-3 pt-1", children: messages.map((message, index) => {
|
|
3069
3316
|
const isLast = index === messages.length - 1;
|
|
3070
3317
|
const streamingThis = isStreaming && isLast;
|
|
3071
3318
|
const text = getMessageText(message);
|
|
3072
3319
|
const toolCalls = (message.tool_calls ?? []).filter(
|
|
3073
|
-
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
3320
|
+
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !shouldHideToolCall(message, toolCall)
|
|
3074
3321
|
);
|
|
3075
3322
|
const orderedParts = getOrderedMessageParts(message, toolCalls);
|
|
3076
3323
|
const showReasoning = !!message.reasoning && isStreaming && index === latestReasoningIndex;
|
|
3077
|
-
return /* @__PURE__ */
|
|
3324
|
+
return /* @__PURE__ */ jsxs10(
|
|
3078
3325
|
"div",
|
|
3079
3326
|
{
|
|
3080
3327
|
className: "flex flex-col gap-3",
|
|
3081
3328
|
children: [
|
|
3082
|
-
showReasoning && message.reasoning ? /* @__PURE__ */
|
|
3329
|
+
showReasoning && message.reasoning ? /* @__PURE__ */ jsx12(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
|
|
3083
3330
|
orderedParts.length > 0 ? orderedParts.map(
|
|
3084
|
-
(part) => part.type === "text" ? /* @__PURE__ */
|
|
3331
|
+
(part) => part.type === "text" ? /* @__PURE__ */ jsx12(
|
|
3085
3332
|
AssistantMessageContent,
|
|
3086
3333
|
{
|
|
3087
3334
|
message: { ...message, content: part.content, tool_calls: turnToolCalls },
|
|
@@ -3090,11 +3337,11 @@ function AssistantTurnBlock({
|
|
|
3090
3337
|
compact: true
|
|
3091
3338
|
},
|
|
3092
3339
|
part.key
|
|
3093
|
-
) : /* @__PURE__ */
|
|
3340
|
+
) : /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-0.5", children: part.toolCalls.map((toolCall) => {
|
|
3094
3341
|
const custom = toolCallRenderer?.(toolCall);
|
|
3095
|
-
return custom !== null && custom !== void 0 ? /* @__PURE__ */
|
|
3342
|
+
return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx12("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx12(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx12(ExecutionToolRow, { toolCall }, toolCall.id);
|
|
3096
3343
|
}) }, part.key)
|
|
3097
|
-
) : hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */
|
|
3344
|
+
) : hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx12(
|
|
3098
3345
|
AssistantMessageContent,
|
|
3099
3346
|
{
|
|
3100
3347
|
message,
|
|
@@ -3103,16 +3350,16 @@ function AssistantTurnBlock({
|
|
|
3103
3350
|
compact: true
|
|
3104
3351
|
}
|
|
3105
3352
|
) : null,
|
|
3106
|
-
orderedParts.length === 0 && toolCalls.length > 0 ? /* @__PURE__ */
|
|
3353
|
+
orderedParts.length === 0 && toolCalls.length > 0 ? /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
|
|
3107
3354
|
const custom = toolCallRenderer?.(toolCall);
|
|
3108
|
-
return custom !== null && custom !== void 0 ? /* @__PURE__ */
|
|
3355
|
+
return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx12("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx12(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx12(ExecutionToolRow, { toolCall }, toolCall.id);
|
|
3109
3356
|
}) }) : null
|
|
3110
3357
|
]
|
|
3111
3358
|
},
|
|
3112
3359
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
3113
3360
|
);
|
|
3114
3361
|
}) }) : null,
|
|
3115
|
-
finalMessage && (effectiveMode === "compact" || finalOrderedParts.length === 0) ? /* @__PURE__ */
|
|
3362
|
+
finalMessage && (effectiveMode === "compact" || finalOrderedParts.length === 0) ? /* @__PURE__ */ jsx12("div", { className: "ml-10", children: /* @__PURE__ */ jsx12(
|
|
3116
3363
|
AssistantMessageContent,
|
|
3117
3364
|
{
|
|
3118
3365
|
message: finalMessage,
|
|
@@ -3120,7 +3367,7 @@ function AssistantTurnBlock({
|
|
|
3120
3367
|
streaming: isStreaming && finalMessage === messages[messages.length - 1]
|
|
3121
3368
|
}
|
|
3122
3369
|
) }) : null,
|
|
3123
|
-
questionToolCalls.map((toolCall) => /* @__PURE__ */
|
|
3370
|
+
questionToolCalls.map((toolCall) => /* @__PURE__ */ jsx12(
|
|
3124
3371
|
ToolCallBlock,
|
|
3125
3372
|
{
|
|
3126
3373
|
toolCall,
|
|
@@ -3145,22 +3392,22 @@ function collectMemoryRefs(messages) {
|
|
|
3145
3392
|
return [...refs.values()];
|
|
3146
3393
|
}
|
|
3147
3394
|
function MemoryRefsHint({ refs }) {
|
|
3148
|
-
const [expanded, setExpanded] =
|
|
3395
|
+
const [expanded, setExpanded] = useState11(false);
|
|
3149
3396
|
const label = refs.some((ref) => ref.skill_name) ? "\u53C2\u8003\u4E86\u8BE5\u6280\u80FD\u7684\u5386\u53F2\u7ECF\u9A8C" : "\u53C2\u8003\u4E86\u5386\u53F2\u7ECF\u9A8C";
|
|
3150
|
-
return /* @__PURE__ */
|
|
3151
|
-
/* @__PURE__ */
|
|
3152
|
-
/* @__PURE__ */
|
|
3153
|
-
/* @__PURE__ */
|
|
3397
|
+
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-memory-refs ml-1 w-full max-w-[680px]", children: [
|
|
3398
|
+
/* @__PURE__ */ jsxs10("button", { type: "button", onClick: () => setExpanded((value) => !value), className: "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.22)] bg-[hsl(var(--primary)/0.07)] px-3 text-xs font-medium text-[hsl(var(--primary))]", children: [
|
|
3399
|
+
/* @__PURE__ */ jsx12(BookOpen, { size: 12 }),
|
|
3400
|
+
/* @__PURE__ */ jsxs10("span", { children: [
|
|
3154
3401
|
label,
|
|
3155
3402
|
"\uFF08",
|
|
3156
3403
|
refs.length,
|
|
3157
3404
|
"\uFF09"
|
|
3158
3405
|
] }),
|
|
3159
|
-
/* @__PURE__ */
|
|
3406
|
+
/* @__PURE__ */ jsx12(ChevronRight, { size: 10, className: cn("transition-transform", expanded && "rotate-90") })
|
|
3160
3407
|
] }),
|
|
3161
|
-
expanded ? /* @__PURE__ */
|
|
3162
|
-
/* @__PURE__ */
|
|
3163
|
-
ref.skill_name ? /* @__PURE__ */
|
|
3408
|
+
expanded ? /* @__PURE__ */ jsx12("div", { className: "mt-2 flex flex-col gap-2 rounded-xl border border-[hsl(var(--border)/0.8)] bg-[hsl(var(--muted)/0.28)] p-2.5", children: refs.map((ref) => /* @__PURE__ */ jsxs10("div", { className: "rounded-lg border border-[hsl(var(--border)/0.55)] bg-[hsl(var(--background)/0.72)] px-3 py-2.5 text-xs", children: [
|
|
3409
|
+
/* @__PURE__ */ jsx12("p", { className: "line-clamp-2 break-words leading-5", children: ref.content_preview }),
|
|
3410
|
+
ref.skill_name ? /* @__PURE__ */ jsx12("span", { className: "mt-1 inline-flex text-[10px] text-[hsl(var(--primary))]", children: ref.skill_name }) : null
|
|
3164
3411
|
] }, ref.id)) }) : null
|
|
3165
3412
|
] });
|
|
3166
3413
|
}
|
|
@@ -3174,15 +3421,15 @@ function AssistantMessageContent({
|
|
|
3174
3421
|
const imageParts = getImageParts(message.content);
|
|
3175
3422
|
const fileParts = getFileParts(message.content);
|
|
3176
3423
|
const failed = message.status === "failed";
|
|
3177
|
-
const failedBadge = failed ? /* @__PURE__ */
|
|
3178
|
-
const textContent = text ? /* @__PURE__ */
|
|
3424
|
+
const failedBadge = failed ? /* @__PURE__ */ jsx12("div", { className: "w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }) : null;
|
|
3425
|
+
const textContent = text ? /* @__PURE__ */ jsx12(
|
|
3179
3426
|
"div",
|
|
3180
3427
|
{
|
|
3181
3428
|
className: cn(
|
|
3182
3429
|
"blade-chat-assistant-text",
|
|
3183
3430
|
compact ? "text-xs leading-[22px] text-[hsl(var(--foreground))]" : "text-[15px] leading-8 text-[hsl(var(--foreground))]"
|
|
3184
3431
|
),
|
|
3185
|
-
children: /* @__PURE__ */
|
|
3432
|
+
children: /* @__PURE__ */ jsx12(
|
|
3186
3433
|
MarkdownContent,
|
|
3187
3434
|
{
|
|
3188
3435
|
mode: streaming ? "streaming" : "static",
|
|
@@ -3195,14 +3442,14 @@ function AssistantMessageContent({
|
|
|
3195
3442
|
) : null;
|
|
3196
3443
|
if (imageParts.length === 0 && fileParts.length === 0) {
|
|
3197
3444
|
if (!failed) return textContent;
|
|
3198
|
-
return failedBadge || textContent ? /* @__PURE__ */
|
|
3445
|
+
return failedBadge || textContent ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
|
|
3199
3446
|
failedBadge,
|
|
3200
3447
|
textContent
|
|
3201
3448
|
] }) : null;
|
|
3202
3449
|
}
|
|
3203
|
-
return /* @__PURE__ */
|
|
3450
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3", children: [
|
|
3204
3451
|
failedBadge,
|
|
3205
|
-
imageParts.length > 0 ? /* @__PURE__ */
|
|
3452
|
+
imageParts.length > 0 ? /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
|
|
3206
3453
|
"img",
|
|
3207
3454
|
{
|
|
3208
3455
|
src: part.image_url.url,
|
|
@@ -3211,14 +3458,14 @@ function AssistantMessageContent({
|
|
|
3211
3458
|
},
|
|
3212
3459
|
part.image_url.url
|
|
3213
3460
|
)) }) : null,
|
|
3214
|
-
fileParts.length > 0 ? /* @__PURE__ */
|
|
3461
|
+
fileParts.length > 0 ? /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
|
|
3215
3462
|
"div",
|
|
3216
3463
|
{
|
|
3217
3464
|
className: "flex min-w-0 items-center gap-1.5 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]",
|
|
3218
3465
|
title: part.name,
|
|
3219
3466
|
children: [
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
/* @__PURE__ */
|
|
3467
|
+
/* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
|
|
3468
|
+
/* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", children: part.name })
|
|
3222
3469
|
]
|
|
3223
3470
|
},
|
|
3224
3471
|
`${part.name}-${part.data.slice(0, 32)}`
|
|
@@ -3229,7 +3476,7 @@ function AssistantMessageContent({
|
|
|
3229
3476
|
|
|
3230
3477
|
// src/components/RenderErrorBoundary.tsx
|
|
3231
3478
|
import { Component } from "react";
|
|
3232
|
-
import { jsx as
|
|
3479
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3233
3480
|
function getFirstComponentName(componentStack) {
|
|
3234
3481
|
const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
|
|
3235
3482
|
return match?.[1] ?? null;
|
|
@@ -3262,26 +3509,26 @@ var RenderErrorBoundary = class extends Component {
|
|
|
3262
3509
|
return children;
|
|
3263
3510
|
}
|
|
3264
3511
|
const componentName = getFirstComponentName(componentStack);
|
|
3265
|
-
return /* @__PURE__ */
|
|
3266
|
-
/* @__PURE__ */
|
|
3267
|
-
/* @__PURE__ */
|
|
3268
|
-
/* @__PURE__ */
|
|
3512
|
+
return /* @__PURE__ */ jsx13("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs11("div", { className: "flex items-start gap-2", children: [
|
|
3513
|
+
/* @__PURE__ */ jsx13(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
|
|
3514
|
+
/* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
|
|
3515
|
+
/* @__PURE__ */ jsxs11("div", { className: "font-medium", children: [
|
|
3269
3516
|
label,
|
|
3270
3517
|
"\u6E32\u67D3\u5931\u8D25"
|
|
3271
3518
|
] }),
|
|
3272
|
-
/* @__PURE__ */
|
|
3519
|
+
/* @__PURE__ */ jsxs11("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
|
|
3273
3520
|
componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
|
|
3274
3521
|
error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
|
|
3275
3522
|
] }),
|
|
3276
|
-
details ? /* @__PURE__ */
|
|
3523
|
+
details ? /* @__PURE__ */ jsx13("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
|
|
3277
3524
|
] })
|
|
3278
3525
|
] }) });
|
|
3279
3526
|
}
|
|
3280
3527
|
};
|
|
3281
3528
|
|
|
3282
3529
|
// src/components/PostChatFollowupBlock.tsx
|
|
3283
|
-
import { useCallback as useCallback6, useEffect as
|
|
3284
|
-
import { Fragment as Fragment2, jsx as
|
|
3530
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef11, useState as useState12 } from "react";
|
|
3531
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3285
3532
|
function emitInteraction(callback, event) {
|
|
3286
3533
|
try {
|
|
3287
3534
|
callback?.(event);
|
|
@@ -3300,10 +3547,10 @@ function ArtifactCard({
|
|
|
3300
3547
|
onArtifactOpened
|
|
3301
3548
|
}) {
|
|
3302
3549
|
const client = useBladeClient();
|
|
3303
|
-
const [downloading, setDownloading] =
|
|
3550
|
+
const [downloading, setDownloading] = useState12(false);
|
|
3304
3551
|
const name = artifact.label || basename(artifact.target);
|
|
3305
3552
|
if (artifact.kind === "link") {
|
|
3306
|
-
return /* @__PURE__ */
|
|
3553
|
+
return /* @__PURE__ */ jsxs12(
|
|
3307
3554
|
"a",
|
|
3308
3555
|
{
|
|
3309
3556
|
href: artifact.target,
|
|
@@ -3314,9 +3561,9 @@ function ArtifactCard({
|
|
|
3314
3561
|
${artifact.target}`,
|
|
3315
3562
|
className: "group relative flex min-w-0 items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2 py-1.5 text-xs text-[hsl(var(--card-foreground))] hover:bg-[hsl(var(--accent))]",
|
|
3316
3563
|
children: [
|
|
3317
|
-
/* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
/* @__PURE__ */
|
|
3564
|
+
/* @__PURE__ */ jsx14(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
|
|
3565
|
+
/* @__PURE__ */ jsx14("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
|
|
3566
|
+
/* @__PURE__ */ jsx14(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
|
|
3320
3567
|
]
|
|
3321
3568
|
}
|
|
3322
3569
|
);
|
|
@@ -3351,7 +3598,7 @@ ${artifact.target}`,
|
|
|
3351
3598
|
setDownloading(false);
|
|
3352
3599
|
}
|
|
3353
3600
|
};
|
|
3354
|
-
return /* @__PURE__ */
|
|
3601
|
+
return /* @__PURE__ */ jsx14(
|
|
3355
3602
|
"a",
|
|
3356
3603
|
{
|
|
3357
3604
|
href: downloadUrl,
|
|
@@ -3379,17 +3626,17 @@ function feedbackReasonLabel(reason) {
|
|
|
3379
3626
|
}
|
|
3380
3627
|
function HistoricalResultFeedback({ feedback }) {
|
|
3381
3628
|
const label = feedbackReasonLabel(feedback.reason);
|
|
3382
|
-
return /* @__PURE__ */
|
|
3629
|
+
return /* @__PURE__ */ jsxs12(
|
|
3383
3630
|
"section",
|
|
3384
3631
|
{
|
|
3385
3632
|
"aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
|
|
3386
3633
|
className: "mt-3 w-fit max-w-full rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
3387
3634
|
children: [
|
|
3388
|
-
/* @__PURE__ */
|
|
3635
|
+
/* @__PURE__ */ jsxs12("span", { children: [
|
|
3389
3636
|
"\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
|
|
3390
3637
|
feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
|
|
3391
3638
|
] }),
|
|
3392
|
-
label ? /* @__PURE__ */
|
|
3639
|
+
label ? /* @__PURE__ */ jsxs12("span", { children: [
|
|
3393
3640
|
" \xB7 ",
|
|
3394
3641
|
label
|
|
3395
3642
|
] }) : null
|
|
@@ -3406,15 +3653,15 @@ function ResultFeedback({
|
|
|
3406
3653
|
onFeedbackSaved
|
|
3407
3654
|
}) {
|
|
3408
3655
|
const client = useBladeClient();
|
|
3409
|
-
const [saved, setSaved] =
|
|
3410
|
-
const [helpful, setHelpful] =
|
|
3411
|
-
const [reason, setReason] =
|
|
3412
|
-
const [saving, setSaving] =
|
|
3413
|
-
const [saveError, setSaveError] =
|
|
3414
|
-
const reportedShown =
|
|
3415
|
-
const latestChoice =
|
|
3656
|
+
const [saved, setSaved] = useState12(savedFeedback ?? null);
|
|
3657
|
+
const [helpful, setHelpful] = useState12(savedFeedback?.helpful ?? null);
|
|
3658
|
+
const [reason, setReason] = useState12(savedFeedback?.reason ?? null);
|
|
3659
|
+
const [saving, setSaving] = useState12(false);
|
|
3660
|
+
const [saveError, setSaveError] = useState12(false);
|
|
3661
|
+
const reportedShown = useRef11(false);
|
|
3662
|
+
const latestChoice = useRef11(null);
|
|
3416
3663
|
const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
|
|
3417
|
-
|
|
3664
|
+
useEffect10(() => {
|
|
3418
3665
|
if (!eligible || reportedShown.current) return;
|
|
3419
3666
|
reportedShown.current = true;
|
|
3420
3667
|
emitInteraction(onInteraction, {
|
|
@@ -3423,7 +3670,7 @@ function ResultFeedback({
|
|
|
3423
3670
|
assistantEntryId: followup.assistant_entry_id
|
|
3424
3671
|
});
|
|
3425
3672
|
}, [eligible, followup.assistant_entry_id, onInteraction, sessionId]);
|
|
3426
|
-
|
|
3673
|
+
useEffect10(() => {
|
|
3427
3674
|
if (!savedFeedback || latestChoice.current) return;
|
|
3428
3675
|
setSaved(savedFeedback);
|
|
3429
3676
|
setHelpful(savedFeedback.helpful);
|
|
@@ -3464,15 +3711,15 @@ function ResultFeedback({
|
|
|
3464
3711
|
[client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
|
|
3465
3712
|
);
|
|
3466
3713
|
if (!eligible) return null;
|
|
3467
|
-
return /* @__PURE__ */
|
|
3714
|
+
return /* @__PURE__ */ jsxs12(
|
|
3468
3715
|
"section",
|
|
3469
3716
|
{
|
|
3470
3717
|
"aria-label": "\u7ED3\u679C\u53CD\u9988",
|
|
3471
3718
|
className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
|
|
3472
3719
|
children: [
|
|
3473
|
-
/* @__PURE__ */
|
|
3474
|
-
/* @__PURE__ */
|
|
3475
|
-
/* @__PURE__ */
|
|
3720
|
+
/* @__PURE__ */ jsx14("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u76EE\u524D\u7684\u6574\u4F53\u7ED3\u679C\u6709\u5E2E\u52A9\u5417\uFF1F" }),
|
|
3721
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
3722
|
+
/* @__PURE__ */ jsx14(
|
|
3476
3723
|
"button",
|
|
3477
3724
|
{
|
|
3478
3725
|
type: "button",
|
|
@@ -3483,7 +3730,7 @@ function ResultFeedback({
|
|
|
3483
3730
|
children: "\u6709\u5E2E\u52A9"
|
|
3484
3731
|
}
|
|
3485
3732
|
),
|
|
3486
|
-
/* @__PURE__ */
|
|
3733
|
+
/* @__PURE__ */ jsx14(
|
|
3487
3734
|
"button",
|
|
3488
3735
|
{
|
|
3489
3736
|
type: "button",
|
|
@@ -3495,7 +3742,7 @@ function ResultFeedback({
|
|
|
3495
3742
|
}
|
|
3496
3743
|
)
|
|
3497
3744
|
] }),
|
|
3498
|
-
helpful === false ? /* @__PURE__ */
|
|
3745
|
+
helpful === false ? /* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1.5", "aria-label": "\u6CA1\u5E2E\u52A9\u7684\u4E3B\u8981\u539F\u56E0", children: FEEDBACK_REASONS.map((item) => /* @__PURE__ */ jsx14(
|
|
3499
3746
|
"button",
|
|
3500
3747
|
{
|
|
3501
3748
|
type: "button",
|
|
@@ -3507,9 +3754,9 @@ function ResultFeedback({
|
|
|
3507
3754
|
},
|
|
3508
3755
|
item.value
|
|
3509
3756
|
)) }) : null,
|
|
3510
|
-
saveError ? /* @__PURE__ */
|
|
3511
|
-
/* @__PURE__ */
|
|
3512
|
-
/* @__PURE__ */
|
|
3757
|
+
saveError ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
|
|
3758
|
+
/* @__PURE__ */ jsx14("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
|
|
3759
|
+
/* @__PURE__ */ jsx14(
|
|
3513
3760
|
"button",
|
|
3514
3761
|
{
|
|
3515
3762
|
type: "button",
|
|
@@ -3521,7 +3768,7 @@ function ResultFeedback({
|
|
|
3521
3768
|
children: "\u91CD\u8BD5"
|
|
3522
3769
|
}
|
|
3523
3770
|
)
|
|
3524
|
-
] }) : saved ? /* @__PURE__ */
|
|
3771
|
+
] }) : saved ? /* @__PURE__ */ jsx14("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
|
|
3525
3772
|
]
|
|
3526
3773
|
}
|
|
3527
3774
|
);
|
|
@@ -3535,14 +3782,14 @@ function PostChatFollowupBlock({
|
|
|
3535
3782
|
savedFeedback,
|
|
3536
3783
|
onFeedbackSaved
|
|
3537
3784
|
}) {
|
|
3538
|
-
const [expanded, setExpanded] =
|
|
3539
|
-
const adopted =
|
|
3540
|
-
const reportedSuggestions =
|
|
3541
|
-
const reportedArtifacts =
|
|
3542
|
-
const openedArtifacts =
|
|
3785
|
+
const [expanded, setExpanded] = useState12(false);
|
|
3786
|
+
const adopted = useRef11(/* @__PURE__ */ new Set());
|
|
3787
|
+
const reportedSuggestions = useRef11(false);
|
|
3788
|
+
const reportedArtifacts = useRef11(/* @__PURE__ */ new Set());
|
|
3789
|
+
const openedArtifacts = useRef11(/* @__PURE__ */ new Set());
|
|
3543
3790
|
const artifacts = followup.final_artifacts ?? [];
|
|
3544
3791
|
const visibleArtifacts = expanded ? artifacts : artifacts.slice(0, 3);
|
|
3545
|
-
|
|
3792
|
+
useEffect10(() => {
|
|
3546
3793
|
if (!reportedSuggestions.current && followup.suggestions.length > 0) {
|
|
3547
3794
|
reportedSuggestions.current = true;
|
|
3548
3795
|
emitInteraction(onInteraction, {
|
|
@@ -3588,15 +3835,15 @@ function PostChatFollowupBlock({
|
|
|
3588
3835
|
);
|
|
3589
3836
|
if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
|
|
3590
3837
|
return null;
|
|
3591
|
-
return /* @__PURE__ */
|
|
3592
|
-
followup.recaption || artifacts.length > 0 ? /* @__PURE__ */
|
|
3593
|
-
/* @__PURE__ */
|
|
3594
|
-
/* @__PURE__ */
|
|
3838
|
+
return /* @__PURE__ */ jsxs12("div", { className: "mt-3 flex w-fit max-w-full flex-col gap-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.28)] p-3 sm:max-w-[680px]", children: [
|
|
3839
|
+
followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
|
|
3840
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
|
|
3841
|
+
/* @__PURE__ */ jsx14(Sparkles, { size: 14 }),
|
|
3595
3842
|
"\u672C\u8F6E\u5C0F\u7ED3"
|
|
3596
3843
|
] }),
|
|
3597
|
-
followup.recaption ? /* @__PURE__ */
|
|
3598
|
-
artifacts.length > 0 ? /* @__PURE__ */
|
|
3599
|
-
/* @__PURE__ */
|
|
3844
|
+
followup.recaption ? /* @__PURE__ */ jsx14("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
|
|
3845
|
+
artifacts.length > 0 ? /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
3846
|
+
/* @__PURE__ */ jsx14("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx14(
|
|
3600
3847
|
ArtifactCard,
|
|
3601
3848
|
{
|
|
3602
3849
|
artifact,
|
|
@@ -3608,7 +3855,7 @@ function PostChatFollowupBlock({
|
|
|
3608
3855
|
},
|
|
3609
3856
|
`${artifact.kind}:${artifactIndex}`
|
|
3610
3857
|
)) }),
|
|
3611
|
-
artifacts.length > 3 ? /* @__PURE__ */
|
|
3858
|
+
artifacts.length > 3 ? /* @__PURE__ */ jsxs12(
|
|
3612
3859
|
"button",
|
|
3613
3860
|
{
|
|
3614
3861
|
type: "button",
|
|
@@ -3617,15 +3864,15 @@ function PostChatFollowupBlock({
|
|
|
3617
3864
|
className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
|
|
3618
3865
|
children: [
|
|
3619
3866
|
expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
|
|
3620
|
-
/* @__PURE__ */
|
|
3867
|
+
/* @__PURE__ */ jsx14(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
|
|
3621
3868
|
]
|
|
3622
3869
|
}
|
|
3623
3870
|
) : null
|
|
3624
3871
|
] }) : null
|
|
3625
3872
|
] }) : null,
|
|
3626
|
-
followup.suggestions.length > 0 ? /* @__PURE__ */
|
|
3627
|
-
/* @__PURE__ */
|
|
3628
|
-
followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */
|
|
3873
|
+
followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
|
|
3874
|
+
/* @__PURE__ */ jsx14("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
|
|
3875
|
+
followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs12(
|
|
3629
3876
|
"button",
|
|
3630
3877
|
{
|
|
3631
3878
|
type: "button",
|
|
@@ -3644,14 +3891,14 @@ function PostChatFollowupBlock({
|
|
|
3644
3891
|
},
|
|
3645
3892
|
className: "group flex items-center gap-2 rounded-xl bg-[hsl(var(--muted)/0.62)] px-3 py-2 text-left text-[13px] disabled:cursor-default disabled:opacity-60",
|
|
3646
3893
|
children: [
|
|
3647
|
-
/* @__PURE__ */
|
|
3648
|
-
/* @__PURE__ */
|
|
3894
|
+
/* @__PURE__ */ jsx14("span", { children: suggestion }),
|
|
3895
|
+
/* @__PURE__ */ jsx14(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
|
|
3649
3896
|
]
|
|
3650
3897
|
},
|
|
3651
3898
|
suggestion
|
|
3652
3899
|
))
|
|
3653
3900
|
] }) : null,
|
|
3654
|
-
/* @__PURE__ */
|
|
3901
|
+
/* @__PURE__ */ jsx14(
|
|
3655
3902
|
ResultFeedback,
|
|
3656
3903
|
{
|
|
3657
3904
|
followup,
|
|
@@ -3726,31 +3973,31 @@ function parseWhatIfPrompt(text) {
|
|
|
3726
3973
|
}
|
|
3727
3974
|
|
|
3728
3975
|
// src/components/WhatIfUserBubble.tsx
|
|
3729
|
-
import { jsx as
|
|
3976
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3730
3977
|
function WhatIfUserBubble({ parsed, onQuoteClick }) {
|
|
3731
3978
|
const { fromStep, quotes, userText } = parsed;
|
|
3732
|
-
return /* @__PURE__ */
|
|
3733
|
-
/* @__PURE__ */
|
|
3734
|
-
/* @__PURE__ */
|
|
3735
|
-
/* @__PURE__ */
|
|
3979
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-end gap-2", children: [
|
|
3980
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.5)] px-2.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children: [
|
|
3981
|
+
/* @__PURE__ */ jsx15(RefreshCcw, { size: 10 }),
|
|
3982
|
+
/* @__PURE__ */ jsx15("span", { children: fromStep != null ? `\u91CD\u8DD1\u81EA step ${fromStep}` : "\u91CD\u8DD1" })
|
|
3736
3983
|
] }),
|
|
3737
|
-
quotes.length > 0 && /* @__PURE__ */
|
|
3984
|
+
quotes.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex max-w-[min(72vw,42rem)] flex-col items-stretch gap-2", children: quotes.map((quote, index) => {
|
|
3738
3985
|
const clickable = quote.stepNumber != null && !!onQuoteClick;
|
|
3739
3986
|
const label = quote.stepNumber != null ? `\u6B65\u9AA4${quote.stepNumber} \xB7 ${quote.label}` : quote.label;
|
|
3740
|
-
return /* @__PURE__ */
|
|
3741
|
-
/* @__PURE__ */
|
|
3742
|
-
/* @__PURE__ */
|
|
3743
|
-
/* @__PURE__ */
|
|
3987
|
+
return /* @__PURE__ */ jsxs13("div", { className: "rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.8)] px-3 py-2 text-left", children: [
|
|
3988
|
+
/* @__PURE__ */ jsxs13("button", { type: "button", disabled: !clickable, onClick: () => clickable && onQuoteClick(quote.stepNumber), className: "inline-flex max-w-full items-center gap-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] disabled:cursor-default", title: clickable ? "\u8DF3\u8F6C\u5230\u5BF9\u5E94\u6B65\u9AA4\u5361\u7247" : void 0, children: [
|
|
3989
|
+
/* @__PURE__ */ jsx15("span", { children: "\u21B3" }),
|
|
3990
|
+
/* @__PURE__ */ jsx15("span", { className: "truncate", children: label })
|
|
3744
3991
|
] }),
|
|
3745
|
-
quote.snapshot ? /* @__PURE__ */
|
|
3992
|
+
quote.snapshot ? /* @__PURE__ */ jsx15("div", { className: "mt-1 border-l-2 border-[hsl(var(--accent-foreground)/0.35)] pl-2 text-xs leading-relaxed text-[hsl(var(--foreground)/0.8)]", children: /* @__PURE__ */ jsx15(MarkdownContent, { className: "blade-chat-prose", children: quote.snapshot }) }) : null
|
|
3746
3993
|
] }, `${quote.stepNumber ?? "x"}-${index}`);
|
|
3747
3994
|
}) }),
|
|
3748
|
-
userText && /* @__PURE__ */
|
|
3995
|
+
userText && /* @__PURE__ */ jsx15("div", { className: "rounded-2xl border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-sm leading-relaxed text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx15(MarkdownContent, { className: "blade-chat-prose", children: userText }) })
|
|
3749
3996
|
] });
|
|
3750
3997
|
}
|
|
3751
3998
|
|
|
3752
3999
|
// src/components/UserMessageBubble.tsx
|
|
3753
|
-
import { jsx as
|
|
4000
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3754
4001
|
function isUserMessage(message) {
|
|
3755
4002
|
return message.role === "user";
|
|
3756
4003
|
}
|
|
@@ -3764,10 +4011,10 @@ function UserMessageBubble({ message, className }) {
|
|
|
3764
4011
|
const imageParts = getImageParts2(message.content);
|
|
3765
4012
|
const whatifParsed = text && imageParts.length === 0 && fileParts.length === 0 ? parseWhatIfPrompt(text) : null;
|
|
3766
4013
|
if (whatifParsed) {
|
|
3767
|
-
return /* @__PURE__ */
|
|
4014
|
+
return /* @__PURE__ */ jsx16("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsx16("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: /* @__PURE__ */ jsx16(WhatIfUserBubble, { parsed: whatifParsed }) }) });
|
|
3768
4015
|
}
|
|
3769
|
-
return /* @__PURE__ */
|
|
3770
|
-
imageParts.length > 0 && /* @__PURE__ */
|
|
4016
|
+
return /* @__PURE__ */ jsx16("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs14("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
|
|
4017
|
+
imageParts.length > 0 && /* @__PURE__ */ jsx16("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx16(
|
|
3771
4018
|
"img",
|
|
3772
4019
|
{
|
|
3773
4020
|
src: part.image_url.url,
|
|
@@ -3776,21 +4023,21 @@ function UserMessageBubble({ message, className }) {
|
|
|
3776
4023
|
},
|
|
3777
4024
|
part.image_url.url
|
|
3778
4025
|
)) }),
|
|
3779
|
-
fileParts.length > 0 && /* @__PURE__ */
|
|
4026
|
+
fileParts.length > 0 && /* @__PURE__ */ jsx16("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs14(
|
|
3780
4027
|
"div",
|
|
3781
4028
|
{
|
|
3782
4029
|
className: "flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]",
|
|
3783
4030
|
children: [
|
|
3784
|
-
/* @__PURE__ */
|
|
3785
|
-
/* @__PURE__ */
|
|
4031
|
+
/* @__PURE__ */ jsx16(FileText, { size: 12, className: "shrink-0" }),
|
|
4032
|
+
/* @__PURE__ */ jsx16("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
|
|
3786
4033
|
]
|
|
3787
4034
|
},
|
|
3788
4035
|
`${part.name}-${part.data.length}`
|
|
3789
4036
|
)) }),
|
|
3790
|
-
text && /* @__PURE__ */
|
|
3791
|
-
text && isSending(message) && /* @__PURE__ */
|
|
3792
|
-
/* @__PURE__ */
|
|
3793
|
-
/* @__PURE__ */
|
|
4037
|
+
text && /* @__PURE__ */ jsx16("div", { className: "blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx16(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
|
|
4038
|
+
text && isSending(message) && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
|
|
4039
|
+
/* @__PURE__ */ jsx16(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
|
|
4040
|
+
/* @__PURE__ */ jsx16("span", { children: "\u53D1\u9001\u4E2D" })
|
|
3794
4041
|
] })
|
|
3795
4042
|
] }) });
|
|
3796
4043
|
}
|
|
@@ -3799,11 +4046,11 @@ function ErrorMessageBlock({
|
|
|
3799
4046
|
className
|
|
3800
4047
|
}) {
|
|
3801
4048
|
const text = chatErrorForDisplay(getTextContent2(message.content));
|
|
3802
|
-
return /* @__PURE__ */
|
|
4049
|
+
return /* @__PURE__ */ jsx16("div", { className: cn("blade-chat-error-row flex min-w-0 justify-start", className), children: /* @__PURE__ */ jsx16("div", { className: "blade-chat-error-block min-w-0 max-w-full whitespace-pre-wrap break-words border-l-[3px] border-[hsl(var(--border))] px-3 py-1 text-left text-sm leading-7 text-[hsl(var(--muted-foreground))] [overflow-wrap:anywhere]", children: text }) });
|
|
3803
4050
|
}
|
|
3804
4051
|
|
|
3805
4052
|
// src/components/MessageList.tsx
|
|
3806
|
-
import { jsx as
|
|
4053
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3807
4054
|
function parseModeChange(message) {
|
|
3808
4055
|
if (message.kind !== "mode_change" || typeof message.content !== "string") {
|
|
3809
4056
|
return null;
|
|
@@ -3844,6 +4091,7 @@ function MessageList({
|
|
|
3844
4091
|
askAnswers,
|
|
3845
4092
|
onAnswer,
|
|
3846
4093
|
toolCallRenderer,
|
|
4094
|
+
hidePlanUpdateTools = false,
|
|
3847
4095
|
emptyState,
|
|
3848
4096
|
className,
|
|
3849
4097
|
sessionId,
|
|
@@ -3929,23 +4177,23 @@ function MessageList({
|
|
|
3929
4177
|
}
|
|
3930
4178
|
return blocks;
|
|
3931
4179
|
}, [messages, isStreaming]);
|
|
3932
|
-
return /* @__PURE__ */
|
|
3933
|
-
isStreaming ? /* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */
|
|
4180
|
+
return /* @__PURE__ */ jsxs15("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: [
|
|
4181
|
+
isStreaming ? /* @__PURE__ */ jsx17("output", { className: "sr-only", children: "\u6B63\u5728\u751F\u6210\u56DE\u590D" }) : null,
|
|
4182
|
+
/* @__PURE__ */ jsxs15(
|
|
3935
4183
|
StickToBottom,
|
|
3936
4184
|
{
|
|
3937
4185
|
className: "h-full overflow-y-hidden",
|
|
3938
4186
|
initial: "instant",
|
|
3939
4187
|
resize: "instant",
|
|
3940
4188
|
children: [
|
|
3941
|
-
/* @__PURE__ */
|
|
3942
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
3943
|
-
/* @__PURE__ */
|
|
3944
|
-
/* @__PURE__ */
|
|
3945
|
-
/* @__PURE__ */
|
|
4189
|
+
/* @__PURE__ */ jsx17(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx17("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 flex-col", children: [
|
|
4190
|
+
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs15("div", { className: "blade-chat-empty", children: [
|
|
4191
|
+
/* @__PURE__ */ jsx17(MessageSquare, { size: 40, strokeWidth: 1.5 }),
|
|
4192
|
+
/* @__PURE__ */ jsx17("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
|
|
4193
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
|
|
3946
4194
|
] }) : renderBlocks.map((block) => {
|
|
3947
4195
|
if (block.type === "message") {
|
|
3948
|
-
return /* @__PURE__ */
|
|
4196
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx17(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx17(ErrorMessageBlock, { message: block.message }) : null }, block.key);
|
|
3949
4197
|
}
|
|
3950
4198
|
if (block.type === "assistant_turn") {
|
|
3951
4199
|
const blockFeedback = block.messages.map(
|
|
@@ -3956,14 +4204,14 @@ function MessageList({
|
|
|
3956
4204
|
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
3957
4205
|
)
|
|
3958
4206
|
);
|
|
3959
|
-
return /* @__PURE__ */
|
|
4207
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs15(
|
|
3960
4208
|
RenderErrorBoundary,
|
|
3961
4209
|
{
|
|
3962
4210
|
label: "\u52A9\u624B\u6D88\u606F",
|
|
3963
4211
|
details: block.key,
|
|
3964
4212
|
resetKey: getMessageResetSignature(block.messages),
|
|
3965
4213
|
children: [
|
|
3966
|
-
/* @__PURE__ */
|
|
4214
|
+
/* @__PURE__ */ jsx17(
|
|
3967
4215
|
AssistantTurnBlock,
|
|
3968
4216
|
{
|
|
3969
4217
|
messages: block.messages,
|
|
@@ -3972,11 +4220,12 @@ function MessageList({
|
|
|
3972
4220
|
onAnswer,
|
|
3973
4221
|
sessionStatus,
|
|
3974
4222
|
toolCallRenderer,
|
|
4223
|
+
hidePlanUpdateTools,
|
|
3975
4224
|
sessionId
|
|
3976
4225
|
}
|
|
3977
4226
|
),
|
|
3978
|
-
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */
|
|
3979
|
-
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */
|
|
4227
|
+
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx17(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
4228
|
+
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx17(
|
|
3980
4229
|
PostChatFollowupBlock,
|
|
3981
4230
|
{
|
|
3982
4231
|
followup: postChatFollowup,
|
|
@@ -3993,23 +4242,23 @@ function MessageList({
|
|
|
3993
4242
|
) }, block.key);
|
|
3994
4243
|
}
|
|
3995
4244
|
if (block.type === "compaction") {
|
|
3996
|
-
return /* @__PURE__ */
|
|
4245
|
+
return /* @__PURE__ */ jsxs15(
|
|
3997
4246
|
"div",
|
|
3998
4247
|
{
|
|
3999
4248
|
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
4000
4249
|
children: [
|
|
4001
|
-
/* @__PURE__ */
|
|
4002
|
-
/* @__PURE__ */
|
|
4250
|
+
/* @__PURE__ */ jsx17(Layers, { size: 12 }),
|
|
4251
|
+
/* @__PURE__ */ jsx17("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
4003
4252
|
]
|
|
4004
4253
|
},
|
|
4005
4254
|
block.key
|
|
4006
4255
|
);
|
|
4007
4256
|
}
|
|
4008
|
-
return /* @__PURE__ */
|
|
4257
|
+
return /* @__PURE__ */ jsx17(PlanningDivider, { kind: block.kind }, block.key);
|
|
4009
4258
|
}),
|
|
4010
|
-
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */
|
|
4259
|
+
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx17("div", { className: "flex", children: /* @__PURE__ */ jsx17("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
|
|
4011
4260
|
] }) }) }),
|
|
4012
|
-
/* @__PURE__ */
|
|
4261
|
+
/* @__PURE__ */ jsx17(
|
|
4013
4262
|
PinLatestUserMessage,
|
|
4014
4263
|
{
|
|
4015
4264
|
userMessageCount: userMessages.length,
|
|
@@ -4018,7 +4267,7 @@ function MessageList({
|
|
|
4018
4267
|
},
|
|
4019
4268
|
sessionId ?? "no-session"
|
|
4020
4269
|
),
|
|
4021
|
-
/* @__PURE__ */
|
|
4270
|
+
/* @__PURE__ */ jsx17(ScrollToBottomButton, {})
|
|
4022
4271
|
]
|
|
4023
4272
|
},
|
|
4024
4273
|
sessionId ?? "no-session"
|
|
@@ -4031,8 +4280,8 @@ function PinLatestUserMessage({
|
|
|
4031
4280
|
targetKey
|
|
4032
4281
|
}) {
|
|
4033
4282
|
const { contentRef, scrollRef, scrollToBottom, stopScroll } = useStickToBottomContext();
|
|
4034
|
-
const previousCountRef =
|
|
4035
|
-
const spacerHeightRef =
|
|
4283
|
+
const previousCountRef = useRef12(userMessageCount);
|
|
4284
|
+
const spacerHeightRef = useRef12(0);
|
|
4036
4285
|
const getScrollElement = useCallback7(() => scrollRef.current, [scrollRef]);
|
|
4037
4286
|
const getContentElement = useCallback7(() => contentRef.current, [contentRef]);
|
|
4038
4287
|
const getTargetElement = useCallback7(() => {
|
|
@@ -4061,7 +4310,7 @@ function PinLatestUserMessage({
|
|
|
4061
4310
|
stopAutoScroll: stopScroll,
|
|
4062
4311
|
scrollToBottom
|
|
4063
4312
|
});
|
|
4064
|
-
|
|
4313
|
+
useEffect11(() => {
|
|
4065
4314
|
if (userMessageCount > previousCountRef.current && !shouldPinLatestUser) {
|
|
4066
4315
|
scrollToBottom("instant");
|
|
4067
4316
|
}
|
|
@@ -4071,9 +4320,9 @@ function PinLatestUserMessage({
|
|
|
4071
4320
|
}
|
|
4072
4321
|
function ScrollToBottomButton() {
|
|
4073
4322
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
4074
|
-
const [visible, setVisible] =
|
|
4075
|
-
const hideTimerRef =
|
|
4076
|
-
|
|
4323
|
+
const [visible, setVisible] = useState13(false);
|
|
4324
|
+
const hideTimerRef = useRef12(null);
|
|
4325
|
+
useEffect11(() => {
|
|
4077
4326
|
if (isAtBottom) {
|
|
4078
4327
|
if (!hideTimerRef.current) {
|
|
4079
4328
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -4104,7 +4353,7 @@ function ScrollToBottomButton() {
|
|
|
4104
4353
|
scrollToBottom();
|
|
4105
4354
|
}, [scrollToBottom]);
|
|
4106
4355
|
if (!visible) return null;
|
|
4107
|
-
return /* @__PURE__ */
|
|
4356
|
+
return /* @__PURE__ */ jsxs15(
|
|
4108
4357
|
"button",
|
|
4109
4358
|
{
|
|
4110
4359
|
type: "button",
|
|
@@ -4112,25 +4361,25 @@ function ScrollToBottomButton() {
|
|
|
4112
4361
|
"aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
|
|
4113
4362
|
className: "blade-chat-scroll-bottom absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
|
|
4114
4363
|
children: [
|
|
4115
|
-
/* @__PURE__ */
|
|
4116
|
-
/* @__PURE__ */
|
|
4364
|
+
/* @__PURE__ */ jsx17(ChevronDown, { size: 14 }),
|
|
4365
|
+
/* @__PURE__ */ jsx17("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
|
|
4117
4366
|
]
|
|
4118
4367
|
}
|
|
4119
4368
|
);
|
|
4120
4369
|
}
|
|
4121
4370
|
function PlanningDivider({ kind }) {
|
|
4122
|
-
return /* @__PURE__ */
|
|
4123
|
-
/* @__PURE__ */
|
|
4124
|
-
/* @__PURE__ */
|
|
4125
|
-
/* @__PURE__ */
|
|
4126
|
-
/* @__PURE__ */
|
|
4371
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-3 py-1", children: [
|
|
4372
|
+
/* @__PURE__ */ jsx17("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
|
|
4373
|
+
/* @__PURE__ */ jsxs15("div", { className: "inline-flex items-center gap-1.5 rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] text-amber-300", children: [
|
|
4374
|
+
/* @__PURE__ */ jsx17(Lightbulb, { size: 12 }),
|
|
4375
|
+
/* @__PURE__ */ jsx17("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
|
|
4127
4376
|
] }),
|
|
4128
|
-
/* @__PURE__ */
|
|
4377
|
+
/* @__PURE__ */ jsx17("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
|
|
4129
4378
|
] });
|
|
4130
4379
|
}
|
|
4131
4380
|
|
|
4132
4381
|
// src/components/ChatSurface.tsx
|
|
4133
|
-
import { jsx as
|
|
4382
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4134
4383
|
function themeAttr(theme) {
|
|
4135
4384
|
return theme === "dark" ? "dark" : void 0;
|
|
4136
4385
|
}
|
|
@@ -4160,9 +4409,11 @@ function ChatSurface({
|
|
|
4160
4409
|
onResultFeedbackSaved,
|
|
4161
4410
|
onFollowupInteraction,
|
|
4162
4411
|
beforeInput,
|
|
4412
|
+
showPlanUpdates = false,
|
|
4413
|
+
planRevealRevision = 0,
|
|
4163
4414
|
banner
|
|
4164
4415
|
}) {
|
|
4165
|
-
return /* @__PURE__ */
|
|
4416
|
+
return /* @__PURE__ */ jsxs16(
|
|
4166
4417
|
"div",
|
|
4167
4418
|
{
|
|
4168
4419
|
"data-theme": themeAttr(theme),
|
|
@@ -4171,14 +4422,14 @@ function ChatSurface({
|
|
|
4171
4422
|
classNames?.root
|
|
4172
4423
|
),
|
|
4173
4424
|
children: [
|
|
4174
|
-
/* @__PURE__ */
|
|
4425
|
+
/* @__PURE__ */ jsx18(ConnectionBanner, { connection, className: classNames?.banner }),
|
|
4175
4426
|
banner,
|
|
4176
|
-
errorMessage && /* @__PURE__ */
|
|
4177
|
-
/* @__PURE__ */
|
|
4178
|
-
/* @__PURE__ */
|
|
4427
|
+
errorMessage && /* @__PURE__ */ jsxs16("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
|
|
4428
|
+
/* @__PURE__ */ jsx18(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
4429
|
+
/* @__PURE__ */ jsx18("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: chatErrorForDisplay2(errorMessage) })
|
|
4179
4430
|
] }),
|
|
4180
4431
|
slots?.header,
|
|
4181
|
-
/* @__PURE__ */
|
|
4432
|
+
/* @__PURE__ */ jsx18(
|
|
4182
4433
|
MessageList,
|
|
4183
4434
|
{
|
|
4184
4435
|
messages,
|
|
@@ -4189,6 +4440,7 @@ function ChatSurface({
|
|
|
4189
4440
|
askAnswers,
|
|
4190
4441
|
onAnswer,
|
|
4191
4442
|
toolCallRenderer: renderers?.toolCall,
|
|
4443
|
+
hidePlanUpdateTools: showPlanUpdates,
|
|
4192
4444
|
emptyState: slots?.emptyState,
|
|
4193
4445
|
className: classNames?.messageList,
|
|
4194
4446
|
sessionId,
|
|
@@ -4198,8 +4450,18 @@ function ChatSurface({
|
|
|
4198
4450
|
onFollowupInteraction
|
|
4199
4451
|
}
|
|
4200
4452
|
),
|
|
4453
|
+
showPlanUpdates ? /* @__PURE__ */ jsx18(
|
|
4454
|
+
CurrentPlanPanel,
|
|
4455
|
+
{
|
|
4456
|
+
messages,
|
|
4457
|
+
running: isStreaming,
|
|
4458
|
+
revealRevision: planRevealRevision,
|
|
4459
|
+
sessionId,
|
|
4460
|
+
className: "border-t border-[hsl(var(--border))]"
|
|
4461
|
+
}
|
|
4462
|
+
) : null,
|
|
4201
4463
|
beforeInput,
|
|
4202
|
-
/* @__PURE__ */
|
|
4464
|
+
/* @__PURE__ */ jsx18(
|
|
4203
4465
|
ChatInput,
|
|
4204
4466
|
{
|
|
4205
4467
|
value: inputText,
|
|
@@ -4219,13 +4481,13 @@ function ChatSurface({
|
|
|
4219
4481
|
}
|
|
4220
4482
|
|
|
4221
4483
|
// src/components/AgentChat.tsx
|
|
4222
|
-
import { Fragment as Fragment3, jsx as
|
|
4484
|
+
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4223
4485
|
function isUnauthorizedError(error) {
|
|
4224
4486
|
return error instanceof BladeApiError && error.status === 401;
|
|
4225
4487
|
}
|
|
4226
4488
|
function LoginCard({ client, onLoggedIn }) {
|
|
4227
|
-
const [loggingIn, setLoggingIn] =
|
|
4228
|
-
const [loginError, setLoginError] =
|
|
4489
|
+
const [loggingIn, setLoggingIn] = useState14(false);
|
|
4490
|
+
const [loginError, setLoginError] = useState14(null);
|
|
4229
4491
|
const handleLogin = async () => {
|
|
4230
4492
|
setLoggingIn(true);
|
|
4231
4493
|
setLoginError(null);
|
|
@@ -4238,11 +4500,11 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4238
4500
|
setLoggingIn(false);
|
|
4239
4501
|
}
|
|
4240
4502
|
};
|
|
4241
|
-
return /* @__PURE__ */
|
|
4242
|
-
/* @__PURE__ */
|
|
4243
|
-
/* @__PURE__ */
|
|
4244
|
-
/* @__PURE__ */
|
|
4245
|
-
/* @__PURE__ */
|
|
4503
|
+
return /* @__PURE__ */ jsx19("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs17("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center", children: [
|
|
4504
|
+
/* @__PURE__ */ jsx19(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
|
|
4505
|
+
/* @__PURE__ */ jsx19("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
|
|
4506
|
+
/* @__PURE__ */ jsx19("div", { className: "text-sm text-[hsl(var(--muted-foreground))]", children: "\u767B\u5F55\u540E\u5373\u53EF\u4E0E\u667A\u80FD\u4F53\u5BF9\u8BDD\uFF0C\u4F60\u7684\u4F1A\u8BDD\u5185\u5BB9\u4EC5\u81EA\u5DF1\u53EF\u89C1\u3002" }),
|
|
4507
|
+
/* @__PURE__ */ jsx19(
|
|
4246
4508
|
"button",
|
|
4247
4509
|
{
|
|
4248
4510
|
type: "button",
|
|
@@ -4252,20 +4514,20 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4252
4514
|
children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
|
|
4253
4515
|
}
|
|
4254
4516
|
),
|
|
4255
|
-
loginError && /* @__PURE__ */
|
|
4517
|
+
loginError && /* @__PURE__ */ jsx19("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
|
|
4256
4518
|
] }) });
|
|
4257
4519
|
}
|
|
4258
4520
|
function AgentChat(props) {
|
|
4259
4521
|
const client = useBladeClient();
|
|
4260
|
-
const [attempt, setAttempt] =
|
|
4261
|
-
const [needLogin, setNeedLogin] =
|
|
4522
|
+
const [attempt, setAttempt] = useState14(0);
|
|
4523
|
+
const [needLogin, setNeedLogin] = useState14(() => !client.hasToken());
|
|
4262
4524
|
if (needLogin) {
|
|
4263
|
-
return /* @__PURE__ */
|
|
4525
|
+
return /* @__PURE__ */ jsx19(
|
|
4264
4526
|
"div",
|
|
4265
4527
|
{
|
|
4266
4528
|
"data-theme": themeAttr(props.theme),
|
|
4267
4529
|
className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
|
|
4268
|
-
children: /* @__PURE__ */
|
|
4530
|
+
children: /* @__PURE__ */ jsx19(
|
|
4269
4531
|
LoginCard,
|
|
4270
4532
|
{
|
|
4271
4533
|
client,
|
|
@@ -4278,7 +4540,7 @@ function AgentChat(props) {
|
|
|
4278
4540
|
}
|
|
4279
4541
|
);
|
|
4280
4542
|
}
|
|
4281
|
-
return /* @__PURE__ */
|
|
4543
|
+
return /* @__PURE__ */ jsx19(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
|
|
4282
4544
|
}
|
|
4283
4545
|
function ChatSessionView({
|
|
4284
4546
|
sessionId,
|
|
@@ -4295,17 +4557,33 @@ function ChatSessionView({
|
|
|
4295
4557
|
onUnauthorized
|
|
4296
4558
|
}) {
|
|
4297
4559
|
const client = useBladeClient();
|
|
4560
|
+
const [planRevealRevisions, setPlanRevealRevisions] = useState14(
|
|
4561
|
+
() => /* @__PURE__ */ new Map()
|
|
4562
|
+
);
|
|
4563
|
+
const handleSessionConnected = useCallback8((connectedSession) => {
|
|
4564
|
+
return connectedSession.on("toolResult", ({ toolCall, turn, source }) => {
|
|
4565
|
+
if (source === "reconnect_replay" || (turn.loop_id || "root") !== "root" || toolCall.status !== "done" || !isPlanUpdateTool(toolCall) || !parsePlanUpdate(toolCall.arguments)) {
|
|
4566
|
+
return;
|
|
4567
|
+
}
|
|
4568
|
+
setPlanRevealRevisions((current) => {
|
|
4569
|
+
const next = new Map(current);
|
|
4570
|
+
next.set(connectedSession.sessionId, (current.get(connectedSession.sessionId) ?? 0) + 1);
|
|
4571
|
+
return next;
|
|
4572
|
+
});
|
|
4573
|
+
});
|
|
4574
|
+
}, []);
|
|
4298
4575
|
const { session, state, error } = useAgentSession(sessionId, {
|
|
4299
4576
|
createOptions,
|
|
4300
|
-
onSessionCreated
|
|
4577
|
+
onSessionCreated,
|
|
4578
|
+
onSessionConnected: handleSessionConnected
|
|
4301
4579
|
});
|
|
4302
4580
|
const replay = useReplay(session);
|
|
4303
|
-
const [stopRequested, setStopRequested] =
|
|
4304
|
-
const [inputText, setInputText] =
|
|
4305
|
-
const [resultFeedback, setResultFeedback] =
|
|
4581
|
+
const [stopRequested, setStopRequested] = useState14(false);
|
|
4582
|
+
const [inputText, setInputText] = useState14("");
|
|
4583
|
+
const [resultFeedback, setResultFeedback] = useState14([]);
|
|
4306
4584
|
const resolvedSessionId = session?.sessionId;
|
|
4307
4585
|
const isViewer = state?.viewerRole === "viewer";
|
|
4308
|
-
|
|
4586
|
+
useEffect12(() => {
|
|
4309
4587
|
setResultFeedback([]);
|
|
4310
4588
|
if (!resolvedSessionId || isViewer) return;
|
|
4311
4589
|
let cancelled = false;
|
|
@@ -4340,12 +4618,12 @@ function ChatSessionView({
|
|
|
4340
4618
|
saved
|
|
4341
4619
|
]);
|
|
4342
4620
|
}, []);
|
|
4343
|
-
|
|
4621
|
+
useEffect12(() => {
|
|
4344
4622
|
if (session) {
|
|
4345
4623
|
onSessionReady?.(session);
|
|
4346
4624
|
}
|
|
4347
4625
|
}, [session, onSessionReady]);
|
|
4348
|
-
|
|
4626
|
+
useEffect12(() => {
|
|
4349
4627
|
if (!session) return;
|
|
4350
4628
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
4351
4629
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -4361,12 +4639,12 @@ ${content}`);
|
|
|
4361
4639
|
offInsert();
|
|
4362
4640
|
};
|
|
4363
4641
|
}, [session]);
|
|
4364
|
-
|
|
4642
|
+
useEffect12(() => {
|
|
4365
4643
|
if (isUnauthorizedError(error)) {
|
|
4366
4644
|
onUnauthorized();
|
|
4367
4645
|
}
|
|
4368
4646
|
}, [error, onUnauthorized]);
|
|
4369
|
-
|
|
4647
|
+
useEffect12(() => {
|
|
4370
4648
|
if (!session || !commands) return;
|
|
4371
4649
|
const unsubscribes = Object.entries(commands).map(
|
|
4372
4650
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -4376,6 +4654,7 @@ ${content}`);
|
|
|
4376
4654
|
};
|
|
4377
4655
|
}, [session, commands]);
|
|
4378
4656
|
const isStreaming = state?.isStreaming ?? false;
|
|
4657
|
+
const planRevealRevision = resolvedSessionId ? planRevealRevisions.get(resolvedSessionId) ?? 0 : 0;
|
|
4379
4658
|
const isStopping = stopRequested && isStreaming;
|
|
4380
4659
|
const connectError = error && !isUnauthorizedError(error) ? error.message || "\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" : null;
|
|
4381
4660
|
const errorMessage = connectError ?? state?.errorMessage ?? replay.error?.message ?? null;
|
|
@@ -4387,7 +4666,7 @@ ${content}`);
|
|
|
4387
4666
|
setStopRequested(true);
|
|
4388
4667
|
void session?.stop();
|
|
4389
4668
|
};
|
|
4390
|
-
return /* @__PURE__ */
|
|
4669
|
+
return /* @__PURE__ */ jsx19(
|
|
4391
4670
|
ChatSurface,
|
|
4392
4671
|
{
|
|
4393
4672
|
theme,
|
|
@@ -4397,8 +4676,8 @@ ${content}`);
|
|
|
4397
4676
|
slots,
|
|
4398
4677
|
placeholder,
|
|
4399
4678
|
connection: state?.connection ?? "connecting",
|
|
4400
|
-
banner: /* @__PURE__ */
|
|
4401
|
-
/* @__PURE__ */
|
|
4679
|
+
banner: /* @__PURE__ */ jsxs17(Fragment3, { children: [
|
|
4680
|
+
/* @__PURE__ */ jsx19(
|
|
4402
4681
|
ReplayBar,
|
|
4403
4682
|
{
|
|
4404
4683
|
isReplay: replay.isReplay,
|
|
@@ -4408,7 +4687,7 @@ ${content}`);
|
|
|
4408
4687
|
onExit: () => void replay.exitToAutonomous()
|
|
4409
4688
|
}
|
|
4410
4689
|
),
|
|
4411
|
-
/* @__PURE__ */
|
|
4690
|
+
/* @__PURE__ */ jsx19(ReplayMismatchPrompt, { mismatch: replay.mismatch })
|
|
4412
4691
|
] }),
|
|
4413
4692
|
errorMessage,
|
|
4414
4693
|
messages: state?.messages ?? [],
|
|
@@ -4416,6 +4695,8 @@ ${content}`);
|
|
|
4416
4695
|
resultFeedbackByEntry,
|
|
4417
4696
|
onResultFeedbackSaved: handleResultFeedbackSaved,
|
|
4418
4697
|
isStreaming,
|
|
4698
|
+
showPlanUpdates: true,
|
|
4699
|
+
planRevealRevision,
|
|
4419
4700
|
isStopping,
|
|
4420
4701
|
inputText,
|
|
4421
4702
|
onInputChange: setInputText,
|
|
@@ -4437,11 +4718,11 @@ ${content}`);
|
|
|
4437
4718
|
}
|
|
4438
4719
|
|
|
4439
4720
|
// src/components/LlmChat.tsx
|
|
4440
|
-
import { useEffect as
|
|
4721
|
+
import { useEffect as useEffect13, useMemo as useMemo9, useState as useState16 } from "react";
|
|
4441
4722
|
|
|
4442
4723
|
// src/components/LlmAdvancedSettings.tsx
|
|
4443
|
-
import { useState as
|
|
4444
|
-
import { jsx as
|
|
4724
|
+
import { useState as useState15 } from "react";
|
|
4725
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4445
4726
|
var FIELDS = [
|
|
4446
4727
|
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
4447
4728
|
{ id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
|
|
@@ -4487,13 +4768,13 @@ function writeOverride(settings, baseURL, override) {
|
|
|
4487
4768
|
}
|
|
4488
4769
|
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
4489
4770
|
const normalized = normalizeAdvanced(settings);
|
|
4490
|
-
const [open, setOpen] =
|
|
4491
|
-
const [draft, setDraft] =
|
|
4771
|
+
const [open, setOpen] = useState15(false);
|
|
4772
|
+
const [draft, setDraft] = useState15(override);
|
|
4492
4773
|
if (!normalized) return null;
|
|
4493
4774
|
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
4494
4775
|
const dirty = Object.keys(override).length > 0;
|
|
4495
|
-
return /* @__PURE__ */
|
|
4496
|
-
/* @__PURE__ */
|
|
4776
|
+
return /* @__PURE__ */ jsxs18("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
|
|
4777
|
+
/* @__PURE__ */ jsxs18(
|
|
4497
4778
|
"button",
|
|
4498
4779
|
{
|
|
4499
4780
|
type: "button",
|
|
@@ -4503,16 +4784,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4503
4784
|
},
|
|
4504
4785
|
className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
4505
4786
|
children: [
|
|
4506
|
-
/* @__PURE__ */
|
|
4787
|
+
/* @__PURE__ */ jsx20(Settings2, { size: 13 }),
|
|
4507
4788
|
"\u9AD8\u7EA7\u8BBE\u7F6E",
|
|
4508
|
-
dirty && /* @__PURE__ */
|
|
4789
|
+
dirty && /* @__PURE__ */ jsx20("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
|
|
4509
4790
|
]
|
|
4510
4791
|
}
|
|
4511
4792
|
),
|
|
4512
|
-
open && /* @__PURE__ */
|
|
4513
|
-
fields.map((field) => /* @__PURE__ */
|
|
4514
|
-
/* @__PURE__ */
|
|
4515
|
-
/* @__PURE__ */
|
|
4793
|
+
open && /* @__PURE__ */ jsxs18("div", { className: "mt-2 flex flex-col gap-2", children: [
|
|
4794
|
+
fields.map((field) => /* @__PURE__ */ jsxs18("label", { className: "flex flex-col gap-1", children: [
|
|
4795
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
|
|
4796
|
+
/* @__PURE__ */ jsx20(
|
|
4516
4797
|
"input",
|
|
4517
4798
|
{
|
|
4518
4799
|
type: field.secret ? "password" : "text",
|
|
@@ -4523,9 +4804,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4523
4804
|
}
|
|
4524
4805
|
)
|
|
4525
4806
|
] }, field.id)),
|
|
4526
|
-
normalized.apiKey && /* @__PURE__ */
|
|
4527
|
-
/* @__PURE__ */
|
|
4528
|
-
/* @__PURE__ */
|
|
4807
|
+
normalized.apiKey && /* @__PURE__ */ jsx20("p", { className: "text-[hsl(var(--muted-foreground))]", children: "\u5BC6\u94A5\u4F1A\u5B58\u5728\u8FD9\u53F0\u6D4F\u89C8\u5668\u91CC\u3002\u53EA\u5728\u4F60\u4FE1\u5F97\u8FC7\u8FD9\u53F0\u673A\u5668\u65F6\u586B\u3002" }),
|
|
4808
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex gap-2", children: [
|
|
4809
|
+
/* @__PURE__ */ jsx20(
|
|
4529
4810
|
"button",
|
|
4530
4811
|
{
|
|
4531
4812
|
type: "button",
|
|
@@ -4540,7 +4821,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4540
4821
|
children: "\u4FDD\u5B58"
|
|
4541
4822
|
}
|
|
4542
4823
|
),
|
|
4543
|
-
/* @__PURE__ */
|
|
4824
|
+
/* @__PURE__ */ jsx20(
|
|
4544
4825
|
"button",
|
|
4545
4826
|
{
|
|
4546
4827
|
type: "button",
|
|
@@ -4559,7 +4840,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4559
4840
|
}
|
|
4560
4841
|
|
|
4561
4842
|
// src/components/LlmChat.tsx
|
|
4562
|
-
import { jsx as
|
|
4843
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
4563
4844
|
function LlmChat({
|
|
4564
4845
|
classNames,
|
|
4565
4846
|
renderers,
|
|
@@ -4571,11 +4852,11 @@ function LlmChat({
|
|
|
4571
4852
|
onOverrideChange,
|
|
4572
4853
|
...options
|
|
4573
4854
|
}) {
|
|
4574
|
-
const [override, setOverride] =
|
|
4855
|
+
const [override, setOverride] = useState16(() => readOverride(advanced, options.baseURL));
|
|
4575
4856
|
const effective = { ...options, ...override };
|
|
4576
4857
|
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
4577
|
-
const [inputText, setInputText] =
|
|
4578
|
-
const [stopRequested, setStopRequested] =
|
|
4858
|
+
const [inputText, setInputText] = useState16("");
|
|
4859
|
+
const [stopRequested, setStopRequested] = useState16(false);
|
|
4579
4860
|
const handle = useMemo9(
|
|
4580
4861
|
() => ({
|
|
4581
4862
|
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
@@ -4585,10 +4866,10 @@ ${text}` : text),
|
|
|
4585
4866
|
}),
|
|
4586
4867
|
[send, reset]
|
|
4587
4868
|
);
|
|
4588
|
-
|
|
4869
|
+
useEffect13(() => {
|
|
4589
4870
|
onReady?.(handle);
|
|
4590
4871
|
}, [handle, onReady]);
|
|
4591
|
-
return /* @__PURE__ */
|
|
4872
|
+
return /* @__PURE__ */ jsx21(
|
|
4592
4873
|
ChatSurface,
|
|
4593
4874
|
{
|
|
4594
4875
|
theme,
|
|
@@ -4613,7 +4894,7 @@ ${text}` : text),
|
|
|
4613
4894
|
setStopRequested(true);
|
|
4614
4895
|
stop();
|
|
4615
4896
|
},
|
|
4616
|
-
beforeInput: advanced ? /* @__PURE__ */
|
|
4897
|
+
beforeInput: advanced ? /* @__PURE__ */ jsx21(
|
|
4617
4898
|
LlmAdvancedSettingsBar,
|
|
4618
4899
|
{
|
|
4619
4900
|
settings: advanced,
|
|
@@ -4631,14 +4912,14 @@ ${text}` : text),
|
|
|
4631
4912
|
}
|
|
4632
4913
|
|
|
4633
4914
|
// src/components/ChatView.tsx
|
|
4634
|
-
import { jsx as
|
|
4915
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
4635
4916
|
function ChatView(props) {
|
|
4636
4917
|
const { mode, llm, onLlmReady, ...rest } = props;
|
|
4637
4918
|
if (mode === "llm") {
|
|
4638
4919
|
if (!llm) {
|
|
4639
4920
|
throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
|
|
4640
4921
|
}
|
|
4641
|
-
return /* @__PURE__ */
|
|
4922
|
+
return /* @__PURE__ */ jsx22(
|
|
4642
4923
|
LlmChat,
|
|
4643
4924
|
{
|
|
4644
4925
|
...llm,
|
|
@@ -4651,7 +4932,7 @@ function ChatView(props) {
|
|
|
4651
4932
|
}
|
|
4652
4933
|
);
|
|
4653
4934
|
}
|
|
4654
|
-
return /* @__PURE__ */
|
|
4935
|
+
return /* @__PURE__ */ jsx22(AgentChat, { ...rest });
|
|
4655
4936
|
}
|
|
4656
4937
|
|
|
4657
4938
|
// src/components/ContextCard.tsx
|
|
@@ -4659,16 +4940,16 @@ import {
|
|
|
4659
4940
|
getContextDisplayState,
|
|
4660
4941
|
getContextGroupDisplayState
|
|
4661
4942
|
} from "@blade-hq/agent-client";
|
|
4662
|
-
import { jsx as
|
|
4943
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4663
4944
|
function ContextCard({ context, className }) {
|
|
4664
4945
|
const display = getContextDisplayState(context);
|
|
4665
|
-
return /* @__PURE__ */
|
|
4946
|
+
return /* @__PURE__ */ jsxs19(
|
|
4666
4947
|
"details",
|
|
4667
4948
|
{
|
|
4668
4949
|
className: `blade-chat-context-card group/context-card rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
|
|
4669
4950
|
children: [
|
|
4670
|
-
/* @__PURE__ */
|
|
4671
|
-
/* @__PURE__ */
|
|
4951
|
+
/* @__PURE__ */ jsxs19("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
|
|
4952
|
+
/* @__PURE__ */ jsx23(
|
|
4672
4953
|
Layers,
|
|
4673
4954
|
{
|
|
4674
4955
|
size: 15,
|
|
@@ -4676,11 +4957,11 @@ function ContextCard({ context, className }) {
|
|
|
4676
4957
|
"aria-hidden": "true"
|
|
4677
4958
|
}
|
|
4678
4959
|
),
|
|
4679
|
-
/* @__PURE__ */
|
|
4680
|
-
/* @__PURE__ */
|
|
4681
|
-
/* @__PURE__ */
|
|
4960
|
+
/* @__PURE__ */ jsxs19("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
|
|
4961
|
+
/* @__PURE__ */ jsx23("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
|
|
4962
|
+
/* @__PURE__ */ jsx23("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
|
|
4682
4963
|
] }),
|
|
4683
|
-
/* @__PURE__ */
|
|
4964
|
+
/* @__PURE__ */ jsx23(
|
|
4684
4965
|
ChevronDown,
|
|
4685
4966
|
{
|
|
4686
4967
|
size: 14,
|
|
@@ -4689,7 +4970,7 @@ function ContextCard({ context, className }) {
|
|
|
4689
4970
|
}
|
|
4690
4971
|
)
|
|
4691
4972
|
] }),
|
|
4692
|
-
/* @__PURE__ */
|
|
4973
|
+
/* @__PURE__ */ jsx23("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: display.detail })
|
|
4693
4974
|
]
|
|
4694
4975
|
}
|
|
4695
4976
|
);
|
|
@@ -4698,9 +4979,9 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
4698
4979
|
if (contexts.length === 0) return null;
|
|
4699
4980
|
const single = contexts.length === 1 ? getContextDisplayState(contexts[0]) : null;
|
|
4700
4981
|
const group = single ? null : getContextGroupDisplayState(contexts);
|
|
4701
|
-
return /* @__PURE__ */
|
|
4702
|
-
/* @__PURE__ */
|
|
4703
|
-
/* @__PURE__ */
|
|
4982
|
+
return /* @__PURE__ */ jsxs19("details", { className: `blade-chat-context-card group/context-group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`, children: [
|
|
4983
|
+
/* @__PURE__ */ jsxs19("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
|
|
4984
|
+
/* @__PURE__ */ jsx23(
|
|
4704
4985
|
Layers,
|
|
4705
4986
|
{
|
|
4706
4987
|
size: 15,
|
|
@@ -4708,11 +4989,11 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
4708
4989
|
"aria-hidden": "true"
|
|
4709
4990
|
}
|
|
4710
4991
|
),
|
|
4711
|
-
/* @__PURE__ */
|
|
4712
|
-
/* @__PURE__ */
|
|
4713
|
-
/* @__PURE__ */
|
|
4992
|
+
/* @__PURE__ */ jsxs19("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
|
|
4993
|
+
/* @__PURE__ */ jsx23("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: single ? single.title : `${group?.title} \xB7 ${group?.count} \u9879` }),
|
|
4994
|
+
/* @__PURE__ */ jsx23("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: single ? single.summary : group?.summary })
|
|
4714
4995
|
] }),
|
|
4715
|
-
/* @__PURE__ */
|
|
4996
|
+
/* @__PURE__ */ jsx23(
|
|
4716
4997
|
ChevronDown,
|
|
4717
4998
|
{
|
|
4718
4999
|
size: 14,
|
|
@@ -4721,7 +5002,7 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
4721
5002
|
}
|
|
4722
5003
|
)
|
|
4723
5004
|
] }),
|
|
4724
|
-
single ? /* @__PURE__ */
|
|
5005
|
+
single ? /* @__PURE__ */ jsx23("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: single.detail }) : /* @__PURE__ */ jsx23("div", { className: "blade-chat-context-group-items flex flex-col gap-1.5 border-t border-[hsl(var(--border))] p-2", children: contexts.map((context) => /* @__PURE__ */ jsx23(
|
|
4725
5006
|
ContextCard,
|
|
4726
5007
|
{
|
|
4727
5008
|
context
|
|
@@ -4731,6 +5012,112 @@ function ContextGroupCard({ contexts, className }) {
|
|
|
4731
5012
|
] });
|
|
4732
5013
|
}
|
|
4733
5014
|
|
|
5015
|
+
// src/components/SessionMemoryToggle.tsx
|
|
5016
|
+
import { useCallback as useCallback9, useEffect as useEffect14, useRef as useRef13, useState as useState17, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
5017
|
+
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5018
|
+
var saveStates = /* @__PURE__ */ new WeakMap();
|
|
5019
|
+
function getSaveState(client, sessionId) {
|
|
5020
|
+
let clientStates = saveStates.get(client);
|
|
5021
|
+
if (!clientStates) {
|
|
5022
|
+
clientStates = /* @__PURE__ */ new Map();
|
|
5023
|
+
saveStates.set(client, clientStates);
|
|
5024
|
+
}
|
|
5025
|
+
let state = clientStates.get(sessionId);
|
|
5026
|
+
if (!state) {
|
|
5027
|
+
state = { saving: false, listeners: /* @__PURE__ */ new Set() };
|
|
5028
|
+
clientStates.set(sessionId, state);
|
|
5029
|
+
}
|
|
5030
|
+
return state;
|
|
5031
|
+
}
|
|
5032
|
+
function notify(state) {
|
|
5033
|
+
for (const listener of state.listeners) listener();
|
|
5034
|
+
}
|
|
5035
|
+
function cleanupSaveState(client, sessionId, state) {
|
|
5036
|
+
if (state.saving || state.listeners.size > 0) return;
|
|
5037
|
+
const clientStates = saveStates.get(client);
|
|
5038
|
+
if (clientStates?.get(sessionId) === state) clientStates.delete(sessionId);
|
|
5039
|
+
}
|
|
5040
|
+
function SessionMemoryToggle({
|
|
5041
|
+
sessionId,
|
|
5042
|
+
enabled,
|
|
5043
|
+
client: clientProp,
|
|
5044
|
+
disabled = false,
|
|
5045
|
+
label = "\u5F53\u524D\u4F1A\u8BDD\u4F7F\u7528\u8BB0\u5FC6",
|
|
5046
|
+
className,
|
|
5047
|
+
labelClassName,
|
|
5048
|
+
inputClassName,
|
|
5049
|
+
onSaved,
|
|
5050
|
+
onError
|
|
5051
|
+
}) {
|
|
5052
|
+
const contextClient = useOptionalBladeClient();
|
|
5053
|
+
const client = clientProp ?? contextClient;
|
|
5054
|
+
if (!client) {
|
|
5055
|
+
throw new Error("SessionMemoryToggle \u5FC5\u987B\u5728 <BladeProvider> \u5185\u4F7F\u7528\u6216\u663E\u5F0F\u4F20\u5165 client");
|
|
5056
|
+
}
|
|
5057
|
+
const saveState = getSaveState(client, sessionId);
|
|
5058
|
+
const subscribe = useCallback9(
|
|
5059
|
+
(listener) => {
|
|
5060
|
+
saveState.listeners.add(listener);
|
|
5061
|
+
return () => {
|
|
5062
|
+
saveState.listeners.delete(listener);
|
|
5063
|
+
cleanupSaveState(client, sessionId, saveState);
|
|
5064
|
+
};
|
|
5065
|
+
},
|
|
5066
|
+
[client, saveState, sessionId]
|
|
5067
|
+
);
|
|
5068
|
+
const getSaving = useCallback9(() => saveState.saving, [saveState]);
|
|
5069
|
+
const saving = useSyncExternalStore2(
|
|
5070
|
+
subscribe,
|
|
5071
|
+
getSaving,
|
|
5072
|
+
getSaving
|
|
5073
|
+
);
|
|
5074
|
+
const [draftEnabled, setDraftEnabled] = useState17(enabled);
|
|
5075
|
+
const activeSessionIdRef = useRef13(sessionId);
|
|
5076
|
+
activeSessionIdRef.current = sessionId;
|
|
5077
|
+
useEffect14(() => {
|
|
5078
|
+
setDraftEnabled(enabled);
|
|
5079
|
+
}, [enabled, sessionId]);
|
|
5080
|
+
const update = useCallback9(
|
|
5081
|
+
(nextEnabled) => {
|
|
5082
|
+
const currentSaveState = getSaveState(client, sessionId);
|
|
5083
|
+
if (currentSaveState.saving) return;
|
|
5084
|
+
currentSaveState.saving = true;
|
|
5085
|
+
notify(currentSaveState);
|
|
5086
|
+
setDraftEnabled(nextEnabled);
|
|
5087
|
+
void client.sessions.updateSessionMemory(sessionId, nextEnabled).then(
|
|
5088
|
+
(updated) => {
|
|
5089
|
+
if (activeSessionIdRef.current === sessionId) {
|
|
5090
|
+
setDraftEnabled(updated.memory_enabled);
|
|
5091
|
+
}
|
|
5092
|
+
onSaved?.(sessionId, updated.memory_enabled);
|
|
5093
|
+
},
|
|
5094
|
+
(error) => {
|
|
5095
|
+
if (activeSessionIdRef.current === sessionId) setDraftEnabled(enabled);
|
|
5096
|
+
onError?.(error);
|
|
5097
|
+
}
|
|
5098
|
+
).finally(() => {
|
|
5099
|
+
currentSaveState.saving = false;
|
|
5100
|
+
notify(currentSaveState);
|
|
5101
|
+
cleanupSaveState(client, sessionId, currentSaveState);
|
|
5102
|
+
});
|
|
5103
|
+
},
|
|
5104
|
+
[client, enabled, onError, onSaved, sessionId]
|
|
5105
|
+
);
|
|
5106
|
+
return /* @__PURE__ */ jsxs20("label", { className: cn("flex items-center justify-between", className), children: [
|
|
5107
|
+
/* @__PURE__ */ jsx24("span", { className: labelClassName, children: label }),
|
|
5108
|
+
/* @__PURE__ */ jsx24(
|
|
5109
|
+
"input",
|
|
5110
|
+
{
|
|
5111
|
+
type: "checkbox",
|
|
5112
|
+
checked: draftEnabled,
|
|
5113
|
+
onChange: (event) => update(event.target.checked),
|
|
5114
|
+
disabled: disabled || saving,
|
|
5115
|
+
className: inputClassName
|
|
5116
|
+
}
|
|
5117
|
+
)
|
|
5118
|
+
] });
|
|
5119
|
+
}
|
|
5120
|
+
|
|
4734
5121
|
// src/lib/agent-computer-command.ts
|
|
4735
5122
|
var COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\n;&|(]\s*)computer\s+launch(?:\s|$)/;
|
|
4736
5123
|
function isAgentComputerCommand(command) {
|
|
@@ -4781,18 +5168,26 @@ export {
|
|
|
4781
5168
|
ChatView,
|
|
4782
5169
|
ContextCard,
|
|
4783
5170
|
ContextGroupCard,
|
|
5171
|
+
CurrentPlanPanel,
|
|
4784
5172
|
LlmChat,
|
|
4785
5173
|
MarkdownContent,
|
|
4786
5174
|
MemoryRefsHint,
|
|
5175
|
+
PLAN_AUTO_COLLAPSE_MS,
|
|
5176
|
+
PlanUpdateBlock,
|
|
4787
5177
|
ReplayBar,
|
|
4788
5178
|
ReplayMismatchPrompt,
|
|
5179
|
+
SessionMemoryToggle,
|
|
4789
5180
|
WhatIfUserBubble,
|
|
4790
5181
|
classifyAgentComputerLaunchOutcome,
|
|
4791
5182
|
collectMemoryRefs,
|
|
5183
|
+
getPlanUpdateDisplayState,
|
|
4792
5184
|
isAgentComputerCommand,
|
|
4793
5185
|
isAgentComputerToolCall,
|
|
5186
|
+
isPlanUpdateTool,
|
|
4794
5187
|
normalizeAdjacentUrlFormatting,
|
|
5188
|
+
parsePlanUpdate,
|
|
4795
5189
|
parseWhatIfPrompt,
|
|
5190
|
+
pickCurrentPlanStep,
|
|
4796
5191
|
useAgentSession,
|
|
4797
5192
|
useBladeClient,
|
|
4798
5193
|
useLlmChat,
|
|
@@ -4814,6 +5209,8 @@ lucide-react/dist/esm/icons/check.js:
|
|
|
4814
5209
|
lucide-react/dist/esm/icons/chevron-down.js:
|
|
4815
5210
|
lucide-react/dist/esm/icons/chevron-right.js:
|
|
4816
5211
|
lucide-react/dist/esm/icons/circle-alert.js:
|
|
5212
|
+
lucide-react/dist/esm/icons/circle-dot.js:
|
|
5213
|
+
lucide-react/dist/esm/icons/circle.js:
|
|
4817
5214
|
lucide-react/dist/esm/icons/copy.js:
|
|
4818
5215
|
lucide-react/dist/esm/icons/earth.js:
|
|
4819
5216
|
lucide-react/dist/esm/icons/file-pen-line.js:
|
|
@@ -4821,6 +5218,7 @@ lucide-react/dist/esm/icons/file-text.js:
|
|
|
4821
5218
|
lucide-react/dist/esm/icons/globe.js:
|
|
4822
5219
|
lucide-react/dist/esm/icons/layers.js:
|
|
4823
5220
|
lucide-react/dist/esm/icons/lightbulb.js:
|
|
5221
|
+
lucide-react/dist/esm/icons/list-checks.js:
|
|
4824
5222
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
4825
5223
|
lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
4826
5224
|
lucide-react/dist/esm/icons/message-square-more.js:
|