@blade-hq/agent-react 2610.0.0-beta.30 → 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 +25 -2
- package/dist/components/AssistantTurnBlock.d.ts +3 -1
- package/dist/components/ChatSurface.d.ts +5 -1
- package/dist/components/ContextCard.d.ts +13 -0
- package/dist/components/MarkdownContent.d.ts +2 -0
- package/dist/components/MessageList.d.ts +2 -1
- package/dist/components/PlanUpdateBlock.d.ts +31 -0
- package/dist/components/UserMessageBubble.d.ts +1 -1
- package/dist/components/WhatIfUserBubble.d.ts +7 -0
- package/dist/embed/entry.d.ts +2 -0
- package/dist/hooks/use-agent-session.d.ts +5 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +945 -515
- package/dist/index.js.map +1 -1
- package/dist/lib/whatif-prompt.d.ts +18 -0
- package/dist/style.css +12 -1
- package/dist/style.full.css +13 -2
- package/package.json +2 -2
- package/public-api.md +146 -4
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" }]
|
|
@@ -1023,6 +1062,14 @@ var Play = createLucideIcon("Play", [
|
|
|
1023
1062
|
["polygon", { points: "6 3 20 12 6 21 6 3", key: "1oa8hb" }]
|
|
1024
1063
|
]);
|
|
1025
1064
|
|
|
1065
|
+
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/refresh-ccw.js
|
|
1066
|
+
var RefreshCcw = createLucideIcon("RefreshCcw", [
|
|
1067
|
+
["path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "14sxne" }],
|
|
1068
|
+
["path", { d: "M3 3v5h5", key: "1xhq8a" }],
|
|
1069
|
+
["path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16", key: "1hlbsb" }],
|
|
1070
|
+
["path", { d: "M16 16h5v5", key: "ccwih5" }]
|
|
1071
|
+
]);
|
|
1072
|
+
|
|
1026
1073
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/search.js
|
|
1027
1074
|
var Search = createLucideIcon("Search", [
|
|
1028
1075
|
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
|
|
@@ -1094,7 +1141,7 @@ var X = createLucideIcon("X", [
|
|
|
1094
1141
|
]);
|
|
1095
1142
|
|
|
1096
1143
|
// src/components/AgentChat.tsx
|
|
1097
|
-
import { useCallback as useCallback8, useEffect as
|
|
1144
|
+
import { useCallback as useCallback8, useEffect as useEffect12, useMemo as useMemo8, useState as useState14 } from "react";
|
|
1098
1145
|
|
|
1099
1146
|
// src/lib/utils.ts
|
|
1100
1147
|
function cn(...inputs) {
|
|
@@ -1221,11 +1268,349 @@ function ReplayMismatchPrompt({ mismatch, className }) {
|
|
|
1221
1268
|
);
|
|
1222
1269
|
}
|
|
1223
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
|
+
|
|
1224
1609
|
// src/components/ChatSurface.tsx
|
|
1225
1610
|
import { chatErrorForDisplay as chatErrorForDisplay2 } from "@blade-hq/agent-client";
|
|
1226
1611
|
|
|
1227
1612
|
// src/components/ChatInput.tsx
|
|
1228
|
-
import { jsx as
|
|
1613
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1229
1614
|
function isImeCompositionKey(event) {
|
|
1230
1615
|
return event.isComposing || event.keyCode === 229;
|
|
1231
1616
|
}
|
|
@@ -1261,8 +1646,8 @@ function ChatInput({
|
|
|
1261
1646
|
void handleSend();
|
|
1262
1647
|
}
|
|
1263
1648
|
};
|
|
1264
|
-
return /* @__PURE__ */
|
|
1265
|
-
/* @__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(
|
|
1266
1651
|
"textarea",
|
|
1267
1652
|
{
|
|
1268
1653
|
value,
|
|
@@ -1279,7 +1664,7 @@ function ChatInput({
|
|
|
1279
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)]"
|
|
1280
1665
|
}
|
|
1281
1666
|
),
|
|
1282
|
-
isStreaming ? /* @__PURE__ */
|
|
1667
|
+
isStreaming ? /* @__PURE__ */ jsx5(
|
|
1283
1668
|
"button",
|
|
1284
1669
|
{
|
|
1285
1670
|
type: "button",
|
|
@@ -1288,9 +1673,9 @@ function ChatInput({
|
|
|
1288
1673
|
"aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1289
1674
|
title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D",
|
|
1290
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",
|
|
1291
|
-
children: isStopping ? /* @__PURE__ */
|
|
1676
|
+
children: isStopping ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Square, { size: 12, fill: "currentColor" })
|
|
1292
1677
|
}
|
|
1293
|
-
) : /* @__PURE__ */
|
|
1678
|
+
) : /* @__PURE__ */ jsx5(
|
|
1294
1679
|
"button",
|
|
1295
1680
|
{
|
|
1296
1681
|
type: "button",
|
|
@@ -1299,23 +1684,23 @@ function ChatInput({
|
|
|
1299
1684
|
"aria-label": "\u53D1\u9001\u6D88\u606F",
|
|
1300
1685
|
title: "\u53D1\u9001\u6D88\u606F",
|
|
1301
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",
|
|
1302
|
-
children: /* @__PURE__ */
|
|
1687
|
+
children: /* @__PURE__ */ jsx5(ArrowUp, { size: 15 })
|
|
1303
1688
|
}
|
|
1304
1689
|
)
|
|
1305
1690
|
] }) });
|
|
1306
1691
|
}
|
|
1307
1692
|
|
|
1308
1693
|
// src/components/ConnectionBanner.tsx
|
|
1309
|
-
import { useEffect as
|
|
1310
|
-
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";
|
|
1311
1696
|
var CONNECTION_NOTICE_DELAY_MS = 3e3;
|
|
1312
1697
|
var CONNECTION_ERROR_DELAY_MS = 15e3;
|
|
1313
1698
|
function useConnectionNoticePhase(connected) {
|
|
1314
|
-
const [phase, setPhase] =
|
|
1315
|
-
const connectedRef =
|
|
1316
|
-
const timersRef =
|
|
1699
|
+
const [phase, setPhase] = useState5("hidden");
|
|
1700
|
+
const connectedRef = useRef5(connected);
|
|
1701
|
+
const timersRef = useRef5([]);
|
|
1317
1702
|
connectedRef.current = connected;
|
|
1318
|
-
|
|
1703
|
+
useEffect5(() => {
|
|
1319
1704
|
const clearTimers = () => {
|
|
1320
1705
|
for (const timer of timersRef.current) clearTimeout(timer);
|
|
1321
1706
|
timersRef.current = [];
|
|
@@ -1355,14 +1740,14 @@ function useConnectionNoticePhase(connected) {
|
|
|
1355
1740
|
return phase;
|
|
1356
1741
|
}
|
|
1357
1742
|
function ConnectionBanner({ connection, className }) {
|
|
1358
|
-
const hasConnectedRef =
|
|
1743
|
+
const hasConnectedRef = useRef5(connection === "connected" || connection === "reconnecting");
|
|
1359
1744
|
if (connection === "connected") hasConnectedRef.current = true;
|
|
1360
1745
|
const connected = connection === "connected";
|
|
1361
1746
|
const phase = useConnectionNoticePhase(connected);
|
|
1362
1747
|
if (connected || phase === "hidden") return null;
|
|
1363
1748
|
const recovering = phase === "recovering";
|
|
1364
1749
|
const firstConnection = !hasConnectedRef.current;
|
|
1365
|
-
return /* @__PURE__ */
|
|
1750
|
+
return /* @__PURE__ */ jsx6("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs5(
|
|
1366
1751
|
"div",
|
|
1367
1752
|
{
|
|
1368
1753
|
className: cn(
|
|
@@ -1370,10 +1755,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1370
1755
|
recovering ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
|
|
1371
1756
|
),
|
|
1372
1757
|
children: [
|
|
1373
|
-
/* @__PURE__ */
|
|
1374
|
-
/* @__PURE__ */
|
|
1375
|
-
/* @__PURE__ */
|
|
1376
|
-
/* @__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" })
|
|
1377
1762
|
] })
|
|
1378
1763
|
]
|
|
1379
1764
|
}
|
|
@@ -1382,10 +1767,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
1382
1767
|
|
|
1383
1768
|
// src/components/MessageList.tsx
|
|
1384
1769
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
1385
|
-
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";
|
|
1386
1771
|
|
|
1387
1772
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
1388
|
-
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";
|
|
1389
1774
|
var DEFAULT_SPRING_ANIMATION = {
|
|
1390
1775
|
/**
|
|
1391
1776
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -1422,10 +1807,10 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
1422
1807
|
mouseDown = false;
|
|
1423
1808
|
});
|
|
1424
1809
|
var useStickToBottom = (options = {}) => {
|
|
1425
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
1426
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
1427
|
-
const [isNearBottom, setIsNearBottom] =
|
|
1428
|
-
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);
|
|
1429
1814
|
optionsRef.current = options;
|
|
1430
1815
|
const isSelecting = useCallback4(() => {
|
|
1431
1816
|
if (!mouseDown) {
|
|
@@ -1729,11 +2114,11 @@ function mergeAnimations(...animations) {
|
|
|
1729
2114
|
|
|
1730
2115
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
1731
2116
|
import * as React from "react";
|
|
1732
|
-
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";
|
|
1733
2118
|
var StickToBottomContext = createContext2(null);
|
|
1734
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
2119
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect6;
|
|
1735
2120
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
1736
|
-
const customTargetScrollTop =
|
|
2121
|
+
const customTargetScrollTop = useRef7(null);
|
|
1737
2122
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
1738
2123
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
1739
2124
|
return get?.(target, elements) ?? target;
|
|
@@ -1815,153 +2200,11 @@ import {
|
|
|
1815
2200
|
getTextContent,
|
|
1816
2201
|
normalizeMessageContent
|
|
1817
2202
|
} from "@blade-hq/agent-client";
|
|
1818
|
-
import { useEffect as
|
|
1819
|
-
|
|
1820
|
-
// src/components/AgentLoopBlock.tsx
|
|
1821
|
-
import { useState as useState6 } from "react";
|
|
1822
|
-
|
|
1823
|
-
// src/components/display-utils.ts
|
|
1824
|
-
var TOOL_NAME_ALIASES = {
|
|
1825
|
-
agent: "Agent",
|
|
1826
|
-
ask_user_question: "AskUserQuestion",
|
|
1827
|
-
bash: "Bash",
|
|
1828
|
-
bg_bash: "BgBash",
|
|
1829
|
-
edit: "Edit",
|
|
1830
|
-
exit_plan_mode: "ExitPlanMode",
|
|
1831
|
-
file_edit: "Edit",
|
|
1832
|
-
file_read: "Read",
|
|
1833
|
-
file_write: "Write",
|
|
1834
|
-
finish_task: "FinishTask",
|
|
1835
|
-
glob: "Glob",
|
|
1836
|
-
grep: "Grep",
|
|
1837
|
-
kb_search: "KbSearch",
|
|
1838
|
-
ls: "Ls",
|
|
1839
|
-
multi_edit: "MultiEdit",
|
|
1840
|
-
read: "Read",
|
|
1841
|
-
read_skill: "ReadSkill",
|
|
1842
|
-
web_fetch: "WebFetch",
|
|
1843
|
-
web_search: "WebSearch",
|
|
1844
|
-
write: "Write"
|
|
1845
|
-
};
|
|
1846
|
-
var TOOL_DISPLAY_LABELS = {
|
|
1847
|
-
Bash: "\u6267\u884C\u547D\u4EE4",
|
|
1848
|
-
BgBash: "\u540E\u53F0\u6267\u884C\u547D\u4EE4",
|
|
1849
|
-
Read: "\u8BFB\u53D6\u6587\u4EF6",
|
|
1850
|
-
Write: "\u5199\u5165\u6587\u4EF6",
|
|
1851
|
-
Edit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1852
|
-
MultiEdit: "\u7F16\u8F91\u6587\u4EF6",
|
|
1853
|
-
Ls: "\u5217\u51FA\u76EE\u5F55",
|
|
1854
|
-
Glob: "\u5339\u914D\u6587\u4EF6",
|
|
1855
|
-
Grep: "\u641C\u7D22\u6587\u672C",
|
|
1856
|
-
KbSearch: "\u68C0\u7D22\u77E5\u8BC6\u5E93",
|
|
1857
|
-
WebSearch: "\u641C\u7D22\u7F51\u9875",
|
|
1858
|
-
WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
|
|
1859
|
-
Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
|
|
1860
|
-
AskUserQuestion: "\u5411\u7528\u6237\u63D0\u95EE",
|
|
1861
|
-
ReadSkill: "\u8BFB\u53D6\u6280\u80FD",
|
|
1862
|
-
FinishTask: "\u4EFB\u52A1\u5B8C\u6210",
|
|
1863
|
-
ExitPlanMode: "\u63D0\u4EA4\u8BA1\u5212",
|
|
1864
|
-
ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
|
|
1865
|
-
GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
|
|
1866
|
-
};
|
|
1867
|
-
function safeParseJson(value) {
|
|
1868
|
-
if (!value) return null;
|
|
1869
|
-
try {
|
|
1870
|
-
return JSON.parse(value);
|
|
1871
|
-
} catch {
|
|
1872
|
-
return null;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
function getStringArgValue(args, key) {
|
|
1876
|
-
const value = args?.[key];
|
|
1877
|
-
return typeof value === "string" ? value.trim() : "";
|
|
1878
|
-
}
|
|
1879
|
-
var SKILL_ENTRY_FILE_NAMES = /* @__PURE__ */ new Set(["skill.md", "command.md"]);
|
|
1880
|
-
var NON_SKILL_DIR_NAMES = /* @__PURE__ */ new Set([".", "..", ".agent", ".agents", ".claude", "skill_data", "skills"]);
|
|
1881
|
-
function getSkillNameFromFilePath(filePath) {
|
|
1882
|
-
if (!filePath) return null;
|
|
1883
|
-
const segments = filePath.split(/[\\/]+/).filter(Boolean);
|
|
1884
|
-
const fileName = segments.pop();
|
|
1885
|
-
if (!fileName || !SKILL_ENTRY_FILE_NAMES.has(fileName.toLowerCase())) return null;
|
|
1886
|
-
const dirName = segments.pop();
|
|
1887
|
-
if (!dirName || NON_SKILL_DIR_NAMES.has(dirName.toLowerCase())) return null;
|
|
1888
|
-
return dirName;
|
|
1889
|
-
}
|
|
1890
|
-
function formatToolName(name) {
|
|
1891
|
-
const trimmed = name.trim();
|
|
1892
|
-
if (!trimmed) return name;
|
|
1893
|
-
const stripped = trimmed.split(":").pop()?.split("/").pop()?.split(".").pop()?.trim() || trimmed;
|
|
1894
|
-
const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
1895
|
-
return TOOL_NAME_ALIASES[normalized] ?? stripped;
|
|
1896
|
-
}
|
|
1897
|
-
function getToolDisplayLabel(toolCall) {
|
|
1898
|
-
const normalized = formatToolName(toolCall.name);
|
|
1899
|
-
const args = safeParseJson(toolCall.arguments);
|
|
1900
|
-
const displayName = toolCall.display_name?.trim() ?? "";
|
|
1901
|
-
const baseLabel = displayName || TOOL_DISPLAY_LABELS[normalized] || normalized;
|
|
1902
|
-
const metaDisplayName = getStringArgValue(args, "_meta_display_name");
|
|
1903
|
-
if (metaDisplayName) {
|
|
1904
|
-
return metaDisplayName;
|
|
1905
|
-
}
|
|
1906
|
-
const description = getStringArgValue(args, "description");
|
|
1907
|
-
if (normalized === "BgBash") {
|
|
1908
|
-
return description ? `\u540E\u53F0\u6267\u884C\uFF1A${description}` : "\u540E\u53F0\u6267\u884C\u547D\u4EE4";
|
|
1909
|
-
}
|
|
1910
|
-
if (normalized === "ReadSkill") {
|
|
1911
|
-
const skillName = getStringArgValue(args, "skill") || getStringArgValue(args, "skill_name");
|
|
1912
|
-
return skillName ? `${baseLabel}\u300C${skillName}\u300D` : baseLabel;
|
|
1913
|
-
}
|
|
1914
|
-
if (normalized === "Read") {
|
|
1915
|
-
const skillName = getSkillNameFromFilePath(
|
|
1916
|
-
getStringArgValue(args, "file_path") || getStringArgValue(args, "path")
|
|
1917
|
-
);
|
|
1918
|
-
if (skillName) return `\u8BFB\u53D6\u6280\u80FD\u300C${skillName}\u300D`;
|
|
1919
|
-
}
|
|
1920
|
-
if (normalized === "FinishTask") {
|
|
1921
|
-
const title = getStringArgValue(args, "title");
|
|
1922
|
-
return title ? `${baseLabel}\uFF1A${title}` : baseLabel;
|
|
1923
|
-
}
|
|
1924
|
-
return description || baseLabel;
|
|
1925
|
-
}
|
|
1926
|
-
function getToolTone(status) {
|
|
1927
|
-
if (status === "error" || status === "cancelled") return "red";
|
|
1928
|
-
if (status === "awaiting_answer") return "amber";
|
|
1929
|
-
if (status === "pending") return "blue";
|
|
1930
|
-
return "emerald";
|
|
1931
|
-
}
|
|
1932
|
-
function getToolStatusLabel(status) {
|
|
1933
|
-
if (status === "pending") return "\u8FD0\u884C\u4E2D";
|
|
1934
|
-
if (status === "awaiting_answer") return "\u7B49\u5F85\u56DE\u7B54";
|
|
1935
|
-
if (status === "error") return "\u9519\u8BEF";
|
|
1936
|
-
if (status === "cancelled") return "\u5DF2\u53D6\u6D88";
|
|
1937
|
-
return "\u5B8C\u6210";
|
|
1938
|
-
}
|
|
1939
|
-
function formatToolDuration(ms) {
|
|
1940
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
1941
|
-
const seconds = ms / 1e3;
|
|
1942
|
-
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
1943
|
-
const minutes = Math.floor(seconds / 60);
|
|
1944
|
-
const remainingSeconds = Math.round(seconds % 60);
|
|
1945
|
-
return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
|
|
1946
|
-
}
|
|
1947
|
-
function formatToolArgs(args) {
|
|
1948
|
-
try {
|
|
1949
|
-
return JSON.stringify(JSON.parse(args), null, 2);
|
|
1950
|
-
} catch {
|
|
1951
|
-
return args;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
var RESULT_PREVIEW_LIMIT = 4e3;
|
|
1955
|
-
function formatToolResult(result) {
|
|
1956
|
-
const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1957
|
-
if (text == null) return "";
|
|
1958
|
-
if (text.length <= RESULT_PREVIEW_LIMIT) return text;
|
|
1959
|
-
return `${text.slice(0, RESULT_PREVIEW_LIMIT)}
|
|
1960
|
-
\u2026\uFF08\u7ED3\u679C\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF09`;
|
|
1961
|
-
}
|
|
2203
|
+
import { useEffect as useEffect9, useRef as useRef10, useState as useState11 } from "react";
|
|
1962
2204
|
|
|
1963
2205
|
// src/components/AgentLoopBlock.tsx
|
|
1964
|
-
import {
|
|
2206
|
+
import { useState as useState7 } from "react";
|
|
2207
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1965
2208
|
function parseAgentDescription(argumentsJson) {
|
|
1966
2209
|
try {
|
|
1967
2210
|
const parsed = JSON.parse(argumentsJson);
|
|
@@ -1971,7 +2214,7 @@ function parseAgentDescription(argumentsJson) {
|
|
|
1971
2214
|
}
|
|
1972
2215
|
}
|
|
1973
2216
|
function AgentLoopBlock({ toolCall }) {
|
|
1974
|
-
const [expanded, setExpanded] =
|
|
2217
|
+
const [expanded, setExpanded] = useState7(false);
|
|
1975
2218
|
const description = parseAgentDescription(toolCall.arguments);
|
|
1976
2219
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
1977
2220
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
@@ -1980,8 +2223,8 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1980
2223
|
"size-3.5 shrink-0",
|
|
1981
2224
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
1982
2225
|
);
|
|
1983
|
-
return /* @__PURE__ */
|
|
1984
|
-
/* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ jsxs6("div", { className: "blade-chat-agent-loop text-xs leading-[22px]", children: [
|
|
2227
|
+
/* @__PURE__ */ jsxs6(
|
|
1985
2228
|
"button",
|
|
1986
2229
|
{
|
|
1987
2230
|
type: "button",
|
|
@@ -1996,12 +2239,12 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1996
2239
|
),
|
|
1997
2240
|
title: `\u5B50\u4EFB\u52A1\uFF1A${description}`,
|
|
1998
2241
|
children: [
|
|
1999
|
-
running ? /* @__PURE__ */
|
|
2000
|
-
/* @__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: [
|
|
2001
2244
|
"\u5B50\u4EFB\u52A1\uFF1A",
|
|
2002
2245
|
description
|
|
2003
2246
|
] }),
|
|
2004
|
-
hasResult ? /* @__PURE__ */
|
|
2247
|
+
hasResult ? /* @__PURE__ */ jsx7(
|
|
2005
2248
|
ChevronRight,
|
|
2006
2249
|
{
|
|
2007
2250
|
size: 14,
|
|
@@ -2015,24 +2258,36 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
2015
2258
|
]
|
|
2016
2259
|
}
|
|
2017
2260
|
),
|
|
2018
|
-
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
|
|
2019
2262
|
] });
|
|
2020
2263
|
}
|
|
2021
2264
|
|
|
2022
2265
|
// src/components/MarkdownContent.tsx
|
|
2023
2266
|
import {
|
|
2024
|
-
useEffect as
|
|
2267
|
+
useEffect as useEffect7,
|
|
2025
2268
|
useMemo as useMemo5,
|
|
2026
|
-
useRef as
|
|
2027
|
-
useState as
|
|
2269
|
+
useRef as useRef8,
|
|
2270
|
+
useState as useState8
|
|
2028
2271
|
} from "react";
|
|
2029
|
-
import { jsx as
|
|
2272
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2030
2273
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
2274
|
+
function normalizeAdjacentUrlFormatting(value) {
|
|
2275
|
+
const protectedSegments = [];
|
|
2276
|
+
const protectedValue = value.replace(/(`{1,3}[\s\S]*?`{1,3}|\[[^\]]*\]\([^)]*\))/g, (segment) => {
|
|
2277
|
+
const index = protectedSegments.push(segment) - 1;
|
|
2278
|
+
return `blade-url-protected-${index}-marker`;
|
|
2279
|
+
});
|
|
2280
|
+
const normalized = protectedValue.replace(
|
|
2281
|
+
/(\*\*|__|~~|\*|_)(https?:\/\/[^\s<>]+?)\1(?=[\s。,、!?;:,.!?;:]|$)/g,
|
|
2282
|
+
(_, marker, url) => `${marker}[${url}](<${url}>)${marker}`
|
|
2283
|
+
);
|
|
2284
|
+
return normalized.replace(/blade-url-protected-(\d+)-marker/g, (_, index) => protectedSegments[Number(index)]);
|
|
2285
|
+
}
|
|
2031
2286
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
2032
|
-
const preRef =
|
|
2033
|
-
const [copied, setCopied] =
|
|
2034
|
-
const [language, setLanguage] =
|
|
2035
|
-
|
|
2287
|
+
const preRef = useRef8(null);
|
|
2288
|
+
const [copied, setCopied] = useState8(false);
|
|
2289
|
+
const [language, setLanguage] = useState8("");
|
|
2290
|
+
useEffect7(() => {
|
|
2036
2291
|
const codeEl = preRef.current?.querySelector("code");
|
|
2037
2292
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
2038
2293
|
}, []);
|
|
@@ -2043,10 +2298,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2043
2298
|
setTimeout(() => setCopied(false), 2e3);
|
|
2044
2299
|
}
|
|
2045
2300
|
};
|
|
2046
|
-
return /* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
2048
|
-
/* @__PURE__ */
|
|
2049
|
-
/* @__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(
|
|
2050
2305
|
"button",
|
|
2051
2306
|
{
|
|
2052
2307
|
type: "button",
|
|
@@ -2056,13 +2311,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2056
2311
|
copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
|
|
2057
2312
|
),
|
|
2058
2313
|
children: [
|
|
2059
|
-
copied ? /* @__PURE__ */
|
|
2060
|
-
/* @__PURE__ */
|
|
2314
|
+
copied ? /* @__PURE__ */ jsx8(Check, { size: 12 }) : /* @__PURE__ */ jsx8(Copy, { size: 12 }),
|
|
2315
|
+
/* @__PURE__ */ jsx8("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
|
|
2061
2316
|
]
|
|
2062
2317
|
}
|
|
2063
2318
|
)
|
|
2064
2319
|
] }),
|
|
2065
|
-
/* @__PURE__ */
|
|
2320
|
+
/* @__PURE__ */ jsx8(
|
|
2066
2321
|
"pre",
|
|
2067
2322
|
{
|
|
2068
2323
|
ref: preRef,
|
|
@@ -2074,7 +2329,7 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
2074
2329
|
] });
|
|
2075
2330
|
}
|
|
2076
2331
|
function ExternalAnchor({ node: _node, children, ...props }) {
|
|
2077
|
-
return /* @__PURE__ */
|
|
2332
|
+
return /* @__PURE__ */ jsx8("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
2078
2333
|
}
|
|
2079
2334
|
var MARKDOWN_COMPONENTS = {
|
|
2080
2335
|
pre: CodeBlockPre,
|
|
@@ -2082,9 +2337,9 @@ var MARKDOWN_COMPONENTS = {
|
|
|
2082
2337
|
};
|
|
2083
2338
|
function MarkdownContent({ children, className, mode, sessionId }) {
|
|
2084
2339
|
const resolvedChildren = useMemo5(() => {
|
|
2085
|
-
return children.replace(SYSTEM_REMINDER_RE, "");
|
|
2340
|
+
return normalizeAdjacentUrlFormatting(children.replace(SYSTEM_REMINDER_RE, ""));
|
|
2086
2341
|
}, [children]);
|
|
2087
|
-
return /* @__PURE__ */
|
|
2342
|
+
return /* @__PURE__ */ jsx8(
|
|
2088
2343
|
_r,
|
|
2089
2344
|
{
|
|
2090
2345
|
className: cn("blade-chat-markdown break-words", className),
|
|
@@ -2097,17 +2352,17 @@ function MarkdownContent({ children, className, mode, sessionId }) {
|
|
|
2097
2352
|
}
|
|
2098
2353
|
|
|
2099
2354
|
// src/components/Shimmer.tsx
|
|
2100
|
-
import { jsx as
|
|
2355
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2101
2356
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
2102
|
-
return /* @__PURE__ */
|
|
2357
|
+
return /* @__PURE__ */ jsx9("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
|
|
2103
2358
|
}
|
|
2104
2359
|
|
|
2105
2360
|
// src/components/ToolCallBlock.tsx
|
|
2106
|
-
import { useState as
|
|
2361
|
+
import { useState as useState10 } from "react";
|
|
2107
2362
|
|
|
2108
2363
|
// src/components/AskUserQuestionBlock.tsx
|
|
2109
|
-
import { useEffect as
|
|
2110
|
-
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";
|
|
2111
2366
|
var CUSTOM_TEXTAREA_MAX_HEIGHT = 160;
|
|
2112
2367
|
function resizeCustomTextarea(textarea) {
|
|
2113
2368
|
textarea.style.height = "auto";
|
|
@@ -2115,12 +2370,12 @@ function resizeCustomTextarea(textarea) {
|
|
|
2115
2370
|
textarea.style.overflowY = textarea.scrollHeight > CUSTOM_TEXTAREA_MAX_HEIGHT ? "auto" : "hidden";
|
|
2116
2371
|
}
|
|
2117
2372
|
function useAutoResizeTextarea(value) {
|
|
2118
|
-
const textareaRef =
|
|
2119
|
-
|
|
2373
|
+
const textareaRef = useRef9(null);
|
|
2374
|
+
useEffect8(() => {
|
|
2120
2375
|
const textarea = textareaRef.current;
|
|
2121
2376
|
if (textarea?.value === value) resizeCustomTextarea(textarea);
|
|
2122
2377
|
}, [value]);
|
|
2123
|
-
|
|
2378
|
+
useEffect8(() => {
|
|
2124
2379
|
const textarea = textareaRef.current;
|
|
2125
2380
|
if (!textarea || typeof ResizeObserver === "undefined") return;
|
|
2126
2381
|
let previousWidth = textarea.clientWidth;
|
|
@@ -2145,12 +2400,12 @@ function AskUserQuestionBlock({
|
|
|
2145
2400
|
answerData,
|
|
2146
2401
|
onAnswer
|
|
2147
2402
|
}) {
|
|
2148
|
-
const [selections, setSelections] =
|
|
2149
|
-
const [customTexts, setCustomTexts] =
|
|
2150
|
-
const [usingCustom, setUsingCustom] =
|
|
2151
|
-
const [note, setNote] =
|
|
2152
|
-
const [submitted, setSubmitted] =
|
|
2153
|
-
|
|
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(() => {
|
|
2154
2409
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
2155
2410
|
setSubmitted(false);
|
|
2156
2411
|
}
|
|
@@ -2248,7 +2503,7 @@ ${parts.join("\n")}`,
|
|
|
2248
2503
|
setSubmitted(true);
|
|
2249
2504
|
onAnswer(text, toolCallId, nextAnswerData);
|
|
2250
2505
|
};
|
|
2251
|
-
return /* @__PURE__ */
|
|
2506
|
+
return /* @__PURE__ */ jsxs8(
|
|
2252
2507
|
"div",
|
|
2253
2508
|
{
|
|
2254
2509
|
className: cn(
|
|
@@ -2256,12 +2511,12 @@ ${parts.join("\n")}`,
|
|
|
2256
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"
|
|
2257
2512
|
),
|
|
2258
2513
|
children: [
|
|
2259
|
-
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: [
|
|
2260
2515
|
"\u5B50\u667A\u80FD\u4F53\u300C",
|
|
2261
2516
|
data.source_loop.description,
|
|
2262
2517
|
"\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
|
|
2263
2518
|
] }),
|
|
2264
|
-
data.questions.map((q, qIdx) => /* @__PURE__ */
|
|
2519
|
+
data.questions.map((q, qIdx) => /* @__PURE__ */ jsx10(
|
|
2265
2520
|
QuestionCard,
|
|
2266
2521
|
{
|
|
2267
2522
|
question: q,
|
|
@@ -2276,7 +2531,7 @@ ${parts.join("\n")}`,
|
|
|
2276
2531
|
},
|
|
2277
2532
|
q.question
|
|
2278
2533
|
)),
|
|
2279
|
-
/* @__PURE__ */
|
|
2534
|
+
/* @__PURE__ */ jsx10(
|
|
2280
2535
|
NoteField,
|
|
2281
2536
|
{
|
|
2282
2537
|
answered,
|
|
@@ -2285,7 +2540,7 @@ ${parts.join("\n")}`,
|
|
|
2285
2540
|
onChange: setNote
|
|
2286
2541
|
}
|
|
2287
2542
|
),
|
|
2288
|
-
!answered && !submitted && onAnswer && /* @__PURE__ */
|
|
2543
|
+
!answered && !submitted && onAnswer && /* @__PURE__ */ jsx10(
|
|
2289
2544
|
"button",
|
|
2290
2545
|
{
|
|
2291
2546
|
type: "button",
|
|
@@ -2295,14 +2550,14 @@ ${parts.join("\n")}`,
|
|
|
2295
2550
|
children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
|
|
2296
2551
|
}
|
|
2297
2552
|
),
|
|
2298
|
-
submitted && !answered && /* @__PURE__ */
|
|
2553
|
+
submitted && !answered && /* @__PURE__ */ jsxs8(
|
|
2299
2554
|
"button",
|
|
2300
2555
|
{
|
|
2301
2556
|
type: "button",
|
|
2302
2557
|
disabled: true,
|
|
2303
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",
|
|
2304
2559
|
children: [
|
|
2305
|
-
/* @__PURE__ */
|
|
2560
|
+
/* @__PURE__ */ jsx10(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
2306
2561
|
"\u786E\u8BA4\u4E2D"
|
|
2307
2562
|
]
|
|
2308
2563
|
}
|
|
@@ -2324,30 +2579,30 @@ function QuestionCard({
|
|
|
2324
2579
|
}) {
|
|
2325
2580
|
const multi = question.multiSelect ?? false;
|
|
2326
2581
|
const customTextareaRef = useAutoResizeTextarea(customText);
|
|
2327
|
-
return /* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
/* @__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(
|
|
2330
2585
|
MessageSquareMore,
|
|
2331
2586
|
{
|
|
2332
2587
|
size: answered ? 12 : 13,
|
|
2333
2588
|
className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
|
|
2334
2589
|
}
|
|
2335
2590
|
),
|
|
2336
|
-
/* @__PURE__ */
|
|
2591
|
+
/* @__PURE__ */ jsx10(
|
|
2337
2592
|
"div",
|
|
2338
2593
|
{
|
|
2339
2594
|
className: cn(
|
|
2340
2595
|
"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
|
|
2341
2596
|
answered ? "text-xs" : "text-sm"
|
|
2342
2597
|
),
|
|
2343
|
-
children: /* @__PURE__ */
|
|
2598
|
+
children: /* @__PURE__ */ jsx10(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
2344
2599
|
}
|
|
2345
2600
|
)
|
|
2346
2601
|
] }),
|
|
2347
|
-
/* @__PURE__ */
|
|
2602
|
+
/* @__PURE__ */ jsxs8("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
|
|
2348
2603
|
question.options.map((opt, optIdx) => {
|
|
2349
2604
|
const isSel = selected.has(optIdx);
|
|
2350
|
-
return /* @__PURE__ */
|
|
2605
|
+
return /* @__PURE__ */ jsxs8(
|
|
2351
2606
|
"button",
|
|
2352
2607
|
{
|
|
2353
2608
|
type: "button",
|
|
@@ -2361,14 +2616,14 @@ function QuestionCard({
|
|
|
2361
2616
|
answered && "cursor-default opacity-70"
|
|
2362
2617
|
),
|
|
2363
2618
|
children: [
|
|
2364
|
-
multi && /* @__PURE__ */
|
|
2619
|
+
multi && /* @__PURE__ */ jsx10(
|
|
2365
2620
|
"div",
|
|
2366
2621
|
{
|
|
2367
2622
|
className: cn(
|
|
2368
2623
|
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
2369
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))]"
|
|
2370
2625
|
),
|
|
2371
|
-
children: isSel && /* @__PURE__ */
|
|
2626
|
+
children: isSel && /* @__PURE__ */ jsx10(
|
|
2372
2627
|
Check,
|
|
2373
2628
|
{
|
|
2374
2629
|
size: 9,
|
|
@@ -2377,9 +2632,9 @@ function QuestionCard({
|
|
|
2377
2632
|
)
|
|
2378
2633
|
}
|
|
2379
2634
|
),
|
|
2380
|
-
/* @__PURE__ */
|
|
2381
|
-
/* @__PURE__ */
|
|
2382
|
-
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(
|
|
2383
2638
|
"div",
|
|
2384
2639
|
{
|
|
2385
2640
|
className: cn(
|
|
@@ -2396,7 +2651,7 @@ function QuestionCard({
|
|
|
2396
2651
|
opt.label
|
|
2397
2652
|
);
|
|
2398
2653
|
}),
|
|
2399
|
-
answered && !isCustom ? null : /* @__PURE__ */
|
|
2654
|
+
answered && !isCustom ? null : /* @__PURE__ */ jsxs8(
|
|
2400
2655
|
"div",
|
|
2401
2656
|
{
|
|
2402
2657
|
className: cn(
|
|
@@ -2406,8 +2661,8 @@ function QuestionCard({
|
|
|
2406
2661
|
answered && "cursor-default opacity-70"
|
|
2407
2662
|
),
|
|
2408
2663
|
children: [
|
|
2409
|
-
/* @__PURE__ */
|
|
2410
|
-
/* @__PURE__ */
|
|
2664
|
+
/* @__PURE__ */ jsx10("span", { className: "shrink-0 pt-1 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
|
|
2665
|
+
/* @__PURE__ */ jsx10(
|
|
2411
2666
|
"textarea",
|
|
2412
2667
|
{
|
|
2413
2668
|
ref: customTextareaRef,
|
|
@@ -2439,7 +2694,7 @@ function NoteField({
|
|
|
2439
2694
|
const textareaRef = useAutoResizeTextarea(note);
|
|
2440
2695
|
const readOnly = answered || submitted;
|
|
2441
2696
|
if (answered && !note.trim()) return null;
|
|
2442
|
-
return /* @__PURE__ */
|
|
2697
|
+
return /* @__PURE__ */ jsxs8(
|
|
2443
2698
|
"label",
|
|
2444
2699
|
{
|
|
2445
2700
|
className: cn(
|
|
@@ -2449,8 +2704,8 @@ function NoteField({
|
|
|
2449
2704
|
readOnly && "cursor-default opacity-70"
|
|
2450
2705
|
),
|
|
2451
2706
|
children: [
|
|
2452
|
-
/* @__PURE__ */
|
|
2453
|
-
/* @__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(
|
|
2454
2709
|
"textarea",
|
|
2455
2710
|
{
|
|
2456
2711
|
ref: textareaRef,
|
|
@@ -2539,7 +2794,7 @@ function normalizeOptionItem(value) {
|
|
|
2539
2794
|
}
|
|
2540
2795
|
|
|
2541
2796
|
// src/components/ToolCallBlock.tsx
|
|
2542
|
-
import { Fragment, jsx as
|
|
2797
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2543
2798
|
function resolveAskQuestionState({
|
|
2544
2799
|
toolStatus,
|
|
2545
2800
|
hasAnswerData,
|
|
@@ -2561,12 +2816,12 @@ function ToolCallBlock({
|
|
|
2561
2816
|
isActiveQuestion,
|
|
2562
2817
|
renderer
|
|
2563
2818
|
}) {
|
|
2564
|
-
const [expanded, setExpanded] =
|
|
2819
|
+
const [expanded, setExpanded] = useState10(false);
|
|
2565
2820
|
const normalizedName = formatToolName(toolCall.name);
|
|
2566
2821
|
if (renderer) {
|
|
2567
2822
|
const custom = renderer(toolCall);
|
|
2568
2823
|
if (custom !== null && custom !== void 0) {
|
|
2569
|
-
return /* @__PURE__ */
|
|
2824
|
+
return /* @__PURE__ */ jsx11(Fragment, { children: custom });
|
|
2570
2825
|
}
|
|
2571
2826
|
}
|
|
2572
2827
|
if (normalizedName === "AskUserQuestion") {
|
|
@@ -2579,7 +2834,7 @@ function ToolCallBlock({
|
|
|
2579
2834
|
});
|
|
2580
2835
|
const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
|
|
2581
2836
|
if (askData) {
|
|
2582
|
-
return /* @__PURE__ */
|
|
2837
|
+
return /* @__PURE__ */ jsx11(
|
|
2583
2838
|
AskUserQuestionBlock,
|
|
2584
2839
|
{
|
|
2585
2840
|
data: askData,
|
|
@@ -2592,31 +2847,31 @@ function ToolCallBlock({
|
|
|
2592
2847
|
);
|
|
2593
2848
|
}
|
|
2594
2849
|
if (toolCall.status === "pending") {
|
|
2595
|
-
return /* @__PURE__ */
|
|
2596
|
-
/* @__PURE__ */
|
|
2597
|
-
/* @__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" })
|
|
2598
2853
|
] });
|
|
2599
2854
|
}
|
|
2600
2855
|
const errorDetail = parseAskUserQuestionError(
|
|
2601
2856
|
typeof toolCall.result === "string" ? toolCall.result : null
|
|
2602
2857
|
);
|
|
2603
|
-
return /* @__PURE__ */
|
|
2604
|
-
/* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
errorDetail?.detail ? /* @__PURE__ */
|
|
2607
|
-
/* @__PURE__ */
|
|
2608
|
-
/* @__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 })
|
|
2609
2864
|
] }) : null
|
|
2610
2865
|
] });
|
|
2611
2866
|
}
|
|
2612
2867
|
const tone = getToolTone(toolCall.status);
|
|
2613
2868
|
const displayName = getToolDisplayLabel(toolCall);
|
|
2614
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))]";
|
|
2615
|
-
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 });
|
|
2616
2871
|
const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
|
|
2617
|
-
return /* @__PURE__ */
|
|
2618
|
-
/* @__PURE__ */
|
|
2619
|
-
/* @__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(
|
|
2620
2875
|
"button",
|
|
2621
2876
|
{
|
|
2622
2877
|
type: "button",
|
|
@@ -2624,7 +2879,7 @@ function ToolCallBlock({
|
|
|
2624
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",
|
|
2625
2880
|
"aria-expanded": expanded,
|
|
2626
2881
|
children: [
|
|
2627
|
-
/* @__PURE__ */
|
|
2882
|
+
/* @__PURE__ */ jsx11(
|
|
2628
2883
|
ChevronRight,
|
|
2629
2884
|
{
|
|
2630
2885
|
size: 11,
|
|
@@ -2634,24 +2889,24 @@ function ToolCallBlock({
|
|
|
2634
2889
|
)
|
|
2635
2890
|
}
|
|
2636
2891
|
),
|
|
2637
|
-
/* @__PURE__ */
|
|
2892
|
+
/* @__PURE__ */ jsxs9("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
2638
2893
|
statusIcon,
|
|
2639
|
-
/* @__PURE__ */
|
|
2894
|
+
/* @__PURE__ */ jsx11("span", { children: getToolStatusLabel(toolCall.status) })
|
|
2640
2895
|
] }),
|
|
2641
|
-
/* @__PURE__ */
|
|
2896
|
+
/* @__PURE__ */ jsx11("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
|
|
2642
2897
|
]
|
|
2643
2898
|
}
|
|
2644
2899
|
),
|
|
2645
|
-
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) })
|
|
2646
2901
|
] }),
|
|
2647
|
-
expanded && /* @__PURE__ */
|
|
2648
|
-
/* @__PURE__ */
|
|
2649
|
-
/* @__PURE__ */
|
|
2650
|
-
/* @__PURE__ */
|
|
2651
|
-
/* @__PURE__ */
|
|
2652
|
-
toolCall.result != null && /* @__PURE__ */
|
|
2653
|
-
/* @__PURE__ */
|
|
2654
|
-
/* @__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) })
|
|
2655
2910
|
] })
|
|
2656
2911
|
] })
|
|
2657
2912
|
] });
|
|
@@ -2669,12 +2924,12 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
2669
2924
|
}
|
|
2670
2925
|
|
|
2671
2926
|
// src/components/AssistantTurnBlock.tsx
|
|
2672
|
-
import { jsx as
|
|
2927
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2673
2928
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
2674
|
-
const [open, setOpen] =
|
|
2929
|
+
const [open, setOpen] = useState11(false);
|
|
2675
2930
|
if (!isStreaming) return null;
|
|
2676
|
-
return /* @__PURE__ */
|
|
2677
|
-
/* @__PURE__ */
|
|
2931
|
+
return /* @__PURE__ */ jsxs10("div", { className: "blade-chat-thinking text-xs", children: [
|
|
2932
|
+
/* @__PURE__ */ jsxs10(
|
|
2678
2933
|
"button",
|
|
2679
2934
|
{
|
|
2680
2935
|
type: "button",
|
|
@@ -2682,8 +2937,8 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2682
2937
|
"aria-expanded": open,
|
|
2683
2938
|
className: "group/thinking inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
2684
2939
|
children: [
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
/* @__PURE__ */
|
|
2940
|
+
/* @__PURE__ */ jsx12(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }),
|
|
2941
|
+
/* @__PURE__ */ jsx12(
|
|
2687
2942
|
ChevronRight,
|
|
2688
2943
|
{
|
|
2689
2944
|
size: 14,
|
|
@@ -2696,7 +2951,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
2696
2951
|
]
|
|
2697
2952
|
}
|
|
2698
2953
|
),
|
|
2699
|
-
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
|
|
2700
2955
|
] });
|
|
2701
2956
|
}
|
|
2702
2957
|
function getMessageText(message) {
|
|
@@ -2888,14 +3143,14 @@ function ExecutionToolRow({ toolCall }) {
|
|
|
2888
3143
|
"size-3.5 shrink-0",
|
|
2889
3144
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
2890
3145
|
);
|
|
2891
|
-
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" });
|
|
2892
3147
|
const rowClassName = cn(
|
|
2893
3148
|
"flex min-w-0 items-center gap-1 py-1.5 text-xs leading-[22px]",
|
|
2894
3149
|
failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
|
|
2895
3150
|
);
|
|
2896
|
-
return /* @__PURE__ */
|
|
3151
|
+
return /* @__PURE__ */ jsxs10("div", { "data-testid": "execution-tool-intent", className: rowClassName, title: label, children: [
|
|
2897
3152
|
icon,
|
|
2898
|
-
/* @__PURE__ */
|
|
3153
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 truncate", children: label })
|
|
2899
3154
|
] });
|
|
2900
3155
|
}
|
|
2901
3156
|
function AssistantTurnBlock({
|
|
@@ -2905,8 +3160,15 @@ function AssistantTurnBlock({
|
|
|
2905
3160
|
onAnswer,
|
|
2906
3161
|
sessionStatus,
|
|
2907
3162
|
toolCallRenderer,
|
|
3163
|
+
hidePlanUpdateTools = false,
|
|
2908
3164
|
sessionId
|
|
2909
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
|
+
};
|
|
2910
3172
|
const hasInterrupted = messages.some((message) => message.status === "interrupted");
|
|
2911
3173
|
const hasFailedWithoutContent = messages.some(
|
|
2912
3174
|
(message) => message.status === "failed" && !hasRenderableMessageContent(message)
|
|
@@ -2916,16 +3178,16 @@ function AssistantTurnBlock({
|
|
|
2916
3178
|
const finalOrderedParts = finalMessage ? getOrderedMessageParts(
|
|
2917
3179
|
finalMessage,
|
|
2918
3180
|
(finalMessage.tool_calls ?? []).filter(
|
|
2919
|
-
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
3181
|
+
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !shouldHideToolCall(finalMessage, toolCall)
|
|
2920
3182
|
)
|
|
2921
3183
|
) : [];
|
|
2922
3184
|
const hasExecutionProcess = messages.some(
|
|
2923
|
-
(message) => message.reasoning || (message.tool_calls
|
|
3185
|
+
(message) => message.reasoning || (message.tool_calls ?? []).some((toolCall) => !shouldHideToolCall(message, toolCall))
|
|
2924
3186
|
);
|
|
2925
3187
|
const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
|
|
2926
3188
|
const hasActionableToolCall = messages.some(
|
|
2927
3189
|
(message) => message.status === "failed" || message.status === "interrupted" || (message.tool_calls ?? []).some(
|
|
2928
|
-
(toolCall) => toolCall.status === "error" || toolCall.status === "cancelled"
|
|
3190
|
+
(toolCall) => !shouldHideToolCall(message, toolCall) && (toolCall.status === "error" || toolCall.status === "cancelled")
|
|
2929
3191
|
)
|
|
2930
3192
|
);
|
|
2931
3193
|
const questionToolCalls = messages.flatMap(
|
|
@@ -2934,12 +3196,12 @@ function AssistantTurnBlock({
|
|
|
2934
3196
|
)
|
|
2935
3197
|
);
|
|
2936
3198
|
const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
|
|
2937
|
-
const [displayMode, setDisplayMode] =
|
|
3199
|
+
const [displayMode, setDisplayMode] = useState11(
|
|
2938
3200
|
() => isStreaming || hasActionableToolCall ? "detail" : "compact"
|
|
2939
3201
|
);
|
|
2940
|
-
const userSelectedDisplayModeRef =
|
|
2941
|
-
const wasStreamingRef =
|
|
2942
|
-
|
|
3202
|
+
const userSelectedDisplayModeRef = useRef10(false);
|
|
3203
|
+
const wasStreamingRef = useRef10(isStreaming);
|
|
3204
|
+
useEffect9(() => {
|
|
2943
3205
|
if (wasStreamingRef.current && !isStreaming && !userSelectedDisplayModeRef.current) {
|
|
2944
3206
|
setDisplayMode(hasActionableToolCall ? "detail" : "compact");
|
|
2945
3207
|
}
|
|
@@ -2947,11 +3209,11 @@ function AssistantTurnBlock({
|
|
|
2947
3209
|
}, [hasActionableToolCall, isStreaming]);
|
|
2948
3210
|
const effectiveMode = resolveTurnDisplayMode({ isStreaming, displayMode });
|
|
2949
3211
|
const executionDurationMs = getExecutionDurationMs({ messages, isStreaming });
|
|
2950
|
-
const [clock, setClock] =
|
|
3212
|
+
const [clock, setClock] = useState11(() => Date.now());
|
|
2951
3213
|
const hasLiveStartTime = messages.some(
|
|
2952
3214
|
(message) => message.timestamp != null && Number.isFinite(Date.parse(message.timestamp))
|
|
2953
3215
|
);
|
|
2954
|
-
|
|
3216
|
+
useEffect9(() => {
|
|
2955
3217
|
if (!isStreaming || !hasLiveStartTime) return;
|
|
2956
3218
|
const timer = window.setInterval(() => setClock(Date.now()), 1e3);
|
|
2957
3219
|
return () => window.clearInterval(timer);
|
|
@@ -2959,21 +3221,21 @@ function AssistantTurnBlock({
|
|
|
2959
3221
|
const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({ messages, isStreaming, now: clock }) : executionDurationMs;
|
|
2960
3222
|
const memoryRefs = collectMemoryRefs(messages);
|
|
2961
3223
|
if (!hasExecutionProcess) {
|
|
2962
|
-
return /* @__PURE__ */
|
|
3224
|
+
return /* @__PURE__ */ jsxs10(
|
|
2963
3225
|
"div",
|
|
2964
3226
|
{
|
|
2965
3227
|
"aria-busy": isStreaming || void 0,
|
|
2966
3228
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
2967
3229
|
children: [
|
|
2968
|
-
memoryRefs.length > 0 ? /* @__PURE__ */
|
|
2969
|
-
hasInterrupted && /* @__PURE__ */
|
|
2970
|
-
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" }),
|
|
2971
3233
|
messages.map((message, index) => {
|
|
2972
|
-
return hasRenderableMessageContent(message) ? /* @__PURE__ */
|
|
3234
|
+
return hasRenderableMessageContent(message) ? /* @__PURE__ */ jsx12(
|
|
2973
3235
|
"div",
|
|
2974
3236
|
{
|
|
2975
3237
|
className: "flex flex-col gap-3",
|
|
2976
|
-
children: /* @__PURE__ */
|
|
3238
|
+
children: /* @__PURE__ */ jsx12(
|
|
2977
3239
|
AssistantMessageContent,
|
|
2978
3240
|
{
|
|
2979
3241
|
message,
|
|
@@ -2989,26 +3251,26 @@ function AssistantTurnBlock({
|
|
|
2989
3251
|
}
|
|
2990
3252
|
);
|
|
2991
3253
|
}
|
|
2992
|
-
return /* @__PURE__ */
|
|
3254
|
+
return /* @__PURE__ */ jsxs10(
|
|
2993
3255
|
"div",
|
|
2994
3256
|
{
|
|
2995
3257
|
"aria-busy": isStreaming || void 0,
|
|
2996
3258
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
2997
3259
|
children: [
|
|
2998
|
-
memoryRefs.length > 0 ? /* @__PURE__ */
|
|
2999
|
-
hasInterrupted && /* @__PURE__ */
|
|
3000
|
-
hasFailedWithoutContent && /* @__PURE__ */
|
|
3001
|
-
/* @__PURE__ */
|
|
3002
|
-
/* @__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(
|
|
3003
3265
|
"span",
|
|
3004
3266
|
{
|
|
3005
3267
|
className: "grid size-[30px] shrink-0 place-items-center rounded-full bg-[hsl(var(--muted)/0.55)] text-[hsl(var(--foreground))]",
|
|
3006
3268
|
"aria-hidden": "true",
|
|
3007
|
-
children: /* @__PURE__ */
|
|
3269
|
+
children: /* @__PURE__ */ jsx12(Bot, { size: 16 })
|
|
3008
3270
|
}
|
|
3009
3271
|
),
|
|
3010
|
-
/* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
3272
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
3273
|
+
/* @__PURE__ */ jsxs10(
|
|
3012
3274
|
"button",
|
|
3013
3275
|
{
|
|
3014
3276
|
type: "button",
|
|
@@ -3021,14 +3283,14 @@ function AssistantTurnBlock({
|
|
|
3021
3283
|
"data-testid": "assistant-execution-summary",
|
|
3022
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",
|
|
3023
3285
|
children: [
|
|
3024
|
-
/* @__PURE__ */
|
|
3286
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 truncate", children: executionSummaryLabel({
|
|
3025
3287
|
messages,
|
|
3026
3288
|
isStreaming,
|
|
3027
3289
|
durationMs: liveExecutionDurationMs,
|
|
3028
3290
|
sessionStatus,
|
|
3029
3291
|
askAnswers
|
|
3030
3292
|
}) }),
|
|
3031
|
-
/* @__PURE__ */
|
|
3293
|
+
/* @__PURE__ */ jsx12(
|
|
3032
3294
|
ChevronRight,
|
|
3033
3295
|
{
|
|
3034
3296
|
size: 14,
|
|
@@ -3042,26 +3304,26 @@ function AssistantTurnBlock({
|
|
|
3042
3304
|
]
|
|
3043
3305
|
}
|
|
3044
3306
|
),
|
|
3045
|
-
/* @__PURE__ */
|
|
3307
|
+
/* @__PURE__ */ jsx12("div", { className: "mt-3 h-px w-full bg-[hsl(var(--border)/0.75)]" })
|
|
3046
3308
|
] })
|
|
3047
3309
|
] }),
|
|
3048
|
-
effectiveMode === "detail" ? /* @__PURE__ */
|
|
3310
|
+
effectiveMode === "detail" ? /* @__PURE__ */ jsx12("div", { className: "ml-10 flex flex-col gap-3 pt-1", children: messages.map((message, index) => {
|
|
3049
3311
|
const isLast = index === messages.length - 1;
|
|
3050
3312
|
const streamingThis = isStreaming && isLast;
|
|
3051
3313
|
const text = getMessageText(message);
|
|
3052
3314
|
const toolCalls = (message.tool_calls ?? []).filter(
|
|
3053
|
-
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
3315
|
+
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !shouldHideToolCall(message, toolCall)
|
|
3054
3316
|
);
|
|
3055
3317
|
const orderedParts = getOrderedMessageParts(message, toolCalls);
|
|
3056
3318
|
const showReasoning = !!message.reasoning && isStreaming && index === latestReasoningIndex;
|
|
3057
|
-
return /* @__PURE__ */
|
|
3319
|
+
return /* @__PURE__ */ jsxs10(
|
|
3058
3320
|
"div",
|
|
3059
3321
|
{
|
|
3060
3322
|
className: "flex flex-col gap-3",
|
|
3061
3323
|
children: [
|
|
3062
|
-
showReasoning && message.reasoning ? /* @__PURE__ */
|
|
3324
|
+
showReasoning && message.reasoning ? /* @__PURE__ */ jsx12(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
|
|
3063
3325
|
orderedParts.length > 0 ? orderedParts.map(
|
|
3064
|
-
(part) => part.type === "text" ? /* @__PURE__ */
|
|
3326
|
+
(part) => part.type === "text" ? /* @__PURE__ */ jsx12(
|
|
3065
3327
|
AssistantMessageContent,
|
|
3066
3328
|
{
|
|
3067
3329
|
message: { ...message, content: part.content, tool_calls: turnToolCalls },
|
|
@@ -3070,11 +3332,11 @@ function AssistantTurnBlock({
|
|
|
3070
3332
|
compact: true
|
|
3071
3333
|
},
|
|
3072
3334
|
part.key
|
|
3073
|
-
) : /* @__PURE__ */
|
|
3335
|
+
) : /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-0.5", children: part.toolCalls.map((toolCall) => {
|
|
3074
3336
|
const custom = toolCallRenderer?.(toolCall);
|
|
3075
|
-
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);
|
|
3076
3338
|
}) }, part.key)
|
|
3077
|
-
) : hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */
|
|
3339
|
+
) : hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx12(
|
|
3078
3340
|
AssistantMessageContent,
|
|
3079
3341
|
{
|
|
3080
3342
|
message,
|
|
@@ -3083,16 +3345,16 @@ function AssistantTurnBlock({
|
|
|
3083
3345
|
compact: true
|
|
3084
3346
|
}
|
|
3085
3347
|
) : null,
|
|
3086
|
-
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) => {
|
|
3087
3349
|
const custom = toolCallRenderer?.(toolCall);
|
|
3088
|
-
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);
|
|
3089
3351
|
}) }) : null
|
|
3090
3352
|
]
|
|
3091
3353
|
},
|
|
3092
3354
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
3093
3355
|
);
|
|
3094
3356
|
}) }) : null,
|
|
3095
|
-
finalMessage && (effectiveMode === "compact" || finalOrderedParts.length === 0) ? /* @__PURE__ */
|
|
3357
|
+
finalMessage && (effectiveMode === "compact" || finalOrderedParts.length === 0) ? /* @__PURE__ */ jsx12("div", { className: "ml-10", children: /* @__PURE__ */ jsx12(
|
|
3096
3358
|
AssistantMessageContent,
|
|
3097
3359
|
{
|
|
3098
3360
|
message: finalMessage,
|
|
@@ -3100,7 +3362,7 @@ function AssistantTurnBlock({
|
|
|
3100
3362
|
streaming: isStreaming && finalMessage === messages[messages.length - 1]
|
|
3101
3363
|
}
|
|
3102
3364
|
) }) : null,
|
|
3103
|
-
questionToolCalls.map((toolCall) => /* @__PURE__ */
|
|
3365
|
+
questionToolCalls.map((toolCall) => /* @__PURE__ */ jsx12(
|
|
3104
3366
|
ToolCallBlock,
|
|
3105
3367
|
{
|
|
3106
3368
|
toolCall,
|
|
@@ -3125,22 +3387,22 @@ function collectMemoryRefs(messages) {
|
|
|
3125
3387
|
return [...refs.values()];
|
|
3126
3388
|
}
|
|
3127
3389
|
function MemoryRefsHint({ refs }) {
|
|
3128
|
-
const [expanded, setExpanded] =
|
|
3390
|
+
const [expanded, setExpanded] = useState11(false);
|
|
3129
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";
|
|
3130
|
-
return /* @__PURE__ */
|
|
3131
|
-
/* @__PURE__ */
|
|
3132
|
-
/* @__PURE__ */
|
|
3133
|
-
/* @__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: [
|
|
3134
3396
|
label,
|
|
3135
3397
|
"\uFF08",
|
|
3136
3398
|
refs.length,
|
|
3137
3399
|
"\uFF09"
|
|
3138
3400
|
] }),
|
|
3139
|
-
/* @__PURE__ */
|
|
3401
|
+
/* @__PURE__ */ jsx12(ChevronRight, { size: 10, className: cn("transition-transform", expanded && "rotate-90") })
|
|
3140
3402
|
] }),
|
|
3141
|
-
expanded ? /* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3143
|
-
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
|
|
3144
3406
|
] }, ref.id)) }) : null
|
|
3145
3407
|
] });
|
|
3146
3408
|
}
|
|
@@ -3154,15 +3416,15 @@ function AssistantMessageContent({
|
|
|
3154
3416
|
const imageParts = getImageParts(message.content);
|
|
3155
3417
|
const fileParts = getFileParts(message.content);
|
|
3156
3418
|
const failed = message.status === "failed";
|
|
3157
|
-
const failedBadge = failed ? /* @__PURE__ */
|
|
3158
|
-
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(
|
|
3159
3421
|
"div",
|
|
3160
3422
|
{
|
|
3161
3423
|
className: cn(
|
|
3162
3424
|
"blade-chat-assistant-text",
|
|
3163
3425
|
compact ? "text-xs leading-[22px] text-[hsl(var(--foreground))]" : "text-[15px] leading-8 text-[hsl(var(--foreground))]"
|
|
3164
3426
|
),
|
|
3165
|
-
children: /* @__PURE__ */
|
|
3427
|
+
children: /* @__PURE__ */ jsx12(
|
|
3166
3428
|
MarkdownContent,
|
|
3167
3429
|
{
|
|
3168
3430
|
mode: streaming ? "streaming" : "static",
|
|
@@ -3175,14 +3437,14 @@ function AssistantMessageContent({
|
|
|
3175
3437
|
) : null;
|
|
3176
3438
|
if (imageParts.length === 0 && fileParts.length === 0) {
|
|
3177
3439
|
if (!failed) return textContent;
|
|
3178
|
-
return failedBadge || textContent ? /* @__PURE__ */
|
|
3440
|
+
return failedBadge || textContent ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
|
|
3179
3441
|
failedBadge,
|
|
3180
3442
|
textContent
|
|
3181
3443
|
] }) : null;
|
|
3182
3444
|
}
|
|
3183
|
-
return /* @__PURE__ */
|
|
3445
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-3", children: [
|
|
3184
3446
|
failedBadge,
|
|
3185
|
-
imageParts.length > 0 ? /* @__PURE__ */
|
|
3447
|
+
imageParts.length > 0 ? /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
|
|
3186
3448
|
"img",
|
|
3187
3449
|
{
|
|
3188
3450
|
src: part.image_url.url,
|
|
@@ -3191,14 +3453,14 @@ function AssistantMessageContent({
|
|
|
3191
3453
|
},
|
|
3192
3454
|
part.image_url.url
|
|
3193
3455
|
)) }) : null,
|
|
3194
|
-
fileParts.length > 0 ? /* @__PURE__ */
|
|
3456
|
+
fileParts.length > 0 ? /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
|
|
3195
3457
|
"div",
|
|
3196
3458
|
{
|
|
3197
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))]",
|
|
3198
3460
|
title: part.name,
|
|
3199
3461
|
children: [
|
|
3200
|
-
/* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3462
|
+
/* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
|
|
3463
|
+
/* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", children: part.name })
|
|
3202
3464
|
]
|
|
3203
3465
|
},
|
|
3204
3466
|
`${part.name}-${part.data.slice(0, 32)}`
|
|
@@ -3209,7 +3471,7 @@ function AssistantMessageContent({
|
|
|
3209
3471
|
|
|
3210
3472
|
// src/components/RenderErrorBoundary.tsx
|
|
3211
3473
|
import { Component } from "react";
|
|
3212
|
-
import { jsx as
|
|
3474
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3213
3475
|
function getFirstComponentName(componentStack) {
|
|
3214
3476
|
const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
|
|
3215
3477
|
return match?.[1] ?? null;
|
|
@@ -3242,26 +3504,26 @@ var RenderErrorBoundary = class extends Component {
|
|
|
3242
3504
|
return children;
|
|
3243
3505
|
}
|
|
3244
3506
|
const componentName = getFirstComponentName(componentStack);
|
|
3245
|
-
return /* @__PURE__ */
|
|
3246
|
-
/* @__PURE__ */
|
|
3247
|
-
/* @__PURE__ */
|
|
3248
|
-
/* @__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: [
|
|
3249
3511
|
label,
|
|
3250
3512
|
"\u6E32\u67D3\u5931\u8D25"
|
|
3251
3513
|
] }),
|
|
3252
|
-
/* @__PURE__ */
|
|
3514
|
+
/* @__PURE__ */ jsxs11("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
|
|
3253
3515
|
componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
|
|
3254
3516
|
error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
|
|
3255
3517
|
] }),
|
|
3256
|
-
details ? /* @__PURE__ */
|
|
3518
|
+
details ? /* @__PURE__ */ jsx13("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
|
|
3257
3519
|
] })
|
|
3258
3520
|
] }) });
|
|
3259
3521
|
}
|
|
3260
3522
|
};
|
|
3261
3523
|
|
|
3262
3524
|
// src/components/PostChatFollowupBlock.tsx
|
|
3263
|
-
import { useCallback as useCallback6, useEffect as
|
|
3264
|
-
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";
|
|
3265
3527
|
function emitInteraction(callback, event) {
|
|
3266
3528
|
try {
|
|
3267
3529
|
callback?.(event);
|
|
@@ -3280,10 +3542,10 @@ function ArtifactCard({
|
|
|
3280
3542
|
onArtifactOpened
|
|
3281
3543
|
}) {
|
|
3282
3544
|
const client = useBladeClient();
|
|
3283
|
-
const [downloading, setDownloading] =
|
|
3545
|
+
const [downloading, setDownloading] = useState12(false);
|
|
3284
3546
|
const name = artifact.label || basename(artifact.target);
|
|
3285
3547
|
if (artifact.kind === "link") {
|
|
3286
|
-
return /* @__PURE__ */
|
|
3548
|
+
return /* @__PURE__ */ jsxs12(
|
|
3287
3549
|
"a",
|
|
3288
3550
|
{
|
|
3289
3551
|
href: artifact.target,
|
|
@@ -3294,9 +3556,9 @@ function ArtifactCard({
|
|
|
3294
3556
|
${artifact.target}`,
|
|
3295
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))]",
|
|
3296
3558
|
children: [
|
|
3297
|
-
/* @__PURE__ */
|
|
3298
|
-
/* @__PURE__ */
|
|
3299
|
-
/* @__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" })
|
|
3300
3562
|
]
|
|
3301
3563
|
}
|
|
3302
3564
|
);
|
|
@@ -3331,7 +3593,7 @@ ${artifact.target}`,
|
|
|
3331
3593
|
setDownloading(false);
|
|
3332
3594
|
}
|
|
3333
3595
|
};
|
|
3334
|
-
return /* @__PURE__ */
|
|
3596
|
+
return /* @__PURE__ */ jsx14(
|
|
3335
3597
|
"a",
|
|
3336
3598
|
{
|
|
3337
3599
|
href: downloadUrl,
|
|
@@ -3359,17 +3621,17 @@ function feedbackReasonLabel(reason) {
|
|
|
3359
3621
|
}
|
|
3360
3622
|
function HistoricalResultFeedback({ feedback }) {
|
|
3361
3623
|
const label = feedbackReasonLabel(feedback.reason);
|
|
3362
|
-
return /* @__PURE__ */
|
|
3624
|
+
return /* @__PURE__ */ jsxs12(
|
|
3363
3625
|
"section",
|
|
3364
3626
|
{
|
|
3365
3627
|
"aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
|
|
3366
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))]",
|
|
3367
3629
|
children: [
|
|
3368
|
-
/* @__PURE__ */
|
|
3630
|
+
/* @__PURE__ */ jsxs12("span", { children: [
|
|
3369
3631
|
"\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
|
|
3370
3632
|
feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
|
|
3371
3633
|
] }),
|
|
3372
|
-
label ? /* @__PURE__ */
|
|
3634
|
+
label ? /* @__PURE__ */ jsxs12("span", { children: [
|
|
3373
3635
|
" \xB7 ",
|
|
3374
3636
|
label
|
|
3375
3637
|
] }) : null
|
|
@@ -3386,15 +3648,15 @@ function ResultFeedback({
|
|
|
3386
3648
|
onFeedbackSaved
|
|
3387
3649
|
}) {
|
|
3388
3650
|
const client = useBladeClient();
|
|
3389
|
-
const [saved, setSaved] =
|
|
3390
|
-
const [helpful, setHelpful] =
|
|
3391
|
-
const [reason, setReason] =
|
|
3392
|
-
const [saving, setSaving] =
|
|
3393
|
-
const [saveError, setSaveError] =
|
|
3394
|
-
const reportedShown =
|
|
3395
|
-
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);
|
|
3396
3658
|
const eligible = followup.feedback_eligible === true && Boolean(sessionId) && !isViewer;
|
|
3397
|
-
|
|
3659
|
+
useEffect10(() => {
|
|
3398
3660
|
if (!eligible || reportedShown.current) return;
|
|
3399
3661
|
reportedShown.current = true;
|
|
3400
3662
|
emitInteraction(onInteraction, {
|
|
@@ -3403,7 +3665,7 @@ function ResultFeedback({
|
|
|
3403
3665
|
assistantEntryId: followup.assistant_entry_id
|
|
3404
3666
|
});
|
|
3405
3667
|
}, [eligible, followup.assistant_entry_id, onInteraction, sessionId]);
|
|
3406
|
-
|
|
3668
|
+
useEffect10(() => {
|
|
3407
3669
|
if (!savedFeedback || latestChoice.current) return;
|
|
3408
3670
|
setSaved(savedFeedback);
|
|
3409
3671
|
setHelpful(savedFeedback.helpful);
|
|
@@ -3444,15 +3706,15 @@ function ResultFeedback({
|
|
|
3444
3706
|
[client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
|
|
3445
3707
|
);
|
|
3446
3708
|
if (!eligible) return null;
|
|
3447
|
-
return /* @__PURE__ */
|
|
3709
|
+
return /* @__PURE__ */ jsxs12(
|
|
3448
3710
|
"section",
|
|
3449
3711
|
{
|
|
3450
3712
|
"aria-label": "\u7ED3\u679C\u53CD\u9988",
|
|
3451
3713
|
className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
|
|
3452
3714
|
children: [
|
|
3453
|
-
/* @__PURE__ */
|
|
3454
|
-
/* @__PURE__ */
|
|
3455
|
-
/* @__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(
|
|
3456
3718
|
"button",
|
|
3457
3719
|
{
|
|
3458
3720
|
type: "button",
|
|
@@ -3463,7 +3725,7 @@ function ResultFeedback({
|
|
|
3463
3725
|
children: "\u6709\u5E2E\u52A9"
|
|
3464
3726
|
}
|
|
3465
3727
|
),
|
|
3466
|
-
/* @__PURE__ */
|
|
3728
|
+
/* @__PURE__ */ jsx14(
|
|
3467
3729
|
"button",
|
|
3468
3730
|
{
|
|
3469
3731
|
type: "button",
|
|
@@ -3475,7 +3737,7 @@ function ResultFeedback({
|
|
|
3475
3737
|
}
|
|
3476
3738
|
)
|
|
3477
3739
|
] }),
|
|
3478
|
-
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(
|
|
3479
3741
|
"button",
|
|
3480
3742
|
{
|
|
3481
3743
|
type: "button",
|
|
@@ -3487,9 +3749,9 @@ function ResultFeedback({
|
|
|
3487
3749
|
},
|
|
3488
3750
|
item.value
|
|
3489
3751
|
)) }) : null,
|
|
3490
|
-
saveError ? /* @__PURE__ */
|
|
3491
|
-
/* @__PURE__ */
|
|
3492
|
-
/* @__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(
|
|
3493
3755
|
"button",
|
|
3494
3756
|
{
|
|
3495
3757
|
type: "button",
|
|
@@ -3501,7 +3763,7 @@ function ResultFeedback({
|
|
|
3501
3763
|
children: "\u91CD\u8BD5"
|
|
3502
3764
|
}
|
|
3503
3765
|
)
|
|
3504
|
-
] }) : 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
|
|
3505
3767
|
]
|
|
3506
3768
|
}
|
|
3507
3769
|
);
|
|
@@ -3515,14 +3777,14 @@ function PostChatFollowupBlock({
|
|
|
3515
3777
|
savedFeedback,
|
|
3516
3778
|
onFeedbackSaved
|
|
3517
3779
|
}) {
|
|
3518
|
-
const [expanded, setExpanded] =
|
|
3519
|
-
const adopted =
|
|
3520
|
-
const reportedSuggestions =
|
|
3521
|
-
const reportedArtifacts =
|
|
3522
|
-
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());
|
|
3523
3785
|
const artifacts = followup.final_artifacts ?? [];
|
|
3524
3786
|
const visibleArtifacts = expanded ? artifacts : artifacts.slice(0, 3);
|
|
3525
|
-
|
|
3787
|
+
useEffect10(() => {
|
|
3526
3788
|
if (!reportedSuggestions.current && followup.suggestions.length > 0) {
|
|
3527
3789
|
reportedSuggestions.current = true;
|
|
3528
3790
|
emitInteraction(onInteraction, {
|
|
@@ -3568,15 +3830,15 @@ function PostChatFollowupBlock({
|
|
|
3568
3830
|
);
|
|
3569
3831
|
if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
|
|
3570
3832
|
return null;
|
|
3571
|
-
return /* @__PURE__ */
|
|
3572
|
-
followup.recaption || artifacts.length > 0 ? /* @__PURE__ */
|
|
3573
|
-
/* @__PURE__ */
|
|
3574
|
-
/* @__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 }),
|
|
3575
3837
|
"\u672C\u8F6E\u5C0F\u7ED3"
|
|
3576
3838
|
] }),
|
|
3577
|
-
followup.recaption ? /* @__PURE__ */
|
|
3578
|
-
artifacts.length > 0 ? /* @__PURE__ */
|
|
3579
|
-
/* @__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(
|
|
3580
3842
|
ArtifactCard,
|
|
3581
3843
|
{
|
|
3582
3844
|
artifact,
|
|
@@ -3588,7 +3850,7 @@ function PostChatFollowupBlock({
|
|
|
3588
3850
|
},
|
|
3589
3851
|
`${artifact.kind}:${artifactIndex}`
|
|
3590
3852
|
)) }),
|
|
3591
|
-
artifacts.length > 3 ? /* @__PURE__ */
|
|
3853
|
+
artifacts.length > 3 ? /* @__PURE__ */ jsxs12(
|
|
3592
3854
|
"button",
|
|
3593
3855
|
{
|
|
3594
3856
|
type: "button",
|
|
@@ -3597,15 +3859,15 @@ function PostChatFollowupBlock({
|
|
|
3597
3859
|
className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
|
|
3598
3860
|
children: [
|
|
3599
3861
|
expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
|
|
3600
|
-
/* @__PURE__ */
|
|
3862
|
+
/* @__PURE__ */ jsx14(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
|
|
3601
3863
|
]
|
|
3602
3864
|
}
|
|
3603
3865
|
) : null
|
|
3604
3866
|
] }) : null
|
|
3605
3867
|
] }) : null,
|
|
3606
|
-
followup.suggestions.length > 0 ? /* @__PURE__ */
|
|
3607
|
-
/* @__PURE__ */
|
|
3608
|
-
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(
|
|
3609
3871
|
"button",
|
|
3610
3872
|
{
|
|
3611
3873
|
type: "button",
|
|
@@ -3624,14 +3886,14 @@ function PostChatFollowupBlock({
|
|
|
3624
3886
|
},
|
|
3625
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",
|
|
3626
3888
|
children: [
|
|
3627
|
-
/* @__PURE__ */
|
|
3628
|
-
/* @__PURE__ */
|
|
3889
|
+
/* @__PURE__ */ jsx14("span", { children: suggestion }),
|
|
3890
|
+
/* @__PURE__ */ jsx14(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
|
|
3629
3891
|
]
|
|
3630
3892
|
},
|
|
3631
3893
|
suggestion
|
|
3632
3894
|
))
|
|
3633
3895
|
] }) : null,
|
|
3634
|
-
/* @__PURE__ */
|
|
3896
|
+
/* @__PURE__ */ jsx14(
|
|
3635
3897
|
ResultFeedback,
|
|
3636
3898
|
{
|
|
3637
3899
|
followup,
|
|
@@ -3652,7 +3914,85 @@ import {
|
|
|
3652
3914
|
getImageParts as getImageParts2,
|
|
3653
3915
|
getTextContent as getTextContent2
|
|
3654
3916
|
} from "@blade-hq/agent-client";
|
|
3655
|
-
|
|
3917
|
+
|
|
3918
|
+
// src/lib/whatif-prompt.ts
|
|
3919
|
+
var HEADER_RE = /^以下消息和 step 产物标记为 deprecated_by_rerun,请基于最新用户假设从 step(\d+) 开始完整重新推演,不要复用旧结论。$/;
|
|
3920
|
+
var QUOTE_HEADER_RE = /^\[步骤(\d+)\s*·\s*(.+?)\]$/;
|
|
3921
|
+
var USER_INPUT_TAG = "[\u7528\u6237\u8F93\u5165]";
|
|
3922
|
+
function parseWhatIfPrompt(text) {
|
|
3923
|
+
const lines = text.replace(/\r\n/g, "\n").trimEnd().split("\n");
|
|
3924
|
+
const headerMatch = lines[0]?.match(HEADER_RE);
|
|
3925
|
+
if (!headerMatch) return null;
|
|
3926
|
+
const userTagIdx = lines.indexOf(USER_INPUT_TAG);
|
|
3927
|
+
const hasUserTag = userTagIdx >= 0;
|
|
3928
|
+
const quoteBlockEndExclusive = hasUserTag ? userTagIdx : lines.length;
|
|
3929
|
+
const quoteHeaderIdxs = [];
|
|
3930
|
+
let quoteBlockFound = false;
|
|
3931
|
+
for (let i = 1; i < quoteBlockEndExclusive; i++) {
|
|
3932
|
+
if (!quoteBlockFound && lines[i].trim() === "[\u5F15\u7528]") {
|
|
3933
|
+
quoteBlockFound = true;
|
|
3934
|
+
} else if (quoteBlockFound && QUOTE_HEADER_RE.test(lines[i])) {
|
|
3935
|
+
quoteHeaderIdxs.push(i);
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
let legacyUserTextStart = -1;
|
|
3939
|
+
if (!hasUserTag && quoteHeaderIdxs.length > 0) {
|
|
3940
|
+
const lastSnapshotStart = quoteHeaderIdxs.at(-1) + 1;
|
|
3941
|
+
let i = lines.length - 1;
|
|
3942
|
+
while (i >= lastSnapshotStart && lines[i].trim() === "") i -= 1;
|
|
3943
|
+
while (i >= lastSnapshotStart && lines[i].trim() !== "") i -= 1;
|
|
3944
|
+
if (i >= lastSnapshotStart) legacyUserTextStart = i + 1;
|
|
3945
|
+
}
|
|
3946
|
+
const quotes = quoteHeaderIdxs.map((headerIdx, index) => {
|
|
3947
|
+
const match = lines[headerIdx].match(QUOTE_HEADER_RE);
|
|
3948
|
+
const nextHeader = quoteHeaderIdxs[index + 1];
|
|
3949
|
+
const end = nextHeader ?? (legacyUserTextStart >= 0 ? legacyUserTextStart : quoteBlockEndExclusive);
|
|
3950
|
+
const snapshotLines = lines.slice(headerIdx + 1, end);
|
|
3951
|
+
while (snapshotLines.at(-1)?.trim() === "") snapshotLines.pop();
|
|
3952
|
+
return {
|
|
3953
|
+
stepNumber: Number.parseInt(match[1], 10),
|
|
3954
|
+
label: match[2].trim(),
|
|
3955
|
+
snapshot: snapshotLines.join("\n")
|
|
3956
|
+
};
|
|
3957
|
+
});
|
|
3958
|
+
const userTextStart = hasUserTag ? userTagIdx + 1 : legacyUserTextStart;
|
|
3959
|
+
const userLines = userTextStart >= 0 ? lines.slice(userTextStart) : [];
|
|
3960
|
+
while (userLines[0]?.trim() === "") userLines.shift();
|
|
3961
|
+
while (userLines.at(-1)?.trim() === "") userLines.pop();
|
|
3962
|
+
const fromStep = Number.parseInt(headerMatch[1], 10);
|
|
3963
|
+
return {
|
|
3964
|
+
fromStep: Number.isFinite(fromStep) ? fromStep : null,
|
|
3965
|
+
quotes,
|
|
3966
|
+
userText: userLines.join("\n")
|
|
3967
|
+
};
|
|
3968
|
+
}
|
|
3969
|
+
|
|
3970
|
+
// src/components/WhatIfUserBubble.tsx
|
|
3971
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3972
|
+
function WhatIfUserBubble({ parsed, onQuoteClick }) {
|
|
3973
|
+
const { fromStep, quotes, userText } = parsed;
|
|
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" })
|
|
3978
|
+
] }),
|
|
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) => {
|
|
3980
|
+
const clickable = quote.stepNumber != null && !!onQuoteClick;
|
|
3981
|
+
const label = quote.stepNumber != null ? `\u6B65\u9AA4${quote.stepNumber} \xB7 ${quote.label}` : quote.label;
|
|
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 })
|
|
3986
|
+
] }),
|
|
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
|
|
3988
|
+
] }, `${quote.stepNumber ?? "x"}-${index}`);
|
|
3989
|
+
}) }),
|
|
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 }) })
|
|
3991
|
+
] });
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3994
|
+
// src/components/UserMessageBubble.tsx
|
|
3995
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3656
3996
|
function isUserMessage(message) {
|
|
3657
3997
|
return message.role === "user";
|
|
3658
3998
|
}
|
|
@@ -3664,8 +4004,12 @@ function UserMessageBubble({ message, className }) {
|
|
|
3664
4004
|
const text = getTextContent2(message.content).trim();
|
|
3665
4005
|
const fileParts = getFileParts2(message.content);
|
|
3666
4006
|
const imageParts = getImageParts2(message.content);
|
|
3667
|
-
|
|
3668
|
-
|
|
4007
|
+
const whatifParsed = text && imageParts.length === 0 && fileParts.length === 0 ? parseWhatIfPrompt(text) : null;
|
|
4008
|
+
if (whatifParsed) {
|
|
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 }) }) });
|
|
4010
|
+
}
|
|
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(
|
|
3669
4013
|
"img",
|
|
3670
4014
|
{
|
|
3671
4015
|
src: part.image_url.url,
|
|
@@ -3674,21 +4018,21 @@ function UserMessageBubble({ message, className }) {
|
|
|
3674
4018
|
},
|
|
3675
4019
|
part.image_url.url
|
|
3676
4020
|
)) }),
|
|
3677
|
-
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(
|
|
3678
4022
|
"div",
|
|
3679
4023
|
{
|
|
3680
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))]",
|
|
3681
4025
|
children: [
|
|
3682
|
-
/* @__PURE__ */
|
|
3683
|
-
/* @__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 })
|
|
3684
4028
|
]
|
|
3685
4029
|
},
|
|
3686
4030
|
`${part.name}-${part.data.length}`
|
|
3687
4031
|
)) }),
|
|
3688
|
-
text && /* @__PURE__ */
|
|
3689
|
-
text && isSending(message) && /* @__PURE__ */
|
|
3690
|
-
/* @__PURE__ */
|
|
3691
|
-
/* @__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" })
|
|
3692
4036
|
] })
|
|
3693
4037
|
] }) });
|
|
3694
4038
|
}
|
|
@@ -3697,11 +4041,11 @@ function ErrorMessageBlock({
|
|
|
3697
4041
|
className
|
|
3698
4042
|
}) {
|
|
3699
4043
|
const text = chatErrorForDisplay(getTextContent2(message.content));
|
|
3700
|
-
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 }) });
|
|
3701
4045
|
}
|
|
3702
4046
|
|
|
3703
4047
|
// src/components/MessageList.tsx
|
|
3704
|
-
import { jsx as
|
|
4048
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3705
4049
|
function parseModeChange(message) {
|
|
3706
4050
|
if (message.kind !== "mode_change" || typeof message.content !== "string") {
|
|
3707
4051
|
return null;
|
|
@@ -3742,6 +4086,7 @@ function MessageList({
|
|
|
3742
4086
|
askAnswers,
|
|
3743
4087
|
onAnswer,
|
|
3744
4088
|
toolCallRenderer,
|
|
4089
|
+
hidePlanUpdateTools = false,
|
|
3745
4090
|
emptyState,
|
|
3746
4091
|
className,
|
|
3747
4092
|
sessionId,
|
|
@@ -3827,23 +4172,23 @@ function MessageList({
|
|
|
3827
4172
|
}
|
|
3828
4173
|
return blocks;
|
|
3829
4174
|
}, [messages, isStreaming]);
|
|
3830
|
-
return /* @__PURE__ */
|
|
3831
|
-
isStreaming ? /* @__PURE__ */
|
|
3832
|
-
/* @__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(
|
|
3833
4178
|
StickToBottom,
|
|
3834
4179
|
{
|
|
3835
4180
|
className: "h-full overflow-y-hidden",
|
|
3836
4181
|
initial: "instant",
|
|
3837
4182
|
resize: "instant",
|
|
3838
4183
|
children: [
|
|
3839
|
-
/* @__PURE__ */
|
|
3840
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
3841
|
-
/* @__PURE__ */
|
|
3842
|
-
/* @__PURE__ */
|
|
3843
|
-
/* @__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" })
|
|
3844
4189
|
] }) : renderBlocks.map((block) => {
|
|
3845
4190
|
if (block.type === "message") {
|
|
3846
|
-
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);
|
|
3847
4192
|
}
|
|
3848
4193
|
if (block.type === "assistant_turn") {
|
|
3849
4194
|
const blockFeedback = block.messages.map(
|
|
@@ -3854,14 +4199,14 @@ function MessageList({
|
|
|
3854
4199
|
(message) => message.entry_id === postChatFollowup.assistant_entry_id
|
|
3855
4200
|
)
|
|
3856
4201
|
);
|
|
3857
|
-
return /* @__PURE__ */
|
|
4202
|
+
return /* @__PURE__ */ jsx17("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs15(
|
|
3858
4203
|
RenderErrorBoundary,
|
|
3859
4204
|
{
|
|
3860
4205
|
label: "\u52A9\u624B\u6D88\u606F",
|
|
3861
4206
|
details: block.key,
|
|
3862
4207
|
resetKey: getMessageResetSignature(block.messages),
|
|
3863
4208
|
children: [
|
|
3864
|
-
/* @__PURE__ */
|
|
4209
|
+
/* @__PURE__ */ jsx17(
|
|
3865
4210
|
AssistantTurnBlock,
|
|
3866
4211
|
{
|
|
3867
4212
|
messages: block.messages,
|
|
@@ -3870,11 +4215,12 @@ function MessageList({
|
|
|
3870
4215
|
onAnswer,
|
|
3871
4216
|
sessionStatus,
|
|
3872
4217
|
toolCallRenderer,
|
|
4218
|
+
hidePlanUpdateTools,
|
|
3873
4219
|
sessionId
|
|
3874
4220
|
}
|
|
3875
4221
|
),
|
|
3876
|
-
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */
|
|
3877
|
-
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */
|
|
4222
|
+
blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx17(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
|
|
4223
|
+
hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx17(
|
|
3878
4224
|
PostChatFollowupBlock,
|
|
3879
4225
|
{
|
|
3880
4226
|
followup: postChatFollowup,
|
|
@@ -3891,23 +4237,23 @@ function MessageList({
|
|
|
3891
4237
|
) }, block.key);
|
|
3892
4238
|
}
|
|
3893
4239
|
if (block.type === "compaction") {
|
|
3894
|
-
return /* @__PURE__ */
|
|
4240
|
+
return /* @__PURE__ */ jsxs15(
|
|
3895
4241
|
"div",
|
|
3896
4242
|
{
|
|
3897
4243
|
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
3898
4244
|
children: [
|
|
3899
|
-
/* @__PURE__ */
|
|
3900
|
-
/* @__PURE__ */
|
|
4245
|
+
/* @__PURE__ */ jsx17(Layers, { size: 12 }),
|
|
4246
|
+
/* @__PURE__ */ jsx17("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
3901
4247
|
]
|
|
3902
4248
|
},
|
|
3903
4249
|
block.key
|
|
3904
4250
|
);
|
|
3905
4251
|
}
|
|
3906
|
-
return /* @__PURE__ */
|
|
4252
|
+
return /* @__PURE__ */ jsx17(PlanningDivider, { kind: block.kind }, block.key);
|
|
3907
4253
|
}),
|
|
3908
|
-
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
|
|
3909
4255
|
] }) }) }),
|
|
3910
|
-
/* @__PURE__ */
|
|
4256
|
+
/* @__PURE__ */ jsx17(
|
|
3911
4257
|
PinLatestUserMessage,
|
|
3912
4258
|
{
|
|
3913
4259
|
userMessageCount: userMessages.length,
|
|
@@ -3916,7 +4262,7 @@ function MessageList({
|
|
|
3916
4262
|
},
|
|
3917
4263
|
sessionId ?? "no-session"
|
|
3918
4264
|
),
|
|
3919
|
-
/* @__PURE__ */
|
|
4265
|
+
/* @__PURE__ */ jsx17(ScrollToBottomButton, {})
|
|
3920
4266
|
]
|
|
3921
4267
|
},
|
|
3922
4268
|
sessionId ?? "no-session"
|
|
@@ -3929,8 +4275,8 @@ function PinLatestUserMessage({
|
|
|
3929
4275
|
targetKey
|
|
3930
4276
|
}) {
|
|
3931
4277
|
const { contentRef, scrollRef, scrollToBottom, stopScroll } = useStickToBottomContext();
|
|
3932
|
-
const previousCountRef =
|
|
3933
|
-
const spacerHeightRef =
|
|
4278
|
+
const previousCountRef = useRef12(userMessageCount);
|
|
4279
|
+
const spacerHeightRef = useRef12(0);
|
|
3934
4280
|
const getScrollElement = useCallback7(() => scrollRef.current, [scrollRef]);
|
|
3935
4281
|
const getContentElement = useCallback7(() => contentRef.current, [contentRef]);
|
|
3936
4282
|
const getTargetElement = useCallback7(() => {
|
|
@@ -3959,7 +4305,7 @@ function PinLatestUserMessage({
|
|
|
3959
4305
|
stopAutoScroll: stopScroll,
|
|
3960
4306
|
scrollToBottom
|
|
3961
4307
|
});
|
|
3962
|
-
|
|
4308
|
+
useEffect11(() => {
|
|
3963
4309
|
if (userMessageCount > previousCountRef.current && !shouldPinLatestUser) {
|
|
3964
4310
|
scrollToBottom("instant");
|
|
3965
4311
|
}
|
|
@@ -3969,9 +4315,9 @@ function PinLatestUserMessage({
|
|
|
3969
4315
|
}
|
|
3970
4316
|
function ScrollToBottomButton() {
|
|
3971
4317
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
3972
|
-
const [visible, setVisible] =
|
|
3973
|
-
const hideTimerRef =
|
|
3974
|
-
|
|
4318
|
+
const [visible, setVisible] = useState13(false);
|
|
4319
|
+
const hideTimerRef = useRef12(null);
|
|
4320
|
+
useEffect11(() => {
|
|
3975
4321
|
if (isAtBottom) {
|
|
3976
4322
|
if (!hideTimerRef.current) {
|
|
3977
4323
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -4002,7 +4348,7 @@ function ScrollToBottomButton() {
|
|
|
4002
4348
|
scrollToBottom();
|
|
4003
4349
|
}, [scrollToBottom]);
|
|
4004
4350
|
if (!visible) return null;
|
|
4005
|
-
return /* @__PURE__ */
|
|
4351
|
+
return /* @__PURE__ */ jsxs15(
|
|
4006
4352
|
"button",
|
|
4007
4353
|
{
|
|
4008
4354
|
type: "button",
|
|
@@ -4010,25 +4356,25 @@ function ScrollToBottomButton() {
|
|
|
4010
4356
|
"aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
|
|
4011
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))]",
|
|
4012
4358
|
children: [
|
|
4013
|
-
/* @__PURE__ */
|
|
4014
|
-
/* @__PURE__ */
|
|
4359
|
+
/* @__PURE__ */ jsx17(ChevronDown, { size: 14 }),
|
|
4360
|
+
/* @__PURE__ */ jsx17("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
|
|
4015
4361
|
]
|
|
4016
4362
|
}
|
|
4017
4363
|
);
|
|
4018
4364
|
}
|
|
4019
4365
|
function PlanningDivider({ kind }) {
|
|
4020
|
-
return /* @__PURE__ */
|
|
4021
|
-
/* @__PURE__ */
|
|
4022
|
-
/* @__PURE__ */
|
|
4023
|
-
/* @__PURE__ */
|
|
4024
|
-
/* @__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" })
|
|
4025
4371
|
] }),
|
|
4026
|
-
/* @__PURE__ */
|
|
4372
|
+
/* @__PURE__ */ jsx17("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
|
|
4027
4373
|
] });
|
|
4028
4374
|
}
|
|
4029
4375
|
|
|
4030
4376
|
// src/components/ChatSurface.tsx
|
|
4031
|
-
import { jsx as
|
|
4377
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4032
4378
|
function themeAttr(theme) {
|
|
4033
4379
|
return theme === "dark" ? "dark" : void 0;
|
|
4034
4380
|
}
|
|
@@ -4058,9 +4404,11 @@ function ChatSurface({
|
|
|
4058
4404
|
onResultFeedbackSaved,
|
|
4059
4405
|
onFollowupInteraction,
|
|
4060
4406
|
beforeInput,
|
|
4407
|
+
showPlanUpdates = false,
|
|
4408
|
+
planRevealRevision = 0,
|
|
4061
4409
|
banner
|
|
4062
4410
|
}) {
|
|
4063
|
-
return /* @__PURE__ */
|
|
4411
|
+
return /* @__PURE__ */ jsxs16(
|
|
4064
4412
|
"div",
|
|
4065
4413
|
{
|
|
4066
4414
|
"data-theme": themeAttr(theme),
|
|
@@ -4069,14 +4417,14 @@ function ChatSurface({
|
|
|
4069
4417
|
classNames?.root
|
|
4070
4418
|
),
|
|
4071
4419
|
children: [
|
|
4072
|
-
/* @__PURE__ */
|
|
4420
|
+
/* @__PURE__ */ jsx18(ConnectionBanner, { connection, className: classNames?.banner }),
|
|
4073
4421
|
banner,
|
|
4074
|
-
errorMessage && /* @__PURE__ */
|
|
4075
|
-
/* @__PURE__ */
|
|
4076
|
-
/* @__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) })
|
|
4077
4425
|
] }),
|
|
4078
4426
|
slots?.header,
|
|
4079
|
-
/* @__PURE__ */
|
|
4427
|
+
/* @__PURE__ */ jsx18(
|
|
4080
4428
|
MessageList,
|
|
4081
4429
|
{
|
|
4082
4430
|
messages,
|
|
@@ -4087,6 +4435,7 @@ function ChatSurface({
|
|
|
4087
4435
|
askAnswers,
|
|
4088
4436
|
onAnswer,
|
|
4089
4437
|
toolCallRenderer: renderers?.toolCall,
|
|
4438
|
+
hidePlanUpdateTools: showPlanUpdates,
|
|
4090
4439
|
emptyState: slots?.emptyState,
|
|
4091
4440
|
className: classNames?.messageList,
|
|
4092
4441
|
sessionId,
|
|
@@ -4096,8 +4445,18 @@ function ChatSurface({
|
|
|
4096
4445
|
onFollowupInteraction
|
|
4097
4446
|
}
|
|
4098
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,
|
|
4099
4458
|
beforeInput,
|
|
4100
|
-
/* @__PURE__ */
|
|
4459
|
+
/* @__PURE__ */ jsx18(
|
|
4101
4460
|
ChatInput,
|
|
4102
4461
|
{
|
|
4103
4462
|
value: inputText,
|
|
@@ -4117,13 +4476,13 @@ function ChatSurface({
|
|
|
4117
4476
|
}
|
|
4118
4477
|
|
|
4119
4478
|
// src/components/AgentChat.tsx
|
|
4120
|
-
import { Fragment as Fragment3, jsx as
|
|
4479
|
+
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4121
4480
|
function isUnauthorizedError(error) {
|
|
4122
4481
|
return error instanceof BladeApiError && error.status === 401;
|
|
4123
4482
|
}
|
|
4124
4483
|
function LoginCard({ client, onLoggedIn }) {
|
|
4125
|
-
const [loggingIn, setLoggingIn] =
|
|
4126
|
-
const [loginError, setLoginError] =
|
|
4484
|
+
const [loggingIn, setLoggingIn] = useState14(false);
|
|
4485
|
+
const [loginError, setLoginError] = useState14(null);
|
|
4127
4486
|
const handleLogin = async () => {
|
|
4128
4487
|
setLoggingIn(true);
|
|
4129
4488
|
setLoginError(null);
|
|
@@ -4136,11 +4495,11 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4136
4495
|
setLoggingIn(false);
|
|
4137
4496
|
}
|
|
4138
4497
|
};
|
|
4139
|
-
return /* @__PURE__ */
|
|
4140
|
-
/* @__PURE__ */
|
|
4141
|
-
/* @__PURE__ */
|
|
4142
|
-
/* @__PURE__ */
|
|
4143
|
-
/* @__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(
|
|
4144
4503
|
"button",
|
|
4145
4504
|
{
|
|
4146
4505
|
type: "button",
|
|
@@ -4150,20 +4509,20 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
4150
4509
|
children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
|
|
4151
4510
|
}
|
|
4152
4511
|
),
|
|
4153
|
-
loginError && /* @__PURE__ */
|
|
4512
|
+
loginError && /* @__PURE__ */ jsx19("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
|
|
4154
4513
|
] }) });
|
|
4155
4514
|
}
|
|
4156
4515
|
function AgentChat(props) {
|
|
4157
4516
|
const client = useBladeClient();
|
|
4158
|
-
const [attempt, setAttempt] =
|
|
4159
|
-
const [needLogin, setNeedLogin] =
|
|
4517
|
+
const [attempt, setAttempt] = useState14(0);
|
|
4518
|
+
const [needLogin, setNeedLogin] = useState14(() => !client.hasToken());
|
|
4160
4519
|
if (needLogin) {
|
|
4161
|
-
return /* @__PURE__ */
|
|
4520
|
+
return /* @__PURE__ */ jsx19(
|
|
4162
4521
|
"div",
|
|
4163
4522
|
{
|
|
4164
4523
|
"data-theme": themeAttr(props.theme),
|
|
4165
4524
|
className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
|
|
4166
|
-
children: /* @__PURE__ */
|
|
4525
|
+
children: /* @__PURE__ */ jsx19(
|
|
4167
4526
|
LoginCard,
|
|
4168
4527
|
{
|
|
4169
4528
|
client,
|
|
@@ -4176,7 +4535,7 @@ function AgentChat(props) {
|
|
|
4176
4535
|
}
|
|
4177
4536
|
);
|
|
4178
4537
|
}
|
|
4179
|
-
return /* @__PURE__ */
|
|
4538
|
+
return /* @__PURE__ */ jsx19(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
|
|
4180
4539
|
}
|
|
4181
4540
|
function ChatSessionView({
|
|
4182
4541
|
sessionId,
|
|
@@ -4193,17 +4552,33 @@ function ChatSessionView({
|
|
|
4193
4552
|
onUnauthorized
|
|
4194
4553
|
}) {
|
|
4195
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
|
+
}, []);
|
|
4196
4570
|
const { session, state, error } = useAgentSession(sessionId, {
|
|
4197
4571
|
createOptions,
|
|
4198
|
-
onSessionCreated
|
|
4572
|
+
onSessionCreated,
|
|
4573
|
+
onSessionConnected: handleSessionConnected
|
|
4199
4574
|
});
|
|
4200
4575
|
const replay = useReplay(session);
|
|
4201
|
-
const [stopRequested, setStopRequested] =
|
|
4202
|
-
const [inputText, setInputText] =
|
|
4203
|
-
const [resultFeedback, setResultFeedback] =
|
|
4576
|
+
const [stopRequested, setStopRequested] = useState14(false);
|
|
4577
|
+
const [inputText, setInputText] = useState14("");
|
|
4578
|
+
const [resultFeedback, setResultFeedback] = useState14([]);
|
|
4204
4579
|
const resolvedSessionId = session?.sessionId;
|
|
4205
4580
|
const isViewer = state?.viewerRole === "viewer";
|
|
4206
|
-
|
|
4581
|
+
useEffect12(() => {
|
|
4207
4582
|
setResultFeedback([]);
|
|
4208
4583
|
if (!resolvedSessionId || isViewer) return;
|
|
4209
4584
|
let cancelled = false;
|
|
@@ -4238,12 +4613,12 @@ function ChatSessionView({
|
|
|
4238
4613
|
saved
|
|
4239
4614
|
]);
|
|
4240
4615
|
}, []);
|
|
4241
|
-
|
|
4616
|
+
useEffect12(() => {
|
|
4242
4617
|
if (session) {
|
|
4243
4618
|
onSessionReady?.(session);
|
|
4244
4619
|
}
|
|
4245
4620
|
}, [session, onSessionReady]);
|
|
4246
|
-
|
|
4621
|
+
useEffect12(() => {
|
|
4247
4622
|
if (!session) return;
|
|
4248
4623
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
4249
4624
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -4259,12 +4634,12 @@ ${content}`);
|
|
|
4259
4634
|
offInsert();
|
|
4260
4635
|
};
|
|
4261
4636
|
}, [session]);
|
|
4262
|
-
|
|
4637
|
+
useEffect12(() => {
|
|
4263
4638
|
if (isUnauthorizedError(error)) {
|
|
4264
4639
|
onUnauthorized();
|
|
4265
4640
|
}
|
|
4266
4641
|
}, [error, onUnauthorized]);
|
|
4267
|
-
|
|
4642
|
+
useEffect12(() => {
|
|
4268
4643
|
if (!session || !commands) return;
|
|
4269
4644
|
const unsubscribes = Object.entries(commands).map(
|
|
4270
4645
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -4274,6 +4649,7 @@ ${content}`);
|
|
|
4274
4649
|
};
|
|
4275
4650
|
}, [session, commands]);
|
|
4276
4651
|
const isStreaming = state?.isStreaming ?? false;
|
|
4652
|
+
const planRevealRevision = resolvedSessionId ? planRevealRevisions.get(resolvedSessionId) ?? 0 : 0;
|
|
4277
4653
|
const isStopping = stopRequested && isStreaming;
|
|
4278
4654
|
const connectError = error && !isUnauthorizedError(error) ? error.message || "\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" : null;
|
|
4279
4655
|
const errorMessage = connectError ?? state?.errorMessage ?? replay.error?.message ?? null;
|
|
@@ -4285,7 +4661,7 @@ ${content}`);
|
|
|
4285
4661
|
setStopRequested(true);
|
|
4286
4662
|
void session?.stop();
|
|
4287
4663
|
};
|
|
4288
|
-
return /* @__PURE__ */
|
|
4664
|
+
return /* @__PURE__ */ jsx19(
|
|
4289
4665
|
ChatSurface,
|
|
4290
4666
|
{
|
|
4291
4667
|
theme,
|
|
@@ -4295,8 +4671,8 @@ ${content}`);
|
|
|
4295
4671
|
slots,
|
|
4296
4672
|
placeholder,
|
|
4297
4673
|
connection: state?.connection ?? "connecting",
|
|
4298
|
-
banner: /* @__PURE__ */
|
|
4299
|
-
/* @__PURE__ */
|
|
4674
|
+
banner: /* @__PURE__ */ jsxs17(Fragment3, { children: [
|
|
4675
|
+
/* @__PURE__ */ jsx19(
|
|
4300
4676
|
ReplayBar,
|
|
4301
4677
|
{
|
|
4302
4678
|
isReplay: replay.isReplay,
|
|
@@ -4306,7 +4682,7 @@ ${content}`);
|
|
|
4306
4682
|
onExit: () => void replay.exitToAutonomous()
|
|
4307
4683
|
}
|
|
4308
4684
|
),
|
|
4309
|
-
/* @__PURE__ */
|
|
4685
|
+
/* @__PURE__ */ jsx19(ReplayMismatchPrompt, { mismatch: replay.mismatch })
|
|
4310
4686
|
] }),
|
|
4311
4687
|
errorMessage,
|
|
4312
4688
|
messages: state?.messages ?? [],
|
|
@@ -4314,6 +4690,8 @@ ${content}`);
|
|
|
4314
4690
|
resultFeedbackByEntry,
|
|
4315
4691
|
onResultFeedbackSaved: handleResultFeedbackSaved,
|
|
4316
4692
|
isStreaming,
|
|
4693
|
+
showPlanUpdates: true,
|
|
4694
|
+
planRevealRevision,
|
|
4317
4695
|
isStopping,
|
|
4318
4696
|
inputText,
|
|
4319
4697
|
onInputChange: setInputText,
|
|
@@ -4335,11 +4713,11 @@ ${content}`);
|
|
|
4335
4713
|
}
|
|
4336
4714
|
|
|
4337
4715
|
// src/components/LlmChat.tsx
|
|
4338
|
-
import { useEffect as
|
|
4716
|
+
import { useEffect as useEffect13, useMemo as useMemo9, useState as useState16 } from "react";
|
|
4339
4717
|
|
|
4340
4718
|
// src/components/LlmAdvancedSettings.tsx
|
|
4341
|
-
import { useState as
|
|
4342
|
-
import { jsx as
|
|
4719
|
+
import { useState as useState15 } from "react";
|
|
4720
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4343
4721
|
var FIELDS = [
|
|
4344
4722
|
{ id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
|
|
4345
4723
|
{ id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
|
|
@@ -4385,13 +4763,13 @@ function writeOverride(settings, baseURL, override) {
|
|
|
4385
4763
|
}
|
|
4386
4764
|
function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
4387
4765
|
const normalized = normalizeAdvanced(settings);
|
|
4388
|
-
const [open, setOpen] =
|
|
4389
|
-
const [draft, setDraft] =
|
|
4766
|
+
const [open, setOpen] = useState15(false);
|
|
4767
|
+
const [draft, setDraft] = useState15(override);
|
|
4390
4768
|
if (!normalized) return null;
|
|
4391
4769
|
const fields = FIELDS.filter((field) => normalized[field.id]);
|
|
4392
4770
|
const dirty = Object.keys(override).length > 0;
|
|
4393
|
-
return /* @__PURE__ */
|
|
4394
|
-
/* @__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(
|
|
4395
4773
|
"button",
|
|
4396
4774
|
{
|
|
4397
4775
|
type: "button",
|
|
@@ -4401,16 +4779,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4401
4779
|
},
|
|
4402
4780
|
className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
4403
4781
|
children: [
|
|
4404
|
-
/* @__PURE__ */
|
|
4782
|
+
/* @__PURE__ */ jsx20(Settings2, { size: 13 }),
|
|
4405
4783
|
"\u9AD8\u7EA7\u8BBE\u7F6E",
|
|
4406
|
-
dirty && /* @__PURE__ */
|
|
4784
|
+
dirty && /* @__PURE__ */ jsx20("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
|
|
4407
4785
|
]
|
|
4408
4786
|
}
|
|
4409
4787
|
),
|
|
4410
|
-
open && /* @__PURE__ */
|
|
4411
|
-
fields.map((field) => /* @__PURE__ */
|
|
4412
|
-
/* @__PURE__ */
|
|
4413
|
-
/* @__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(
|
|
4414
4792
|
"input",
|
|
4415
4793
|
{
|
|
4416
4794
|
type: field.secret ? "password" : "text",
|
|
@@ -4421,9 +4799,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4421
4799
|
}
|
|
4422
4800
|
)
|
|
4423
4801
|
] }, field.id)),
|
|
4424
|
-
normalized.apiKey && /* @__PURE__ */
|
|
4425
|
-
/* @__PURE__ */
|
|
4426
|
-
/* @__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(
|
|
4427
4805
|
"button",
|
|
4428
4806
|
{
|
|
4429
4807
|
type: "button",
|
|
@@ -4438,7 +4816,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4438
4816
|
children: "\u4FDD\u5B58"
|
|
4439
4817
|
}
|
|
4440
4818
|
),
|
|
4441
|
-
/* @__PURE__ */
|
|
4819
|
+
/* @__PURE__ */ jsx20(
|
|
4442
4820
|
"button",
|
|
4443
4821
|
{
|
|
4444
4822
|
type: "button",
|
|
@@ -4457,7 +4835,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
|
|
|
4457
4835
|
}
|
|
4458
4836
|
|
|
4459
4837
|
// src/components/LlmChat.tsx
|
|
4460
|
-
import { jsx as
|
|
4838
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
4461
4839
|
function LlmChat({
|
|
4462
4840
|
classNames,
|
|
4463
4841
|
renderers,
|
|
@@ -4469,11 +4847,11 @@ function LlmChat({
|
|
|
4469
4847
|
onOverrideChange,
|
|
4470
4848
|
...options
|
|
4471
4849
|
}) {
|
|
4472
|
-
const [override, setOverride] =
|
|
4850
|
+
const [override, setOverride] = useState16(() => readOverride(advanced, options.baseURL));
|
|
4473
4851
|
const effective = { ...options, ...override };
|
|
4474
4852
|
const { messages, isStreaming, error, send, stop, reset } = useLlmChat(effective);
|
|
4475
|
-
const [inputText, setInputText] =
|
|
4476
|
-
const [stopRequested, setStopRequested] =
|
|
4853
|
+
const [inputText, setInputText] = useState16("");
|
|
4854
|
+
const [stopRequested, setStopRequested] = useState16(false);
|
|
4477
4855
|
const handle = useMemo9(
|
|
4478
4856
|
() => ({
|
|
4479
4857
|
insertText: (text) => setInputText((prev) => prev ? `${prev}
|
|
@@ -4483,10 +4861,10 @@ ${text}` : text),
|
|
|
4483
4861
|
}),
|
|
4484
4862
|
[send, reset]
|
|
4485
4863
|
);
|
|
4486
|
-
|
|
4864
|
+
useEffect13(() => {
|
|
4487
4865
|
onReady?.(handle);
|
|
4488
4866
|
}, [handle, onReady]);
|
|
4489
|
-
return /* @__PURE__ */
|
|
4867
|
+
return /* @__PURE__ */ jsx21(
|
|
4490
4868
|
ChatSurface,
|
|
4491
4869
|
{
|
|
4492
4870
|
theme,
|
|
@@ -4511,7 +4889,7 @@ ${text}` : text),
|
|
|
4511
4889
|
setStopRequested(true);
|
|
4512
4890
|
stop();
|
|
4513
4891
|
},
|
|
4514
|
-
beforeInput: advanced ? /* @__PURE__ */
|
|
4892
|
+
beforeInput: advanced ? /* @__PURE__ */ jsx21(
|
|
4515
4893
|
LlmAdvancedSettingsBar,
|
|
4516
4894
|
{
|
|
4517
4895
|
settings: advanced,
|
|
@@ -4529,14 +4907,14 @@ ${text}` : text),
|
|
|
4529
4907
|
}
|
|
4530
4908
|
|
|
4531
4909
|
// src/components/ChatView.tsx
|
|
4532
|
-
import { jsx as
|
|
4910
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
4533
4911
|
function ChatView(props) {
|
|
4534
4912
|
const { mode, llm, onLlmReady, ...rest } = props;
|
|
4535
4913
|
if (mode === "llm") {
|
|
4536
4914
|
if (!llm) {
|
|
4537
4915
|
throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
|
|
4538
4916
|
}
|
|
4539
|
-
return /* @__PURE__ */
|
|
4917
|
+
return /* @__PURE__ */ jsx22(
|
|
4540
4918
|
LlmChat,
|
|
4541
4919
|
{
|
|
4542
4920
|
...llm,
|
|
@@ -4549,23 +4927,24 @@ function ChatView(props) {
|
|
|
4549
4927
|
}
|
|
4550
4928
|
);
|
|
4551
4929
|
}
|
|
4552
|
-
return /* @__PURE__ */
|
|
4930
|
+
return /* @__PURE__ */ jsx22(AgentChat, { ...rest });
|
|
4553
4931
|
}
|
|
4554
4932
|
|
|
4555
4933
|
// src/components/ContextCard.tsx
|
|
4556
4934
|
import {
|
|
4557
|
-
getContextDisplayState
|
|
4935
|
+
getContextDisplayState,
|
|
4936
|
+
getContextGroupDisplayState
|
|
4558
4937
|
} from "@blade-hq/agent-client";
|
|
4559
|
-
import { jsx as
|
|
4938
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4560
4939
|
function ContextCard({ context, className }) {
|
|
4561
4940
|
const display = getContextDisplayState(context);
|
|
4562
|
-
return /* @__PURE__ */
|
|
4941
|
+
return /* @__PURE__ */ jsxs19(
|
|
4563
4942
|
"details",
|
|
4564
4943
|
{
|
|
4565
|
-
className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
|
|
4944
|
+
className: `blade-chat-context-card group/context-card rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
|
|
4566
4945
|
children: [
|
|
4567
|
-
/* @__PURE__ */
|
|
4568
|
-
/* @__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(
|
|
4569
4948
|
Layers,
|
|
4570
4949
|
{
|
|
4571
4950
|
size: 15,
|
|
@@ -4573,24 +4952,60 @@ function ContextCard({ context, className }) {
|
|
|
4573
4952
|
"aria-hidden": "true"
|
|
4574
4953
|
}
|
|
4575
4954
|
),
|
|
4576
|
-
/* @__PURE__ */
|
|
4577
|
-
/* @__PURE__ */
|
|
4578
|
-
/* @__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 })
|
|
4579
4958
|
] }),
|
|
4580
|
-
/* @__PURE__ */
|
|
4959
|
+
/* @__PURE__ */ jsx23(
|
|
4581
4960
|
ChevronDown,
|
|
4582
4961
|
{
|
|
4583
4962
|
size: 14,
|
|
4584
|
-
className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
|
|
4963
|
+
className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open/context-card:rotate-180",
|
|
4585
4964
|
"aria-hidden": "true"
|
|
4586
4965
|
}
|
|
4587
4966
|
)
|
|
4588
4967
|
] }),
|
|
4589
|
-
/* @__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 })
|
|
4590
4969
|
]
|
|
4591
4970
|
}
|
|
4592
4971
|
);
|
|
4593
4972
|
}
|
|
4973
|
+
function ContextGroupCard({ contexts, className }) {
|
|
4974
|
+
if (contexts.length === 0) return null;
|
|
4975
|
+
const single = contexts.length === 1 ? getContextDisplayState(contexts[0]) : null;
|
|
4976
|
+
const group = single ? null : getContextGroupDisplayState(contexts);
|
|
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(
|
|
4980
|
+
Layers,
|
|
4981
|
+
{
|
|
4982
|
+
size: 15,
|
|
4983
|
+
className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
|
|
4984
|
+
"aria-hidden": "true"
|
|
4985
|
+
}
|
|
4986
|
+
),
|
|
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 })
|
|
4990
|
+
] }),
|
|
4991
|
+
/* @__PURE__ */ jsx23(
|
|
4992
|
+
ChevronDown,
|
|
4993
|
+
{
|
|
4994
|
+
size: 14,
|
|
4995
|
+
className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open/context-group:rotate-180",
|
|
4996
|
+
"aria-hidden": "true"
|
|
4997
|
+
}
|
|
4998
|
+
)
|
|
4999
|
+
] }),
|
|
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(
|
|
5001
|
+
ContextCard,
|
|
5002
|
+
{
|
|
5003
|
+
context
|
|
5004
|
+
},
|
|
5005
|
+
`${context.context_kind}:${context.context_key}`
|
|
5006
|
+
)) })
|
|
5007
|
+
] });
|
|
5008
|
+
}
|
|
4594
5009
|
|
|
4595
5010
|
// src/lib/agent-computer-command.ts
|
|
4596
5011
|
var COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\n;&|(]\s*)computer\s+launch(?:\s|$)/;
|
|
@@ -4641,15 +5056,26 @@ export {
|
|
|
4641
5056
|
BladeProvider,
|
|
4642
5057
|
ChatView,
|
|
4643
5058
|
ContextCard,
|
|
5059
|
+
ContextGroupCard,
|
|
5060
|
+
CurrentPlanPanel,
|
|
4644
5061
|
LlmChat,
|
|
4645
5062
|
MarkdownContent,
|
|
4646
5063
|
MemoryRefsHint,
|
|
5064
|
+
PLAN_AUTO_COLLAPSE_MS,
|
|
5065
|
+
PlanUpdateBlock,
|
|
4647
5066
|
ReplayBar,
|
|
4648
5067
|
ReplayMismatchPrompt,
|
|
5068
|
+
WhatIfUserBubble,
|
|
4649
5069
|
classifyAgentComputerLaunchOutcome,
|
|
4650
5070
|
collectMemoryRefs,
|
|
5071
|
+
getPlanUpdateDisplayState,
|
|
4651
5072
|
isAgentComputerCommand,
|
|
4652
5073
|
isAgentComputerToolCall,
|
|
5074
|
+
isPlanUpdateTool,
|
|
5075
|
+
normalizeAdjacentUrlFormatting,
|
|
5076
|
+
parsePlanUpdate,
|
|
5077
|
+
parseWhatIfPrompt,
|
|
5078
|
+
pickCurrentPlanStep,
|
|
4653
5079
|
useAgentSession,
|
|
4654
5080
|
useBladeClient,
|
|
4655
5081
|
useLlmChat,
|
|
@@ -4671,6 +5097,8 @@ lucide-react/dist/esm/icons/check.js:
|
|
|
4671
5097
|
lucide-react/dist/esm/icons/chevron-down.js:
|
|
4672
5098
|
lucide-react/dist/esm/icons/chevron-right.js:
|
|
4673
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:
|
|
4674
5102
|
lucide-react/dist/esm/icons/copy.js:
|
|
4675
5103
|
lucide-react/dist/esm/icons/earth.js:
|
|
4676
5104
|
lucide-react/dist/esm/icons/file-pen-line.js:
|
|
@@ -4678,11 +5106,13 @@ lucide-react/dist/esm/icons/file-text.js:
|
|
|
4678
5106
|
lucide-react/dist/esm/icons/globe.js:
|
|
4679
5107
|
lucide-react/dist/esm/icons/layers.js:
|
|
4680
5108
|
lucide-react/dist/esm/icons/lightbulb.js:
|
|
5109
|
+
lucide-react/dist/esm/icons/list-checks.js:
|
|
4681
5110
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
4682
5111
|
lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
4683
5112
|
lucide-react/dist/esm/icons/message-square-more.js:
|
|
4684
5113
|
lucide-react/dist/esm/icons/message-square.js:
|
|
4685
5114
|
lucide-react/dist/esm/icons/play.js:
|
|
5115
|
+
lucide-react/dist/esm/icons/refresh-ccw.js:
|
|
4686
5116
|
lucide-react/dist/esm/icons/search.js:
|
|
4687
5117
|
lucide-react/dist/esm/icons/settings-2.js:
|
|
4688
5118
|
lucide-react/dist/esm/icons/sparkles.js:
|