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

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
@@ -1861,16 +1861,6 @@ var TOOL_DISPLAY_LABELS = {
1861
1861
  ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
1862
1862
  GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
1863
1863
  };
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
1864
  function safeParseJson(value) {
1875
1865
  if (!value) return null;
1876
1866
  try {
@@ -1879,38 +1869,6 @@ function safeParseJson(value) {
1879
1869
  return null;
1880
1870
  }
1881
1871
  }
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
1872
  function getStringArgValue(args, key) {
1915
1873
  const value = args?.[key];
1916
1874
  return typeof value === "string" ? value.trim() : "";
@@ -1933,15 +1891,6 @@ function formatToolName(name) {
1933
1891
  const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
1934
1892
  return TOOL_NAME_ALIASES[normalized] ?? stripped;
1935
1893
  }
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
1894
  function getToolDisplayLabel(toolCall) {
1946
1895
  const normalized = formatToolName(toolCall.name);
1947
1896
  const args = safeParseJson(toolCall.arguments);
@@ -2543,6 +2492,26 @@ function parseAskUserQuestion(toolResult) {
2543
2492
  }
2544
2493
  return null;
2545
2494
  }
2495
+ function parseAskUserQuestionError(toolResult) {
2496
+ if (!toolResult) return null;
2497
+ try {
2498
+ const parsed = JSON.parse(toolResult);
2499
+ let detail = null;
2500
+ if (typeof parsed.error === "string") detail = parsed.error;
2501
+ if (parsed.error && typeof parsed.error === "object") {
2502
+ const message = parsed.error.message;
2503
+ if (typeof message === "string") detail = message;
2504
+ }
2505
+ if (!detail && typeof parsed.message === "string") detail = parsed.message;
2506
+ if (!detail) return null;
2507
+ return {
2508
+ 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",
2509
+ detail
2510
+ };
2511
+ } catch {
2512
+ return null;
2513
+ }
2514
+ }
2546
2515
  function normalizeQuestionItem(value) {
2547
2516
  if (!value || typeof value !== "object") return null;
2548
2517
  const item = value;
@@ -2571,9 +2540,10 @@ import { Fragment, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2571
2540
  function resolveAskQuestionState({
2572
2541
  toolStatus,
2573
2542
  hasAnswerData,
2574
- fallbackAnswered
2543
+ fallbackAnswered,
2544
+ fallbackAwaiting
2575
2545
  }) {
2576
- const awaitingAnswer = !hasAnswerData && toolStatus === "awaiting_answer";
2546
+ const awaitingAnswer = !hasAnswerData && (toolStatus === "awaiting_answer" || toolStatus === "pending" && fallbackAwaiting === true);
2577
2547
  return {
2578
2548
  awaitingAnswer,
2579
2549
  answered: hasAnswerData || !awaitingAnswer && (Boolean(fallbackAnswered) || toolStatus === "done" || toolStatus === "cancelled" || toolStatus === "error")
@@ -2585,6 +2555,7 @@ function ToolCallBlock({
2585
2555
  answered,
2586
2556
  answerData,
2587
2557
  sessionStatus,
2558
+ isActiveQuestion,
2588
2559
  renderer
2589
2560
  }) {
2590
2561
  const [expanded, setExpanded] = useState9(false);
@@ -2600,7 +2571,8 @@ function ToolCallBlock({
2600
2571
  const questionState = resolveAskQuestionState({
2601
2572
  toolStatus: toolCall.status,
2602
2573
  hasAnswerData: Boolean(answerData),
2603
- fallbackAnswered: answered
2574
+ fallbackAnswered: answered,
2575
+ fallbackAwaiting: isActiveQuestion === true && (sessionStatus === "paused" || sessionStatus === "waiting_for_input")
2604
2576
  });
2605
2577
  const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
2606
2578
  if (askData) {
@@ -2622,9 +2594,16 @@ function ToolCallBlock({
2622
2594
  /* @__PURE__ */ jsx10("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
2623
2595
  ] });
2624
2596
  }
2597
+ const errorDetail = parseAskUserQuestionError(
2598
+ typeof toolCall.result === "string" ? toolCall.result : null
2599
+ );
2625
2600
  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
2601
  /* @__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" })
2602
+ /* @__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" }),
2603
+ errorDetail?.detail ? /* @__PURE__ */ jsxs8("details", { className: "mt-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
2604
+ /* @__PURE__ */ jsx10("summary", { className: "cursor-pointer", children: "\u67E5\u770B\u5177\u4F53\u539F\u56E0" }),
2605
+ /* @__PURE__ */ jsx10("div", { className: "mt-1 break-words font-mono", children: errorDetail.detail })
2606
+ ] }) : null
2628
2607
  ] });
2629
2608
  }
2630
2609
  const tone = getToolTone(toolCall.status);
@@ -2690,6 +2669,7 @@ function buildAskUserPayload(argumentsJson) {
2690
2669
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2691
2670
  function ThinkingBlock({ reasoning, isStreaming }) {
2692
2671
  const [open, setOpen] = useState10(false);
2672
+ if (!isStreaming) return null;
2693
2673
  return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-thinking text-xs", children: [
2694
2674
  /* @__PURE__ */ jsxs9(
2695
2675
  "button",
@@ -2699,7 +2679,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
2699
2679
  "aria-expanded": open,
2700
2680
  className: "group/thinking inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
2701
2681
  children: [
2702
- isStreaming ? /* @__PURE__ */ jsx11(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx11("span", { children: "\u5DF2\u601D\u8003" }),
2682
+ /* @__PURE__ */ jsx11(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }),
2703
2683
  /* @__PURE__ */ jsx11(
2704
2684
  ChevronRight,
2705
2685
  {
@@ -2713,7 +2693,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
2713
2693
  ]
2714
2694
  }
2715
2695
  ),
2716
- open && /* @__PURE__ */ jsx11("div", { className: "mt-1.5 whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: reasoning })
2696
+ open ? /* @__PURE__ */ jsx11("div", { className: "mt-1.5 whitespace-pre-wrap text-xs leading-[22px] text-[hsl(var(--muted-foreground))]", children: reasoning }) : null
2717
2697
  ] });
2718
2698
  }
2719
2699
  function getMessageText(message) {
@@ -2811,6 +2791,12 @@ function executionSummaryLabel({
2811
2791
  }
2812
2792
  return completedLabel;
2813
2793
  }
2794
+ function businessToolDisplayName(toolCall) {
2795
+ const displayName = toolCall.display_name?.trim() ?? "";
2796
+ if (!displayName) return "";
2797
+ const rawName = toolCall.name.trim();
2798
+ return displayName !== rawName && formatToolName(displayName) !== formatToolName(rawName) ? displayName : "";
2799
+ }
2814
2800
  function executionToolTypeLabel(toolCall) {
2815
2801
  switch (formatToolName(toolCall.name)) {
2816
2802
  case "WebSearch":
@@ -2838,7 +2824,7 @@ function executionToolTypeLabel(toolCall) {
2838
2824
  case "run_skill_tool":
2839
2825
  return "\u6267\u884C\u6280\u80FD";
2840
2826
  default:
2841
- return toolCall.display_name?.trim() || "\u6267\u884C\u6B65\u9AA4";
2827
+ return businessToolDisplayName(toolCall) || "\u6267\u884C\u6B65\u9AA4";
2842
2828
  }
2843
2829
  }
2844
2830
  function executionToolIntent(toolCall) {
@@ -2854,7 +2840,7 @@ function executionToolIntent(toolCall) {
2854
2840
  const value = args?.[key];
2855
2841
  return typeof value === "string" ? value.trim() : "";
2856
2842
  };
2857
- const explicitIntent = getString("description") || getString("_meta_display_name") || getString("display_name") || toolCall.display_name?.trim() || "";
2843
+ const explicitIntent = getString("description") || getString("_meta_display_name") || getString("display_name") || "";
2858
2844
  if (explicitIntent) return explicitIntent;
2859
2845
  if (normalizedName === "search_skills") return getString("query");
2860
2846
  if (normalizedName === "get_skill_content" || normalizedName === "ReadSkill") {
@@ -2869,58 +2855,18 @@ function ExecutionToolRow({ toolCall }) {
2869
2855
  const intent = executionToolIntent(toolCall);
2870
2856
  const label = intent ? `${typeLabel}\uFF1A${intent}` : typeLabel;
2871
2857
  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
2858
  const iconClass = cn(
2875
2859
  "size-3.5 shrink-0",
2876
2860
  failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
2877
2861
  );
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" });
2862
+ 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
2863
  const rowClassName = cn(
2880
2864
  "flex min-w-0 items-center gap-1 py-1.5 text-xs leading-[22px]",
2881
2865
  failed ? "text-red-500" : "text-[hsl(var(--muted-foreground))]"
2882
2866
  );
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
2867
+ return /* @__PURE__ */ jsxs9("div", { "data-testid": "execution-tool-intent", className: rowClassName, title: label, children: [
2868
+ icon,
2869
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: label })
2924
2870
  ] });
2925
2871
  }
2926
2872
  function AssistantTurnBlock({
@@ -2951,6 +2897,7 @@ function AssistantTurnBlock({
2951
2897
  (toolCall) => formatToolName(toolCall.name) === "AskUserQuestion"
2952
2898
  )
2953
2899
  );
2900
+ const activeQuestionId = questionToolCalls.filter((toolCall) => toolCall.status === "pending").at(-1)?.id;
2954
2901
  const [displayMode, setDisplayMode] = useState10(
2955
2902
  () => isStreaming || hasActionableToolCall ? "detail" : "compact"
2956
2903
  );
@@ -2975,132 +2922,146 @@ function AssistantTurnBlock({
2975
2922
  }, [hasLiveStartTime, isStreaming]);
2976
2923
  const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({ messages, isStreaming, now: clock }) : executionDurationMs;
2977
2924
  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,
2925
+ return /* @__PURE__ */ jsxs9(
2926
+ "div",
2927
+ {
2928
+ "aria-busy": isStreaming || void 0,
2929
+ className: "blade-chat-assistant-turn flex flex-col gap-3",
2930
+ children: [
2931
+ 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" }),
2932
+ 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" }),
2933
+ messages.map((message, index) => {
2934
+ return hasRenderableMessageContent(message) ? /* @__PURE__ */ jsx11(
2935
+ "div",
2988
2936
  {
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
- ] });
2937
+ className: "flex flex-col gap-3",
2938
+ children: /* @__PURE__ */ jsx11(
2939
+ AssistantMessageContent,
2940
+ {
2941
+ message,
2942
+ sessionId,
2943
+ streaming: isStreaming && index === messages.length - 1
2944
+ }
2945
+ )
2946
+ },
2947
+ message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
2948
+ ) : null;
2949
+ })
2950
+ ]
2951
+ }
2952
+ );
3000
2953
  }
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,
2954
+ return /* @__PURE__ */ jsxs9(
2955
+ "div",
2956
+ {
2957
+ "aria-busy": isStreaming || void 0,
2958
+ className: "blade-chat-assistant-turn flex flex-col gap-3",
2959
+ children: [
2960
+ 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" }),
2961
+ 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" }),
2962
+ /* @__PURE__ */ jsxs9("div", { className: "flex w-full items-start gap-2.5", children: [
2963
+ /* @__PURE__ */ jsx11(
2964
+ "span",
2965
+ {
2966
+ className: "grid size-[30px] shrink-0 place-items-center rounded-full bg-[hsl(var(--muted)/0.55)] text-[hsl(var(--foreground))]",
2967
+ "aria-hidden": "true",
2968
+ children: /* @__PURE__ */ jsx11(Bot, { size: 16 })
2969
+ }
2970
+ ),
2971
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1 pt-0.5", children: [
2972
+ /* @__PURE__ */ jsxs9(
2973
+ "button",
3067
2974
  {
3068
- message,
3069
- sessionId,
3070
- streaming: streamingThis,
3071
- compact: true
2975
+ type: "button",
2976
+ onClick: () => {
2977
+ userSelectedDisplayModeRef.current = true;
2978
+ setDisplayMode(displayMode === "detail" ? "compact" : "detail");
2979
+ },
2980
+ "aria-expanded": effectiveMode === "detail",
2981
+ "aria-label": effectiveMode === "detail" ? "\u6536\u8D77\u6267\u884C\u8FC7\u7A0B" : "\u5C55\u5F00\u6267\u884C\u8FC7\u7A0B",
2982
+ "data-testid": "assistant-execution-summary",
2983
+ 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",
2984
+ children: [
2985
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: executionSummaryLabel({
2986
+ messages,
2987
+ isStreaming,
2988
+ durationMs: liveExecutionDurationMs,
2989
+ sessionStatus,
2990
+ askAnswers
2991
+ }) }),
2992
+ /* @__PURE__ */ jsx11(
2993
+ ChevronRight,
2994
+ {
2995
+ size: 14,
2996
+ className: cn(
2997
+ "shrink-0 transition-transform duration-300",
2998
+ effectiveMode === "detail" && "rotate-90"
2999
+ ),
3000
+ "aria-hidden": "true"
3001
+ }
3002
+ )
3003
+ ]
3072
3004
  }
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
- ] });
3005
+ ),
3006
+ /* @__PURE__ */ jsx11("div", { className: "mt-3 h-px w-full bg-[hsl(var(--border)/0.75)]" })
3007
+ ] })
3008
+ ] }),
3009
+ effectiveMode === "detail" ? /* @__PURE__ */ jsx11("div", { className: "ml-10 flex flex-col gap-3 pt-1", children: messages.map((message, index) => {
3010
+ const isLast = index === messages.length - 1;
3011
+ const streamingThis = isStreaming && isLast;
3012
+ const text = getMessageText(message);
3013
+ const toolCalls = (message.tool_calls ?? []).filter(
3014
+ (toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
3015
+ );
3016
+ const showReasoning = !!message.reasoning && isStreaming && index === latestReasoningIndex;
3017
+ return /* @__PURE__ */ jsxs9(
3018
+ "div",
3019
+ {
3020
+ className: "flex flex-col gap-3",
3021
+ children: [
3022
+ showReasoning && message.reasoning ? /* @__PURE__ */ jsx11(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
3023
+ hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx11(
3024
+ AssistantMessageContent,
3025
+ {
3026
+ message,
3027
+ sessionId,
3028
+ streaming: streamingThis,
3029
+ compact: true
3030
+ }
3031
+ ) : null,
3032
+ toolCalls.length > 0 ? /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
3033
+ const custom = toolCallRenderer?.(toolCall);
3034
+ 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);
3035
+ }) }) : null
3036
+ ]
3037
+ },
3038
+ message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
3039
+ );
3040
+ }) }) : null,
3041
+ finalMessage ? /* @__PURE__ */ jsx11("div", { className: "ml-10", children: /* @__PURE__ */ jsx11(
3042
+ AssistantMessageContent,
3043
+ {
3044
+ message: finalMessage,
3045
+ sessionId,
3046
+ streaming: isStreaming && finalMessage === messages[messages.length - 1]
3047
+ }
3048
+ ) }) : null,
3049
+ questionToolCalls.map((toolCall) => /* @__PURE__ */ jsx11(
3050
+ ToolCallBlock,
3051
+ {
3052
+ toolCall,
3053
+ answerData: askAnswers?.[toolCall.id],
3054
+ onAnswer,
3055
+ answered: sessionStatus !== "waiting_for_input",
3056
+ sessionStatus,
3057
+ isActiveQuestion: toolCall.id === activeQuestionId,
3058
+ renderer: toolCallRenderer
3059
+ },
3060
+ toolCall.id
3061
+ ))
3062
+ ]
3063
+ }
3064
+ );
3104
3065
  }
