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