@blade-hq/agent-react 2610.0.0-beta.26 → 2610.0.0-beta.27

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
@@ -1831,7 +1831,6 @@ var TOOL_NAME_ALIASES = {
1831
1831
  finish_task: "FinishTask",
1832
1832
  glob: "Glob",
1833
1833
  grep: "Grep",
1834
- kb_search: "KbSearch",
1835
1834
  ls: "Ls",
1836
1835
  multi_edit: "MultiEdit",
1837
1836
  read: "Read",
@@ -1850,7 +1849,6 @@ var TOOL_DISPLAY_LABELS = {
1850
1849
  Ls: "\u5217\u51FA\u76EE\u5F55",
1851
1850
  Glob: "\u5339\u914D\u6587\u4EF6",
1852
1851
  Grep: "\u641C\u7D22\u6587\u672C",
1853
- KbSearch: "\u68C0\u7D22\u77E5\u8BC6\u5E93",
1854
1852
  WebSearch: "\u641C\u7D22\u7F51\u9875",
1855
1853
  WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
1856
1854
  Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
@@ -1861,16 +1859,6 @@ var TOOL_DISPLAY_LABELS = {
1861
1859
  ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
1862
1860
  GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
1863
1861
  };
1864
- var PRIORITY_FILE_KEYS = [
1865
- "file_path",
1866
- "output_file",
1867
- "output_path",
1868
- "path",
1869
- "filepath",
1870
- "target_file",
1871
- "destination",
1872
- "filename"
1873
- ];
1874
1862
  function safeParseJson(value) {
1875
1863
  if (!value) return null;
1876
1864
  try {
@@ -1879,38 +1867,6 @@ function safeParseJson(value) {
1879
1867
  return null;
1880
1868
  }
1881
1869
  }
1882
- function isPlainObject(value) {
1883
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1884
- }
1885
- function findFileLikeValue(value, depth = 0, allowPlainString = false) {
1886
- if (depth > 3) return null;
1887
- if (typeof value === "string") {
1888
- const trimmed = value.trim();
1889
- if (!trimmed) return null;
1890
- if (allowPlainString || trimmed.includes("/") || /\.[a-z0-9]{1,8}$/i.test(trimmed)) {
1891
- return trimmed;
1892
- }
1893
- return null;
1894
- }
1895
- if (Array.isArray(value)) {
1896
- for (const item of value) {
1897
- const found = findFileLikeValue(item, depth + 1, allowPlainString);
1898
- if (found) return found;
1899
- }
1900
- return null;
1901
- }
1902
- if (isPlainObject(value)) {
1903
- for (const key of PRIORITY_FILE_KEYS) {
1904
- const direct = findFileLikeValue(value[key], depth + 1, true);
1905
- if (direct) return direct;
1906
- }
1907
- for (const nested of Object.values(value)) {
1908
- const found = findFileLikeValue(nested, depth + 1, allowPlainString);
1909
- if (found) return found;
1910
- }
1911
- }
1912
- return null;
1913
- }
1914
1870
  function getStringArgValue(args, key) {
1915
1871
  const value = args?.[key];
1916
1872
  return typeof value === "string" ? value.trim() : "";
@@ -1933,15 +1889,6 @@ function formatToolName(name) {
1933
1889
  const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
1934
1890
  return TOOL_NAME_ALIASES[normalized] ?? stripped;
1935
1891
  }
1936
- function extractToolFilePath(toolCall) {
1937
- const formattedName = formatToolName(toolCall.name);
1938
- if (formattedName !== "Read" && formattedName !== "Write" && formattedName !== "Edit" && formattedName !== "MultiEdit") {
1939
- return null;
1940
- }
1941
- const filePath = findFileLikeValue(safeParseJson(toolCall.arguments));
1942
- if (!filePath || filePath.split("/").pop()?.toLowerCase() === "phase.json") return null;
1943
- return filePath;
1944
- }
1945
1892
  function getToolDisplayLabel(toolCall) {
1946
1893
  const normalized = formatToolName(toolCall.name);
1947
1894
  const args = safeParseJson(toolCall.arguments);
@@ -2543,6 +2490,26 @@ function parseAskUserQuestion(toolResult) {
2543
2490
  }
2544
2491
  return null;
2545
2492
  }
2493
+ function parseAskUserQuestionError(toolResult) {
2494
+ if (!toolResult) return null;
2495
+ try {
2496
+ const parsed = JSON.parse(toolResult);
2497
+ let detail = null;
2498
+ if (typeof parsed.error === "string") detail = parsed.error;
2499
+ if (parsed.error && typeof parsed.error === "object") {
2500
+ const message = parsed.error.message;
2501
+ if (typeof message === "string") detail = message;
2502
+ }
2503
+ if (!detail && typeof parsed.message === "string") detail = parsed.message;
2504
+ if (!detail) return null;
2505
+ return {
2506
+ message: parsed.error_code === "invalid_questions" ? "\u63D0\u95EE\u5185\u5BB9\u4E0D\u5B8C\u6574\uFF0C\u5F53\u524D\u6CA1\u6709\u7B49\u5F85\u4F60\u56DE\u7B54\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" : "\u8FD9\u6B21\u63D0\u95EE\u6CA1\u6709\u6210\u529F\uFF0C\u5F53\u524D\u6CA1\u6709\u7B49\u5F85\u4F60\u56DE\u7B54\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002",
2507
+ detail
2508
+ };
2509
+ } catch {
2510
+ return null;
2511
+ }
2512
+ }
2546
2513
  function normalizeQuestionItem(value) {
2547
2514
  if (!value || typeof value !== "object") return null;
2548
2515
  const item = value;
@@ -2571,9 +2538,10 @@ import { Fragment, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2571
2538
  function resolveAskQuestionState({
2572
2539
  toolStatus,
2573
2540
  hasAnswerData,
2574
- fallbackAnswered
2541
+ fallbackAnswered,
2542
+ fallbackAwaiting
2575
2543
  }) {
2576
- const awaitingAnswer = !hasAnswerData && toolStatus === "awaiting_answer";
2544
+ const awaitingAnswer = !hasAnswerData && (toolStatus === "awaiting_answer" || toolStatus === "pending" && fallbackAwaiting === true);
2577
2545
  return {
2578
2546
  awaitingAnswer,
2579
2547
  answered: hasAnswerData || !awaitingAnswer && (Boolean(fallbackAnswered) || toolStatus === "done" || toolStatus === "cancelled" || toolStatus === "error")
@@ -2585,6 +2553,7 @@ function ToolCallBlock({
2585
2553
  answered,
2586
2554
  answerData,
2587
2555
  sessionStatus,
2556
+ isActiveQuestion,
2588
2557
  renderer
2589
2558
  }) {
2590
2559
  const [expanded, setExpanded] = useState9(false);
@@ -2600,7 +2569,8 @@ function ToolCallBlock({
2600
2569
  const questionState = resolveAskQuestionState({
2601
2570
  toolStatus: toolCall.status,
2602
2571
  hasAnswerData: Boolean(answerData),
2603
- fallbackAnswered: answered
2572
+ fallbackAnswered: answered,
2573
+ fallbackAwaiting: isActiveQuestion === true && (sessionStatus === "paused" || sessionStatus === "waiting_for_input")
2604
2574
  });
2605
2575
  const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
2606
2576
  if (askData) {
@@ -2622,9 +2592,16 @@ function ToolCallBlock({
2622
2592
  /* @__PURE__ */ jsx10("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
2623
2593
  ] });
2624
2594
  }
2595
+ const errorDetail = parseAskUserQuestionError(
2596
+ typeof toolCall.result === "string" ? toolCall.result : null
2597
+ );
2625
2598
  return /* @__PURE__ */ jsxs8("div", { className: "ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]", children: [
2626
2599
  /* @__PURE__ */ jsx10("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
2627
- /* @__PURE__ */ jsx10("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" })
2600
+ /* @__PURE__ */ jsx10("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: errorDetail?.message ?? "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" }),
2601
+ errorDetail?.detail ? /* @__PURE__ */ jsxs8("details", { className: "mt-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
2602
+ /* @__PURE__ */ jsx10("summary", { className: "cursor-pointer", children: "\u67E5\u770B\u5177\u4F53\u539F\u56E0" }),
2603
+ /* @__PURE__ */ jsx10("div", { className: "mt-1 break-words font-mono", children: errorDetail.detail })
2604
+ ] }) : null
2628
2605
  ] });
2629
2606
  }
2630
2607
  const tone = getToolTone(toolCall.status);
@@ -2690,6 +2667,7 @@ function buildAskUserPayload(argumentsJson) {
2690
2667
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2691
2668
  function ThinkingBlock({ reasoning, isStreaming }) {
2692
2669
  const [open, setOpen] = useState10(false);
2670
+ if (!isStreaming) return null;
2693
2671
  return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-thinking text-xs", children: [
2694
2672
  /* @__PURE__ */ jsxs9(
2695
2673
  "button",
@@ -2699,7 +2677,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
2699
2677
  "aria-expanded": open,
2700
2678
  className: "group/thinking inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
2701
2679
  children: [
2702
- isStreaming ? /* @__PURE__ */ jsx11(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx11("span", { children: "\u5DF2\u601D\u8003" }),
2680
+ /* @__PURE__ */ jsx11(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }),
2703
2681
  /* @__PURE__ */ jsx11(
2704
2682
  ChevronRight,
2705
2683
  {
@@ -2713,7 +2691,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
2713
2691
  ]
2714
2692
  }
2715
2693
  ),
2716
- open && /* @__PURE__ */ jsx11("div", { className: "mt-1.5 whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: reasoning })
2694
+ open ? /* @__PURE__ */ jsx11("div", { className: "mt-1.5 whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: reasoning }) : null
2717
2695
  ] });
2718
2696
  }
2719
2697
  function getMessageText(message) {
@@ -2811,6 +2789,12 @@ function executionSummaryLabel({
2811
2789
  }
2812
2790
  return completedLabel;
2813
2791
  }
2792
+ function businessToolDisplayName(toolCall) {
2793
+ const displayName = toolCall.display_name?.trim() ?? "";
2794
+ if (!displayName) return "";
2795
+ const rawName = toolCall.name.trim();
2796
+ return displayName !== rawName && formatToolName(displayName) !== formatToolName(rawName) ? displayName : "";
2797
+ }
2814
2798
  function executionToolTypeLabel(toolCall) {
2815
2799
  switch (formatToolName(toolCall.name)) {
2816
2800
  case "WebSearch":
@@ -2838,7 +2822,7 @@ function executionToolTypeLabel(toolCall) {
2838
2822
  case "run_skill_tool":
2839
2823
  return "\u6267\u884C\u6280\u80FD";
2840
2824
  default:
2841
- return toolCall.display_name?.trim() || "\u6267\u884C\u6B65\u9AA4";
2825
+ return businessToolDisplayName(toolCall) || "\u6267\u884C\u6B65\u9AA4";
2842
2826
  }
2843
2827
  }
2844
2828
  function executionToolIntent(toolCall) {
@@ -2854,7 +2838,7 @@ function executionToolIntent(toolCall) {
2854
2838
  const value = args?.[key];
2855
2839
  return typeof value === "string" ? value.trim() : "";
2856
2840
  };
2857
- const explicitIntent = getString("description") || getString("_meta_display_name") || getString("display_name") || toolCall.display_name?.trim() || "";
2841
+ const explicitIntent = getString("description") || getString("_meta_display_name") || getString("display_name") || "";
2858
2842
  if (explicitIntent) return explicitIntent;
2859
2843
  if (normalizedName === "search_skills") return getString("query");
2860
2844
  if (normalizedName === "get_skill_content" || normalizedName === "ReadSkill") {
@@ -2869,58 +2853,18 @@ function ExecutionToolRow({ toolCall }) {
2869
2853
  const intent = executionToolIntent(toolCall);
2870
2854
  const label = intent ? `${typeLabel}\uFF1A${intent}` : typeLabel;
2871
2855
  const failed = toolCall.status === "error" || toolCall.status === "cancelled";
2872
- const filePath = toolCall.status === "done" && (normalizedName === "Write" || normalizedName === "Edit" || normalizedName === "MultiEdit") ? extractToolFilePath(toolCall) : null;
2873
- const [fileOpen, setFileOpen] = useState10(false);
2874
2856
  const iconClass = cn(
2875
2857
  "size-3.5 shrink-0",
2876
2858
  failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
2877
2859
  );
2878
- const icon = toolCall.status === "pending" ? /* @__PURE__ */ jsx11(LoaderCircle, { className: cn(iconClass, "animate-spin"), "aria-hidden": "true" }) : toolCall.status === "error" ? /* @__PURE__ */ jsx11(CircleAlert, { className: iconClass, "aria-hidden": "true" }) : toolCall.status === "cancelled" ? /* @__PURE__ */ jsx11(X, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "WebSearch" || normalizedName === "WebFetch" ? /* @__PURE__ */ jsx11(Earth, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Bash" || normalizedName === "BgBash" ? /* @__PURE__ */ jsx11(Terminal, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Write" || normalizedName === "Edit" || normalizedName === "MultiEdit" ? /* @__PURE__ */ jsx11(FilePenLine, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Read" || normalizedName === "ReadSkill" ? /* @__PURE__ */ jsx11(BookOpen, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Grep" || normalizedName === "Glob" || normalizedName === "search_skills" ? /* @__PURE__ */ jsx11(Search, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "get_skill_content" ? /* @__PURE__ */ jsx11(BookOpen, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Agent" ? /* @__PURE__ */ jsx11(Bot, { className: iconClass, "aria-hidden": "true" }) : /* @__PURE__ */ jsx11(Wrench, { className: iconClass, "aria-hidden": "true" });
2860
+ const icon = toolCall.status === "pending" ? /* @__PURE__ */ jsx11(LoaderCircle, { className: cn(iconClass, "animate-spin"), "aria-hidden": "true" }) : toolCall.status === "error" ? /* @__PURE__ */ jsx11(CircleAlert, { className: iconClass, "aria-hidden": "true" }) : toolCall.status === "cancelled" ? /* @__PURE__ */ jsx11(X, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "WebSearch" || normalizedName === "WebFetch" ? /* @__PURE__ */ jsx11(Earth, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Bash" || normalizedName === "BgBash" ? /* @__PURE__ */ jsx11(Terminal, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Write" || normalizedName === "Edit" || normalizedName === "MultiEdit" ? /* @__PURE__ */ jsx11(FilePenLine, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Read" || normalizedName === "ReadSkill" || normalizedName === "get_skill_content" ? /* @__PURE__ */ jsx11(BookOpen, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Grep" || normalizedName === "Glob" || normalizedName === "search_skills" ? /* @__PURE__ */ jsx11(Search, { className: iconClass, "aria-hidden": "true" }) : normalizedName === "Agent" ? /* @__PURE__ */ jsx11(Bot, { className: iconClass, "aria-hidden": "true" }) : /* @__PURE__ */ jsx11(Wrench, { className: iconClass, "aria-hidden": "true" });
2879
2861
  const rowClassName = cn(
2880
2862
  "flex min-w-0 items-center gap-1 py-1.5 text-xs leading-[22px]",
2881
2863
  failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
2882
2864
  );
2883
- if (!filePath) {
2884
- return /* @__PURE__ */ jsxs9("div", { "data-testid": "execution-tool-intent", className: rowClassName, title: label, children: [
2885
- icon,
2886
- /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: label })
2887
- ] });
2888
- }
2889
- return /* @__PURE__ */ jsxs9("div", { className: "min-w-0", children: [
2890
- /* @__PURE__ */ jsxs9(
2891
- "button",
2892
- {
2893
- type: "button",
2894
- "data-testid": "execution-tool-intent",
2895
- className: cn(rowClassName, "w-full text-left"),
2896
- title: label,
2897
- "aria-expanded": fileOpen,
2898
- onClick: () => setFileOpen((open) => !open),
2899
- children: [
2900
- icon,
2901
- /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: label }),
2902
- /* @__PURE__ */ jsx11(
2903
- ChevronRight,
2904
- {
2905
- size: 14,
2906
- className: cn("shrink-0 transition-transform", fileOpen && "rotate-90"),
2907
- "aria-hidden": "true"
2908
- }
2909
- )
2910
- ]
2911
- }
2912
- ),
2913
- fileOpen ? /* @__PURE__ */ jsxs9(
2914
- "div",
2915
- {
2916
- className: "ml-[18px] truncate text-xs leading-[22px] text-[hsl(var(--muted-foreground))]",
2917
- title: filePath,
2918
- children: [
2919
- "\u6587\u4EF6\uFF1A",
2920
- filePath
2921
- ]
2922
- }
2923
- ) : null
2865
+ return /* @__PURE__ */ jsxs9("div", { "data-testid": "execution-tool-intent", className: rowClassName, title: label, children: [
2866
+ icon,
2867
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: label })
2924
2868
  ] });
2925
2869
  }
2926
2870
  function AssistantTurnBlock({
@@ -2951,6 +2895,7 @@ function AssistantTurnBlock({
2951
2895
  (toolCall) => formatToolName(toolCall.name) === "AskUserQuestion"
2952
2896
  )
2953
2897
  );
2898
+ const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
2954
2899
  const [displayMode, setDisplayMode] = useState10(
2955
2900
  () => isStreaming || hasActionableToolCall ? "detail" : "compact"
2956
2901
  );
@@ -2975,132 +2920,146 @@ function AssistantTurnBlock({
2975
2920
  }, [hasLiveStartTime, isStreaming]);
2976
2921
  const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({ messages, isStreaming, now: clock }) : executionDurationMs;
2977
2922
  if (!hasExecutionProcess) {
2978
- return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
2979
- hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
2980
- hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
2981
- messages.map((message, index) => {
2982
- return hasRenderableMessageContent(message) ? /* @__PURE__ */ jsx11(
2983
- "div",
2984
- {
2985
- className: "flex flex-col gap-3",
2986
- children: /* @__PURE__ */ jsx11(
2987
- AssistantMessageContent,
2923
+ return /* @__PURE__ */ jsxs9(
2924
+ "div",
2925
+ {
2926
+ "aria-busy": isStreaming || void 0,
2927
+ className: "blade-chat-assistant-turn flex flex-col gap-3",
2928
+ children: [
2929
+ hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
2930
+ hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
2931
+ messages.map((message, index) => {
2932
+ return hasRenderableMessageContent(message) ? /* @__PURE__ */ jsx11(
2933
+ "div",
2988
2934
  {
2989
- message,
2990
- sessionId,
2991
- streaming: isStreaming && index === messages.length - 1
2992
- }
2993
- )
2994
- },
2995
- message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
2996
- ) : null;
2997
- }),
2998
- isStreaming && !finalMessage ? /* @__PURE__ */ jsx11(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." }) : null
2999
- ] });
2935
+ className: "flex flex-col gap-3",
2936
+ children: /* @__PURE__ */ jsx11(
2937
+ AssistantMessageContent,
2938
+ {
2939
+ message,
2940
+ sessionId,
2941
+ streaming: isStreaming && index === messages.length - 1
2942
+ }
2943
+ )
2944
+ },
2945
+ message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
2946
+ ) : null;
2947
+ })
2948
+ ]
2949
+ }
2950
+ );
3000
2951
  }
3001
- return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
3002
- hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
3003
- hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
3004
- /* @__PURE__ */ jsxs9("div", { className: "flex w-full items-start gap-2.5", children: [
3005
- /* @__PURE__ */ jsx11(
3006
- "span",
3007
- {
3008
- className: "grid size-[30px] shrink-0 place-items-center rounded-full bg-[hsl(var(--muted)/0.55)] text-[hsl(var(--foreground))]",
3009
- "aria-hidden": "true",
3010
- children: /* @__PURE__ */ jsx11(Bot, { size: 16 })
3011
- }
3012
- ),
3013
- /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1 pt-0.5", children: [
3014
- /* @__PURE__ */ jsxs9(
3015
- "button",
3016
- {
3017
- type: "button",
3018
- onClick: () => {
3019
- userSelectedDisplayModeRef.current = true;
3020
- setDisplayMode(displayMode === "detail" ? "compact" : "detail");
3021
- },
3022
- "aria-expanded": effectiveMode === "detail",
3023
- "aria-label": effectiveMode === "detail" ? "\u6536\u8D77\u6267\u884C\u8FC7\u7A0B" : "\u5C55\u5F00\u6267\u884C\u8FC7\u7A0B",
3024
- "data-testid": "assistant-execution-summary",
3025
- className: "inline-flex min-w-0 max-w-full select-none items-center gap-1 bg-transparent p-0 text-left text-xs leading-[22px] text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
3026
- children: [
3027
- /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: executionSummaryLabel({
3028
- messages,
3029
- isStreaming,
3030
- durationMs: liveExecutionDurationMs,
3031
- sessionStatus,
3032
- askAnswers
3033
- }) }),
3034
- /* @__PURE__ */ jsx11(
3035
- ChevronRight,
3036
- {
3037
- size: 14,
3038
- className: cn(
3039
- "shrink-0 transition-transform duration-300",
3040
- effectiveMode === "detail" && "rotate-90"
3041
- ),
3042
- "aria-hidden": "true"
3043
- }
3044
- )
3045
- ]
3046
- }
3047
- ),
3048
- /* @__PURE__ */ jsx11("div", { className: "mt-3 h-px w-full bg-[hsl(var(--border)/0.75)]" })
3049
- ] })
3050
- ] }),
3051
- effectiveMode === "detail" ? /* @__PURE__ */ jsx11("div", { className: "ml-10 flex flex-col gap-3 pt-1", children: messages.map((message, index) => {
3052
- const isLast = index === messages.length - 1;
3053
- const streamingThis = isStreaming && isLast;
3054
- const text = getMessageText(message);
3055
- const toolCalls = (message.tool_calls ?? []).filter(
3056
- (toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
3057
- );
3058
- const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
3059
- return /* @__PURE__ */ jsxs9(
3060
- "div",
3061
- {
3062
- className: "flex flex-col gap-3",
3063
- children: [
3064
- showReasoning && message.reasoning ? /* @__PURE__ */ jsx11(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
3065
- hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx11(
3066
- AssistantMessageContent,
2952
+ return /* @__PURE__ */ jsxs9(
2953
+ "div",
2954
+ {
2955
+ "aria-busy": isStreaming || void 0,
2956
+ className: "blade-chat-assistant-turn flex flex-col gap-3",
2957
+ children: [
2958
+ hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
2959
+ hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
2960
+ /* @__PURE__ */ jsxs9("div", { className: "flex w-full items-start gap-2.5", children: [
2961
+ /* @__PURE__ */ jsx11(
2962
+ "span",
2963
+ {
2964
+ className: "grid size-[30px] shrink-0 place-items-center rounded-full bg-[hsl(var(--muted)/0.55)] text-[hsl(var(--foreground))]",
2965
+ "aria-hidden": "true",
2966
+ children: /* @__PURE__ */ jsx11(Bot, { size: 16 })
2967
+ }
2968
+ ),
2969
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1 pt-0.5", children: [
2970
+ /* @__PURE__ */ jsxs9(
2971
+ "button",
3067
2972
  {
3068
- message,
3069
- sessionId,
3070
- streaming: streamingThis,
3071
- compact: true
2973
+ type: "button",
2974
+ onClick: () => {
2975
+ userSelectedDisplayModeRef.current = true;
2976
+ setDisplayMode(displayMode === "detail" ? "compact" : "detail");
2977
+ },
2978
+ "aria-expanded": effectiveMode === "detail",
2979
+ "aria-label": effectiveMode === "detail" ? "\u6536\u8D77\u6267\u884C\u8FC7\u7A0B" : "\u5C55\u5F00\u6267\u884C\u8FC7\u7A0B",
2980
+ "data-testid": "assistant-execution-summary",
2981
+ className: "inline-flex min-w-0 max-w-full select-none items-center gap-1 bg-transparent p-0 text-left text-xs leading-[22px] text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
2982
+ children: [
2983
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: executionSummaryLabel({
2984
+ messages,
2985
+ isStreaming,
2986
+ durationMs: liveExecutionDurationMs,
2987
+ sessionStatus,
2988
+ askAnswers
2989
+ }) }),
2990
+ /* @__PURE__ */ jsx11(
2991
+ ChevronRight,
2992
+ {
2993
+ size: 14,
2994
+ className: cn(
2995
+ "shrink-0 transition-transform duration-300",
2996
+ effectiveMode === "detail" && "rotate-90"
2997
+ ),
2998
+ "aria-hidden": "true"
2999
+ }
3000
+ )
3001
+ ]
3072
3002
  }
3073
- ) : null,
3074
- toolCalls.length > 0 ? /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
3075
- const custom = toolCallRenderer?.(toolCall);
3076
- return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx11("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx11(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx11(ExecutionToolRow, { toolCall }, toolCall.id);
3077
- }) }) : null
3078
- ]
3079
- },
3080
- message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
3081
- );
3082
- }) }) : null,
3083
- finalMessage ? /* @__PURE__ */ jsx11("div", { className: "ml-10", children: /* @__PURE__ */ jsx11(
3084
- AssistantMessageContent,
3085
- {
3086
- message: finalMessage,
3087
- sessionId,
3088
- streaming: isStreaming && finalMessage === messages[messages.length - 1]
3089
- }
3090
- ) }) : null,
3091
- questionToolCalls.map((toolCall) => /* @__PURE__ */ jsx11(
3092
- ToolCallBlock,
3093
- {
3094
- toolCall,
3095
- answerData: askAnswers?.[toolCall.id],
3096
- onAnswer,
3097
- answered: sessionStatus !== "waiting_for_input",
3098
- sessionStatus,
3099
- renderer: toolCallRenderer
3100
- },
3101
- toolCall.id
3102
- ))
3103
- ] });
3003
+ ),
3004
+ /* @__PURE__ */ jsx11("div", { className: "mt-3 h-px w-full bg-[hsl(var(--border)/0.75)]" })
3005
+ ] })
3006
+ ] }),
3007
+ effectiveMode === "detail" ? /* @__PURE__ */ jsx11("div", { className: "ml-10 flex flex-col gap-3 pt-1", children: messages.map((message, index) => {
3008
+ const isLast = index === messages.length - 1;
3009
+ const streamingThis = isStreaming && isLast;
3010
+ const text = getMessageText(message);
3011
+ const toolCalls = (message.tool_calls ?? []).filter(
3012
+ (toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
3013
+ );
3014
+ const showReasoning = !!message.reasoning && isStreaming && index === latestReasoningIndex;
3015
+ return /* @__PURE__ */ jsxs9(
3016
+ "div",
3017
+ {
3018
+ className: "flex flex-col gap-3",
3019
+ children: [
3020
+ showReasoning && message.reasoning ? /* @__PURE__ */ jsx11(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
3021
+ hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx11(
3022
+ AssistantMessageContent,
3023
+ {
3024
+ message,
3025
+ sessionId,
3026
+ streaming: streamingThis,
3027
+ compact: true
3028
+ }
3029
+ ) : null,
3030
+ toolCalls.length > 0 ? /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
3031
+ const custom = toolCallRenderer?.(toolCall);
3032
+ return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx11("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx11(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx11(ExecutionToolRow, { toolCall }, toolCall.id);
3033
+ }) }) : null
3034
+ ]
3035
+ },
3036
+ message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
3037
+ );
3038
+ }) }) : null,
3039
+ finalMessage ? /* @__PURE__ */ jsx11("div", { className: "ml-10", children: /* @__PURE__ */ jsx11(
3040
+ AssistantMessageContent,
3041
+ {
3042
+ message: finalMessage,
3043
+ sessionId,
3044
+ streaming: isStreaming && finalMessage === messages[messages.length - 1]
3045
+ }
3046
+ ) }) : null,
3047
+ questionToolCalls.map((toolCall) => /* @__PURE__ */ jsx11(
3048
+ ToolCallBlock,
3049
+ {
3050
+ toolCall,
3051
+ answerData: askAnswers?.[toolCall.id],
3052
+ onAnswer,
3053
+ answered: sessionStatus !== "waiting_for_input",
3054
+ sessionStatus,
3055
+ isActiveQuestion: toolCall.id === activeQuestionId,
3056
+ renderer: toolCallRenderer
3057
+ },
3058
+ toolCall.id
3059
+ ))
3060
+ ]
3061
+ }
3062
+ );
3104
3063
  }
3105
3064
  function AssistantMessageContent({
3106
3065
  message,
@@ -3165,49 +3124,9 @@ function AssistantMessageContent({
3165
3124
  ] });
3166
3125
  }
3167
3126
 
3168
- // src/components/ContextCard.tsx
3169
- import {
3170
- getContextDisplayState
3171
- } from "@blade-hq/agent-client";
3172
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3173
- function ContextCard({ context, className }) {
3174
- const display = getContextDisplayState(context);
3175
- return /* @__PURE__ */ jsxs10(
3176
- "details",
3177
- {
3178
- className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
3179
- children: [
3180
- /* @__PURE__ */ jsxs10("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
3181
- /* @__PURE__ */ jsx12(
3182
- Layers,
3183
- {
3184
- size: 15,
3185
- className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
3186
- "aria-hidden": "true"
3187
- }
3188
- ),
3189
- /* @__PURE__ */ jsxs10("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
3190
- /* @__PURE__ */ jsx12("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
3191
- /* @__PURE__ */ jsx12("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
3192
- ] }),
3193
- /* @__PURE__ */ jsx12(
3194
- ChevronDown,
3195
- {
3196
- size: 14,
3197
- className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
3198
- "aria-hidden": "true"
3199
- }
3200
- )
3201
- ] }),
3202
- /* @__PURE__ */ jsx12("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: display.detail })
3203
- ]
3204
- }
3205
- );
3206
- }
3207
-
3208
3127
  // src/components/RenderErrorBoundary.tsx
3209
3128
  import { Component } from "react";
3210
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3129
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3211
3130
  function getFirstComponentName(componentStack) {
3212
3131
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
3213
3132
  return match?.[1] ?? null;
@@ -3240,18 +3159,18 @@ var RenderErrorBoundary = class extends Component {
3240
3159
  return children;
3241
3160
  }
3242
3161
  const componentName = getFirstComponentName(componentStack);
3243
- return /* @__PURE__ */ jsx13("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs11("div", { className: "flex items-start gap-2", children: [
3244
- /* @__PURE__ */ jsx13(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
3245
- /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
3246
- /* @__PURE__ */ jsxs11("div", { className: "font-medium", children: [
3162
+ return /* @__PURE__ */ jsx12("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-2", children: [
3163
+ /* @__PURE__ */ jsx12(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
3164
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
3165
+ /* @__PURE__ */ jsxs10("div", { className: "font-medium", children: [
3247
3166
  label,
3248
3167
  "\u6E32\u67D3\u5931\u8D25"
3249
3168
  ] }),
3250
- /* @__PURE__ */ jsxs11("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
3169
+ /* @__PURE__ */ jsxs10("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
3251
3170
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
3252
3171
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
3253
3172
  ] }),
3254
- details ? /* @__PURE__ */ jsx13("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
3173
+ details ? /* @__PURE__ */ jsx12("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
3255
3174
  ] })
3256
3175
  ] }) });
3257
3176
  }
@@ -3259,7 +3178,7 @@ var RenderErrorBoundary = class extends Component {
3259
3178
 
3260
3179
  // src/components/PostChatFollowupBlock.tsx
3261
3180
  import { useCallback as useCallback6, useEffect as useEffect9, useRef as useRef10, useState as useState11 } from "react";
3262
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3181
+ import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3263
3182
  function emitInteraction(callback, event) {
3264
3183
  try {
3265
3184
  callback?.(event);
@@ -3281,7 +3200,7 @@ function ArtifactCard({
3281
3200
  const [downloading, setDownloading] = useState11(false);
3282
3201
  const name = artifact.label || basename(artifact.target);
3283
3202
  if (artifact.kind === "link") {
3284
- return /* @__PURE__ */ jsxs12(
3203
+ return /* @__PURE__ */ jsxs11(
3285
3204
  "a",
3286
3205
  {
3287
3206
  href: artifact.target,
@@ -3292,9 +3211,9 @@ function ArtifactCard({
3292
3211
  ${artifact.target}`,
3293
3212
  className: "group relative flex min-w-0 items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2 py-1.5 text-xs text-[hsl(var(--card-foreground))] hover:bg-[hsl(var(--accent))]",
3294
3213
  children: [
3295
- /* @__PURE__ */ jsx14(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
3296
- /* @__PURE__ */ jsx14("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
3297
- /* @__PURE__ */ jsx14(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
3214
+ /* @__PURE__ */ jsx13(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
3215
+ /* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
3216
+ /* @__PURE__ */ jsx13(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
3298
3217
  ]
3299
3218
  }
3300
3219
  );
@@ -3329,7 +3248,7 @@ ${artifact.target}`,
3329
3248
  setDownloading(false);
3330
3249
  }
3331
3250
  };
3332
- return /* @__PURE__ */ jsx14(
3251
+ return /* @__PURE__ */ jsx13(
3333
3252
  "a",
3334
3253
  {
3335
3254
  href: downloadUrl,
@@ -3357,17 +3276,17 @@ function feedbackReasonLabel(reason) {
3357
3276
  }
3358
3277
  function HistoricalResultFeedback({ feedback }) {
3359
3278
  const label = feedbackReasonLabel(feedback.reason);
3360
- return /* @__PURE__ */ jsxs12(
3279
+ return /* @__PURE__ */ jsxs11(
3361
3280
  "section",
3362
3281
  {
3363
3282
  "aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
3364
3283
  className: "mt-3 w-fit max-w-full rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]",
3365
3284
  children: [
3366
- /* @__PURE__ */ jsxs12("span", { children: [
3285
+ /* @__PURE__ */ jsxs11("span", { children: [
3367
3286
  "\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
3368
3287
  feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
3369
3288
  ] }),
3370
- label ? /* @__PURE__ */ jsxs12("span", { children: [
3289
+ label ? /* @__PURE__ */ jsxs11("span", { children: [
3371
3290
  " \xB7 ",
3372
3291
  label
3373
3292
  ] }) : null
@@ -3442,15 +3361,15 @@ function ResultFeedback({
3442
3361
  [client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
3443
3362
  );
3444
3363
  if (!eligible) return null;
3445
- return /* @__PURE__ */ jsxs12(
3364
+ return /* @__PURE__ */ jsxs11(
3446
3365
  "section",
3447
3366
  {
3448
3367
  "aria-label": "\u7ED3\u679C\u53CD\u9988",
3449
3368
  className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
3450
3369
  children: [
3451
- /* @__PURE__ */ jsx14("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u76EE\u524D\u7684\u6574\u4F53\u7ED3\u679C\u6709\u5E2E\u52A9\u5417\uFF1F" }),
3452
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-1.5", children: [
3453
- /* @__PURE__ */ jsx14(
3370
+ /* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u76EE\u524D\u7684\u6574\u4F53\u7ED3\u679C\u6709\u5E2E\u52A9\u5417\uFF1F" }),
3371
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-1.5", children: [
3372
+ /* @__PURE__ */ jsx13(
3454
3373
  "button",
3455
3374
  {
3456
3375
  type: "button",
@@ -3461,7 +3380,7 @@ function ResultFeedback({
3461
3380
  children: "\u6709\u5E2E\u52A9"
3462
3381
  }
3463
3382
  ),
3464
- /* @__PURE__ */ jsx14(
3383
+ /* @__PURE__ */ jsx13(
3465
3384
  "button",
3466
3385
  {
3467
3386
  type: "button",
@@ -3473,7 +3392,7 @@ function ResultFeedback({
3473
3392
  }
3474
3393
  )
3475
3394
  ] }),
3476
- helpful === false ? /* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1.5", "aria-label": "\u6CA1\u5E2E\u52A9\u7684\u4E3B\u8981\u539F\u56E0", children: FEEDBACK_REASONS.map((item) => /* @__PURE__ */ jsx14(
3395
+ helpful === false ? /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1.5", "aria-label": "\u6CA1\u5E2E\u52A9\u7684\u4E3B\u8981\u539F\u56E0", children: FEEDBACK_REASONS.map((item) => /* @__PURE__ */ jsx13(
3477
3396
  "button",
3478
3397
  {
3479
3398
  type: "button",
@@ -3485,9 +3404,9 @@ function ResultFeedback({
3485
3404
  },
3486
3405
  item.value
3487
3406
  )) }) : null,
3488
- saveError ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
3489
- /* @__PURE__ */ jsx14("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
3490
- /* @__PURE__ */ jsx14(
3407
+ saveError ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
3408
+ /* @__PURE__ */ jsx13("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
3409
+ /* @__PURE__ */ jsx13(
3491
3410
  "button",
3492
3411
  {
3493
3412
  type: "button",
@@ -3499,7 +3418,7 @@ function ResultFeedback({
3499
3418
  children: "\u91CD\u8BD5"
3500
3419
  }
3501
3420
  )
3502
- ] }) : saved ? /* @__PURE__ */ jsx14("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
3421
+ ] }) : saved ? /* @__PURE__ */ jsx13("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
3503
3422
  ]
3504
3423
  }
3505
3424
  );
@@ -3566,15 +3485,15 @@ function PostChatFollowupBlock({
3566
3485
  );
3567
3486
  if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
3568
3487
  return null;
3569
- return /* @__PURE__ */ jsxs12("div", { className: "mt-3 flex w-fit max-w-full flex-col gap-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.28)] p-3 sm:max-w-[680px]", children: [
3570
- followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
3571
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
3572
- /* @__PURE__ */ jsx14(Sparkles, { size: 14 }),
3488
+ return /* @__PURE__ */ jsxs11("div", { className: "mt-3 flex w-fit max-w-full flex-col gap-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.28)] p-3 sm:max-w-[680px]", children: [
3489
+ followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
3490
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
3491
+ /* @__PURE__ */ jsx13(Sparkles, { size: 14 }),
3573
3492
  "\u672C\u8F6E\u5C0F\u7ED3"
3574
3493
  ] }),
3575
- followup.recaption ? /* @__PURE__ */ jsx14("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
3576
- artifacts.length > 0 ? /* @__PURE__ */ jsxs12(Fragment2, { children: [
3577
- /* @__PURE__ */ jsx14("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx14(
3494
+ followup.recaption ? /* @__PURE__ */ jsx13("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
3495
+ artifacts.length > 0 ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
3496
+ /* @__PURE__ */ jsx13("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx13(
3578
3497
  ArtifactCard,
3579
3498
  {
3580
3499
  artifact,
@@ -3586,7 +3505,7 @@ function PostChatFollowupBlock({
3586
3505
  },
3587
3506
  `${artifact.kind}:${artifactIndex}`
3588
3507
  )) }),
3589
- artifacts.length > 3 ? /* @__PURE__ */ jsxs12(
3508
+ artifacts.length > 3 ? /* @__PURE__ */ jsxs11(
3590
3509
  "button",
3591
3510
  {
3592
3511
  type: "button",
@@ -3595,15 +3514,15 @@ function PostChatFollowupBlock({
3595
3514
  className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
3596
3515
  children: [
3597
3516
  expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
3598
- /* @__PURE__ */ jsx14(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
3517
+ /* @__PURE__ */ jsx13(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
3599
3518
  ]
3600
3519
  }
3601
3520
  ) : null
3602
3521
  ] }) : null
3603
3522
  ] }) : null,
3604
- followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
3605
- /* @__PURE__ */ jsx14("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
3606
- followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs12(
3523
+ followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
3524
+ /* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
3525
+ followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs11(
3607
3526
  "button",
3608
3527
  {
3609
3528
  type: "button",
@@ -3622,14 +3541,14 @@ function PostChatFollowupBlock({
3622
3541
  },
3623
3542
  className: "group flex items-center gap-2 rounded-xl bg-[hsl(var(--muted)/0.62)] px-3 py-2 text-left text-[13px] disabled:cursor-default disabled:opacity-60",
3624
3543
  children: [
3625
- /* @__PURE__ */ jsx14("span", { children: suggestion }),
3626
- /* @__PURE__ */ jsx14(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
3544
+ /* @__PURE__ */ jsx13("span", { children: suggestion }),
3545
+ /* @__PURE__ */ jsx13(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
3627
3546
  ]
3628
3547
  },
3629
3548
  suggestion
3630
3549
  ))
3631
3550
  ] }) : null,
3632
- /* @__PURE__ */ jsx14(
3551
+ /* @__PURE__ */ jsx13(
3633
3552
  ResultFeedback,
3634
3553
  {
3635
3554
  followup,
@@ -3645,7 +3564,7 @@ function PostChatFollowupBlock({
3645
3564
 
3646
3565
  // src/components/UserMessageBubble.tsx
3647
3566
  import { getFileParts as getFileParts2, getImageParts as getImageParts2, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
3648
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3567
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3649
3568
  function isUserMessage(message) {
3650
3569
  return message.role === "user";
3651
3570
  }
@@ -3657,8 +3576,8 @@ function UserMessageBubble({ message, className }) {
3657
3576
  const text = getTextContent2(message.content).trim();
3658
3577
  const fileParts = getFileParts2(message.content);
3659
3578
  const imageParts = getImageParts2(message.content);
3660
- return /* @__PURE__ */ jsx15("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs13("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
3661
- imageParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx15(
3579
+ return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs12("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
3580
+ imageParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx14(
3662
3581
  "img",
3663
3582
  {
3664
3583
  src: part.image_url.url,
@@ -3667,21 +3586,21 @@ function UserMessageBubble({ message, className }) {
3667
3586
  },
3668
3587
  part.image_url.url
3669
3588
  )) }),
3670
- fileParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs13(
3589
+ fileParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs12(
3671
3590
  "div",
3672
3591
  {
3673
3592
  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))]",
3674
3593
  children: [
3675
- /* @__PURE__ */ jsx15(FileText, { size: 12, className: "shrink-0" }),
3676
- /* @__PURE__ */ jsx15("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
3594
+ /* @__PURE__ */ jsx14(FileText, { size: 12, className: "shrink-0" }),
3595
+ /* @__PURE__ */ jsx14("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
3677
3596
  ]
3678
3597
  },
3679
3598
  `${part.name}-${part.data.length}`
3680
3599
  )) }),
3681
- text && /* @__PURE__ */ jsx15("div", { className: "blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx15(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
3682
- text && isSending(message) && /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
3683
- /* @__PURE__ */ jsx15(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
3684
- /* @__PURE__ */ jsx15("span", { children: "\u53D1\u9001\u4E2D" })
3600
+ text && /* @__PURE__ */ jsx14("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__ */ jsx14(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
3601
+ text && isSending(message) && /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
3602
+ /* @__PURE__ */ jsx14(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
3603
+ /* @__PURE__ */ jsx14("span", { children: "\u53D1\u9001\u4E2D" })
3685
3604
  ] })
3686
3605
  ] }) });
3687
3606
  }
@@ -3690,11 +3609,11 @@ function ErrorMessageBlock({
3690
3609
  className
3691
3610
  }) {
3692
3611
  const text = getTextContent2(message.content);
3693
- return /* @__PURE__ */ jsx15("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx15("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]", children: text }) });
3612
+ return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx14("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]", children: text }) });
3694
3613
  }
3695
3614
 
3696
3615
  // src/components/MessageList.tsx
3697
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3616
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3698
3617
  function parseModeChange(message) {
3699
3618
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
3700
3619
  return null;
@@ -3750,7 +3669,7 @@ function MessageList({
3750
3669
  const visible = messages.filter((message) => {
3751
3670
  if ((message.loop_name ?? "root") !== "root") return false;
3752
3671
  if (isHiddenInternalMessage(message)) return false;
3753
- if (message.kind === "context") return Boolean(message.context);
3672
+ if (message.kind === "context") return false;
3754
3673
  if (message.kind === "compaction") return true;
3755
3674
  return message.role !== "tool" || getPlanningDividerKind(message) !== null;
3756
3675
  });
@@ -3785,15 +3704,6 @@ function MessageList({
3785
3704
  blocks.push({ type: "compaction", key: message.entry_id ?? `compaction-${blocks.length}` });
3786
3705
  continue;
3787
3706
  }
3788
- if (message.kind === "context" && message.context) {
3789
- flushAssistant();
3790
- blocks.push({
3791
- type: "context",
3792
- message,
3793
- key: message.entry_id ?? `context-${blocks.length}`
3794
- });
3795
- continue;
3796
- }
3797
3707
  if (message.role === "assistant") {
3798
3708
  assistantBuffer.push(message);
3799
3709
  continue;
@@ -3829,101 +3739,101 @@ function MessageList({
3829
3739
  }
3830
3740
  return blocks;
3831
3741
  }, [messages, isStreaming]);
3832
- return /* @__PURE__ */ jsx16("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs14(
3833
- StickToBottom,
3834
- {
3835
- className: "h-full overflow-y-hidden",
3836
- initial: "instant",
3837
- resize: "instant",
3838
- children: [
3839
- /* @__PURE__ */ jsx16(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx16("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs14("div", { className: "flex min-w-0 flex-col", children: [
3840
- renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs14("div", { className: "blade-chat-empty", children: [
3841
- /* @__PURE__ */ jsx16(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3842
- /* @__PURE__ */ jsx16("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3843
- /* @__PURE__ */ jsx16("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3844
- ] }) : renderBlocks.map((block) => {
3845
- if (block.type === "message") {
3846
- return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx16(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx16(ErrorMessageBlock, { message: block.message }) : null }, block.key);
3847
- }
3848
- if (block.type === "assistant_turn") {
3849
- const blockFeedback = block.messages.map(
3850
- (message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
3851
- ).find((feedback) => feedback != null);
3852
- const hasActiveFollowup = Boolean(
3853
- postChatFollowup && block.messages.some(
3854
- (message) => message.entry_id === postChatFollowup.assistant_entry_id
3855
- )
3856
- );
3857
- return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs14(
3858
- RenderErrorBoundary,
3859
- {
3860
- label: "\u52A9\u624B\u6D88\u606F",
3861
- details: block.key,
3862
- resetKey: getMessageResetSignature(block.messages),
3863
- children: [
3864
- /* @__PURE__ */ jsx16(
3865
- AssistantTurnBlock,
3866
- {
3867
- messages: block.messages,
3868
- isStreaming: block.isStreaming,
3869
- askAnswers,
3870
- onAnswer,
3871
- sessionStatus,
3872
- toolCallRenderer,
3873
- sessionId
3874
- }
3875
- ),
3876
- blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx16(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3877
- hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx16(
3878
- PostChatFollowupBlock,
3879
- {
3880
- followup: postChatFollowup,
3881
- sessionId,
3882
- onSuggestion,
3883
- isViewer,
3884
- onInteraction: onFollowupInteraction,
3885
- savedFeedback: blockFeedback,
3886
- onFeedbackSaved: onResultFeedbackSaved
3887
- }
3888
- ) : null
3889
- ]
3890
- }
3891
- ) }, block.key);
3892
- }
3893
- if (block.type === "context") {
3894
- return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.message.entry_id, children: /* @__PURE__ */ jsx16(ContextCard, { context: block.message.context }) }, block.key);
3895
- }
3896
- if (block.type === "compaction") {
3897
- return /* @__PURE__ */ jsxs14(
3898
- "div",
3899
- {
3900
- className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
3901
- children: [
3902
- /* @__PURE__ */ jsx16(Layers, { size: 12 }),
3903
- /* @__PURE__ */ jsx16("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3904
- ]
3905
- },
3906
- block.key
3907
- );
3908
- }
3909
- return /* @__PURE__ */ jsx16(PlanningDivider, { kind: block.kind }, block.key);
3910
- }),
3911
- sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx16("div", { className: "flex", children: /* @__PURE__ */ jsx16("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
3912
- ] }) }) }),
3913
- /* @__PURE__ */ jsx16(
3914
- PinLatestUserMessage,
3915
- {
3916
- userMessageCount: userMessages.length,
3917
- shouldPinLatestUser,
3918
- targetKey: latestUserMessage?.render_id ?? latestUserMessage?.entry_id ?? (latestUserMessage ? `user:${userMessages.length}` : null)
3919
- },
3920
- sessionId ?? "no-session"
3921
- ),
3922
- /* @__PURE__ */ jsx16(ScrollToBottomButton, {})
3923
- ]
3924
- },
3925
- sessionId ?? "no-session"
3926
- ) });
3742
+ return /* @__PURE__ */ jsxs13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: [
3743
+ isStreaming ? /* @__PURE__ */ jsx15("output", { className: "sr-only", children: "\u6B63\u5728\u751F\u6210\u56DE\u590D" }) : null,
3744
+ /* @__PURE__ */ jsxs13(
3745
+ StickToBottom,
3746
+ {
3747
+ className: "h-full overflow-y-hidden",
3748
+ initial: "instant",
3749
+ resize: "instant",
3750
+ children: [
3751
+ /* @__PURE__ */ jsx15(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx15("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs13("div", { className: "flex min-w-0 flex-col", children: [
3752
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs13("div", { className: "blade-chat-empty", children: [
3753
+ /* @__PURE__ */ jsx15(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3754
+ /* @__PURE__ */ jsx15("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3755
+ /* @__PURE__ */ jsx15("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3756
+ ] }) : renderBlocks.map((block) => {
3757
+ if (block.type === "message") {
3758
+ return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx15(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx15(ErrorMessageBlock, { message: block.message }) : null }, block.key);
3759
+ }
3760
+ if (block.type === "assistant_turn") {
3761
+ const blockFeedback = block.messages.map(
3762
+ (message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
3763
+ ).find((feedback) => feedback != null);
3764
+ const hasActiveFollowup = Boolean(
3765
+ postChatFollowup && block.messages.some(
3766
+ (message) => message.entry_id === postChatFollowup.assistant_entry_id
3767
+ )
3768
+ );
3769
+ return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs13(
3770
+ RenderErrorBoundary,
3771
+ {
3772
+ label: "\u52A9\u624B\u6D88\u606F",
3773
+ details: block.key,
3774
+ resetKey: getMessageResetSignature(block.messages),
3775
+ children: [
3776
+ /* @__PURE__ */ jsx15(
3777
+ AssistantTurnBlock,
3778
+ {
3779
+ messages: block.messages,
3780
+ isStreaming: block.isStreaming,
3781
+ askAnswers,
3782
+ onAnswer,
3783
+ sessionStatus,
3784
+ toolCallRenderer,
3785
+ sessionId
3786
+ }
3787
+ ),
3788
+ blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx15(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3789
+ hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx15(
3790
+ PostChatFollowupBlock,
3791
+ {
3792
+ followup: postChatFollowup,
3793
+ sessionId,
3794
+ onSuggestion,
3795
+ isViewer,
3796
+ onInteraction: onFollowupInteraction,
3797
+ savedFeedback: blockFeedback,
3798
+ onFeedbackSaved: onResultFeedbackSaved
3799
+ }
3800
+ ) : null
3801
+ ]
3802
+ }
3803
+ ) }, block.key);
3804
+ }
3805
+ if (block.type === "compaction") {
3806
+ return /* @__PURE__ */ jsxs13(
3807
+ "div",
3808
+ {
3809
+ className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
3810
+ children: [
3811
+ /* @__PURE__ */ jsx15(Layers, { size: 12 }),
3812
+ /* @__PURE__ */ jsx15("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3813
+ ]
3814
+ },
3815
+ block.key
3816
+ );
3817
+ }
3818
+ return /* @__PURE__ */ jsx15(PlanningDivider, { kind: block.kind }, block.key);
3819
+ }),
3820
+ sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx15("div", { className: "flex", children: /* @__PURE__ */ jsx15("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
3821
+ ] }) }) }),
3822
+ /* @__PURE__ */ jsx15(
3823
+ PinLatestUserMessage,
3824
+ {
3825
+ userMessageCount: userMessages.length,
3826
+ shouldPinLatestUser,
3827
+ targetKey: latestUserMessage?.render_id ?? latestUserMessage?.entry_id ?? (latestUserMessage ? `user:${userMessages.length}` : null)
3828
+ },
3829
+ sessionId ?? "no-session"
3830
+ ),
3831
+ /* @__PURE__ */ jsx15(ScrollToBottomButton, {})
3832
+ ]
3833
+ },
3834
+ sessionId ?? "no-session"
3835
+ )
3836
+ ] });
3927
3837
  }
3928
3838
  function PinLatestUserMessage({
3929
3839
  userMessageCount,
@@ -4004,7 +3914,7 @@ function ScrollToBottomButton() {
4004
3914
  scrollToBottom();
4005
3915
  }, [scrollToBottom]);
4006
3916
  if (!visible) return null;
4007
- return /* @__PURE__ */ jsxs14(
3917
+ return /* @__PURE__ */ jsxs13(
4008
3918
  "button",
4009
3919
  {
4010
3920
  type: "button",
@@ -4012,25 +3922,25 @@ function ScrollToBottomButton() {
4012
3922
  "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
4013
3923
  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))]",
4014
3924
  children: [
4015
- /* @__PURE__ */ jsx16(ChevronDown, { size: 14 }),
4016
- /* @__PURE__ */ jsx16("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
3925
+ /* @__PURE__ */ jsx15(ChevronDown, { size: 14 }),
3926
+ /* @__PURE__ */ jsx15("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
4017
3927
  ]
4018
3928
  }
4019
3929
  );
4020
3930
  }
4021
3931
  function PlanningDivider({ kind }) {
4022
- return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-3 py-1", children: [
4023
- /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
4024
- /* @__PURE__ */ jsxs14("div", { className: "inline-flex items-center gap-1.5 rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] text-amber-300", children: [
4025
- /* @__PURE__ */ jsx16(Lightbulb, { size: 12 }),
4026
- /* @__PURE__ */ jsx16("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
3932
+ return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 py-1", children: [
3933
+ /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
3934
+ /* @__PURE__ */ jsxs13("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: [
3935
+ /* @__PURE__ */ jsx15(Lightbulb, { size: 12 }),
3936
+ /* @__PURE__ */ jsx15("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
4027
3937
  ] }),
4028
- /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
3938
+ /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
4029
3939
  ] });
4030
3940
  }
4031
3941
 
4032
3942
  // src/components/ChatSurface.tsx
4033
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3943
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4034
3944
  function themeAttr(theme) {
4035
3945
  return theme === "dark" ? "dark" : void 0;
4036
3946
  }
@@ -4062,7 +3972,7 @@ function ChatSurface({
4062
3972
  beforeInput,
4063
3973
  banner
4064
3974
  }) {
4065
- return /* @__PURE__ */ jsxs15(
3975
+ return /* @__PURE__ */ jsxs14(
4066
3976
  "div",
4067
3977
  {
4068
3978
  "data-theme": themeAttr(theme),
@@ -4071,14 +3981,14 @@ function ChatSurface({
4071
3981
  classNames?.root
4072
3982
  ),
4073
3983
  children: [
4074
- /* @__PURE__ */ jsx17(ConnectionBanner, { connection, className: classNames?.banner }),
3984
+ /* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
4075
3985
  banner,
4076
- errorMessage && /* @__PURE__ */ jsxs15("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
4077
- /* @__PURE__ */ jsx17(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
4078
- /* @__PURE__ */ jsx17("span", { children: errorMessage })
3986
+ errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
3987
+ /* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
3988
+ /* @__PURE__ */ jsx16("span", { children: errorMessage })
4079
3989
  ] }),
4080
3990
  slots?.header,
4081
- /* @__PURE__ */ jsx17(
3991
+ /* @__PURE__ */ jsx16(
4082
3992
  MessageList,
4083
3993
  {
4084
3994
  messages,
@@ -4099,7 +4009,7 @@ function ChatSurface({
4099
4009
  }
4100
4010
  ),
4101
4011
  beforeInput,
4102
- /* @__PURE__ */ jsx17(
4012
+ /* @__PURE__ */ jsx16(
4103
4013
  ChatInput,
4104
4014
  {
4105
4015
  value: inputText,
@@ -4119,7 +4029,7 @@ function ChatSurface({
4119
4029
  }
4120
4030
 
4121
4031
  // src/components/AgentChat.tsx
4122
- import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4032
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4123
4033
  function isUnauthorizedError(error) {
4124
4034
  return error instanceof BladeApiError && error.status === 401;
4125
4035
  }
@@ -4138,11 +4048,11 @@ function LoginCard({ client, onLoggedIn }) {
4138
4048
  setLoggingIn(false);
4139
4049
  }
4140
4050
  };
4141
- return /* @__PURE__ */ jsx18("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs16("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center", children: [
4142
- /* @__PURE__ */ jsx18(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
4143
- /* @__PURE__ */ jsx18("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
4144
- /* @__PURE__ */ jsx18("div", { className: "text-sm text-[hsl(var(--muted-foreground))]", children: "\u767B\u5F55\u540E\u5373\u53EF\u4E0E\u667A\u80FD\u4F53\u5BF9\u8BDD\uFF0C\u4F60\u7684\u4F1A\u8BDD\u5185\u5BB9\u4EC5\u81EA\u5DF1\u53EF\u89C1\u3002" }),
4145
- /* @__PURE__ */ jsx18(
4051
+ return /* @__PURE__ */ jsx17("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs15("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: [
4052
+ /* @__PURE__ */ jsx17(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
4053
+ /* @__PURE__ */ jsx17("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
4054
+ /* @__PURE__ */ jsx17("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" }),
4055
+ /* @__PURE__ */ jsx17(
4146
4056
  "button",
4147
4057
  {
4148
4058
  type: "button",
@@ -4152,7 +4062,7 @@ function LoginCard({ client, onLoggedIn }) {
4152
4062
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
4153
4063
  }
4154
4064
  ),
4155
- loginError && /* @__PURE__ */ jsx18("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4065
+ loginError && /* @__PURE__ */ jsx17("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4156
4066
  ] }) });
4157
4067
  }
4158
4068
  function AgentChat(props) {
@@ -4160,12 +4070,12 @@ function AgentChat(props) {
4160
4070
  const [attempt, setAttempt] = useState13(0);
4161
4071
  const [needLogin, setNeedLogin] = useState13(() => !client.hasToken());
4162
4072
  if (needLogin) {
4163
- return /* @__PURE__ */ jsx18(
4073
+ return /* @__PURE__ */ jsx17(
4164
4074
  "div",
4165
4075
  {
4166
4076
  "data-theme": themeAttr(props.theme),
4167
4077
  className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
4168
- children: /* @__PURE__ */ jsx18(
4078
+ children: /* @__PURE__ */ jsx17(
4169
4079
  LoginCard,
4170
4080
  {
4171
4081
  client,
@@ -4178,7 +4088,7 @@ function AgentChat(props) {
4178
4088
  }
4179
4089
  );
4180
4090
  }
4181
- return /* @__PURE__ */ jsx18(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4091
+ return /* @__PURE__ */ jsx17(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4182
4092
  }
4183
4093
  function ChatSessionView({
4184
4094
  sessionId,
@@ -4287,7 +4197,7 @@ ${content}`);
4287
4197
  setStopRequested(true);
4288
4198
  void session?.stop();
4289
4199
  };
4290
- return /* @__PURE__ */ jsx18(
4200
+ return /* @__PURE__ */ jsx17(
4291
4201
  ChatSurface,
4292
4202
  {
4293
4203
  theme,
@@ -4297,8 +4207,8 @@ ${content}`);
4297
4207
  slots,
4298
4208
  placeholder,
4299
4209
  connection: state?.connection ?? "connecting",
4300
- banner: /* @__PURE__ */ jsxs16(Fragment3, { children: [
4301
- /* @__PURE__ */ jsx18(
4210
+ banner: /* @__PURE__ */ jsxs15(Fragment3, { children: [
4211
+ /* @__PURE__ */ jsx17(
4302
4212
  ReplayBar,
4303
4213
  {
4304
4214
  isReplay: replay.isReplay,
@@ -4308,7 +4218,7 @@ ${content}`);
4308
4218
  onExit: () => void replay.exitToAutonomous()
4309
4219
  }
4310
4220
  ),
4311
- /* @__PURE__ */ jsx18(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4221
+ /* @__PURE__ */ jsx17(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4312
4222
  ] }),
4313
4223
  errorMessage,
4314
4224
  messages: state?.messages ?? [],
@@ -4341,7 +4251,7 @@ import { useEffect as useEffect12, useMemo as useMemo9, useState as useState15 }
4341
4251
 
4342
4252
  // src/components/LlmAdvancedSettings.tsx
4343
4253
  import { useState as useState14 } from "react";
4344
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4254
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4345
4255
  var FIELDS = [
4346
4256
  { id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
4347
4257
  { id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
@@ -4392,8 +4302,8 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4392
4302
  if (!normalized) return null;
4393
4303
  const fields = FIELDS.filter((field) => normalized[field.id]);
4394
4304
  const dirty = Object.keys(override).length > 0;
4395
- return /* @__PURE__ */ jsxs17("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
4396
- /* @__PURE__ */ jsxs17(
4305
+ return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
4306
+ /* @__PURE__ */ jsxs16(
4397
4307
  "button",
4398
4308
  {
4399
4309
  type: "button",
@@ -4403,16 +4313,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4403
4313
  },
4404
4314
  className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
4405
4315
  children: [
4406
- /* @__PURE__ */ jsx19(Settings2, { size: 13 }),
4316
+ /* @__PURE__ */ jsx18(Settings2, { size: 13 }),
4407
4317
  "\u9AD8\u7EA7\u8BBE\u7F6E",
4408
- dirty && /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4318
+ dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4409
4319
  ]
4410
4320
  }
4411
4321
  ),
4412
- open && /* @__PURE__ */ jsxs17("div", { className: "mt-2 flex flex-col gap-2", children: [
4413
- fields.map((field) => /* @__PURE__ */ jsxs17("label", { className: "flex flex-col gap-1", children: [
4414
- /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
4415
- /* @__PURE__ */ jsx19(
4322
+ open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
4323
+ fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
4324
+ /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
4325
+ /* @__PURE__ */ jsx18(
4416
4326
  "input",
4417
4327
  {
4418
4328
  type: field.secret ? "password" : "text",
@@ -4423,9 +4333,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4423
4333
  }
4424
4334
  )
4425
4335
  ] }, field.id)),
4426
- normalized.apiKey && /* @__PURE__ */ jsx19("p", { className: "text-[hsl(var(--muted-foreground))]", children: "\u5BC6\u94A5\u4F1A\u5B58\u5728\u8FD9\u53F0\u6D4F\u89C8\u5668\u91CC\u3002\u53EA\u5728\u4F60\u4FE1\u5F97\u8FC7\u8FD9\u53F0\u673A\u5668\u65F6\u586B\u3002" }),
4427
- /* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
4428
- /* @__PURE__ */ jsx19(
4336
+ normalized.apiKey && /* @__PURE__ */ jsx18("p", { className: "text-[hsl(var(--muted-foreground))]", children: "\u5BC6\u94A5\u4F1A\u5B58\u5728\u8FD9\u53F0\u6D4F\u89C8\u5668\u91CC\u3002\u53EA\u5728\u4F60\u4FE1\u5F97\u8FC7\u8FD9\u53F0\u673A\u5668\u65F6\u586B\u3002" }),
4337
+ /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
4338
+ /* @__PURE__ */ jsx18(
4429
4339
  "button",
4430
4340
  {
4431
4341
  type: "button",
@@ -4440,7 +4350,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4440
4350
  children: "\u4FDD\u5B58"
4441
4351
  }
4442
4352
  ),
4443
- /* @__PURE__ */ jsx19(
4353
+ /* @__PURE__ */ jsx18(
4444
4354
  "button",
4445
4355
  {
4446
4356
  type: "button",
@@ -4459,7 +4369,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4459
4369
  }
4460
4370
 
4461
4371
  // src/components/LlmChat.tsx
4462
- import { jsx as jsx20 } from "react/jsx-runtime";
4372
+ import { jsx as jsx19 } from "react/jsx-runtime";
4463
4373
  function LlmChat({
4464
4374
  classNames,
4465
4375
  renderers,
@@ -4488,7 +4398,7 @@ ${text}` : text),
4488
4398
  useEffect12(() => {
4489
4399
  onReady?.(handle);
4490
4400
  }, [handle, onReady]);
4491
- return /* @__PURE__ */ jsx20(
4401
+ return /* @__PURE__ */ jsx19(
4492
4402
  ChatSurface,
4493
4403
  {
4494
4404
  theme,
@@ -4513,7 +4423,7 @@ ${text}` : text),
4513
4423
  setStopRequested(true);
4514
4424
  stop();
4515
4425
  },
4516
- beforeInput: advanced ? /* @__PURE__ */ jsx20(
4426
+ beforeInput: advanced ? /* @__PURE__ */ jsx19(
4517
4427
  LlmAdvancedSettingsBar,
4518
4428
  {
4519
4429
  settings: advanced,
@@ -4531,14 +4441,14 @@ ${text}` : text),
4531
4441
  }
4532
4442
 
4533
4443
  // src/components/ChatView.tsx
4534
- import { jsx as jsx21 } from "react/jsx-runtime";
4444
+ import { jsx as jsx20 } from "react/jsx-runtime";
4535
4445
  function ChatView(props) {
4536
4446
  const { mode, llm, onLlmReady, ...rest } = props;
4537
4447
  if (mode === "llm") {
4538
4448
  if (!llm) {
4539
4449
  throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
4540
4450
  }
4541
- return /* @__PURE__ */ jsx21(
4451
+ return /* @__PURE__ */ jsx20(
4542
4452
  LlmChat,
4543
4453
  {
4544
4454
  ...llm,
@@ -4551,7 +4461,89 @@ function ChatView(props) {
4551
4461
  }
4552
4462
  );
4553
4463
  }
4554
- return /* @__PURE__ */ jsx21(AgentChat, { ...rest });
4464
+ return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
4465
+ }
4466
+
4467
+ // src/components/ContextCard.tsx
4468
+ import {
4469
+ getContextDisplayState
4470
+ } from "@blade-hq/agent-client";
4471
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
4472
+ function ContextCard({ context, className }) {
4473
+ const display = getContextDisplayState(context);
4474
+ return /* @__PURE__ */ jsxs17(
4475
+ "details",
4476
+ {
4477
+ className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
4478
+ children: [
4479
+ /* @__PURE__ */ jsxs17("summary", { className: "blade-chat-context-summary flex cursor-pointer list-none items-center gap-2 px-3 py-2.5 [&::-webkit-details-marker]:hidden", children: [
4480
+ /* @__PURE__ */ jsx21(
4481
+ Layers,
4482
+ {
4483
+ size: 15,
4484
+ className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
4485
+ "aria-hidden": "true"
4486
+ }
4487
+ ),
4488
+ /* @__PURE__ */ jsxs17("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
4489
+ /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
4490
+ /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
4491
+ ] }),
4492
+ /* @__PURE__ */ jsx21(
4493
+ ChevronDown,
4494
+ {
4495
+ size: 14,
4496
+ className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
4497
+ "aria-hidden": "true"
4498
+ }
4499
+ )
4500
+ ] }),
4501
+ /* @__PURE__ */ jsx21("div", { className: "blade-chat-context-detail border-t border-[hsl(var(--border))] px-3 py-2.5 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: display.detail })
4502
+ ]
4503
+ }
4504
+ );
4505
+ }
4506
+
4507
+ // src/lib/agent-computer-command.ts
4508
+ var COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\n;&|(]\s*)computer\s+launch(?:\s|$)/;
4509
+ function isAgentComputerCommand(command) {
4510
+ return COMPUTER_LAUNCH_COMMAND_PATTERN.test(command);
4511
+ }
4512
+ function isAgentComputerToolCall(argumentsJson) {
4513
+ if (!argumentsJson) return false;
4514
+ let command;
4515
+ try {
4516
+ const parsed = JSON.parse(argumentsJson);
4517
+ if (typeof parsed !== "object" || parsed === null) return false;
4518
+ command = parsed.command;
4519
+ } catch {
4520
+ return false;
4521
+ }
4522
+ return typeof command === "string" && isAgentComputerCommand(command);
4523
+ }
4524
+ var LAUNCH_SUCCESS_MARKER = "\u5DF2\u542F\u52A8 ";
4525
+ function resultContainsLaunchSuccessMarker(result, depth = 0) {
4526
+ if (depth > 2) return false;
4527
+ if (typeof result === "string") {
4528
+ if (result.includes(LAUNCH_SUCCESS_MARKER)) return true;
4529
+ try {
4530
+ return resultContainsLaunchSuccessMarker(JSON.parse(result), depth + 1);
4531
+ } catch {
4532
+ return false;
4533
+ }
4534
+ }
4535
+ if (typeof result === "object" && result !== null) {
4536
+ for (const value of Object.values(result)) {
4537
+ if (typeof value === "string" && value.includes(LAUNCH_SUCCESS_MARKER)) return true;
4538
+ }
4539
+ }
4540
+ return false;
4541
+ }
4542
+ function classifyAgentComputerLaunchOutcome(toolCall) {
4543
+ if (toolCall.status === "error" || toolCall.status === "cancelled") return "failed";
4544
+ if (toolCall.status !== "done") return "pending";
4545
+ if (toolCall.result === void 0 || toolCall.result === null) return "unknown";
4546
+ return resultContainsLaunchSuccessMarker(toolCall.result) ? "succeeded" : "failed";
4555
4547
  }
4556
4548
 
4557
4549
  // src/index.ts
@@ -4565,6 +4557,9 @@ export {
4565
4557
  MarkdownContent,
4566
4558
  ReplayBar,
4567
4559
  ReplayMismatchPrompt,
4560
+ classifyAgentComputerLaunchOutcome,
4561
+ isAgentComputerCommand,
4562
+ isAgentComputerToolCall,
4568
4563
  useAgentSession,
4569
4564
  useBladeClient,
4570
4565
  useLlmChat,