3105
3066
  function AssistantMessageContent({
3106
3067
  message,
@@ -3165,49 +3126,9 @@ function AssistantMessageContent({
3165
3126
  ] });
3166
3127
  }
3167
3128
 
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
3129
  // src/components/RenderErrorBoundary.tsx
3209
3130
  import { Component } from "react";
3210
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3131
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3211
3132
  function getFirstComponentName(componentStack) {
3212
3133
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
3213
3134
  return match?.[1] ?? null;
@@ -3240,18 +3161,18 @@ var RenderErrorBoundary = class extends Component {
3240
3161
  return children;
3241
3162
  }
3242
3163
  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: [
3164
+ 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: [
3165
+ /* @__PURE__ */ jsx12(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
3166
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
3167
+ /* @__PURE__ */ jsxs10("div", { className: "font-medium", children: [
3247
3168
  label,
3248
3169
  "\u6E32\u67D3\u5931\u8D25"
3249
3170
  ] }),
3250
- /* @__PURE__ */ jsxs11("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
3171
+ /* @__PURE__ */ jsxs10("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
3251
3172
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
3252
3173
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
3253
3174
  ] }),
3254
- details ? /* @__PURE__ */ jsx13("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
3175
+ details ? /* @__PURE__ */ jsx12("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
3255
3176
  ] })
3256
3177
  ] }) });
3257
3178
  }
@@ -3259,7 +3180,7 @@ var RenderErrorBoundary = class extends Component {
3259
3180
 
3260
3181
  // src/components/PostChatFollowupBlock.tsx
3261
3182
  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";
3183
+ import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3263
3184
  function emitInteraction(callback, event) {
3264
3185
  try {
3265
3186
  callback?.(event);
@@ -3281,7 +3202,7 @@ function ArtifactCard({
3281
3202
  const [downloading, setDownloading] = useState11(false);
3282
3203
  const name = artifact.label || basename(artifact.target);
3283
3204
  if (artifact.kind === "link") {
3284
- return /* @__PURE__ */ jsxs12(
3205
+ return /* @__PURE__ */ jsxs11(
3285
3206
  "a",
3286
3207
  {
3287
3208
  href: artifact.target,
@@ -3292,9 +3213,9 @@ function ArtifactCard({
3292
3213
  ${artifact.target}`,
3293
3214
  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
3215
  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" })
3216
+ /* @__PURE__ */ jsx13(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
3217
+ /* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
3218
+ /* @__PURE__ */ jsx13(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
3298
3219
  ]
3299
3220
  }
3300
3221
  );
@@ -3329,7 +3250,7 @@ ${artifact.target}`,
3329
3250
  setDownloading(false);
3330
3251
  }
3331
3252
  };
3332
- return /* @__PURE__ */ jsx14(
3253
+ return /* @__PURE__ */ jsx13(
3333
3254
  "a",
3334
3255
  {
3335
3256
  href: downloadUrl,
@@ -3357,17 +3278,17 @@ function feedbackReasonLabel(reason) {
3357
3278
  }
3358
3279
  function HistoricalResultFeedback({ feedback }) {
3359
3280
  const label = feedbackReasonLabel(feedback.reason);
3360
- return /* @__PURE__ */ jsxs12(
3281
+ return /* @__PURE__ */ jsxs11(
3361
3282
  "section",
3362
3283
  {
3363
3284
  "aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
3364
3285
  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
3286
  children: [
3366
- /* @__PURE__ */ jsxs12("span", { children: [
3287
+ /* @__PURE__ */ jsxs11("span", { children: [
3367
3288
  "\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
3368
3289
  feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
3369
3290
  ] }),
3370
- label ? /* @__PURE__ */ jsxs12("span", { children: [
3291
+ label ? /* @__PURE__ */ jsxs11("span", { children: [
3371
3292
  " \xB7 ",
3372
3293
  label
3373
3294
  ] }) : null
@@ -3442,15 +3363,15 @@ function ResultFeedback({
3442
3363
  [client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
3443
3364
  );
3444
3365
  if (!eligible) return null;
3445
- return /* @__PURE__ */ jsxs12(
3366
+ return /* @__PURE__ */ jsxs11(
3446
3367
  "section",
3447
3368
  {
3448
3369
  "aria-label": "\u7ED3\u679C\u53CD\u9988",
3449
3370
  className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
3450
3371
  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(
3372
+ /* @__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" }),
3373
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-1.5", children: [
3374
+ /* @__PURE__ */ jsx13(
3454
3375
  "button",
3455
3376
  {
3456
3377
  type: "button",
@@ -3461,7 +3382,7 @@ function ResultFeedback({
3461
3382
  children: "\u6709\u5E2E\u52A9"
3462
3383
  }
3463
3384
  ),
3464
- /* @__PURE__ */ jsx14(
3385
+ /* @__PURE__ */ jsx13(
3465
3386
  "button",
3466
3387
  {
3467
3388
  type: "button",
@@ -3473,7 +3394,7 @@ function ResultFeedback({
3473
3394
  }
3474
3395
  )
3475
3396
  ] }),
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(
3397
+ 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
3398
  "button",
3478
3399
  {
3479
3400
  type: "button",
@@ -3485,9 +3406,9 @@ function ResultFeedback({
3485
3406
  },
3486
3407
  item.value
3487
3408
  )) }) : 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(
3409
+ saveError ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
3410
+ /* @__PURE__ */ jsx13("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
3411
+ /* @__PURE__ */ jsx13(
3491
3412
  "button",
3492
3413
  {
3493
3414
  type: "button",
@@ -3499,7 +3420,7 @@ function ResultFeedback({
3499
3420
  children: "\u91CD\u8BD5"
3500
3421
  }
3501
3422
  )
3502
- ] }) : saved ? /* @__PURE__ */ jsx14("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
3423
+ ] }) : saved ? /* @__PURE__ */ jsx13("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
3503
3424
  ]
3504
3425
  }
3505
3426
  );
@@ -3566,15 +3487,15 @@ function PostChatFollowupBlock({
3566
3487
  );
3567
3488
  if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
3568
3489
  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 }),
3490
+ 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: [
3491
+ followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
3492
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
3493
+ /* @__PURE__ */ jsx13(Sparkles, { size: 14 }),
3573
3494
  "\u672C\u8F6E\u5C0F\u7ED3"
3574
3495
  ] }),
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(
3496
+ followup.recaption ? /* @__PURE__ */ jsx13("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
3497
+ artifacts.length > 0 ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
3498
+ /* @__PURE__ */ jsx13("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx13(
3578
3499
  ArtifactCard,
3579
3500
  {
3580
3501
  artifact,
@@ -3586,7 +3507,7 @@ function PostChatFollowupBlock({
3586
3507
  },
3587
3508
  `${artifact.kind}:${artifactIndex}`
3588
3509
  )) }),
3589
- artifacts.length > 3 ? /* @__PURE__ */ jsxs12(
3510
+ artifacts.length > 3 ? /* @__PURE__ */ jsxs11(
3590
3511
  "button",
3591
3512
  {
3592
3513
  type: "button",
@@ -3595,15 +3516,15 @@ function PostChatFollowupBlock({
3595
3516
  className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
3596
3517
  children: [
3597
3518
  expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
3598
- /* @__PURE__ */ jsx14(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
3519
+ /* @__PURE__ */ jsx13(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
3599
3520
  ]
3600
3521
  }
3601
3522
  ) : null
3602
3523
  ] }) : null
3603
3524
  ] }) : 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(
3525
+ followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
3526
+ /* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
3527
+ followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs11(
3607
3528
  "button",
3608
3529
  {
3609
3530
  type: "button",
@@ -3622,14 +3543,14 @@ function PostChatFollowupBlock({
3622
3543
  },
3623
3544
  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
3545
  children: [
3625
- /* @__PURE__ */ jsx14("span", { children: suggestion }),
3626
- /* @__PURE__ */ jsx14(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
3546
+ /* @__PURE__ */ jsx13("span", { children: suggestion }),
3547
+ /* @__PURE__ */ jsx13(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
3627
3548
  ]
3628
3549
  },
3629
3550
  suggestion
3630
3551
  ))
3631
3552
  ] }) : null,
3632
- /* @__PURE__ */ jsx14(
3553
+ /* @__PURE__ */ jsx13(
3633
3554
  ResultFeedback,
3634
3555
  {
3635
3556
  followup,
@@ -3645,7 +3566,7 @@ function PostChatFollowupBlock({
3645
3566
 
3646
3567
  // src/components/UserMessageBubble.tsx
3647
3568
  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";
3569
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3649
3570
  function isUserMessage(message) {
3650
3571
  return message.role === "user";
3651
3572
  }
@@ -3657,8 +3578,8 @@ function UserMessageBubble({ message, className }) {
3657
3578
  const text = getTextContent2(message.content).trim();
3658
3579
  const fileParts = getFileParts2(message.content);
3659
3580
  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(
3581
+ 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: [
3582
+ imageParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx14(
3662
3583
  "img",
3663
3584
  {
3664
3585
  src: part.image_url.url,
@@ -3667,21 +3588,21 @@ function UserMessageBubble({ message, className }) {
3667
3588
  },
3668
3589
  part.image_url.url
3669
3590
  )) }),
3670
- fileParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs13(
3591
+ fileParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs12(
3671
3592
  "div",
3672
3593
  {
3673
3594
  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
3595
  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 })
3596
+ /* @__PURE__ */ jsx14(FileText, { size: 12, className: "shrink-0" }),
3597
+ /* @__PURE__ */ jsx14("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
3677
3598
  ]
3678
3599
  },
3679
3600
  `${part.name}-${part.data.length}`
3680
3601
  )) }),
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" })
3602
+ 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 }) }),
3603
+ 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: [
3604
+ /* @__PURE__ */ jsx14(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
3605
+ /* @__PURE__ */ jsx14("span", { children: "\u53D1\u9001\u4E2D" })
3685
3606
  ] })
3686
3607
  ] }) });
3687
3608
  }
@@ -3690,11 +3611,11 @@ function ErrorMessageBlock({
3690
3611
  className
3691
3612
  }) {
3692
3613
  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 }) });
3614
+ 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
3615
  }
3695
3616
 
3696
3617
  // src/components/MessageList.tsx
3697
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3618
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3698
3619
  function parseModeChange(message) {
3699
3620
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
3700
3621
  return null;
@@ -3750,7 +3671,7 @@ function MessageList({
3750
3671
  const visible = messages.filter((message) => {
3751
3672
  if ((message.loop_name ?? "root") !== "root") return false;
3752
3673
  if (isHiddenInternalMessage(message)) return false;
3753
- if (message.kind === "context") return Boolean(message.context);
3674
+ if (message.kind === "context") return false;
3754
3675
  if (message.kind === "compaction") return true;
3755
3676
  return message.role !== "tool" || getPlanningDividerKind(message) !== null;
3756
3677
  });
@@ -3785,15 +3706,6 @@ function MessageList({
3785
3706
  blocks.push({ type: "compaction", key: message.entry_id ?? `compaction-${blocks.length}` });
3786
3707
  continue;
3787
3708
  }
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
3709
  if (message.role === "assistant") {
3798
3710
  assistantBuffer.push(message);
3799
3711
  continue;
@@ -3829,101 +3741,101 @@ function MessageList({
3829
3741
  }
3830
3742
  return blocks;
3831
3743
  }, [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
- ) });
3744
+ return /* @__PURE__ */ jsxs13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: [
3745
+ isStreaming ? /* @__PURE__ */ jsx15("output", { className: "sr-only", children: "\u6B63\u5728\u751F\u6210\u56DE\u590D" }) : null,
3746
+ /* @__PURE__ */ jsxs13(
3747
+ StickToBottom,
3748
+ {
3749
+ className: "h-full overflow-y-hidden",
3750
+ initial: "instant",
3751
+ resize: "instant",
3752
+ children: [
3753
+ /* @__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: [
3754
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs13("div", { className: "blade-chat-empty", children: [
3755
+ /* @__PURE__ */ jsx15(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3756
+ /* @__PURE__ */ jsx15("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3757
+ /* @__PURE__ */ jsx15("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3758
+ ] }) : renderBlocks.map((block) => {
3759
+ if (block.type === "message") {
3760
+ 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);
3761
+ }
3762
+ if (block.type === "assistant_turn") {
3763
+ const blockFeedback = block.messages.map(
3764
+ (message) => message.entry_id ? resultFeedbackByEntry.get(message.entry_id) : void 0
3765
+ ).find((feedback) => feedback != null);
3766
+ const hasActiveFollowup = Boolean(
3767
+ postChatFollowup && block.messages.some(
3768
+ (message) => message.entry_id === postChatFollowup.assistant_entry_id
3769
+ )
3770
+ );
3771
+ return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs13(
3772
+ RenderErrorBoundary,
3773
+ {
3774
+ label: "\u52A9\u624B\u6D88\u606F",
3775
+ details: block.key,
3776
+ resetKey: getMessageResetSignature(block.messages),
3777
+ children: [
3778
+ /* @__PURE__ */ jsx15(
3779
+ AssistantTurnBlock,
3780
+ {
3781
+ messages: block.messages,
3782
+ isStreaming: block.isStreaming,
3783
+ askAnswers,
3784
+ onAnswer,
3785
+ sessionStatus,
3786
+ toolCallRenderer,
3787
+ sessionId
3788
+ }
3789
+ ),
3790
+ blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx15(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3791
+ hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx15(
3792
+ PostChatFollowupBlock,
3793
+ {
3794
+ followup: postChatFollowup,
3795
+ sessionId,
3796
+ onSuggestion,
3797
+ isViewer,
3798
+ onInteraction: onFollowupInteraction,
3799
+ savedFeedback: blockFeedback,
3800
+ onFeedbackSaved: onResultFeedbackSaved
3801
+ }
3802
+ ) : null
3803
+ ]
3804
+ }
3805
+ ) }, block.key);
3806
+ }
3807
+ if (block.type === "compaction") {
3808
+ return /* @__PURE__ */ jsxs13(
3809
+ "div",
3810
+ {
3811
+ className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
3812
+ children: [
3813
+ /* @__PURE__ */ jsx15(Layers, { size: 12 }),
3814
+ /* @__PURE__ */ jsx15("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3815
+ ]
3816
+ },
3817
+ block.key
3818
+ );
3819
+ }
3820
+ return /* @__PURE__ */ jsx15(PlanningDivider, { kind: block.kind }, block.key);
3821
+ }),
3822
+ 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
3823
+ ] }) }) }),
3824
+ /* @__PURE__ */ jsx15(
3825
+ PinLatestUserMessage,
3826
+ {
3827
+ userMessageCount: userMessages.length,
3828
+ shouldPinLatestUser,
3829
+ targetKey: latestUserMessage?.render_id ?? latestUserMessage?.entry_id ?? (latestUserMessage ? `user:${userMessages.length}` : null)
3830
+ },
3831
+ sessionId ?? "no-session"
3832
+ ),
3833
+ /* @__PURE__ */ jsx15(ScrollToBottomButton, {})
3834
+ ]
3835
+ },
3836
+ sessionId ?? "no-session"
3837
+ )
3838
+ ] });
3927
3839
  }
3928
3840
  function PinLatestUserMessage({
3929
3841
  userMessageCount,
@@ -4004,7 +3916,7 @@ function ScrollToBottomButton() {
4004
3916
  scrollToBottom();
4005
3917
  }, [scrollToBottom]);
4006
3918
  if (!visible) return null;
4007
- return /* @__PURE__ */ jsxs14(
3919
+ return /* @__PURE__ */ jsxs13(
4008
3920
  "button",
4009
3921
  {
4010
3922
  type: "button",
@@ -4012,25 +3924,25 @@ function ScrollToBottomButton() {
4012
3924
  "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
4013
3925
  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
3926
  children: [
4015
- /* @__PURE__ */ jsx16(ChevronDown, { size: 14 }),
4016
- /* @__PURE__ */ jsx16("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
3927
+ /* @__PURE__ */ jsx15(ChevronDown, { size: 14 }),
3928
+ /* @__PURE__ */ jsx15("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
4017
3929
  ]
4018
3930
  }
4019
3931
  );
4020
3932
  }
4021
3933
  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" })
3934
+ return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 py-1", children: [
3935
+ /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
3936
+ /* @__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: [
3937
+ /* @__PURE__ */ jsx15(Lightbulb, { size: 12 }),
3938
+ /* @__PURE__ */ jsx15("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
4027
3939
  ] }),
4028
- /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
3940
+ /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
4029
3941
  ] });
