@blade-hq/agent-react 2610.0.0-beta.31 → 2610.0.0-beta.32

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