@blade-hq/agent-react 2610.0.0-beta.16 → 2610.0.0-beta.18

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
@@ -1588,6 +1588,17 @@ function getStringArgValue(args, key) {
1588
1588
  const value = args?.[key];
1589
1589
  return typeof value === "string" ? value.trim() : "";
1590
1590
  }
1591
+ var SKILL_ENTRY_FILE_NAMES = /* @__PURE__ */ new Set(["skill.md", "command.md"]);
1592
+ var NON_SKILL_DIR_NAMES = /* @__PURE__ */ new Set([".", "..", ".agent", ".agents", ".claude", "skill_data", "skills"]);
1593
+ function getSkillNameFromFilePath(filePath) {
1594
+ if (!filePath) return null;
1595
+ const segments = filePath.split(/[\\/]+/).filter(Boolean);
1596
+ const fileName = segments.pop();
1597
+ if (!fileName || !SKILL_ENTRY_FILE_NAMES.has(fileName.toLowerCase())) return null;
1598
+ const dirName = segments.pop();
1599
+ if (!dirName || NON_SKILL_DIR_NAMES.has(dirName.toLowerCase())) return null;
1600
+ return dirName;
1601
+ }
1591
1602
  function formatToolName(name) {
1592
1603
  const trimmed = name.trim();
1593
1604
  if (!trimmed) return name;
@@ -1612,6 +1623,12 @@ function getToolDisplayLabel(toolCall) {
1612
1623
  const skillName = getStringArgValue(args, "skill") || getStringArgValue(args, "skill_name");
1613
1624
  return skillName ? `${baseLabel}\u300C${skillName}\u300D` : baseLabel;
1614
1625
  }
1626
+ if (normalized === "Read") {
1627
+ const skillName = getSkillNameFromFilePath(
1628
+ getStringArgValue(args, "file_path") || getStringArgValue(args, "path")
1629
+ );
1630
+ if (skillName) return `\u8BFB\u53D6\u6280\u80FD\u300C${skillName}\u300D`;
1631
+ }
1615
1632
  if (normalized === "FinishTask") {
1616
1633
  const title = getStringArgValue(args, "title");
1617
1634
  return title ? `${baseLabel}\uFF1A${title}` : baseLabel;
@@ -1858,6 +1875,7 @@ function AskUserQuestionBlock({
1858
1875
  const [selections, setSelections] = useState8(/* @__PURE__ */ new Map());
1859
1876
  const [customTexts, setCustomTexts] = useState8(/* @__PURE__ */ new Map());
1860
1877
  const [usingCustom, setUsingCustom] = useState8(/* @__PURE__ */ new Set());
1878
+ const [note, setNote] = useState8("");
1861
1879
  const [submitted, setSubmitted] = useState8(false);
1862
1880
  useEffect6(() => {
1863
1881
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
@@ -1866,7 +1884,7 @@ function AskUserQuestionBlock({
1866
1884
  }, [sessionStatus]);
1867
1885
  const displayAnswerState = useMemo6(() => {
1868
1886
  if (!(answered && answerData)) {
1869
- return { selections, customTexts, usingCustom };
1887
+ return { selections, customTexts, usingCustom, note };
1870
1888
  }
1871
1889
  const nextSelections = /* @__PURE__ */ new Map();
1872
1890
  const nextCustomTexts = /* @__PURE__ */ new Map();
@@ -1882,9 +1900,10 @@ function AskUserQuestionBlock({
1882
1900
  return {
1883
1901
  selections: nextSelections,
1884
1902
  customTexts: nextCustomTexts,
1885
- usingCustom: nextUsingCustom
1903
+ usingCustom: nextUsingCustom,
1904
+ note: answerData.note ?? ""
1886
1905
  };
1887
- }, [answerData, answered, customTexts, selections, usingCustom]);
1906
+ }, [answerData, answered, customTexts, note, selections, usingCustom]);
1888
1907
  const toggleOption = (qIdx, optIdx, multi) => {
1889
1908
  if (answered || submitted) return;
1890
1909
  setSelections((prev) => {
@@ -1932,6 +1951,7 @@ function AskUserQuestionBlock({
1932
1951
  const allAnswered = data.questions.every((_, i) => getAnswer(i) !== null);
1933
1952
  const handleSubmit = () => {
1934
1953
  if (answered || submitted || !allAnswered || !onAnswer) return;
1954
+ const trimmedNote = note.trim();
1935
1955
  const nextAnswerData = {
1936
1956
  selections: Object.fromEntries(
1937
1957
  Array.from(selections.entries()).map(([qIdx, optionIndexes]) => [
@@ -1941,13 +1961,17 @@ function AskUserQuestionBlock({
1941
1961
  ),
1942
1962
  custom: Object.fromEntries(
1943
1963
  Array.from(usingCustom).map((qIdx) => [qIdx, (customTexts.get(qIdx) ?? "").trim()]).filter(([, text2]) => text2.length > 0)
1944
- )
1964
+ ),
1965
+ ...trimmedNote ? { note: trimmedNote } : {}
1945
1966
  };
1946
1967
  const parts = data.questions.map(
1947
1968
  (q, i) => `- ${q.question} -> ${indentAnswerContinuationLines(getAnswer(i) ?? "")}`
1948
1969
  );
1949
- const text = `\u5173\u4E8E\u9700\u8981\u786E\u8BA4\u7684\u95EE\u9898\uFF0C\u7528\u6237\u7684\u56DE\u7B54\u5982\u4E0B\uFF1A
1950
- ${parts.join("\n")}`;
1970
+ const text = [
1971
+ `\u5173\u4E8E\u9700\u8981\u786E\u8BA4\u7684\u95EE\u9898\uFF0C\u7528\u6237\u7684\u56DE\u7B54\u5982\u4E0B\uFF1A
1972
+ ${parts.join("\n")}`,
1973
+ trimmedNote ? `\u8865\u5145\u8BF4\u660E\uFF1A${indentAnswerContinuationLines(trimmedNote)}` : ""
1974
+ ].filter(Boolean).join("\n");
1951
1975
  setSubmitted(true);
1952
1976
  onAnswer(text, toolCallId, nextAnswerData);
1953
1977
  };
@@ -1979,6 +2003,15 @@ ${parts.join("\n")}`;
1979
2003
  },
1980
2004
  q.question
1981
2005
  )),
2006
+ /* @__PURE__ */ jsx9(
2007
+ NoteField,
2008
+ {
2009
+ answered,
2010
+ submitted,
2011
+ note: displayAnswerState.note,
2012
+ onChange: setNote
2013
+ }
2014
+ ),
1982
2015
  !answered && !submitted && onAnswer && /* @__PURE__ */ jsx9(
1983
2016
  "button",
1984
2017
  {
@@ -2124,6 +2157,49 @@ function QuestionCard({
2124
2157
  ] })
2125
2158
  ] });
2126
2159
  }
2160
+ function NoteField({
2161
+ answered,
2162
+ submitted,
2163
+ note,
2164
+ onChange
2165
+ }) {
2166
+ const textareaRef = useAutoResizeTextarea(note);
2167
+ const readOnly = answered || submitted;
2168
+ if (answered && !note.trim()) return null;
2169
+ return /* @__PURE__ */ jsxs7(
2170
+ "label",
2171
+ {
2172
+ className: cn(
2173
+ "block rounded-lg border transition-all focus-within:ring-2 focus-within:ring-[hsl(var(--ring)/0.35)]",
2174
+ answered ? "px-2.5 py-1.5" : "px-3 py-2.5",
2175
+ note.trim() ? "border-[hsl(var(--ring)/0.6)] bg-[hsl(var(--accent))]" : "border-[hsl(var(--border))] hover:border-[hsl(var(--ring)/0.3)] hover:bg-[hsl(var(--accent))]",
2176
+ readOnly && "cursor-default opacity-70"
2177
+ ),
2178
+ children: [
2179
+ /* @__PURE__ */ jsx9("span", { className: "mb-1.5 block text-xs text-[hsl(var(--muted-foreground))]", children: "\u8865\u5145\u8BF4\u660E\uFF08\u53EF\u9009\uFF09" }),
2180
+ /* @__PURE__ */ jsx9(
2181
+ "textarea",
2182
+ {
2183
+ ref: textareaRef,
2184
+ rows: 2,
2185
+ value: note,
2186
+ readOnly,
2187
+ onChange: (event) => {
2188
+ if (readOnly) return;
2189
+ onChange(event.target.value);
2190
+ },
2191
+ "aria-label": "\u8865\u5145\u8BF4\u660E",
2192
+ placeholder: "\u9009\u5B8C\u8FD8\u53EF\u4EE5\u518D\u8BB2\u4E24\u53E5\uFF0C\u7A7A\u7740\u5C31\u5F53\u6CA1\u6709",
2193
+ className: cn(
2194
+ "min-h-10 w-full resize-none bg-transparent leading-5 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.5)]",
2195
+ answered ? "text-xs" : "text-sm"
2196
+ )
2197
+ }
2198
+ )
2199
+ ]
2200
+ }
2201
+ );
2202
+ }
2127
2203
  function parseAskUserQuestion(toolResult) {
2128
2204
  if (!toolResult) return null;
2129
2205
  try {
@@ -2391,9 +2467,49 @@ function AssistantTurnBlock({
2391
2467
  ] });
2392
2468
  }
2393
2469
 
2470
+ // src/components/ContextCard.tsx
2471
+ import {
2472
+ getContextDisplayState
2473
+ } from "@blade-hq/agent-client";
2474
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2475
+ function ContextCard({ context, className }) {
2476
+ const display = getContextDisplayState(context);
2477
+ return /* @__PURE__ */ jsxs10(
2478
+ "details",
2479
+ {
2480
+ className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
2481
+ children: [
2482
+ /* @__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: [
2483
+ /* @__PURE__ */ jsx12(
2484
+ Layers,
2485
+ {
2486
+ size: 15,
2487
+ className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
2488
+ "aria-hidden": "true"
2489
+ }
2490
+ ),
2491
+ /* @__PURE__ */ jsxs10("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
2492
+ /* @__PURE__ */ jsx12("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
2493
+ /* @__PURE__ */ jsx12("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
2494
+ ] }),
2495
+ /* @__PURE__ */ jsx12(
2496
+ ChevronDown,
2497
+ {
2498
+ size: 14,
2499
+ className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
2500
+ "aria-hidden": "true"
2501
+ }
2502
+ )
2503
+ ] }),
2504
+ /* @__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 })
2505
+ ]
2506
+ }
2507
+ );
2508
+ }
2509
+
2394
2510
  // src/components/RenderErrorBoundary.tsx
2395
2511
  import { Component } from "react";
2396
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2512
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2397
2513
  function getFirstComponentName(componentStack) {
2398
2514
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
2399
2515
  return match?.[1] ?? null;
@@ -2426,18 +2542,18 @@ var RenderErrorBoundary = class extends Component {
2426
2542
  return children;
2427
2543
  }
2428
2544
  const componentName = getFirstComponentName(componentStack);
2429
- 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: [
2430
- /* @__PURE__ */ jsx12(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
2431
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
2432
- /* @__PURE__ */ jsxs10("div", { className: "font-medium", children: [
2545
+ 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: [
2546
+ /* @__PURE__ */ jsx13(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
2547
+ /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
2548
+ /* @__PURE__ */ jsxs11("div", { className: "font-medium", children: [
2433
2549
  label,
2434
2550
  "\u6E32\u67D3\u5931\u8D25"
2435
2551
  ] }),
2436
- /* @__PURE__ */ jsxs10("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
2552
+ /* @__PURE__ */ jsxs11("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
2437
2553
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
2438
2554
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
2439
2555
  ] }),
2440
- details ? /* @__PURE__ */ jsx12("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
2556
+ details ? /* @__PURE__ */ jsx13("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
2441
2557
  ] })
2442
2558
  ] }) });
2443
2559
  }
@@ -2445,7 +2561,7 @@ var RenderErrorBoundary = class extends Component {
2445
2561
 
2446
2562
  // src/components/PostChatFollowupBlock.tsx
2447
2563
  import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef8, useState as useState11 } from "react";
2448
- import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2564
+ import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2449
2565
  function emitInteraction(callback, event) {
2450
2566
  try {
2451
2567
  callback?.(event);
@@ -2467,7 +2583,7 @@ function ArtifactCard({
2467
2583
  const [downloading, setDownloading] = useState11(false);
2468
2584
  const name = artifact.label || basename(artifact.target);
2469
2585
  if (artifact.kind === "link") {
2470
- return /* @__PURE__ */ jsxs11(
2586
+ return /* @__PURE__ */ jsxs12(
2471
2587
  "a",
2472
2588
  {
2473
2589
  href: artifact.target,
@@ -2478,9 +2594,9 @@ function ArtifactCard({
2478
2594
  ${artifact.target}`,
2479
2595
  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))]",
2480
2596
  children: [
2481
- /* @__PURE__ */ jsx13(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
2482
- /* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
2483
- /* @__PURE__ */ jsx13(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
2597
+ /* @__PURE__ */ jsx14(Globe, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
2598
+ /* @__PURE__ */ jsx14("span", { className: "min-w-0 flex-1 truncate font-medium", children: name }),
2599
+ /* @__PURE__ */ jsx14(ArrowUpRight, { size: 13, className: "absolute right-2 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" })
2484
2600
  ]
2485
2601
  }
2486
2602
  );
@@ -2515,7 +2631,7 @@ ${artifact.target}`,
2515
2631
  setDownloading(false);
2516
2632
  }
2517
2633
  };
2518
- return /* @__PURE__ */ jsx13(
2634
+ return /* @__PURE__ */ jsx14(
2519
2635
  "a",
2520
2636
  {
2521
2637
  href: downloadUrl,
@@ -2543,17 +2659,17 @@ function feedbackReasonLabel(reason) {
2543
2659
  }
2544
2660
  function HistoricalResultFeedback({ feedback }) {
2545
2661
  const label = feedbackReasonLabel(feedback.reason);
2546
- return /* @__PURE__ */ jsxs11(
2662
+ return /* @__PURE__ */ jsxs12(
2547
2663
  "section",
2548
2664
  {
2549
2665
  "aria-label": "\u5386\u53F2\u7ED3\u679C\u53CD\u9988",
2550
2666
  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))]",
2551
2667
  children: [
2552
- /* @__PURE__ */ jsxs11("span", { children: [
2668
+ /* @__PURE__ */ jsxs12("span", { children: [
2553
2669
  "\u4F60\u5BF9\u6B64\u8F6E\u7ED3\u679C\u7684\u8BC4\u4EF7\uFF1A",
2554
2670
  feedback.helpful ? "\u6709\u5E2E\u52A9" : "\u6CA1\u5E2E\u52A9"
2555
2671
  ] }),
2556
- label ? /* @__PURE__ */ jsxs11("span", { children: [
2672
+ label ? /* @__PURE__ */ jsxs12("span", { children: [
2557
2673
  " \xB7 ",
2558
2674
  label
2559
2675
  ] }) : null
@@ -2628,15 +2744,15 @@ function ResultFeedback({
2628
2744
  [client, followup.assistant_entry_id, onFeedbackSaved, onInteraction, sessionId]
2629
2745
  );
2630
2746
  if (!eligible) return null;
2631
- return /* @__PURE__ */ jsxs11(
2747
+ return /* @__PURE__ */ jsxs12(
2632
2748
  "section",
2633
2749
  {
2634
2750
  "aria-label": "\u7ED3\u679C\u53CD\u9988",
2635
2751
  className: "flex flex-col gap-2 border-t border-[hsl(var(--border))] pt-3",
2636
2752
  children: [
2637
- /* @__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" }),
2638
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap gap-1.5", children: [
2639
- /* @__PURE__ */ jsx13(
2753
+ /* @__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" }),
2754
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-1.5", children: [
2755
+ /* @__PURE__ */ jsx14(
2640
2756
  "button",
2641
2757
  {
2642
2758
  type: "button",
@@ -2647,7 +2763,7 @@ function ResultFeedback({
2647
2763
  children: "\u6709\u5E2E\u52A9"
2648
2764
  }
2649
2765
  ),
2650
- /* @__PURE__ */ jsx13(
2766
+ /* @__PURE__ */ jsx14(
2651
2767
  "button",
2652
2768
  {
2653
2769
  type: "button",
@@ -2659,7 +2775,7 @@ function ResultFeedback({
2659
2775
  }
2660
2776
  )
2661
2777
  ] }),
2662
- 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(
2778
+ 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(
2663
2779
  "button",
2664
2780
  {
2665
2781
  type: "button",
@@ -2671,9 +2787,9 @@ function ResultFeedback({
2671
2787
  },
2672
2788
  item.value
2673
2789
  )) }) : null,
2674
- saveError ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
2675
- /* @__PURE__ */ jsx13("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
2676
- /* @__PURE__ */ jsx13(
2790
+ saveError ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--destructive))]", children: [
2791
+ /* @__PURE__ */ jsx14("span", { children: "\u53CD\u9988\u6682\u672A\u4FDD\u5B58\uFF0C\u53EF\u91CD\u8BD5" }),
2792
+ /* @__PURE__ */ jsx14(
2677
2793
  "button",
2678
2794
  {
2679
2795
  type: "button",
@@ -2685,7 +2801,7 @@ function ResultFeedback({
2685
2801
  children: "\u91CD\u8BD5"
2686
2802
  }
2687
2803
  )
2688
- ] }) : saved ? /* @__PURE__ */ jsx13("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
2804
+ ] }) : saved ? /* @__PURE__ */ jsx14("div", { className: "text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u5DF2\u4FDD\u5B58\uFF0C\u53EF\u968F\u65F6\u4FEE\u6539" }) : null
2689
2805
  ]
2690
2806
  }
2691
2807
  );
@@ -2752,15 +2868,15 @@ function PostChatFollowupBlock({
2752
2868
  );
2753
2869
  if (!followup.recaption && artifacts.length === 0 && followup.suggestions.length === 0 && !followup.feedback_eligible)
2754
2870
  return null;
2755
- 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: [
2756
- followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
2757
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
2758
- /* @__PURE__ */ jsx13(Sparkles, { size: 14 }),
2871
+ 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: [
2872
+ followup.recaption || artifacts.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u672C\u8F6E\u5C0F\u7ED3", className: "flex flex-col gap-2", children: [
2873
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--muted-foreground))]", children: [
2874
+ /* @__PURE__ */ jsx14(Sparkles, { size: 14 }),
2759
2875
  "\u672C\u8F6E\u5C0F\u7ED3"
2760
2876
  ] }),
2761
- followup.recaption ? /* @__PURE__ */ jsx13("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
2762
- artifacts.length > 0 ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
2763
- /* @__PURE__ */ jsx13("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx13(
2877
+ followup.recaption ? /* @__PURE__ */ jsx14("p", { className: "text-[13px] leading-5", children: followup.recaption }) : null,
2878
+ artifacts.length > 0 ? /* @__PURE__ */ jsxs12(Fragment2, { children: [
2879
+ /* @__PURE__ */ jsx14("div", { className: "grid max-w-full grid-cols-3 gap-1.5", children: visibleArtifacts.map((artifact, artifactIndex) => /* @__PURE__ */ jsx14(
2764
2880
  ArtifactCard,
2765
2881
  {
2766
2882
  artifact,
@@ -2772,7 +2888,7 @@ function PostChatFollowupBlock({
2772
2888
  },
2773
2889
  `${artifact.kind}:${artifactIndex}`
2774
2890
  )) }),
2775
- artifacts.length > 3 ? /* @__PURE__ */ jsxs11(
2891
+ artifacts.length > 3 ? /* @__PURE__ */ jsxs12(
2776
2892
  "button",
2777
2893
  {
2778
2894
  type: "button",
@@ -2781,15 +2897,15 @@ function PostChatFollowupBlock({
2781
2897
  className: "flex w-fit items-center gap-0.5 text-[11px] text-[hsl(var(--muted-foreground))]",
2782
2898
  children: [
2783
2899
  expanded ? "\u6536\u8D77" : `\u5C55\u5F00 ${artifacts.length - 3} \u4E2A`,
2784
- /* @__PURE__ */ jsx13(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
2900
+ /* @__PURE__ */ jsx14(ChevronDown, { size: 13, className: expanded ? "rotate-180" : void 0 })
2785
2901
  ]
2786
2902
  }
2787
2903
  ) : null
2788
2904
  ] }) : null
2789
2905
  ] }) : null,
2790
- followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs11("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
2791
- /* @__PURE__ */ jsx13("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
2792
- followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs11(
2906
+ followup.suggestions.length > 0 ? /* @__PURE__ */ jsxs12("section", { "aria-label": "\u4E0B\u4E00\u6B65\u5EFA\u8BAE", className: "flex flex-col gap-1.5", children: [
2907
+ /* @__PURE__ */ jsx14("div", { className: "text-xs font-medium text-[hsl(var(--muted-foreground))]", children: "\u4E0B\u4E00\u6B65\u53EF\u4EE5" }),
2908
+ followup.suggestions.map((suggestion, suggestionIndex) => /* @__PURE__ */ jsxs12(
2793
2909
  "button",
2794
2910
  {
2795
2911
  type: "button",
@@ -2808,14 +2924,14 @@ function PostChatFollowupBlock({
2808
2924
  },
2809
2925
  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",
2810
2926
  children: [
2811
- /* @__PURE__ */ jsx13("span", { children: suggestion }),
2812
- /* @__PURE__ */ jsx13(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
2927
+ /* @__PURE__ */ jsx14("span", { children: suggestion }),
2928
+ /* @__PURE__ */ jsx14(ArrowRight, { size: 14, className: "ml-auto shrink-0" })
2813
2929
  ]
2814
2930
  },
2815
2931
  suggestion
2816
2932
  ))
2817
2933
  ] }) : null,
2818
- /* @__PURE__ */ jsx13(
2934
+ /* @__PURE__ */ jsx14(
2819
2935
  ResultFeedback,
2820
2936
  {
2821
2937
  followup,
@@ -2831,7 +2947,7 @@ function PostChatFollowupBlock({
2831
2947
 
2832
2948
  // src/components/UserMessageBubble.tsx
2833
2949
  import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
2834
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2950
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2835
2951
  function isUserMessage(message) {
2836
2952
  return message.role === "user";
2837
2953
  }
@@ -2843,8 +2959,8 @@ function UserMessageBubble({ message, className }) {
2843
2959
  const text = getTextContent2(message.content).trim();
2844
2960
  const fileParts = getFileParts(message.content);
2845
2961
  const imageParts = getImageParts(message.content);
2846
- 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: [
2847
- imageParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx14(
2962
+ 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: [
2963
+ imageParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx15(
2848
2964
  "img",
2849
2965
  {
2850
2966
  src: part.image_url.url,
@@ -2853,21 +2969,21 @@ function UserMessageBubble({ message, className }) {
2853
2969
  },
2854
2970
  part.image_url.url
2855
2971
  )) }),
2856
- fileParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs12(
2972
+ fileParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs13(
2857
2973
  "div",
2858
2974
  {
2859
2975
  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))]",
2860
2976
  children: [
2861
- /* @__PURE__ */ jsx14(FileText, { size: 12, className: "shrink-0" }),
2862
- /* @__PURE__ */ jsx14("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
2977
+ /* @__PURE__ */ jsx15(FileText, { size: 12, className: "shrink-0" }),
2978
+ /* @__PURE__ */ jsx15("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
2863
2979
  ]
2864
2980
  },
2865
2981
  `${part.name}-${part.data.length}`
2866
2982
  )) }),
2867
- 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 }) }),
2868
- 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: [
2869
- /* @__PURE__ */ jsx14(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
2870
- /* @__PURE__ */ jsx14("span", { children: "\u53D1\u9001\u4E2D" })
2983
+ 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 }) }),
2984
+ 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: [
2985
+ /* @__PURE__ */ jsx15(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
2986
+ /* @__PURE__ */ jsx15("span", { children: "\u53D1\u9001\u4E2D" })
2871
2987
  ] })
2872
2988
  ] }) });
2873
2989
  }
@@ -2876,11 +2992,11 @@ function ErrorMessageBlock({
2876
2992
  className
2877
2993
  }) {
2878
2994
  const text = getTextContent2(message.content);
2879
- 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 }) });
2995
+ 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 }) });
2880
2996
  }
2881
2997
 
2882
2998
  // src/components/MessageList.tsx
2883
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2999
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2884
3000
  function parseModeChange(message) {
2885
3001
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
2886
3002
  return null;
@@ -2933,6 +3049,7 @@ function MessageList({
2933
3049
  const visible = messages.filter((message) => {
2934
3050
  if ((message.loop_name ?? "root") !== "root") return false;
2935
3051
  if (isHiddenInternalMessage(message)) return false;
3052
+ if (message.kind === "context") return Boolean(message.context);
2936
3053
  if (message.kind === "compaction") return true;
2937
3054
  return message.role !== "tool" || getPlanningDividerKind(message) !== null;
2938
3055
  });
@@ -2967,6 +3084,15 @@ function MessageList({
2967
3084
  blocks.push({ type: "compaction", key: message.entry_id ?? `compaction-${blocks.length}` });
2968
3085
  continue;
2969
3086
  }
3087
+ if (message.kind === "context" && message.context) {
3088
+ flushAssistant();
3089
+ blocks.push({
3090
+ type: "context",
3091
+ message,
3092
+ key: message.entry_id ?? `context-${blocks.length}`
3093
+ });
3094
+ continue;
3095
+ }
2970
3096
  if (message.role === "assistant") {
2971
3097
  assistantBuffer.push(message);
2972
3098
  continue;
@@ -3002,15 +3128,15 @@ function MessageList({
3002
3128
  }
3003
3129
  return blocks;
3004
3130
  }, [messages, isStreaming]);
3005
- return /* @__PURE__ */ jsx15("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs13(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
3006
- /* @__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: [
3007
- renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs13("div", { className: "blade-chat-empty", children: [
3008
- /* @__PURE__ */ jsx15(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3009
- /* @__PURE__ */ jsx15("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3010
- /* @__PURE__ */ jsx15("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3131
+ return /* @__PURE__ */ jsx16("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs14(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
3132
+ /* @__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: [
3133
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs14("div", { className: "blade-chat-empty", children: [
3134
+ /* @__PURE__ */ jsx16(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3135
+ /* @__PURE__ */ jsx16("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3136
+ /* @__PURE__ */ jsx16("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3011
3137
  ] }) : renderBlocks.map((block) => {
3012
3138
  if (block.type === "message") {
3013
- 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);
3139
+ 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);
3014
3140
  }
3015
3141
  if (block.type === "assistant_turn") {
3016
3142
  const blockFeedback = block.messages.map(
@@ -3021,14 +3147,14 @@ function MessageList({
3021
3147
  (message) => message.entry_id === postChatFollowup.assistant_entry_id
3022
3148
  )
3023
3149
  );
3024
- return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs13(
3150
+ return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs14(
3025
3151
  RenderErrorBoundary,
3026
3152
  {
3027
3153
  label: "\u52A9\u624B\u6D88\u606F",
3028
3154
  details: block.key,
3029
3155
  resetKey: getMessageResetSignature(block.messages),
3030
3156
  children: [
3031
- /* @__PURE__ */ jsx15(
3157
+ /* @__PURE__ */ jsx16(
3032
3158
  AssistantTurnBlock,
3033
3159
  {
3034
3160
  messages: block.messages,
@@ -3040,8 +3166,8 @@ function MessageList({
3040
3166
  sessionId
3041
3167
  }
3042
3168
  ),
3043
- blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx15(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3044
- hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx15(
3169
+ blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx16(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3170
+ hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx16(
3045
3171
  PostChatFollowupBlock,
3046
3172
  {
3047
3173
  followup: postChatFollowup,
@@ -3057,25 +3183,28 @@ function MessageList({
3057
3183
  }
3058
3184
  ) }, block.key);
3059
3185
  }
3186
+ if (block.type === "context") {
3187
+ return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.message.entry_id, children: /* @__PURE__ */ jsx16(ContextCard, { context: block.message.context }) }, block.key);
3188
+ }
3060
3189
  if (block.type === "compaction") {
3061
- return /* @__PURE__ */ jsxs13(
3190
+ return /* @__PURE__ */ jsxs14(
3062
3191
  "div",
3063
3192
  {
3064
3193
  className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
3065
3194
  children: [
3066
- /* @__PURE__ */ jsx15(Layers, { size: 12 }),
3067
- /* @__PURE__ */ jsx15("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3195
+ /* @__PURE__ */ jsx16(Layers, { size: 12 }),
3196
+ /* @__PURE__ */ jsx16("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3068
3197
  ]
3069
3198
  },
3070
3199
  block.key
3071
3200
  );
3072
3201
  }
3073
- return /* @__PURE__ */ jsx15(PlanningDivider, { kind: block.kind }, block.key);
3202
+ return /* @__PURE__ */ jsx16(PlanningDivider, { kind: block.kind }, block.key);
3074
3203
  }),
3075
- 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
3204
+ 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
3076
3205
  ] }) }) }),
3077
- /* @__PURE__ */ jsx15(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
3078
- /* @__PURE__ */ jsx15(ScrollToBottomButton, {})
3206
+ /* @__PURE__ */ jsx16(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
3207
+ /* @__PURE__ */ jsx16(ScrollToBottomButton, {})
3079
3208
  ] }) });
3080
3209
  }
3081
3210
  function AutoScrollOnUserSend({ userMessageCount }) {
@@ -3124,7 +3253,7 @@ function ScrollToBottomButton() {
3124
3253
  scrollToBottom();
3125
3254
  }, [scrollToBottom]);
3126
3255
  if (!visible) return null;
3127
- return /* @__PURE__ */ jsxs13(
3256
+ return /* @__PURE__ */ jsxs14(
3128
3257
  "button",
3129
3258
  {
3130
3259
  type: "button",
@@ -3132,25 +3261,25 @@ function ScrollToBottomButton() {
3132
3261
  "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
3133
3262
  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))]",
3134
3263
  children: [
3135
- /* @__PURE__ */ jsx15(ChevronDown, { size: 14 }),
3136
- /* @__PURE__ */ jsx15("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
3264
+ /* @__PURE__ */ jsx16(ChevronDown, { size: 14 }),
3265
+ /* @__PURE__ */ jsx16("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
3137
3266
  ]
3138
3267
  }
3139
3268
  );
3140
3269
  }
3141
3270
  function PlanningDivider({ kind }) {
3142
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 py-1", children: [
3143
- /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
3144
- /* @__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: [
3145
- /* @__PURE__ */ jsx15(Lightbulb, { size: 12 }),
3146
- /* @__PURE__ */ jsx15("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
3271
+ return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-3 py-1", children: [
3272
+ /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
3273
+ /* @__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: [
3274
+ /* @__PURE__ */ jsx16(Lightbulb, { size: 12 }),
3275
+ /* @__PURE__ */ jsx16("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
3147
3276
  ] }),
3148
- /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
3277
+ /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
3149
3278
  ] });
3150
3279
  }
3151
3280
 
3152
3281
  // src/components/ChatSurface.tsx
3153
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3282
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3154
3283
  function themeAttr(theme) {
3155
3284
  return theme === "dark" ? "dark" : void 0;
3156
3285
  }
@@ -3182,7 +3311,7 @@ function ChatSurface({
3182
3311
  beforeInput,
3183
3312
  banner
3184
3313
  }) {
3185
- return /* @__PURE__ */ jsxs14(
3314
+ return /* @__PURE__ */ jsxs15(
3186
3315
  "div",
3187
3316
  {
3188
3317
  "data-theme": themeAttr(theme),
@@ -3191,14 +3320,14 @@ function ChatSurface({
3191
3320
  classNames?.root
3192
3321
  ),
3193
3322
  children: [
3194
- /* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
3323
+ /* @__PURE__ */ jsx17(ConnectionBanner, { connection, className: classNames?.banner }),
3195
3324
  banner,
3196
- errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
3197
- /* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
3198
- /* @__PURE__ */ jsx16("span", { children: errorMessage })
3325
+ errorMessage && /* @__PURE__ */ jsxs15("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
3326
+ /* @__PURE__ */ jsx17(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
3327
+ /* @__PURE__ */ jsx17("span", { children: errorMessage })
3199
3328
  ] }),
3200
3329
  slots?.header,
3201
- /* @__PURE__ */ jsx16(
3330
+ /* @__PURE__ */ jsx17(
3202
3331
  MessageList,
3203
3332
  {
3204
3333
  messages,
@@ -3219,7 +3348,7 @@ function ChatSurface({
3219
3348
  }
3220
3349
  ),
3221
3350
  beforeInput,
3222
- /* @__PURE__ */ jsx16(
3351
+ /* @__PURE__ */ jsx17(
3223
3352
  ChatInput,
3224
3353
  {
3225
3354
  value: inputText,
@@ -3239,7 +3368,7 @@ function ChatSurface({
3239
3368
  }
3240
3369
 
3241
3370
  // src/components/AgentChat.tsx
3242
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3371
+ import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3243
3372
  function isUnauthorizedError(error) {
3244
3373
  return error instanceof BladeApiError && error.status === 401;
3245
3374
  }
@@ -3258,11 +3387,11 @@ function LoginCard({ client, onLoggedIn }) {
3258
3387
  setLoggingIn(false);
3259
3388
  }
3260
3389
  };
3261
- 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: [
3262
- /* @__PURE__ */ jsx17(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
3263
- /* @__PURE__ */ jsx17("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
3264
- /* @__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" }),
3265
- /* @__PURE__ */ jsx17(
3390
+ 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: [
3391
+ /* @__PURE__ */ jsx18(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
3392
+ /* @__PURE__ */ jsx18("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
3393
+ /* @__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" }),
3394
+ /* @__PURE__ */ jsx18(
3266
3395
  "button",
3267
3396
  {
3268
3397
  type: "button",
@@ -3272,7 +3401,7 @@ function LoginCard({ client, onLoggedIn }) {
3272
3401
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
3273
3402
  }
3274
3403
  ),
3275
- loginError && /* @__PURE__ */ jsx17("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
3404
+ loginError && /* @__PURE__ */ jsx18("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
3276
3405
  ] }) });
3277
3406
  }
3278
3407
  function AgentChat(props) {
@@ -3280,12 +3409,12 @@ function AgentChat(props) {
3280
3409
  const [attempt, setAttempt] = useState13(0);
3281
3410
  const [needLogin, setNeedLogin] = useState13(() => !client.hasToken());
3282
3411
  if (needLogin) {
3283
- return /* @__PURE__ */ jsx17(
3412
+ return /* @__PURE__ */ jsx18(
3284
3413
  "div",
3285
3414
  {
3286
3415
  "data-theme": themeAttr(props.theme),
3287
3416
  className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
3288
- children: /* @__PURE__ */ jsx17(
3417
+ children: /* @__PURE__ */ jsx18(
3289
3418
  LoginCard,
3290
3419
  {
3291
3420
  client,
@@ -3298,7 +3427,7 @@ function AgentChat(props) {
3298
3427
  }
3299
3428
  );
3300
3429
  }
3301
- return /* @__PURE__ */ jsx17(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
3430
+ return /* @__PURE__ */ jsx18(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
3302
3431
  }
3303
3432
  function ChatSessionView({
3304
3433
  sessionId,
@@ -3407,7 +3536,7 @@ ${content}`);
3407
3536
  setStopRequested(true);
3408
3537
  void session?.stop();
3409
3538
  };
3410
- return /* @__PURE__ */ jsx17(
3539
+ return /* @__PURE__ */ jsx18(
3411
3540
  ChatSurface,
3412
3541
  {
3413
3542
  theme,
@@ -3417,8 +3546,8 @@ ${content}`);
3417
3546
  slots,
3418
3547
  placeholder,
3419
3548
  connection: state?.connection ?? "connecting",
3420
- banner: /* @__PURE__ */ jsxs15(Fragment3, { children: [
3421
- /* @__PURE__ */ jsx17(
3549
+ banner: /* @__PURE__ */ jsxs16(Fragment3, { children: [
3550
+ /* @__PURE__ */ jsx18(
3422
3551
  ReplayBar,
3423
3552
  {
3424
3553
  isReplay: replay.isReplay,
@@ -3428,7 +3557,7 @@ ${content}`);
3428
3557
  onExit: () => void replay.exitToAutonomous()
3429
3558
  }
3430
3559
  ),
3431
- /* @__PURE__ */ jsx17(ReplayMismatchPrompt, { mismatch: replay.mismatch })
3560
+ /* @__PURE__ */ jsx18(ReplayMismatchPrompt, { mismatch: replay.mismatch })
3432
3561
  ] }),
3433
3562
  errorMessage,
3434
3563
  messages: state?.messages ?? [],
@@ -3461,7 +3590,7 @@ import { useEffect as useEffect10, useMemo as useMemo9, useState as useState15 }
3461
3590
 
3462
3591
  // src/components/LlmAdvancedSettings.tsx
3463
3592
  import { useState as useState14 } from "react";
3464
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3593
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3465
3594
  var FIELDS = [
3466
3595
  { id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
3467
3596
  { id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
@@ -3512,8 +3641,8 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3512
3641
  if (!normalized) return null;
3513
3642
  const fields = FIELDS.filter((field) => normalized[field.id]);
3514
3643
  const dirty = Object.keys(override).length > 0;
3515
- return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
3516
- /* @__PURE__ */ jsxs16(
3644
+ return /* @__PURE__ */ jsxs17("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
3645
+ /* @__PURE__ */ jsxs17(
3517
3646
  "button",
3518
3647
  {
3519
3648
  type: "button",
@@ -3523,16 +3652,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3523
3652
  },
3524
3653
  className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
3525
3654
  children: [
3526
- /* @__PURE__ */ jsx18(Settings2, { size: 13 }),
3655
+ /* @__PURE__ */ jsx19(Settings2, { size: 13 }),
3527
3656
  "\u9AD8\u7EA7\u8BBE\u7F6E",
3528
- dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
3657
+ dirty && /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
3529
3658
  ]
3530
3659
  }
3531
3660
  ),
3532
- open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
3533
- fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
3534
- /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
3535
- /* @__PURE__ */ jsx18(
3661
+ open && /* @__PURE__ */ jsxs17("div", { className: "mt-2 flex flex-col gap-2", children: [
3662
+ fields.map((field) => /* @__PURE__ */ jsxs17("label", { className: "flex flex-col gap-1", children: [
3663
+ /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
3664
+ /* @__PURE__ */ jsx19(
3536
3665
  "input",
3537
3666
  {
3538
3667
  type: field.secret ? "password" : "text",
@@ -3543,9 +3672,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3543
3672
  }
3544
3673
  )
3545
3674
  ] }, field.id)),
3546
- 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" }),
3547
- /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
3548
- /* @__PURE__ */ jsx18(
3675
+ 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" }),
3676
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
3677
+ /* @__PURE__ */ jsx19(
3549
3678
  "button",
3550
3679
  {
3551
3680
  type: "button",
@@ -3560,7 +3689,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3560
3689
  children: "\u4FDD\u5B58"
3561
3690
  }
3562
3691
  ),
3563
- /* @__PURE__ */ jsx18(
3692
+ /* @__PURE__ */ jsx19(
3564
3693
  "button",
3565
3694
  {
3566
3695
  type: "button",
@@ -3579,7 +3708,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
3579
3708
  }
3580
3709
 
3581
3710
  // src/components/LlmChat.tsx
3582
- import { jsx as jsx19 } from "react/jsx-runtime";
3711
+ import { jsx as jsx20 } from "react/jsx-runtime";
3583
3712
  function LlmChat({
3584
3713
  classNames,
3585
3714
  renderers,
@@ -3608,7 +3737,7 @@ ${text}` : text),
3608
3737
  useEffect10(() => {
3609
3738
  onReady?.(handle);
3610
3739
  }, [handle, onReady]);
3611
- return /* @__PURE__ */ jsx19(
3740
+ return /* @__PURE__ */ jsx20(
3612
3741
  ChatSurface,
3613
3742
  {
3614
3743
  theme,
@@ -3633,7 +3762,7 @@ ${text}` : text),
3633
3762
  setStopRequested(true);
3634
3763
  stop();
3635
3764
  },
3636
- beforeInput: advanced ? /* @__PURE__ */ jsx19(
3765
+ beforeInput: advanced ? /* @__PURE__ */ jsx20(
3637
3766
  LlmAdvancedSettingsBar,
3638
3767
  {
3639
3768
  settings: advanced,
@@ -3651,14 +3780,14 @@ ${text}` : text),
3651
3780
  }
3652
3781
 
3653
3782
  // src/components/ChatView.tsx
3654
- import { jsx as jsx20 } from "react/jsx-runtime";
3783
+ import { jsx as jsx21 } from "react/jsx-runtime";
3655
3784
  function ChatView(props) {
3656
3785
  const { mode, llm, onLlmReady, ...rest } = props;
3657
3786
  if (mode === "llm") {
3658
3787
  if (!llm) {
3659
3788
  throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
3660
3789
  }
3661
- return /* @__PURE__ */ jsx20(
3790
+ return /* @__PURE__ */ jsx21(
3662
3791
  LlmChat,
3663
3792
  {
3664
3793
  ...llm,
@@ -3671,7 +3800,7 @@ function ChatView(props) {
3671
3800
  }
3672
3801
  );
3673
3802
  }
3674
- return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
3803
+ return /* @__PURE__ */ jsx21(AgentChat, { ...rest });
3675
3804
  }
3676
3805
 
3677
3806
  // src/index.ts
@@ -3680,6 +3809,7 @@ export {
3680
3809
  AgentChat,
3681
3810
  BladeProvider,
3682
3811
  ChatView,
3812
+ ContextCard,
3683
3813
  LlmChat,
3684
3814
  MarkdownContent,
3685
3815
  ReplayBar,