4030
3942
  }
4031
3943
 
4032
3944
  // src/components/ChatSurface.tsx
4033
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3945
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4034
3946
  function themeAttr(theme) {
4035
3947
  return theme === "dark" ? "dark" : void 0;
4036
3948
  }
@@ -4062,7 +3974,7 @@ function ChatSurface({
4062
3974
  beforeInput,
4063
3975
  banner
4064
3976
  }) {
4065
- return /* @__PURE__ */ jsxs15(
3977
+ return /* @__PURE__ */ jsxs14(
4066
3978
  "div",
4067
3979
  {
4068
3980
  "data-theme": themeAttr(theme),
@@ -4071,14 +3983,14 @@ function ChatSurface({
4071
3983
  classNames?.root
4072
3984
  ),
4073
3985
  children: [
4074
- /* @__PURE__ */ jsx17(ConnectionBanner, { connection, className: classNames?.banner }),
3986
+ /* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
4075
3987
  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 })
3988
+ errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
3989
+ /* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
3990
+ /* @__PURE__ */ jsx16("span", { children: errorMessage })
4079
3991
  ] }),
4080
3992
  slots?.header,
4081
- /* @__PURE__ */ jsx17(
3993
+ /* @__PURE__ */ jsx16(
4082
3994
  MessageList,
4083
3995
  {
4084
3996
  messages,
@@ -4099,7 +4011,7 @@ function ChatSurface({
4099
4011
  }
4100
4012
  ),
4101
4013
  beforeInput,
4102
- /* @__PURE__ */ jsx17(
4014
+ /* @__PURE__ */ jsx16(
4103
4015
  ChatInput,
4104
4016
  {
4105
4017
  value: inputText,
@@ -4119,7 +4031,7 @@ function ChatSurface({
4119
4031
  }
4120
4032
 
4121
4033
  // src/components/AgentChat.tsx
4122
- import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4034
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4123
4035
  function isUnauthorizedError(error) {
4124
4036
  return error instanceof BladeApiError && error.status === 401;
4125
4037
  }
@@ -4138,11 +4050,11 @@ function LoginCard({ client, onLoggedIn }) {
4138
4050
  setLoggingIn(false);
4139
4051
  }
4140
4052
  };
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(
4053
+ 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: [
4054
+ /* @__PURE__ */ jsx17(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
4055
+ /* @__PURE__ */ jsx17("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
4056
+ /* @__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" }),
4057
+ /* @__PURE__ */ jsx17(
4146
4058
  "button",
4147
4059
  {
4148
4060
  type: "button",
@@ -4152,7 +4064,7 @@ function LoginCard({ client, onLoggedIn }) {
4152
4064
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
4153
4065
  }
4154
4066
  ),
4155
- loginError && /* @__PURE__ */ jsx18("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4067
+ loginError && /* @__PURE__ */ jsx17("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4156
4068
  ] }) });
4157
4069
  }
4158
4070
  function AgentChat(props) {
@@ -4160,12 +4072,12 @@ function AgentChat(props) {
4160
4072
  const [attempt, setAttempt] = useState13(0);
4161
4073
  const [needLogin, setNeedLogin] = useState13(() => !client.hasToken());
4162
4074
  if (needLogin) {
4163
- return /* @__PURE__ */ jsx18(
4075
+ return /* @__PURE__ */ jsx17(
4164
4076
  "div",
4165
4077
  {
4166
4078
  "data-theme": themeAttr(props.theme),
4167
4079
  className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
4168
- children: /* @__PURE__ */ jsx18(
4080
+ children: /* @__PURE__ */ jsx17(
4169
4081
  LoginCard,
4170
4082
  {
4171
4083
  client,
@@ -4178,7 +4090,7 @@ function AgentChat(props) {
4178
4090
  }
4179
4091
  );
4180
4092
  }
4181
- return /* @__PURE__ */ jsx18(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4093
+ return /* @__PURE__ */ jsx17(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4182
4094
  }
4183
4095
  function ChatSessionView({
4184
4096
  sessionId,
@@ -4287,7 +4199,7 @@ ${content}`);
4287
4199
  setStopRequested(true);
4288
4200
  void session?.stop();
4289
4201
  };
4290
- return /* @__PURE__ */ jsx18(
4202
+ return /* @__PURE__ */ jsx17(
4291
4203
  ChatSurface,
4292
4204
  {
4293
4205
  theme,
@@ -4297,8 +4209,8 @@ ${content}`);
4297
4209
  slots,
4298
4210
  placeholder,
4299
4211
  connection: state?.connection ?? "connecting",
4300
- banner: /* @__PURE__ */ jsxs16(Fragment3, { children: [
4301
- /* @__PURE__ */ jsx18(
4212
+ banner: /* @__PURE__ */ jsxs15(Fragment3, { children: [
4213
+ /* @__PURE__ */ jsx17(
4302
4214
  ReplayBar,
4303
4215
  {
4304
4216
  isReplay: replay.isReplay,
@@ -4308,7 +4220,7 @@ ${content}`);
4308
4220
  onExit: () => void replay.exitToAutonomous()
4309
4221
  }
4310
4222
  ),
4311
- /* @__PURE__ */ jsx18(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4223
+ /* @__PURE__ */ jsx17(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4312
4224
  ] }),
4313
4225
  errorMessage,
4314
4226
  messages: state?.messages ?? [],
@@ -4341,7 +4253,7 @@ import { useEffect as useEffect12, useMemo as useMemo9, useState as useState15 }
4341
4253
 
4342
4254
  // src/components/LlmAdvancedSettings.tsx
4343
4255
  import { useState as useState14 } from "react";
4344
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4256
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4345
4257
  var FIELDS = [
4346
4258
  { id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
4347
4259
  { id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
@@ -4392,8 +4304,8 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4392
4304
  if (!normalized) return null;
4393
4305
  const fields = FIELDS.filter((field) => normalized[field.id]);
4394
4306
  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(
4307
+ return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
4308
+ /* @__PURE__ */ jsxs16(
4397
4309
  "button",
4398
4310
  {
4399
4311
  type: "button",
@@ -4403,16 +4315,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4403
4315
  },
4404
4316
  className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
4405
4317
  children: [
4406
- /* @__PURE__ */ jsx19(Settings2, { size: 13 }),
4318
+ /* @__PURE__ */ jsx18(Settings2, { size: 13 }),
4407
4319
  "\u9AD8\u7EA7\u8BBE\u7F6E",
4408
- dirty && /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4320
+ dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4409
4321
  ]
4410
4322
  }
4411
4323
  ),
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(
4324
+ open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
4325
+ fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
4326
+ /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
4327
+ /* @__PURE__ */ jsx18(
4416
4328
  "input",
4417
4329
  {
4418
4330
  type: field.secret ? "password" : "text",
@@ -4423,9 +4335,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4423
4335
  }
4424
4336
  )
4425
4337
  ] }, 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(
4338
+ 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" }),
4339
+ /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
4340
+ /* @__PURE__ */ jsx18(
4429
4341
  "button",
4430
4342
  {
4431
4343
  type: "button",
@@ -4440,7 +4352,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4440
4352
  children: "\u4FDD\u5B58"
4441
4353
  }
4442
4354
  ),
4443
- /* @__PURE__ */ jsx19(
4355
+ /* @__PURE__ */ jsx18(
4444
4356
  "button",
4445
4357
  {
4446
4358
  type: "button",
@@ -4459,7 +4371,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4459
4371
  }
4460
4372
 
4461
4373
  // src/components/LlmChat.tsx
4462
- import { jsx as jsx20 } from "react/jsx-runtime";
4374
+ import { jsx as jsx19 } from "react/jsx-runtime";
4463
4375
  function LlmChat({
4464
4376
  classNames,
4465
4377
  renderers,
@@ -4488,7 +4400,7 @@ ${text}` : text),
4488
4400
  useEffect12(() => {
4489
4401
  onReady?.(handle);
4490
4402
  }, [handle, onReady]);
4491
- return /* @__PURE__ */ jsx20(
4403
+ return /* @__PURE__ */ jsx19(
4492
4404
  ChatSurface,
4493
4405
  {
4494
4406
  theme,
@@ -4513,7 +4425,7 @@ ${text}` : text),
4513
4425
  setStopRequested(true);
4514
4426
  stop();
4515
4427
  },
4516
- beforeInput: advanced ? /* @__PURE__ */ jsx20(
4428
+ beforeInput: advanced ? /* @__PURE__ */ jsx19(
4517
4429
  LlmAdvancedSettingsBar,
4518
4430
  {
4519
4431
  settings: advanced,
@@ -4531,14 +4443,14 @@ ${text}` : text),
4531
4443
  }
4532
4444
 
4533
4445
  // src/components/ChatView.tsx
4534
- import { jsx as jsx21 } from "react/jsx-runtime";
4446
+ import { jsx as jsx20 } from "react/jsx-runtime";
4535
4447
  function ChatView(props) {
4536
4448
  const { mode, llm, onLlmReady, ...rest } = props;
4537
4449
  if (mode === "llm") {
4538
4450
  if (!llm) {
4539
4451
  throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
4540
4452
  }
4541
- return /* @__PURE__ */ jsx21(
4453
+ return /* @__PURE__ */ jsx20(
4542
4454
  LlmChat,
4543
4455
  {
4544
4456
  ...llm,
@@ -4551,7 +4463,89 @@ function ChatView(props) {
4551
4463
  }
4552
4464
  );
4553
4465
  }
4554
- return /* @__PURE__ */ jsx21(AgentChat, { ...rest });
4466
+ return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
4467
+ }
4468
+
4469
+ // src/components/ContextCard.tsx
4470
+ import {
4471
+ getContextDisplayState
4472
+ } from "@blade-hq/agent-client";
4473
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
4474
+ function ContextCard({ context, className }) {
4475
+ const display = getContextDisplayState(context);
4476
+ return /* @__PURE__ */ jsxs17(
4477
+ "details",
4478
+ {
4479
+ className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
4480
+ children: [
4481
+ /* @__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: [
4482
+ /* @__PURE__ */ jsx21(
4483
+ Layers,
4484
+ {
4485
+ size: 15,
4486
+ className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
4487
+ "aria-hidden": "true"
4488
+ }
4489
+ ),
4490
+ /* @__PURE__ */ jsxs17("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
4491
+ /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
4492
+ /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
4493
+ ] }),
4494
+ /* @__PURE__ */ jsx21(
4495
+ ChevronDown,
4496
+ {
4497
+ size: 14,
4498
+ className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
4499
+ "aria-hidden": "true"
4500
+ }
4501
+ )
4502
+ ] }),
4503
+ /* @__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 })
4504
+ ]
4505
+ }
4506
+ );
4507
+ }
4508
+
4509
+ // src/lib/agent-computer-command.ts
4510
+ var COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\n;&|(]\s*)computer\s+launch(?:\s|$)/;
4511
+ function isAgentComputerCommand(command) {
4512
+ return COMPUTER_LAUNCH_COMMAND_PATTERN.test(command);
4513
+ }
4514
+ function isAgentComputerToolCall(argumentsJson) {
4515
+ if (!argumentsJson) return false;
4516
+ let command;
4517
+ try {
4518
+ const parsed = JSON.parse(argumentsJson);
4519
+ if (typeof parsed !== "object" || parsed === null) return false;
4520
+ command = parsed.command;
4521
+ } catch {
4522
+ return false;
4523
+ }
4524
+ return typeof command === "string" && isAgentComputerCommand(command);
4525
+ }
4526
+ var LAUNCH_SUCCESS_MARKER = "\u5DF2\u542F\u52A8 ";
4527
+ function resultContainsLaunchSuccessMarker(result, depth = 0) {
4528
+ if (depth > 2) return false;
4529
+ if (typeof result === "string") {
4530
+ if (result.includes(LAUNCH_SUCCESS_MARKER)) return true;
4531
+ try {
4532
+ return resultContainsLaunchSuccessMarker(JSON.parse(result), depth + 1);
4533
+ } catch {
4534
+ return false;
4535
+ }
4536
+ }
4537
+ if (typeof result === "object" && result !== null) {
4538
+ for (const value of Object.values(result)) {
4539
+ if (typeof value === "string" && value.includes(LAUNCH_SUCCESS_MARKER)) return true;
4540
+ }
4541
+ }
4542
+ return false;
4543
+ }
4544
+ function classifyAgentComputerLaunchOutcome(toolCall) {
4545
+ if (toolCall.status === "error" || toolCall.status === "cancelled") return "failed";
4546
+ if (toolCall.status !== "done") return "pending";
4547
+ if (toolCall.result === void 0 || toolCall.result === null) return "unknown";
4548
+ return resultContainsLaunchSuccessMarker(toolCall.result) ? "succeeded" : "failed";
4555
4549
  }
4556
4550
 
4557
4551
  // src/index.ts
@@ -4565,6 +4559,9 @@ export {
4565
4559
  MarkdownContent,
4566
4560
  ReplayBar,
4567
4561
  ReplayMismatchPrompt,
4562
+ classifyAgentComputerLaunchOutcome,
4563
+ isAgentComputerCommand,
4564
+ isAgentComputerToolCall,
4568
4565
  useAgentSession,
4569
4566
  useBladeClient,
4570
4567
  useLlmChat,