@blade-hq/agent-react 1.2.1-beta.1 → 1.2.1-beta.11

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
@@ -173,6 +173,13 @@ var createLucideIcon = (iconName, iconNode) => {
173
173
  return Component2;
174
174
  };
175
175
 
176
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/archive.js
177
+ var Archive = createLucideIcon("Archive", [
178
+ ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
179
+ ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
180
+ ["path", { d: "M10 12h4", key: "a56b0p" }]
181
+ ]);
182
+
176
183
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up.js
177
184
  var ArrowUp = createLucideIcon("ArrowUp", [
178
185
  ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
@@ -240,6 +247,31 @@ var Copy = createLucideIcon("Copy", [
240
247
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
241
248
  ]);
242
249
 
250
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/download.js
251
+ var Download = createLucideIcon("Download", [
252
+ ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
253
+ ["polyline", { points: "7 10 12 15 17 10", key: "2ggqvy" }],
254
+ ["line", { x1: "12", x2: "12", y1: "15", y2: "3", key: "1vk2je" }]
255
+ ]);
256
+
257
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-code-2.js
258
+ var FileCode2 = createLucideIcon("FileCode2", [
259
+ ["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
260
+ ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
261
+ ["path", { d: "m5 12-3 3 3 3", key: "oke12k" }],
262
+ ["path", { d: "m9 18 3-3-3-3", key: "112psh" }]
263
+ ]);
264
+
265
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js
266
+ var FileSpreadsheet = createLucideIcon("FileSpreadsheet", [
267
+ ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
268
+ ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
269
+ ["path", { d: "M8 13h2", key: "yr2amv" }],
270
+ ["path", { d: "M14 13h2", key: "un5t4a" }],
271
+ ["path", { d: "M8 17h2", key: "2yhykz" }],
272
+ ["path", { d: "M14 17h2", key: "10kma7" }]
273
+ ]);
274
+
243
275
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-text.js
244
276
  var FileText = createLucideIcon("FileText", [
245
277
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
@@ -249,6 +281,31 @@ var FileText = createLucideIcon("FileText", [
249
281
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
250
282
  ]);
251
283
 
284
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file.js
285
+ var File = createLucideIcon("File", [
286
+ ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
287
+ ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }]
288
+ ]);
289
+
290
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/film.js
291
+ var Film = createLucideIcon("Film", [
292
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
293
+ ["path", { d: "M7 3v18", key: "bbkbws" }],
294
+ ["path", { d: "M3 7.5h4", key: "zfgn84" }],
295
+ ["path", { d: "M3 12h18", key: "1i2n21" }],
296
+ ["path", { d: "M3 16.5h4", key: "1230mu" }],
297
+ ["path", { d: "M17 3v18", key: "in4fa5" }],
298
+ ["path", { d: "M17 7.5h4", key: "myr1c1" }],
299
+ ["path", { d: "M17 16.5h4", key: "go4c1d" }]
300
+ ]);
301
+
302
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/image.js
303
+ var Image = createLucideIcon("Image", [
304
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
305
+ ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
306
+ ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
307
+ ]);
308
+
252
309
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/layers.js
253
310
  var Layers = createLucideIcon("Layers", [
254
311
  [
@@ -312,6 +369,13 @@ var MessageSquare = createLucideIcon("MessageSquare", [
312
369
  ["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }]
313
370
  ]);
314
371
 
372
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/music.js
373
+ var Music = createLucideIcon("Music", [
374
+ ["path", { d: "M9 18V5l12-2v13", key: "1jmyc2" }],
375
+ ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
376
+ ["circle", { cx: "18", cy: "16", r: "3", key: "1hluhg" }]
377
+ ]);
378
+
315
379
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/square.js
316
380
  var Square = createLucideIcon("Square", [
317
381
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
@@ -337,7 +401,7 @@ var X = createLucideIcon("X", [
337
401
  ]);
338
402
 
339
403
  // src/components/ChatView.tsx
340
- import { useEffect as useEffect6, useState as useState8 } from "react";
404
+ import { useEffect as useEffect6, useState as useState9 } from "react";
341
405
 
342
406
  // src/lib/utils.ts
343
407
  function cn(...inputs) {
@@ -378,7 +442,7 @@ function ChatInput({
378
442
  void handleSend();
379
443
  }
380
444
  };
381
- return /* @__PURE__ */ jsx2("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] px-4 py-3", className), children: /* @__PURE__ */ jsxs("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: [
445
+ return /* @__PURE__ */ jsx2("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: /* @__PURE__ */ jsxs("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: [
382
446
  /* @__PURE__ */ jsx2(
383
447
  "textarea",
384
448
  {
@@ -877,7 +941,7 @@ function useStickToBottomContext() {
877
941
 
878
942
  // src/components/AssistantTurnBlock.tsx
879
943
  import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
880
- import { useState as useState7 } from "react";
944
+ import { useState as useState8 } from "react";
881
945
 
882
946
  // src/components/AgentLoopBlock.tsx
883
947
  import { useState as useState3 } from "react";
@@ -1080,14 +1144,142 @@ import {
1080
1144
  useEffect as useEffect3,
1081
1145
  useMemo as useMemo4,
1082
1146
  useRef as useRef4,
1083
- useState as useState4
1147
+ useState as useState5
1084
1148
  } from "react";
1149
+
1150
+ // src/lib/media-tags.ts
1151
+ var FILE_CARD_TAG = "blade-file-card";
1152
+ var MEDIA_LINE_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?(?<wrap>[`"'*_]*)MEDIA:[ \t]*(?<path>.+?)\k<wrap>[ \t]*[。,、;;,]?[ \t]*\r?$/gm;
1153
+ var MEDIA_LINE_START_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?[`"'*_]*MEDIA:/;
1154
+ function basename(path) {
1155
+ return path.split(/[/\\]/).filter(Boolean).pop() || path;
1156
+ }
1157
+ function unwrapMediaPath(path) {
1158
+ if (!path.startsWith("<")) return path;
1159
+ const closingBracket = path.indexOf(">");
1160
+ if (closingBracket < 0) return null;
1161
+ return `${path.slice(1, closingBracket)}${path.slice(closingBracket + 1)}`;
1162
+ }
1163
+ function isSafeMediaPath(path) {
1164
+ if (!path) return false;
1165
+ return !path.split(/[/\\]/).includes("..");
1166
+ }
1167
+ function escapeAttribute(value) {
1168
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1169
+ }
1170
+ function foldMediaLines(text) {
1171
+ return text.replace(MEDIA_LINE_RE, (match, _wrap, rawPath) => {
1172
+ const path = unwrapMediaPath(rawPath);
1173
+ if (path === null) return match;
1174
+ const name = basename(path);
1175
+ if (!isSafeMediaPath(path)) {
1176
+ return `\`${name}\``;
1177
+ }
1178
+ return `<${FILE_CARD_TAG} data-path="${escapeAttribute(path)}" data-name="${escapeAttribute(name)}">${escapeAttribute(name)}</${FILE_CARD_TAG}>`;
1179
+ });
1180
+ }
1181
+ function collapseMediaTags(text, options) {
1182
+ if (!text.includes("MEDIA:")) return text;
1183
+ if (!options?.streaming) return foldMediaLines(text);
1184
+ const newlineIndex = text.lastIndexOf("\n");
1185
+ const head = newlineIndex < 0 ? "" : text.slice(0, newlineIndex + 1);
1186
+ const lastLine = newlineIndex < 0 ? text : text.slice(newlineIndex + 1);
1187
+ if (MEDIA_LINE_START_RE.test(lastLine)) {
1188
+ return foldMediaLines(head);
1189
+ }
1190
+ return foldMediaLines(head) + lastLine;
1191
+ }
1192
+
1193
+ // src/components/FileCard.tsx
1194
+ import { useState as useState4 } from "react";
1085
1195
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1196
+ var IMAGE_EXTS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"]);
1197
+ var SHEET_EXTS = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "csv"]);
1198
+ var TEXT_EXTS = /* @__PURE__ */ new Set(["txt", "md", "markdown", "pdf", "doc", "docx", "rtf"]);
1199
+ var CODE_EXTS = /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx", "py", "go", "json", "yaml", "yml", "html", "css"]);
1200
+ var VIDEO_EXTS = /* @__PURE__ */ new Set(["mp4", "webm", "mov", "mkv", "avi"]);
1201
+ var AUDIO_EXTS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "m4a", "flac"]);
1202
+ var ARCHIVE_EXTS = /* @__PURE__ */ new Set(["zip", "tar", "gz", "tgz", "rar", "7z"]);
1203
+ function getFileIcon(name) {
1204
+ const ext = name.split(".").pop()?.toLowerCase() ?? "";
1205
+ if (IMAGE_EXTS.has(ext)) return Image;
1206
+ if (SHEET_EXTS.has(ext)) return FileSpreadsheet;
1207
+ if (TEXT_EXTS.has(ext)) return FileText;
1208
+ if (CODE_EXTS.has(ext)) return FileCode2;
1209
+ if (VIDEO_EXTS.has(ext)) return Film;
1210
+ if (AUDIO_EXTS.has(ext)) return Music;
1211
+ if (ARCHIVE_EXTS.has(ext)) return Archive;
1212
+ return File;
1213
+ }
1214
+ function stringValue(value) {
1215
+ return typeof value === "string" ? value : void 0;
1216
+ }
1217
+ function extractChildrenText(children) {
1218
+ if (typeof children === "string") return children;
1219
+ if (Array.isArray(children)) return children.map(extractChildrenText).join("");
1220
+ if (children && typeof children === "object" && "props" in children) {
1221
+ return extractChildrenText(children.props?.children);
1222
+ }
1223
+ return "";
1224
+ }
1225
+ function FileCard({
1226
+ node,
1227
+ "data-path": pathAttribute,
1228
+ "data-name": nameAttribute,
1229
+ dataPath,
1230
+ dataName,
1231
+ sessionId,
1232
+ children,
1233
+ className,
1234
+ ...props
1235
+ }) {
1236
+ const client = useBladeClient();
1237
+ const [downloading, setDownloading] = useState4(false);
1238
+ const [failed, setFailed] = useState4(false);
1239
+ const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
1240
+ const path = pathAttribute ?? dataPath ?? stringValue(nodeProperties?.["data-path"]) ?? stringValue(nodeProperties?.dataPath) ?? "";
1241
+ const name = nameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName) ?? extractChildrenText(children) ?? "";
1242
+ const disabled = !sessionId || !isSafeMediaPath(path);
1243
+ const Icon2 = getFileIcon(name);
1244
+ const handleDownload = async () => {
1245
+ if (disabled || downloading || !sessionId) return;
1246
+ setDownloading(true);
1247
+ setFailed(false);
1248
+ try {
1249
+ await client.sessions.downloadFile(sessionId, path, name);
1250
+ } catch {
1251
+ setFailed(true);
1252
+ } finally {
1253
+ setDownloading(false);
1254
+ }
1255
+ };
1256
+ return /* @__PURE__ */ jsxs4("span", { ...props, className: cn("blade-chat-file-card", className), children: [
1257
+ /* @__PURE__ */ jsxs4(
1258
+ "button",
1259
+ {
1260
+ type: "button",
1261
+ onClick: handleDownload,
1262
+ disabled: disabled || downloading,
1263
+ "aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
1264
+ title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" : `\u4E0B\u8F7D ${name}`,
1265
+ children: [
1266
+ /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-icon", children: downloading ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 15, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Icon2, { size: 15 }) }),
1267
+ /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-name", children: name }),
1268
+ /* @__PURE__ */ jsx5(Download, { size: 13, className: "blade-chat-file-card-action" })
1269
+ ]
1270
+ }
1271
+ ),
1272
+ failed && /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-error", children: "\u4E0B\u8F7D\u5931\u8D25" })
1273
+ ] });
1274
+ }
1275
+
1276
+ // src/components/MarkdownContent.tsx
1277
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1086
1278
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
1087
1279
  function CodeBlockPre({ children, node: _node, ...props }) {
1088
1280
  const preRef = useRef4(null);
1089
- const [copied, setCopied] = useState4(false);
1090
- const [language, setLanguage] = useState4("");
1281
+ const [copied, setCopied] = useState5(false);
1282
+ const [language, setLanguage] = useState5("");
1091
1283
  useEffect3(() => {
1092
1284
  const codeEl = preRef.current?.querySelector("code");
1093
1285
  setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
@@ -1099,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1099
1291
  setTimeout(() => setCopied(false), 2e3);
1100
1292
  }
1101
1293
  };
1102
- return /* @__PURE__ */ jsxs4("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
1103
- /* @__PURE__ */ jsxs4("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: [
1104
- /* @__PURE__ */ jsx5("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
1105
- /* @__PURE__ */ jsxs4(
1294
+ return /* @__PURE__ */ jsxs5("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
1295
+ /* @__PURE__ */ jsxs5("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: [
1296
+ /* @__PURE__ */ jsx6("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
1297
+ /* @__PURE__ */ jsxs5(
1106
1298
  "button",
1107
1299
  {
1108
1300
  type: "button",
@@ -1112,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1112
1304
  copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
1113
1305
  ),
1114
1306
  children: [
1115
- copied ? /* @__PURE__ */ jsx5(Check, { size: 12 }) : /* @__PURE__ */ jsx5(Copy, { size: 12 }),
1116
- /* @__PURE__ */ jsx5("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
1307
+ copied ? /* @__PURE__ */ jsx6(Check, { size: 12 }) : /* @__PURE__ */ jsx6(Copy, { size: 12 }),
1308
+ /* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
1117
1309
  ]
1118
1310
  }
1119
1311
  )
1120
1312
  ] }),
1121
- /* @__PURE__ */ jsx5(
1313
+ /* @__PURE__ */ jsx6(
1122
1314
  "pre",
1123
1315
  {
1124
1316
  ref: preRef,
@@ -1130,37 +1322,54 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1130
1322
  ] });
1131
1323
  }
1132
1324
  function ExternalAnchor({ node: _node, children, ...props }) {
1133
- return /* @__PURE__ */ jsx5("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1325
+ return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1134
1326
  }
1135
1327
  var MARKDOWN_COMPONENTS = {
1136
1328
  pre: CodeBlockPre,
1137
1329
  a: ExternalAnchor
1138
1330
  };
1139
- function MarkdownContent({ children, className, mode }) {
1140
- const resolvedChildren = useMemo4(() => children.replace(SYSTEM_REMINDER_RE, ""), [children]);
1141
- return /* @__PURE__ */ jsx5(
1331
+ var CUSTOM_ALLOWED_TAGS = {
1332
+ [FILE_CARD_TAG]: ["dataPath", "dataName", "data-path", "data-name"]
1333
+ };
1334
+ function MarkdownContent({ children, className, mode, sessionId }) {
1335
+ const streaming = mode === "streaming";
1336
+ const resolvedChildren = useMemo4(() => {
1337
+ const withoutReminders = children.replace(SYSTEM_REMINDER_RE, "");
1338
+ if (!sessionId) return withoutReminders;
1339
+ return collapseMediaTags(withoutReminders, { streaming });
1340
+ }, [children, sessionId, streaming]);
1341
+ const components = useMemo4(
1342
+ () => ({
1343
+ ...MARKDOWN_COMPONENTS,
1344
+ [FILE_CARD_TAG]: (fileCardProps) => /* @__PURE__ */ jsx6(FileCard, { ...fileCardProps, sessionId })
1345
+ }),
1346
+ [sessionId]
1347
+ );
1348
+ return /* @__PURE__ */ jsx6(
1142
1349
  _r,
1143
1350
  {
1144
1351
  className: cn("blade-chat-markdown break-words", className),
1145
1352
  mode: mode ?? "static",
1146
- components: MARKDOWN_COMPONENTS,
1353
+ components,
1354
+ allowedTags: CUSTOM_ALLOWED_TAGS,
1147
1355
  children: resolvedChildren
1148
- }
1356
+ },
1357
+ sessionId ?? "no-session"
1149
1358
  );
1150
1359
  }
1151
1360
 
1152
1361
  // src/components/Shimmer.tsx
1153
- import { jsx as jsx6 } from "react/jsx-runtime";
1362
+ import { jsx as jsx7 } from "react/jsx-runtime";
1154
1363
  function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
1155
- return /* @__PURE__ */ jsx6("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
1364
+ return /* @__PURE__ */ jsx7("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
1156
1365
  }
1157
1366
 
1158
1367
  // src/components/ToolCallBlock.tsx
1159
- import { useState as useState6 } from "react";
1368
+ import { useState as useState7 } from "react";
1160
1369
 
1161
1370
  // src/components/AskUserQuestionBlock.tsx
1162
- import { useEffect as useEffect4, useMemo as useMemo5, useState as useState5 } from "react";
1163
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1371
+ import { useEffect as useEffect4, useMemo as useMemo5, useState as useState6 } from "react";
1372
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1164
1373
  function AskUserQuestionBlock({
1165
1374
  data,
1166
1375
  answered,
@@ -1169,10 +1378,10 @@ function AskUserQuestionBlock({
1169
1378
  answerData,
1170
1379
  onAnswer
1171
1380
  }) {
1172
- const [selections, setSelections] = useState5(/* @__PURE__ */ new Map());
1173
- const [customTexts, setCustomTexts] = useState5(/* @__PURE__ */ new Map());
1174
- const [usingCustom, setUsingCustom] = useState5(/* @__PURE__ */ new Set());
1175
- const [submitted, setSubmitted] = useState5(false);
1381
+ const [selections, setSelections] = useState6(/* @__PURE__ */ new Map());
1382
+ const [customTexts, setCustomTexts] = useState6(/* @__PURE__ */ new Map());
1383
+ const [usingCustom, setUsingCustom] = useState6(/* @__PURE__ */ new Set());
1384
+ const [submitted, setSubmitted] = useState6(false);
1176
1385
  useEffect4(() => {
1177
1386
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
1178
1387
  setSubmitted(false);
@@ -1263,7 +1472,7 @@ ${parts.join("\n")}`;
1263
1472
  setSubmitted(true);
1264
1473
  onAnswer(text, toolCallId, nextAnswerData);
1265
1474
  };
1266
- return /* @__PURE__ */ jsxs5(
1475
+ return /* @__PURE__ */ jsxs6(
1267
1476
  "div",
1268
1477
  {
1269
1478
  className: cn(
@@ -1271,12 +1480,12 @@ ${parts.join("\n")}`;
1271
1480
  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"
1272
1481
  ),
1273
1482
  children: [
1274
- data.source_loop?.description && /* @__PURE__ */ jsxs5("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1483
+ data.source_loop?.description && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1275
1484
  "\u5B50\u667A\u80FD\u4F53\u300C",
1276
1485
  data.source_loop.description,
1277
1486
  "\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
1278
1487
  ] }),
1279
- data.questions.map((q, qIdx) => /* @__PURE__ */ jsx7(
1488
+ data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
1280
1489
  QuestionCard,
1281
1490
  {
1282
1491
  question: q,
@@ -1291,7 +1500,7 @@ ${parts.join("\n")}`;
1291
1500
  },
1292
1501
  q.question
1293
1502
  )),
1294
- !answered && !submitted && onAnswer && /* @__PURE__ */ jsx7(
1503
+ !answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
1295
1504
  "button",
1296
1505
  {
1297
1506
  type: "button",
@@ -1301,14 +1510,14 @@ ${parts.join("\n")}`;
1301
1510
  children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
1302
1511
  }
1303
1512
  ),
1304
- submitted && !answered && /* @__PURE__ */ jsxs5(
1513
+ submitted && !answered && /* @__PURE__ */ jsxs6(
1305
1514
  "button",
1306
1515
  {
1307
1516
  type: "button",
1308
1517
  disabled: true,
1309
1518
  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",
1310
1519
  children: [
1311
- /* @__PURE__ */ jsx7(LoaderCircle, { size: 14, className: "animate-spin" }),
1520
+ /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1312
1521
  "\u786E\u8BA4\u4E2D"
1313
1522
  ]
1314
1523
  }
@@ -1329,30 +1538,30 @@ function QuestionCard({
1329
1538
  onCustomChange
1330
1539
  }) {
1331
1540
  const multi = question.multiSelect ?? false;
1332
- return /* @__PURE__ */ jsxs5("div", { children: [
1333
- /* @__PURE__ */ jsxs5("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1334
- /* @__PURE__ */ jsx7(
1541
+ return /* @__PURE__ */ jsxs6("div", { children: [
1542
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1543
+ /* @__PURE__ */ jsx8(
1335
1544
  MessageSquareMore,
1336
1545
  {
1337
1546
  size: answered ? 12 : 13,
1338
1547
  className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
1339
1548
  }
1340
1549
  ),
1341
- /* @__PURE__ */ jsx7(
1550
+ /* @__PURE__ */ jsx8(
1342
1551
  "div",
1343
1552
  {
1344
1553
  className: cn(
1345
1554
  "min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
1346
1555
  answered ? "text-xs" : "text-sm"
1347
1556
  ),
1348
- children: /* @__PURE__ */ jsx7(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1557
+ children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1349
1558
  }
1350
1559
  )
1351
1560
  ] }),
1352
- /* @__PURE__ */ jsxs5("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1561
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1353
1562
  question.options.map((opt, optIdx) => {
1354
1563
  const isSel = selected.has(optIdx);
1355
- return /* @__PURE__ */ jsxs5(
1564
+ return /* @__PURE__ */ jsxs6(
1356
1565
  "button",
1357
1566
  {
1358
1567
  type: "button",
@@ -1366,14 +1575,14 @@ function QuestionCard({
1366
1575
  answered && "cursor-default opacity-70"
1367
1576
  ),
1368
1577
  children: [
1369
- multi && /* @__PURE__ */ jsx7(
1578
+ multi && /* @__PURE__ */ jsx8(
1370
1579
  "div",
1371
1580
  {
1372
1581
  className: cn(
1373
1582
  "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
1374
1583
  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))]"
1375
1584
  ),
1376
- children: isSel && /* @__PURE__ */ jsx7(
1585
+ children: isSel && /* @__PURE__ */ jsx8(
1377
1586
  Check,
1378
1587
  {
1379
1588
  size: 9,
@@ -1382,9 +1591,9 @@ function QuestionCard({
1382
1591
  )
1383
1592
  }
1384
1593
  ),
1385
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1386
- /* @__PURE__ */ jsx7("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1387
- opt.description && /* @__PURE__ */ jsx7(
1594
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
1595
+ /* @__PURE__ */ jsx8("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1596
+ opt.description && /* @__PURE__ */ jsx8(
1388
1597
  "div",
1389
1598
  {
1390
1599
  className: cn(
@@ -1401,7 +1610,7 @@ function QuestionCard({
1401
1610
  opt.label
1402
1611
  );
1403
1612
  }),
1404
- answered && !isCustom ? null : /* @__PURE__ */ jsxs5(
1613
+ answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
1405
1614
  "div",
1406
1615
  {
1407
1616
  className: cn(
@@ -1411,8 +1620,8 @@ function QuestionCard({
1411
1620
  answered && "cursor-default opacity-70"
1412
1621
  ),
1413
1622
  children: [
1414
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1415
- /* @__PURE__ */ jsx7(
1623
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1624
+ /* @__PURE__ */ jsx8(
1416
1625
  "input",
1417
1626
  {
1418
1627
  type: "text",
@@ -1480,7 +1689,7 @@ function normalizeOptionItem(value) {
1480
1689
  }
1481
1690
 
1482
1691
  // src/components/ToolCallBlock.tsx
1483
- import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1692
+ import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1484
1693
  function ToolCallBlock({
1485
1694
  toolCall,
1486
1695
  onAnswer,
@@ -1489,19 +1698,19 @@ function ToolCallBlock({
1489
1698
  sessionStatus,
1490
1699
  renderer
1491
1700
  }) {
1492
- const [expanded, setExpanded] = useState6(false);
1701
+ const [expanded, setExpanded] = useState7(false);
1493
1702
  const normalizedName = formatToolName(toolCall.name);
1494
1703
  if (renderer) {
1495
1704
  const custom = renderer(toolCall);
1496
1705
  if (custom !== null && custom !== void 0) {
1497
- return /* @__PURE__ */ jsx8(Fragment, { children: custom });
1706
+ return /* @__PURE__ */ jsx9(Fragment, { children: custom });
1498
1707
  }
1499
1708
  }
1500
1709
  if (normalizedName === "AskUserQuestion") {
1501
1710
  const askData = parseAskUserQuestion(typeof toolCall.result === "string" ? toolCall.result : null) ?? parseAskUserQuestion(buildAskUserPayload(toolCall.arguments));
1502
1711
  const canAnswer = toolCall.status === "awaiting_answer" && Boolean(onAnswer);
1503
1712
  if (askData) {
1504
- return /* @__PURE__ */ jsx8(
1713
+ return /* @__PURE__ */ jsx9(
1505
1714
  AskUserQuestionBlock,
1506
1715
  {
1507
1716
  data: askData,
@@ -1514,24 +1723,24 @@ function ToolCallBlock({
1514
1723
  );
1515
1724
  }
1516
1725
  if (toolCall.status === "pending") {
1517
- return /* @__PURE__ */ jsxs6("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: [
1518
- /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1519
- /* @__PURE__ */ jsx8("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
1726
+ return /* @__PURE__ */ jsxs7("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: [
1727
+ /* @__PURE__ */ jsx9(LoaderCircle, { size: 14, className: "animate-spin" }),
1728
+ /* @__PURE__ */ jsx9("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
1520
1729
  ] });
1521
1730
  }
1522
- return /* @__PURE__ */ jsxs6("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: [
1523
- /* @__PURE__ */ jsx8("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
1524
- /* @__PURE__ */ jsx8("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" })
1731
+ return /* @__PURE__ */ jsxs7("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: [
1732
+ /* @__PURE__ */ jsx9("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
1733
+ /* @__PURE__ */ jsx9("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" })
1525
1734
  ] });
1526
1735
  }
1527
1736
  const tone = getToolTone(toolCall.status);
1528
1737
  const displayName = getToolDisplayLabel(toolCall);
1529
1738
  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))]";
1530
- const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx8(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx8(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx8(X, { size: 11 }) : /* @__PURE__ */ jsx8(Check, { size: 11 });
1739
+ const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx9(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx9(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx9(X, { size: 11 }) : /* @__PURE__ */ jsx9(Check, { size: 11 });
1531
1740
  const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
1532
- return /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool ml-4 text-xs", children: [
1533
- /* @__PURE__ */ jsxs6("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
1534
- /* @__PURE__ */ jsxs6(
1741
+ return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool ml-4 text-xs", children: [
1742
+ /* @__PURE__ */ jsxs7("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
1743
+ /* @__PURE__ */ jsxs7(
1535
1744
  "button",
1536
1745
  {
1537
1746
  type: "button",
@@ -1539,7 +1748,7 @@ function ToolCallBlock({
1539
1748
  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",
1540
1749
  "aria-expanded": expanded,
1541
1750
  children: [
1542
- /* @__PURE__ */ jsx8(
1751
+ /* @__PURE__ */ jsx9(
1543
1752
  ChevronRight,
1544
1753
  {
1545
1754
  size: 11,
@@ -1549,24 +1758,24 @@ function ToolCallBlock({
1549
1758
  )
1550
1759
  }
1551
1760
  ),
1552
- /* @__PURE__ */ jsxs6("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
1761
+ /* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
1553
1762
  statusIcon,
1554
- /* @__PURE__ */ jsx8("span", { children: getToolStatusLabel(toolCall.status) })
1763
+ /* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
1555
1764
  ] }),
1556
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
1765
+ /* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
1557
1766
  ]
1558
1767
  }
1559
1768
  ),
1560
- typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx8("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
1769
+ typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx9("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
1561
1770
  ] }),
1562
- expanded && /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
1563
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
1564
- /* @__PURE__ */ jsx8("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
1565
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
1566
- /* @__PURE__ */ jsx8("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) }),
1567
- toolCall.result != null && /* @__PURE__ */ jsxs6(Fragment, { children: [
1568
- /* @__PURE__ */ jsx8("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
1569
- /* @__PURE__ */ jsx8("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) })
1771
+ expanded && /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
1772
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
1773
+ /* @__PURE__ */ jsx9("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
1774
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
1775
+ /* @__PURE__ */ jsx9("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) }),
1776
+ toolCall.result != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
1777
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
1778
+ /* @__PURE__ */ jsx9("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) })
1570
1779
  ] })
1571
1780
  ] })
1572
1781
  ] });
@@ -1584,11 +1793,11 @@ function buildAskUserPayload(argumentsJson) {
1584
1793
  }
1585
1794
 
1586
1795
  // src/components/AssistantTurnBlock.tsx
1587
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1796
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1588
1797
  function ThinkingBlock({ reasoning, isStreaming }) {
1589
- const [open, setOpen] = useState7(false);
1590
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
1591
- /* @__PURE__ */ jsxs7(
1798
+ const [open, setOpen] = useState8(false);
1799
+ return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
1800
+ /* @__PURE__ */ jsxs8(
1592
1801
  "button",
1593
1802
  {
1594
1803
  type: "button",
@@ -1596,9 +1805,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1596
1805
  "aria-expanded": open,
1597
1806
  className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
1598
1807
  children: [
1599
- /* @__PURE__ */ jsx9(Brain, { size: 12, className: "shrink-0" }),
1600
- isStreaming ? /* @__PURE__ */ jsx9(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003..." }) : /* @__PURE__ */ jsx9("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1601
- /* @__PURE__ */ jsx9(
1808
+ /* @__PURE__ */ jsx10(Brain, { size: 12, className: "shrink-0" }),
1809
+ isStreaming ? /* @__PURE__ */ jsx10(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx10("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1810
+ /* @__PURE__ */ jsxs8("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
1811
+ "\xB7 ",
1812
+ new Intl.NumberFormat("zh-CN").format(reasoning.length),
1813
+ " \u5B57"
1814
+ ] }),
1815
+ /* @__PURE__ */ jsx10(
1602
1816
  ChevronDown,
1603
1817
  {
1604
1818
  size: 12,
@@ -1608,47 +1822,57 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1608
1822
  ]
1609
1823
  }
1610
1824
  ),
1611
- open && /* @__PURE__ */ jsx9("div", { className: "mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]", children: reasoning })
1825
+ open && /* @__PURE__ */ jsx10("div", { className: "mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]", children: reasoning })
1612
1826
  ] });
1613
1827
  }
1614
1828
  function getMessageText(message) {
1615
1829
  return getTextContent(normalizeMessageContent(message.content)).trim();
1616
1830
  }
1831
+ function findLatestReasoningMessageIndex(messages) {
1832
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1833
+ if (messages[index].reasoning) return index;
1834
+ }
1835
+ return -1;
1836
+ }
1617
1837
  function AssistantTurnBlock({
1618
1838
  messages,
1619
1839
  isStreaming = false,
1620
1840
  askAnswers,
1621
1841
  onAnswer,
1622
1842
  sessionStatus,
1623
- toolCallRenderer
1843
+ toolCallRenderer,
1844
+ sessionId
1624
1845
  }) {
1625
1846
  const hasInterrupted = messages.some((message) => message.status === "interrupted");
1626
1847
  const hasAnyContent = messages.some(
1627
1848
  (message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
1628
1849
  );
1629
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1630
- hasInterrupted && /* @__PURE__ */ jsx9("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" }),
1850
+ const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
1851
+ return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1852
+ hasInterrupted && /* @__PURE__ */ jsx10("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" }),
1631
1853
  messages.map((message, index) => {
1632
1854
  const isLast = index === messages.length - 1;
1633
1855
  const streamingThis = isStreaming && isLast;
1634
1856
  const text = getMessageText(message);
1635
1857
  const toolCalls = message.tool_calls ?? [];
1636
- return /* @__PURE__ */ jsxs7(
1858
+ const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
1859
+ return /* @__PURE__ */ jsxs8(
1637
1860
  "div",
1638
1861
  {
1639
1862
  className: "flex flex-col gap-3",
1640
1863
  children: [
1641
- message.reasoning && /* @__PURE__ */ jsx9(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1642
- text && /* @__PURE__ */ jsx9("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx9(
1864
+ showReasoning && message.reasoning && /* @__PURE__ */ jsx10(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1865
+ text && /* @__PURE__ */ jsx10("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx10(
1643
1866
  MarkdownContent,
1644
1867
  {
1645
1868
  mode: streamingThis ? "streaming" : "static",
1646
1869
  className: "blade-chat-prose",
1870
+ sessionId,
1647
1871
  children: text
1648
1872
  }
1649
1873
  ) }),
1650
- toolCalls.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-2", children: toolCalls.map(
1651
- (toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx9(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx9(
1874
+ toolCalls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: toolCalls.map(
1875
+ (toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx10(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx10(
1652
1876
  ToolCallBlock,
1653
1877
  {
1654
1878
  toolCall,
@@ -1666,13 +1890,13 @@ function AssistantTurnBlock({
1666
1890
  message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
1667
1891
  );
1668
1892
  }),
1669
- isStreaming && !hasAnyContent && /* @__PURE__ */ jsx9(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
1893
+ isStreaming && !hasAnyContent && /* @__PURE__ */ jsx10(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
1670
1894
  ] });
1671
1895
  }
1672
1896
 
1673
1897
  // src/components/RenderErrorBoundary.tsx
1674
1898
  import { Component } from "react";
1675
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1899
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1676
1900
  function getFirstComponentName(componentStack) {
1677
1901
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
1678
1902
  return match?.[1] ?? null;
@@ -1705,18 +1929,18 @@ var RenderErrorBoundary = class extends Component {
1705
1929
  return children;
1706
1930
  }
1707
1931
  const componentName = getFirstComponentName(componentStack);
1708
- return /* @__PURE__ */ jsx10("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__ */ jsxs8("div", { className: "flex items-start gap-2", children: [
1709
- /* @__PURE__ */ jsx10(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
1710
- /* @__PURE__ */ jsxs8("div", { className: "min-w-0 flex-1", children: [
1711
- /* @__PURE__ */ jsxs8("div", { className: "font-medium", children: [
1932
+ return /* @__PURE__ */ jsx11("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__ */ jsxs9("div", { className: "flex items-start gap-2", children: [
1933
+ /* @__PURE__ */ jsx11(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
1934
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1935
+ /* @__PURE__ */ jsxs9("div", { className: "font-medium", children: [
1712
1936
  label,
1713
1937
  "\u6E32\u67D3\u5931\u8D25"
1714
1938
  ] }),
1715
- /* @__PURE__ */ jsxs8("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
1939
+ /* @__PURE__ */ jsxs9("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
1716
1940
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
1717
1941
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
1718
1942
  ] }),
1719
- details ? /* @__PURE__ */ jsx10("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
1943
+ details ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
1720
1944
  ] })
1721
1945
  ] }) });
1722
1946
  }
@@ -1724,7 +1948,7 @@ var RenderErrorBoundary = class extends Component {
1724
1948
 
1725
1949
  // src/components/UserMessageBubble.tsx
1726
1950
  import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
1727
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1951
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1728
1952
  function isUserMessage(message) {
1729
1953
  return message.role === "user";
1730
1954
  }
@@ -1736,8 +1960,8 @@ function UserMessageBubble({ message, className }) {
1736
1960
  const text = getTextContent2(message.content).trim();
1737
1961
  const fileParts = getFileParts(message.content);
1738
1962
  const imageParts = getImageParts(message.content);
1739
- return /* @__PURE__ */ jsx11("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs9("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
1740
- imageParts.length > 0 && /* @__PURE__ */ jsx11("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx11(
1963
+ return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs10("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
1964
+ imageParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
1741
1965
  "img",
1742
1966
  {
1743
1967
  src: part.image_url.url,
@@ -1746,21 +1970,21 @@ function UserMessageBubble({ message, className }) {
1746
1970
  },
1747
1971
  part.image_url.url
1748
1972
  )) }),
1749
- fileParts.length > 0 && /* @__PURE__ */ jsx11("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs9(
1973
+ fileParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
1750
1974
  "div",
1751
1975
  {
1752
1976
  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))]",
1753
1977
  children: [
1754
- /* @__PURE__ */ jsx11(FileText, { size: 12, className: "shrink-0" }),
1755
- /* @__PURE__ */ jsx11("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
1978
+ /* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
1979
+ /* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
1756
1980
  ]
1757
1981
  },
1758
1982
  `${part.name}-${part.data.length}`
1759
1983
  )) }),
1760
- text && /* @__PURE__ */ jsx11("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__ */ jsx11(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
1761
- text && isSending(message) && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
1762
- /* @__PURE__ */ jsx11(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
1763
- /* @__PURE__ */ jsx11("span", { children: "\u53D1\u9001\u4E2D" })
1984
+ text && /* @__PURE__ */ jsx12("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__ */ jsx12(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
1985
+ text && isSending(message) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
1986
+ /* @__PURE__ */ jsx12(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
1987
+ /* @__PURE__ */ jsx12("span", { children: "\u53D1\u9001\u4E2D" })
1764
1988
  ] })
1765
1989
  ] }) });
1766
1990
  }
@@ -1769,11 +1993,11 @@ function ErrorMessageBlock({
1769
1993
  className
1770
1994
  }) {
1771
1995
  const text = getTextContent2(message.content);
1772
- return /* @__PURE__ */ jsx11("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx11("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]", children: text }) });
1996
+ return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx12("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]", children: text }) });
1773
1997
  }
1774
1998
 
1775
1999
  // src/components/MessageList.tsx
1776
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2000
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1777
2001
  function parseModeChange(message) {
1778
2002
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
1779
2003
  return null;
@@ -1813,7 +2037,8 @@ function MessageList({
1813
2037
  onAnswer,
1814
2038
  toolCallRenderer,
1815
2039
  emptyState,
1816
- className
2040
+ className,
2041
+ sessionId
1817
2042
  }) {
1818
2043
  const renderBlocks = useMemo6(() => {
1819
2044
  const visible = messages.filter((message) => {
@@ -1888,24 +2113,24 @@ function MessageList({
1888
2113
  }
1889
2114
  return blocks;
1890
2115
  }, [messages, isStreaming]);
1891
- return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs10(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
1892
- /* @__PURE__ */ jsx12(StickToBottom.Content, { className: "px-5 pb-7 pt-8 sm:px-10 sm:pt-10", children: /* @__PURE__ */ jsx12("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-col gap-9", children: [
1893
- renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col items-center justify-center gap-3 py-24 text-[hsl(var(--muted-foreground))]", children: [
1894
- /* @__PURE__ */ jsx12(MessageSquare, { size: 40, strokeWidth: 1.5 }),
1895
- /* @__PURE__ */ jsx12("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
1896
- /* @__PURE__ */ jsx12("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
2116
+ return /* @__PURE__ */ jsx13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs11(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
2117
+ /* @__PURE__ */ jsx13(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx13("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-col", children: [
2118
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs11("div", { className: "blade-chat-empty", children: [
2119
+ /* @__PURE__ */ jsx13(MessageSquare, { size: 40, strokeWidth: 1.5 }),
2120
+ /* @__PURE__ */ jsx13("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
2121
+ /* @__PURE__ */ jsx13("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
1897
2122
  ] }) : renderBlocks.map((block) => {
1898
2123
  if (block.type === "message") {
1899
- return /* @__PURE__ */ jsx12("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx12(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx12(ErrorMessageBlock, { message: block.message }) : null }, block.key);
2124
+ return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx13(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx13(ErrorMessageBlock, { message: block.message }) : null }, block.key);
1900
2125
  }
1901
2126
  if (block.type === "assistant_turn") {
1902
- return /* @__PURE__ */ jsx12("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx12(
2127
+ return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx13(
1903
2128
  RenderErrorBoundary,
1904
2129
  {
1905
2130
  label: "\u52A9\u624B\u6D88\u606F",
1906
2131
  details: block.key,
1907
2132
  resetKey: getMessageResetSignature(block.messages),
1908
- children: /* @__PURE__ */ jsx12(
2133
+ children: /* @__PURE__ */ jsx13(
1909
2134
  AssistantTurnBlock,
1910
2135
  {
1911
2136
  messages: block.messages,
@@ -1913,31 +2138,32 @@ function MessageList({
1913
2138
  askAnswers,
1914
2139
  onAnswer,
1915
2140
  sessionStatus,
1916
- toolCallRenderer
2141
+ toolCallRenderer,
2142
+ sessionId
1917
2143
  }
1918
2144
  )
1919
2145
  }
1920
2146
  ) }, block.key);
1921
2147
  }
1922
2148
  if (block.type === "compaction") {
1923
- return /* @__PURE__ */ jsxs10(
2149
+ return /* @__PURE__ */ jsxs11(
1924
2150
  "div",
1925
2151
  {
1926
2152
  className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
1927
2153
  children: [
1928
- /* @__PURE__ */ jsx12(Layers, { size: 12 }),
1929
- /* @__PURE__ */ jsx12("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
2154
+ /* @__PURE__ */ jsx13(Layers, { size: 12 }),
2155
+ /* @__PURE__ */ jsx13("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
1930
2156
  ]
1931
2157
  },
1932
2158
  block.key
1933
2159
  );
1934
2160
  }
1935
- return /* @__PURE__ */ jsx12(PlanningDivider, { kind: block.kind }, block.key);
2161
+ return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
1936
2162
  }),
1937
- sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx12("div", { className: "flex", children: /* @__PURE__ */ jsx12("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
2163
+ sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx13("div", { className: "flex", children: /* @__PURE__ */ jsx13("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
1938
2164
  ] }) }) }),
1939
- /* @__PURE__ */ jsx12(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
1940
- /* @__PURE__ */ jsx12(ScrollToBottomButton, {})
2165
+ /* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
2166
+ /* @__PURE__ */ jsx13(ScrollToBottomButton, {})
1941
2167
  ] }) });
1942
2168
  }
1943
2169
  function AutoScrollOnUserSend({ userMessageCount }) {
@@ -1954,38 +2180,39 @@ function AutoScrollOnUserSend({ userMessageCount }) {
1954
2180
  function ScrollToBottomButton() {
1955
2181
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();
1956
2182
  if (isAtBottom) return null;
1957
- return /* @__PURE__ */ jsxs10(
2183
+ return /* @__PURE__ */ jsxs11(
1958
2184
  "button",
1959
2185
  {
1960
2186
  type: "button",
1961
2187
  onClick: () => scrollToBottom(),
1962
- className: "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))]",
2188
+ "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
2189
+ 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))]",
1963
2190
  children: [
1964
- /* @__PURE__ */ jsx12(ChevronDown, { size: 14 }),
1965
- /* @__PURE__ */ jsx12("span", { children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
2191
+ /* @__PURE__ */ jsx13(ChevronDown, { size: 14 }),
2192
+ /* @__PURE__ */ jsx13("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
1966
2193
  ]
1967
2194
  }
1968
2195
  );
1969
2196
  }
1970
2197
  function PlanningDivider({ kind }) {
1971
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 py-1", children: [
1972
- /* @__PURE__ */ jsx12("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
1973
- /* @__PURE__ */ jsxs10("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: [
1974
- /* @__PURE__ */ jsx12(Lightbulb, { size: 12 }),
1975
- /* @__PURE__ */ jsx12("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
2198
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 py-1", children: [
2199
+ /* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
2200
+ /* @__PURE__ */ jsxs11("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: [
2201
+ /* @__PURE__ */ jsx13(Lightbulb, { size: 12 }),
2202
+ /* @__PURE__ */ jsx13("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
1976
2203
  ] }),
1977
- /* @__PURE__ */ jsx12("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
2204
+ /* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
1978
2205
  ] });
1979
2206
  }
1980
2207
 
1981
2208
  // src/components/ChatView.tsx
1982
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2209
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1983
2210
  function isUnauthorizedError(error) {
1984
2211
  return error instanceof BladeApiError && error.status === 401;
1985
2212
  }
1986
2213
  function LoginCard({ client, onLoggedIn }) {
1987
- const [loggingIn, setLoggingIn] = useState8(false);
1988
- const [loginError, setLoginError] = useState8(null);
2214
+ const [loggingIn, setLoggingIn] = useState9(false);
2215
+ const [loginError, setLoginError] = useState9(null);
1989
2216
  const handleLogin = async () => {
1990
2217
  setLoggingIn(true);
1991
2218
  setLoginError(null);
@@ -1998,11 +2225,11 @@ function LoginCard({ client, onLoggedIn }) {
1998
2225
  setLoggingIn(false);
1999
2226
  }
2000
2227
  };
2001
- return /* @__PURE__ */ jsx13("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs11("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: [
2002
- /* @__PURE__ */ jsx13(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
2003
- /* @__PURE__ */ jsx13("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
2004
- /* @__PURE__ */ jsx13("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" }),
2005
- /* @__PURE__ */ jsx13(
2228
+ return /* @__PURE__ */ jsx14("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs12("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: [
2229
+ /* @__PURE__ */ jsx14(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
2230
+ /* @__PURE__ */ jsx14("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
2231
+ /* @__PURE__ */ jsx14("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" }),
2232
+ /* @__PURE__ */ jsx14(
2006
2233
  "button",
2007
2234
  {
2008
2235
  type: "button",
@@ -2012,15 +2239,15 @@ function LoginCard({ client, onLoggedIn }) {
2012
2239
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
2013
2240
  }
2014
2241
  ),
2015
- loginError && /* @__PURE__ */ jsx13("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
2242
+ loginError && /* @__PURE__ */ jsx14("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
2016
2243
  ] }) });
2017
2244
  }
2018
2245
  function ChatView(props) {
2019
2246
  const client = useBladeClient();
2020
- const [attempt, setAttempt] = useState8(0);
2021
- const [needLogin, setNeedLogin] = useState8(() => !client.hasToken());
2247
+ const [attempt, setAttempt] = useState9(0);
2248
+ const [needLogin, setNeedLogin] = useState9(() => !client.hasToken());
2022
2249
  if (needLogin) {
2023
- return /* @__PURE__ */ jsx13("div", { className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root), children: /* @__PURE__ */ jsx13(
2250
+ return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root), children: /* @__PURE__ */ jsx14(
2024
2251
  LoginCard,
2025
2252
  {
2026
2253
  client,
@@ -2031,7 +2258,7 @@ function ChatView(props) {
2031
2258
  }
2032
2259
  ) });
2033
2260
  }
2034
- return /* @__PURE__ */ jsx13(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2261
+ return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2035
2262
  }
2036
2263
  function ChatSessionView({
2037
2264
  sessionId,
@@ -2049,8 +2276,8 @@ function ChatSessionView({
2049
2276
  createOptions,
2050
2277
  onSessionCreated
2051
2278
  });
2052
- const [stopRequested, setStopRequested] = useState8(false);
2053
- const [inputText, setInputText] = useState8("");
2279
+ const [stopRequested, setStopRequested] = useState9(false);
2280
+ const [inputText, setInputText] = useState9("");
2054
2281
  useEffect6(() => {
2055
2282
  if (session) {
2056
2283
  onSessionReady?.(session);
@@ -2098,7 +2325,7 @@ ${content}`);
2098
2325
  setStopRequested(true);
2099
2326
  void session?.stop();
2100
2327
  };
2101
- return /* @__PURE__ */ jsxs11(
2328
+ return /* @__PURE__ */ jsxs12(
2102
2329
  "div",
2103
2330
  {
2104
2331
  className: cn(
@@ -2106,19 +2333,19 @@ ${content}`);
2106
2333
  classNames?.root
2107
2334
  ),
2108
2335
  children: [
2109
- /* @__PURE__ */ jsx13(
2336
+ /* @__PURE__ */ jsx14(
2110
2337
  ConnectionBanner,
2111
2338
  {
2112
2339
  connection: state?.connection ?? "connecting",
2113
2340
  className: classNames?.banner
2114
2341
  }
2115
2342
  ),
2116
- errorMessage && /* @__PURE__ */ jsxs11("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300", children: [
2117
- /* @__PURE__ */ jsx13(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2118
- /* @__PURE__ */ jsx13("span", { children: errorMessage })
2343
+ errorMessage && /* @__PURE__ */ jsxs12("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300", children: [
2344
+ /* @__PURE__ */ jsx14(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2345
+ /* @__PURE__ */ jsx14("span", { children: errorMessage })
2119
2346
  ] }),
2120
2347
  slots?.header,
2121
- /* @__PURE__ */ jsx13(
2348
+ /* @__PURE__ */ jsx14(
2122
2349
  MessageList,
2123
2350
  {
2124
2351
  messages: state?.messages ?? [],
@@ -2133,10 +2360,11 @@ ${content}`);
2133
2360
  },
2134
2361
  toolCallRenderer: renderers?.toolCall,
2135
2362
  emptyState: slots?.emptyState,
2136
- className: classNames?.messageList
2363
+ className: classNames?.messageList,
2364
+ sessionId: session?.sessionId
2137
2365
  }
2138
2366
  ),
2139
- /* @__PURE__ */ jsx13(
2367
+ /* @__PURE__ */ jsx14(
2140
2368
  ChatInput,
2141
2369
  {
2142
2370
  value: inputText,
@@ -2170,6 +2398,7 @@ lucide-react/dist/esm/shared/src/utils.js:
2170
2398
  lucide-react/dist/esm/defaultAttributes.js:
2171
2399
  lucide-react/dist/esm/Icon.js:
2172
2400
  lucide-react/dist/esm/createLucideIcon.js:
2401
+ lucide-react/dist/esm/icons/archive.js:
2173
2402
  lucide-react/dist/esm/icons/arrow-up.js:
2174
2403
  lucide-react/dist/esm/icons/bot.js:
2175
2404
  lucide-react/dist/esm/icons/brain.js:
@@ -2178,13 +2407,20 @@ lucide-react/dist/esm/icons/chevron-down.js:
2178
2407
  lucide-react/dist/esm/icons/chevron-right.js:
2179
2408
  lucide-react/dist/esm/icons/circle-alert.js:
2180
2409
  lucide-react/dist/esm/icons/copy.js:
2410
+ lucide-react/dist/esm/icons/download.js:
2411
+ lucide-react/dist/esm/icons/file-code-2.js:
2412
+ lucide-react/dist/esm/icons/file-spreadsheet.js:
2181
2413
  lucide-react/dist/esm/icons/file-text.js:
2414
+ lucide-react/dist/esm/icons/file.js:
2415
+ lucide-react/dist/esm/icons/film.js:
2416
+ lucide-react/dist/esm/icons/image.js:
2182
2417
  lucide-react/dist/esm/icons/layers.js:
2183
2418
  lucide-react/dist/esm/icons/lightbulb.js:
2184
2419
  lucide-react/dist/esm/icons/loader-circle.js:
2185
2420
  lucide-react/dist/esm/icons/lock-keyhole.js:
2186
2421
  lucide-react/dist/esm/icons/message-square-more.js:
2187
2422
  lucide-react/dist/esm/icons/message-square.js:
2423
+ lucide-react/dist/esm/icons/music.js:
2188
2424
  lucide-react/dist/esm/icons/square.js:
2189
2425
  lucide-react/dist/esm/icons/triangle-alert.js:
2190
2426
  lucide-react/dist/esm/icons/x.js: