@blade-hq/agent-react 1.2.1-alpha.4 → 1.2.1-beta.10

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) {
@@ -366,18 +430,19 @@ function ChatInput({
366
430
  }) {
367
431
  const trimmed = value.trim();
368
432
  const canSend = trimmed.length > 0 && !isStreaming;
369
- const handleSend = () => {
433
+ const handleSend = async () => {
370
434
  if (!canSend) return;
371
- onSend(trimmed);
435
+ const accepted = await onSend(trimmed);
436
+ if (!accepted) return;
372
437
  onValueChange("");
373
438
  };
374
439
  const handleKeyDown = (event) => {
375
440
  if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
376
441
  event.preventDefault();
377
- handleSend();
442
+ void handleSend();
378
443
  }
379
444
  };
380
- 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: [
381
446
  /* @__PURE__ */ jsx2(
382
447
  "textarea",
383
448
  {
@@ -876,7 +941,7 @@ function useStickToBottomContext() {
876
941
 
877
942
  // src/components/AssistantTurnBlock.tsx
878
943
  import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
879
- import { useState as useState7 } from "react";
944
+ import { useState as useState8 } from "react";
880
945
 
881
946
  // src/components/AgentLoopBlock.tsx
882
947
  import { useState as useState3 } from "react";
@@ -1079,14 +1144,142 @@ import {
1079
1144
  useEffect as useEffect3,
1080
1145
  useMemo as useMemo4,
1081
1146
  useRef as useRef4,
1082
- useState as useState4
1147
+ useState as useState5
1083
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";
1084
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";
1085
1278
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
1086
1279
  function CodeBlockPre({ children, node: _node, ...props }) {
1087
1280
  const preRef = useRef4(null);
1088
- const [copied, setCopied] = useState4(false);
1089
- const [language, setLanguage] = useState4("");
1281
+ const [copied, setCopied] = useState5(false);
1282
+ const [language, setLanguage] = useState5("");
1090
1283
  useEffect3(() => {
1091
1284
  const codeEl = preRef.current?.querySelector("code");
1092
1285
  setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
@@ -1098,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1098
1291
  setTimeout(() => setCopied(false), 2e3);
1099
1292
  }
1100
1293
  };
1101
- return /* @__PURE__ */ jsxs4("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
1102
- /* @__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: [
1103
- /* @__PURE__ */ jsx5("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
1104
- /* @__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(
1105
1298
  "button",
1106
1299
  {
1107
1300
  type: "button",
@@ -1111,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1111
1304
  copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
1112
1305
  ),
1113
1306
  children: [
1114
- copied ? /* @__PURE__ */ jsx5(Check, { size: 12 }) : /* @__PURE__ */ jsx5(Copy, { size: 12 }),
1115
- /* @__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" })
1116
1309
  ]
1117
1310
  }
1118
1311
  )
1119
1312
  ] }),
1120
- /* @__PURE__ */ jsx5(
1313
+ /* @__PURE__ */ jsx6(
1121
1314
  "pre",
1122
1315
  {
1123
1316
  ref: preRef,
@@ -1129,37 +1322,54 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1129
1322
  ] });
1130
1323
  }
1131
1324
  function ExternalAnchor({ node: _node, children, ...props }) {
1132
- return /* @__PURE__ */ jsx5("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1325
+ return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1133
1326
  }
1134
1327
  var MARKDOWN_COMPONENTS = {
1135
1328
  pre: CodeBlockPre,
1136
1329
  a: ExternalAnchor
1137
1330
  };
1138
- function MarkdownContent({ children, className, mode }) {
1139
- const resolvedChildren = useMemo4(() => children.replace(SYSTEM_REMINDER_RE, ""), [children]);
1140
- 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(
1141
1349
  _r,
1142
1350
  {
1143
1351
  className: cn("blade-chat-markdown break-words", className),
1144
1352
  mode: mode ?? "static",
1145
- components: MARKDOWN_COMPONENTS,
1353
+ components,
1354
+ allowedTags: CUSTOM_ALLOWED_TAGS,
1146
1355
  children: resolvedChildren
1147
- }
1356
+ },
1357
+ sessionId ?? "no-session"
1148
1358
  );
1149
1359
  }
1150
1360
 
1151
1361
  // src/components/Shimmer.tsx
1152
- import { jsx as jsx6 } from "react/jsx-runtime";
1362
+ import { jsx as jsx7 } from "react/jsx-runtime";
1153
1363
  function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
1154
- 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 });
1155
1365
  }
1156
1366
 
1157
1367
  // src/components/ToolCallBlock.tsx
1158
- import { useState as useState6 } from "react";
1368
+ import { useState as useState7 } from "react";
1159
1369
 
1160
1370
  // src/components/AskUserQuestionBlock.tsx
1161
- import { useEffect as useEffect4, useMemo as useMemo5, useState as useState5 } from "react";
1162
- 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";
1163
1373
  function AskUserQuestionBlock({
1164
1374
  data,
1165
1375
  answered,
@@ -1168,10 +1378,10 @@ function AskUserQuestionBlock({
1168
1378
  answerData,
1169
1379
  onAnswer
1170
1380
  }) {
1171
- const [selections, setSelections] = useState5(/* @__PURE__ */ new Map());
1172
- const [customTexts, setCustomTexts] = useState5(/* @__PURE__ */ new Map());
1173
- const [usingCustom, setUsingCustom] = useState5(/* @__PURE__ */ new Set());
1174
- 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);
1175
1385
  useEffect4(() => {
1176
1386
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
1177
1387
  setSubmitted(false);
@@ -1262,7 +1472,7 @@ ${parts.join("\n")}`;
1262
1472
  setSubmitted(true);
1263
1473
  onAnswer(text, toolCallId, nextAnswerData);
1264
1474
  };
1265
- return /* @__PURE__ */ jsxs5(
1475
+ return /* @__PURE__ */ jsxs6(
1266
1476
  "div",
1267
1477
  {
1268
1478
  className: cn(
@@ -1270,12 +1480,12 @@ ${parts.join("\n")}`;
1270
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"
1271
1481
  ),
1272
1482
  children: [
1273
- 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: [
1274
1484
  "\u5B50\u667A\u80FD\u4F53\u300C",
1275
1485
  data.source_loop.description,
1276
1486
  "\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
1277
1487
  ] }),
1278
- data.questions.map((q, qIdx) => /* @__PURE__ */ jsx7(
1488
+ data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
1279
1489
  QuestionCard,
1280
1490
  {
1281
1491
  question: q,
@@ -1290,7 +1500,7 @@ ${parts.join("\n")}`;
1290
1500
  },
1291
1501
  q.question
1292
1502
  )),
1293
- !answered && !submitted && onAnswer && /* @__PURE__ */ jsx7(
1503
+ !answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
1294
1504
  "button",
1295
1505
  {
1296
1506
  type: "button",
@@ -1300,14 +1510,14 @@ ${parts.join("\n")}`;
1300
1510
  children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
1301
1511
  }
1302
1512
  ),
1303
- submitted && !answered && /* @__PURE__ */ jsxs5(
1513
+ submitted && !answered && /* @__PURE__ */ jsxs6(
1304
1514
  "button",
1305
1515
  {
1306
1516
  type: "button",
1307
1517
  disabled: true,
1308
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",
1309
1519
  children: [
1310
- /* @__PURE__ */ jsx7(LoaderCircle, { size: 14, className: "animate-spin" }),
1520
+ /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1311
1521
  "\u786E\u8BA4\u4E2D"
1312
1522
  ]
1313
1523
  }
@@ -1328,30 +1538,30 @@ function QuestionCard({
1328
1538
  onCustomChange
1329
1539
  }) {
1330
1540
  const multi = question.multiSelect ?? false;
1331
- return /* @__PURE__ */ jsxs5("div", { children: [
1332
- /* @__PURE__ */ jsxs5("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1333
- /* @__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(
1334
1544
  MessageSquareMore,
1335
1545
  {
1336
1546
  size: answered ? 12 : 13,
1337
1547
  className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
1338
1548
  }
1339
1549
  ),
1340
- /* @__PURE__ */ jsx7(
1550
+ /* @__PURE__ */ jsx8(
1341
1551
  "div",
1342
1552
  {
1343
1553
  className: cn(
1344
1554
  "min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
1345
1555
  answered ? "text-xs" : "text-sm"
1346
1556
  ),
1347
- children: /* @__PURE__ */ jsx7(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1557
+ children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1348
1558
  }
1349
1559
  )
1350
1560
  ] }),
1351
- /* @__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: [
1352
1562
  question.options.map((opt, optIdx) => {
1353
1563
  const isSel = selected.has(optIdx);
1354
- return /* @__PURE__ */ jsxs5(
1564
+ return /* @__PURE__ */ jsxs6(
1355
1565
  "button",
1356
1566
  {
1357
1567
  type: "button",
@@ -1365,14 +1575,14 @@ function QuestionCard({
1365
1575
  answered && "cursor-default opacity-70"
1366
1576
  ),
1367
1577
  children: [
1368
- multi && /* @__PURE__ */ jsx7(
1578
+ multi && /* @__PURE__ */ jsx8(
1369
1579
  "div",
1370
1580
  {
1371
1581
  className: cn(
1372
1582
  "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
1373
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))]"
1374
1584
  ),
1375
- children: isSel && /* @__PURE__ */ jsx7(
1585
+ children: isSel && /* @__PURE__ */ jsx8(
1376
1586
  Check,
1377
1587
  {
1378
1588
  size: 9,
@@ -1381,9 +1591,9 @@ function QuestionCard({
1381
1591
  )
1382
1592
  }
1383
1593
  ),
1384
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1385
- /* @__PURE__ */ jsx7("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1386
- 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(
1387
1597
  "div",
1388
1598
  {
1389
1599
  className: cn(
@@ -1400,7 +1610,7 @@ function QuestionCard({
1400
1610
  opt.label
1401
1611
  );
1402
1612
  }),
1403
- answered && !isCustom ? null : /* @__PURE__ */ jsxs5(
1613
+ answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
1404
1614
  "div",
1405
1615
  {
1406
1616
  className: cn(
@@ -1410,8 +1620,8 @@ function QuestionCard({
1410
1620
  answered && "cursor-default opacity-70"
1411
1621
  ),
1412
1622
  children: [
1413
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1414
- /* @__PURE__ */ jsx7(
1623
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1624
+ /* @__PURE__ */ jsx8(
1415
1625
  "input",
1416
1626
  {
1417
1627
  type: "text",
@@ -1479,7 +1689,7 @@ function normalizeOptionItem(value) {
1479
1689
  }
1480
1690
 
1481
1691
  // src/components/ToolCallBlock.tsx
1482
- 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";
1483
1693
  function ToolCallBlock({
1484
1694
  toolCall,
1485
1695
  onAnswer,
@@ -1488,19 +1698,19 @@ function ToolCallBlock({
1488
1698
  sessionStatus,
1489
1699
  renderer
1490
1700
  }) {
1491
- const [expanded, setExpanded] = useState6(false);
1701
+ const [expanded, setExpanded] = useState7(false);
1492
1702
  const normalizedName = formatToolName(toolCall.name);
1493
1703
  if (renderer) {
1494
1704
  const custom = renderer(toolCall);
1495
1705
  if (custom !== null && custom !== void 0) {
1496
- return /* @__PURE__ */ jsx8(Fragment, { children: custom });
1706
+ return /* @__PURE__ */ jsx9(Fragment, { children: custom });
1497
1707
  }
1498
1708
  }
1499
1709
  if (normalizedName === "AskUserQuestion") {
1500
1710
  const askData = parseAskUserQuestion(typeof toolCall.result === "string" ? toolCall.result : null) ?? parseAskUserQuestion(buildAskUserPayload(toolCall.arguments));
1501
1711
  const canAnswer = toolCall.status === "awaiting_answer" && Boolean(onAnswer);
1502
1712
  if (askData) {
1503
- return /* @__PURE__ */ jsx8(
1713
+ return /* @__PURE__ */ jsx9(
1504
1714
  AskUserQuestionBlock,
1505
1715
  {
1506
1716
  data: askData,
@@ -1513,24 +1723,24 @@ function ToolCallBlock({
1513
1723
  );
1514
1724
  }
1515
1725
  if (toolCall.status === "pending") {
1516
- 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: [
1517
- /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1518
- /* @__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" })
1519
1729
  ] });
1520
1730
  }
1521
- 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: [
1522
- /* @__PURE__ */ jsx8("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
1523
- /* @__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" })
1524
1734
  ] });
1525
1735
  }
1526
1736
  const tone = getToolTone(toolCall.status);
1527
1737
  const displayName = getToolDisplayLabel(toolCall);
1528
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))]";
1529
- 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 });
1530
1740
  const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
1531
- return /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool ml-4 text-xs", children: [
1532
- /* @__PURE__ */ jsxs6("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
1533
- /* @__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(
1534
1744
  "button",
1535
1745
  {
1536
1746
  type: "button",
@@ -1538,7 +1748,7 @@ function ToolCallBlock({
1538
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",
1539
1749
  "aria-expanded": expanded,
1540
1750
  children: [
1541
- /* @__PURE__ */ jsx8(
1751
+ /* @__PURE__ */ jsx9(
1542
1752
  ChevronRight,
1543
1753
  {
1544
1754
  size: 11,
@@ -1548,24 +1758,24 @@ function ToolCallBlock({
1548
1758
  )
1549
1759
  }
1550
1760
  ),
1551
- /* @__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: [
1552
1762
  statusIcon,
1553
- /* @__PURE__ */ jsx8("span", { children: getToolStatusLabel(toolCall.status) })
1763
+ /* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
1554
1764
  ] }),
1555
- /* @__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 })
1556
1766
  ]
1557
1767
  }
1558
1768
  ),
1559
- 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) })
1560
1770
  ] }),
1561
- expanded && /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
1562
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
1563
- /* @__PURE__ */ jsx8("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
1564
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
1565
- /* @__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) }),
1566
- toolCall.result != null && /* @__PURE__ */ jsxs6(Fragment, { children: [
1567
- /* @__PURE__ */ jsx8("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
1568
- /* @__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) })
1569
1779
  ] })
1570
1780
  ] })
1571
1781
  ] });
@@ -1583,11 +1793,11 @@ function buildAskUserPayload(argumentsJson) {
1583
1793
  }
1584
1794
 
1585
1795
  // src/components/AssistantTurnBlock.tsx
1586
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1796
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1587
1797
  function ThinkingBlock({ reasoning, isStreaming }) {
1588
- const [open, setOpen] = useState7(false);
1589
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
1590
- /* @__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(
1591
1801
  "button",
1592
1802
  {
1593
1803
  type: "button",
@@ -1595,9 +1805,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1595
1805
  "aria-expanded": open,
1596
1806
  className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
1597
1807
  children: [
1598
- /* @__PURE__ */ jsx9(Brain, { size: 12, className: "shrink-0" }),
1599
- isStreaming ? /* @__PURE__ */ jsx9(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003..." }) : /* @__PURE__ */ jsx9("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1600
- /* @__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(
1601
1816
  ChevronDown,
1602
1817
  {
1603
1818
  size: 12,
@@ -1607,47 +1822,57 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1607
1822
  ]
1608
1823
  }
1609
1824
  ),
1610
- 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 })
1611
1826
  ] });
1612
1827
  }
1613
1828
  function getMessageText(message) {
1614
1829
  return getTextContent(normalizeMessageContent(message.content)).trim();
1615
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
+ }
1616
1837
  function AssistantTurnBlock({
1617
1838
  messages,
1618
1839
  isStreaming = false,
1619
1840
  askAnswers,
1620
1841
  onAnswer,
1621
1842
  sessionStatus,
1622
- toolCallRenderer
1843
+ toolCallRenderer,
1844
+ sessionId
1623
1845
  }) {
1624
1846
  const hasInterrupted = messages.some((message) => message.status === "interrupted");
1625
1847
  const hasAnyContent = messages.some(
1626
1848
  (message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
1627
1849
  );
1628
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1629
- 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" }),
1630
1853
  messages.map((message, index) => {
1631
1854
  const isLast = index === messages.length - 1;
1632
1855
  const streamingThis = isStreaming && isLast;
1633
1856
  const text = getMessageText(message);
1634
1857
  const toolCalls = message.tool_calls ?? [];
1635
- return /* @__PURE__ */ jsxs7(
1858
+ const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
1859
+ return /* @__PURE__ */ jsxs8(
1636
1860
  "div",
1637
1861
  {
1638
1862
  className: "flex flex-col gap-3",
1639
1863
  children: [
1640
- message.reasoning && /* @__PURE__ */ jsx9(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1641
- 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(
1642
1866
  MarkdownContent,
1643
1867
  {
1644
1868
  mode: streamingThis ? "streaming" : "static",
1645
1869
  className: "blade-chat-prose",
1870
+ sessionId,
1646
1871
  children: text
1647
1872
  }
1648
1873
  ) }),
1649
- toolCalls.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-2", children: toolCalls.map(
1650
- (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(
1651
1876
  ToolCallBlock,
1652
1877
  {
1653
1878
  toolCall,
@@ -1665,13 +1890,13 @@ function AssistantTurnBlock({
1665
1890
  message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
1666
1891
  );
1667
1892
  }),
1668
- 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..." })
1669
1894
  ] });
1670
1895
  }
1671
1896
 
1672
1897
  // src/components/RenderErrorBoundary.tsx
1673
1898
  import { Component } from "react";
1674
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1899
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1675
1900
  function getFirstComponentName(componentStack) {
1676
1901
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
1677
1902
  return match?.[1] ?? null;
@@ -1704,18 +1929,18 @@ var RenderErrorBoundary = class extends Component {
1704
1929
  return children;
1705
1930
  }
1706
1931
  const componentName = getFirstComponentName(componentStack);
1707
- 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: [
1708
- /* @__PURE__ */ jsx10(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
1709
- /* @__PURE__ */ jsxs8("div", { className: "min-w-0 flex-1", children: [
1710
- /* @__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: [
1711
1936
  label,
1712
1937
  "\u6E32\u67D3\u5931\u8D25"
1713
1938
  ] }),
1714
- /* @__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: [
1715
1940
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
1716
1941
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
1717
1942
  ] }),
1718
- 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
1719
1944
  ] })
1720
1945
  ] }) });
1721
1946
  }
@@ -1723,7 +1948,7 @@ var RenderErrorBoundary = class extends Component {
1723
1948
 
1724
1949
  // src/components/UserMessageBubble.tsx
1725
1950
  import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
1726
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1951
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1727
1952
  function isUserMessage(message) {
1728
1953
  return message.role === "user";
1729
1954
  }
@@ -1735,8 +1960,8 @@ function UserMessageBubble({ message, className }) {
1735
1960
  const text = getTextContent2(message.content).trim();
1736
1961
  const fileParts = getFileParts(message.content);
1737
1962
  const imageParts = getImageParts(message.content);
1738
- 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: [
1739
- 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(
1740
1965
  "img",
1741
1966
  {
1742
1967
  src: part.image_url.url,
@@ -1745,21 +1970,21 @@ function UserMessageBubble({ message, className }) {
1745
1970
  },
1746
1971
  part.image_url.url
1747
1972
  )) }),
1748
- 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(
1749
1974
  "div",
1750
1975
  {
1751
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))]",
1752
1977
  children: [
1753
- /* @__PURE__ */ jsx11(FileText, { size: 12, className: "shrink-0" }),
1754
- /* @__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 })
1755
1980
  ]
1756
1981
  },
1757
1982
  `${part.name}-${part.data.length}`
1758
1983
  )) }),
1759
- 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 }) }),
1760
- 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: [
1761
- /* @__PURE__ */ jsx11(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
1762
- /* @__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" })
1763
1988
  ] })
1764
1989
  ] }) });
1765
1990
  }
@@ -1768,11 +1993,11 @@ function ErrorMessageBlock({
1768
1993
  className
1769
1994
  }) {
1770
1995
  const text = getTextContent2(message.content);
1771
- 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 }) });
1772
1997
  }
1773
1998
 
1774
1999
  // src/components/MessageList.tsx
1775
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2000
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1776
2001
  function parseModeChange(message) {
1777
2002
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
1778
2003
  return null;
@@ -1812,7 +2037,8 @@ function MessageList({
1812
2037
  onAnswer,
1813
2038
  toolCallRenderer,
1814
2039
  emptyState,
1815
- className
2040
+ className,
2041
+ sessionId
1816
2042
  }) {
1817
2043
  const renderBlocks = useMemo6(() => {
1818
2044
  const visible = messages.filter((message) => {
@@ -1887,24 +2113,24 @@ function MessageList({
1887
2113
  }
1888
2114
  return blocks;
1889
2115
  }, [messages, isStreaming]);
1890
- 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: [
1891
- /* @__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: [
1892
- 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: [
1893
- /* @__PURE__ */ jsx12(MessageSquare, { size: 40, strokeWidth: 1.5 }),
1894
- /* @__PURE__ */ jsx12("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
1895
- /* @__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" })
1896
2122
  ] }) : renderBlocks.map((block) => {
1897
2123
  if (block.type === "message") {
1898
- 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);
1899
2125
  }
1900
2126
  if (block.type === "assistant_turn") {
1901
- 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(
1902
2128
  RenderErrorBoundary,
1903
2129
  {
1904
2130
  label: "\u52A9\u624B\u6D88\u606F",
1905
2131
  details: block.key,
1906
2132
  resetKey: getMessageResetSignature(block.messages),
1907
- children: /* @__PURE__ */ jsx12(
2133
+ children: /* @__PURE__ */ jsx13(
1908
2134
  AssistantTurnBlock,
1909
2135
  {
1910
2136
  messages: block.messages,
@@ -1912,31 +2138,32 @@ function MessageList({
1912
2138
  askAnswers,
1913
2139
  onAnswer,
1914
2140
  sessionStatus,
1915
- toolCallRenderer
2141
+ toolCallRenderer,
2142
+ sessionId
1916
2143
  }
1917
2144
  )
1918
2145
  }
1919
2146
  ) }, block.key);
1920
2147
  }
1921
2148
  if (block.type === "compaction") {
1922
- return /* @__PURE__ */ jsxs10(
2149
+ return /* @__PURE__ */ jsxs11(
1923
2150
  "div",
1924
2151
  {
1925
2152
  className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
1926
2153
  children: [
1927
- /* @__PURE__ */ jsx12(Layers, { size: 12 }),
1928
- /* @__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" })
1929
2156
  ]
1930
2157
  },
1931
2158
  block.key
1932
2159
  );
1933
2160
  }
1934
- return /* @__PURE__ */ jsx12(PlanningDivider, { kind: block.kind }, block.key);
2161
+ return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
1935
2162
  }),
1936
- 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
1937
2164
  ] }) }) }),
1938
- /* @__PURE__ */ jsx12(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
1939
- /* @__PURE__ */ jsx12(ScrollToBottomButton, {})
2165
+ /* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
2166
+ /* @__PURE__ */ jsx13(ScrollToBottomButton, {})
1940
2167
  ] }) });
1941
2168
  }
1942
2169
  function AutoScrollOnUserSend({ userMessageCount }) {
@@ -1953,38 +2180,39 @@ function AutoScrollOnUserSend({ userMessageCount }) {
1953
2180
  function ScrollToBottomButton() {
1954
2181
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();
1955
2182
  if (isAtBottom) return null;
1956
- return /* @__PURE__ */ jsxs10(
2183
+ return /* @__PURE__ */ jsxs11(
1957
2184
  "button",
1958
2185
  {
1959
2186
  type: "button",
1960
2187
  onClick: () => scrollToBottom(),
1961
- 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))]",
1962
2190
  children: [
1963
- /* @__PURE__ */ jsx12(ChevronDown, { size: 14 }),
1964
- /* @__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" })
1965
2193
  ]
1966
2194
  }
1967
2195
  );
1968
2196
  }
1969
2197
  function PlanningDivider({ kind }) {
1970
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 py-1", children: [
1971
- /* @__PURE__ */ jsx12("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
1972
- /* @__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: [
1973
- /* @__PURE__ */ jsx12(Lightbulb, { size: 12 }),
1974
- /* @__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" })
1975
2203
  ] }),
1976
- /* @__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" })
1977
2205
  ] });
1978
2206
  }
1979
2207
 
1980
2208
  // src/components/ChatView.tsx
1981
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2209
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1982
2210
  function isUnauthorizedError(error) {
1983
2211
  return error instanceof BladeApiError && error.status === 401;
1984
2212
  }
1985
2213
  function LoginCard({ client, onLoggedIn }) {
1986
- const [loggingIn, setLoggingIn] = useState8(false);
1987
- const [loginError, setLoginError] = useState8(null);
2214
+ const [loggingIn, setLoggingIn] = useState9(false);
2215
+ const [loginError, setLoginError] = useState9(null);
1988
2216
  const handleLogin = async () => {
1989
2217
  setLoggingIn(true);
1990
2218
  setLoginError(null);
@@ -1997,11 +2225,11 @@ function LoginCard({ client, onLoggedIn }) {
1997
2225
  setLoggingIn(false);
1998
2226
  }
1999
2227
  };
2000
- 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: [
2001
- /* @__PURE__ */ jsx13(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
2002
- /* @__PURE__ */ jsx13("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
2003
- /* @__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" }),
2004
- /* @__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(
2005
2233
  "button",
2006
2234
  {
2007
2235
  type: "button",
@@ -2011,15 +2239,15 @@ function LoginCard({ client, onLoggedIn }) {
2011
2239
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
2012
2240
  }
2013
2241
  ),
2014
- 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 })
2015
2243
  ] }) });
2016
2244
  }
2017
2245
  function ChatView(props) {
2018
2246
  const client = useBladeClient();
2019
- const [attempt, setAttempt] = useState8(0);
2020
- const [needLogin, setNeedLogin] = useState8(() => !client.hasToken());
2247
+ const [attempt, setAttempt] = useState9(0);
2248
+ const [needLogin, setNeedLogin] = useState9(() => !client.hasToken());
2021
2249
  if (needLogin) {
2022
- 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(
2023
2251
  LoginCard,
2024
2252
  {
2025
2253
  client,
@@ -2030,7 +2258,7 @@ function ChatView(props) {
2030
2258
  }
2031
2259
  ) });
2032
2260
  }
2033
- return /* @__PURE__ */ jsx13(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2261
+ return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2034
2262
  }
2035
2263
  function ChatSessionView({
2036
2264
  sessionId,
@@ -2048,8 +2276,8 @@ function ChatSessionView({
2048
2276
  createOptions,
2049
2277
  onSessionCreated
2050
2278
  });
2051
- const [stopRequested, setStopRequested] = useState8(false);
2052
- const [inputText, setInputText] = useState8("");
2279
+ const [stopRequested, setStopRequested] = useState9(false);
2280
+ const [inputText, setInputText] = useState9("");
2053
2281
  useEffect6(() => {
2054
2282
  if (session) {
2055
2283
  onSessionReady?.(session);
@@ -2091,13 +2319,13 @@ ${content}`);
2091
2319
  const errorMessage = connectError ?? state?.errorMessage ?? null;
2092
2320
  const handleSend = (text) => {
2093
2321
  setStopRequested(false);
2094
- void session?.send(text, { mode: state?.mode ?? void 0 });
2322
+ return session?.send(text, { mode: state?.mode ?? void 0 }) ?? Promise.resolve(false);
2095
2323
  };
2096
2324
  const handleStop = () => {
2097
2325
  setStopRequested(true);
2098
2326
  void session?.stop();
2099
2327
  };
2100
- return /* @__PURE__ */ jsxs11(
2328
+ return /* @__PURE__ */ jsxs12(
2101
2329
  "div",
2102
2330
  {
2103
2331
  className: cn(
@@ -2105,19 +2333,19 @@ ${content}`);
2105
2333
  classNames?.root
2106
2334
  ),
2107
2335
  children: [
2108
- /* @__PURE__ */ jsx13(
2336
+ /* @__PURE__ */ jsx14(
2109
2337
  ConnectionBanner,
2110
2338
  {
2111
2339
  connection: state?.connection ?? "connecting",
2112
2340
  className: classNames?.banner
2113
2341
  }
2114
2342
  ),
2115
- 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: [
2116
- /* @__PURE__ */ jsx13(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2117
- /* @__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 })
2118
2346
  ] }),
2119
2347
  slots?.header,
2120
- /* @__PURE__ */ jsx13(
2348
+ /* @__PURE__ */ jsx14(
2121
2349
  MessageList,
2122
2350
  {
2123
2351
  messages: state?.messages ?? [],
@@ -2132,10 +2360,11 @@ ${content}`);
2132
2360
  },
2133
2361
  toolCallRenderer: renderers?.toolCall,
2134
2362
  emptyState: slots?.emptyState,
2135
- className: classNames?.messageList
2363
+ className: classNames?.messageList,
2364
+ sessionId: session?.sessionId
2136
2365
  }
2137
2366
  ),
2138
- /* @__PURE__ */ jsx13(
2367
+ /* @__PURE__ */ jsx14(
2139
2368
  ChatInput,
2140
2369
  {
2141
2370
  value: inputText,
@@ -2169,6 +2398,7 @@ lucide-react/dist/esm/shared/src/utils.js:
2169
2398
  lucide-react/dist/esm/defaultAttributes.js:
2170
2399
  lucide-react/dist/esm/Icon.js:
2171
2400
  lucide-react/dist/esm/createLucideIcon.js:
2401
+ lucide-react/dist/esm/icons/archive.js:
2172
2402
  lucide-react/dist/esm/icons/arrow-up.js:
2173
2403
  lucide-react/dist/esm/icons/bot.js:
2174
2404
  lucide-react/dist/esm/icons/brain.js:
@@ -2177,13 +2407,20 @@ lucide-react/dist/esm/icons/chevron-down.js:
2177
2407
  lucide-react/dist/esm/icons/chevron-right.js:
2178
2408
  lucide-react/dist/esm/icons/circle-alert.js:
2179
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:
2180
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:
2181
2417
  lucide-react/dist/esm/icons/layers.js:
2182
2418
  lucide-react/dist/esm/icons/lightbulb.js:
2183
2419
  lucide-react/dist/esm/icons/loader-circle.js:
2184
2420
  lucide-react/dist/esm/icons/lock-keyhole.js:
2185
2421
  lucide-react/dist/esm/icons/message-square-more.js:
2186
2422
  lucide-react/dist/esm/icons/message-square.js:
2423
+ lucide-react/dist/esm/icons/music.js:
2187
2424
  lucide-react/dist/esm/icons/square.js:
2188
2425
  lucide-react/dist/esm/icons/triangle-alert.js:
2189
2426
  lucide-react/dist/esm/icons/x.js: