@blade-hq/agent-react 2610.0.0-beta.30 → 2610.0.0-beta.31

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
@@ -1023,6 +1023,14 @@ var Play = createLucideIcon("Play", [
1023
1023
  ["polygon", { points: "6 3 20 12 6 21 6 3", key: "1oa8hb" }]
1024
1024
  ]);
1025
1025
 
1026
+ // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/refresh-ccw.js
1027
+ var RefreshCcw = createLucideIcon("RefreshCcw", [
1028
+ ["path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "14sxne" }],
1029
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
1030
+ ["path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16", key: "1hlbsb" }],
1031
+ ["path", { d: "M16 16h5v5", key: "ccwih5" }]
1032
+ ]);
1033
+
1026
1034
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/search.js
1027
1035
  var Search = createLucideIcon("Search", [
1028
1036
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
@@ -2028,6 +2036,18 @@ import {
2028
2036
  } from "react";
2029
2037
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2030
2038
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
2039
+ function normalizeAdjacentUrlFormatting(value) {
2040
+ const protectedSegments = [];
2041
+ const protectedValue = value.replace(/(`{1,3}[\s\S]*?`{1,3}|\[[^\]]*\]\([^)]*\))/g, (segment) => {
2042
+ const index = protectedSegments.push(segment) - 1;
2043
+ return `blade-url-protected-${index}-marker`;
2044
+ });
2045
+ const normalized = protectedValue.replace(
2046
+ /(\*\*|__|~~|\*|_)(https?:\/\/[^\s<>]+?)\1(?=[\s。,、!?;:,.!?;:]|$)/g,
2047
+ (_, marker, url) => `${marker}[${url}](<${url}>)${marker}`
2048
+ );
2049
+ return normalized.replace(/blade-url-protected-(\d+)-marker/g, (_, index) => protectedSegments[Number(index)]);
2050
+ }
2031
2051
  function CodeBlockPre({ children, node: _node, ...props }) {
2032
2052
  const preRef = useRef7(null);
2033
2053
  const [copied, setCopied] = useState7(false);
@@ -2082,7 +2102,7 @@ var MARKDOWN_COMPONENTS = {
2082
2102
  };
2083
2103
  function MarkdownContent({ children, className, mode, sessionId }) {
2084
2104
  const resolvedChildren = useMemo5(() => {
2085
- return children.replace(SYSTEM_REMINDER_RE, "");
2105
+ return normalizeAdjacentUrlFormatting(children.replace(SYSTEM_REMINDER_RE, ""));
2086
2106
  }, [children]);
2087
2107
  return /* @__PURE__ */ jsx7(
2088
2108
  _r,
@@ -3652,7 +3672,85 @@ import {
3652
3672
  getImageParts as getImageParts2,
3653
3673
  getTextContent as getTextContent2
3654
3674
  } from "@blade-hq/agent-client";
3675
+
3676
+ // src/lib/whatif-prompt.ts
3677
+ var HEADER_RE = /^以下消息和 step 产物标记为 deprecated_by_rerun,请基于最新用户假设从 step(\d+) 开始完整重新推演,不要复用旧结论。$/;
3678
+ var QUOTE_HEADER_RE = /^\[步骤(\d+)\s*·\s*(.+?)\]$/;
3679
+ var USER_INPUT_TAG = "[\u7528\u6237\u8F93\u5165]";
3680
+ function parseWhatIfPrompt(text) {
3681
+ const lines = text.replace(/\r\n/g, "\n").trimEnd().split("\n");
3682
+ const headerMatch = lines[0]?.match(HEADER_RE);
3683
+ if (!headerMatch) return null;
3684
+ const userTagIdx = lines.indexOf(USER_INPUT_TAG);
3685
+ const hasUserTag = userTagIdx >= 0;
3686
+ const quoteBlockEndExclusive = hasUserTag ? userTagIdx : lines.length;
3687
+ const quoteHeaderIdxs = [];
3688
+ let quoteBlockFound = false;
3689
+ for (let i = 1; i < quoteBlockEndExclusive; i++) {
3690
+ if (!quoteBlockFound && lines[i].trim() === "[\u5F15\u7528]") {
3691
+ quoteBlockFound = true;
3692
+ } else if (quoteBlockFound && QUOTE_HEADER_RE.test(lines[i])) {
3693
+ quoteHeaderIdxs.push(i);
3694
+ }
3695
+ }
3696
+ let legacyUserTextStart = -1;
3697
+ if (!hasUserTag && quoteHeaderIdxs.length > 0) {
3698
+ const lastSnapshotStart = quoteHeaderIdxs.at(-1) + 1;
3699
+ let i = lines.length - 1;
3700
+ while (i >= lastSnapshotStart && lines[i].trim() === "") i -= 1;
3701
+ while (i >= lastSnapshotStart && lines[i].trim() !== "") i -= 1;
3702
+ if (i >= lastSnapshotStart) legacyUserTextStart = i + 1;
3703
+ }
3704
+ const quotes = quoteHeaderIdxs.map((headerIdx, index) => {
3705
+ const match = lines[headerIdx].match(QUOTE_HEADER_RE);
3706
+ const nextHeader = quoteHeaderIdxs[index + 1];
3707
+ const end = nextHeader ?? (legacyUserTextStart >= 0 ? legacyUserTextStart : quoteBlockEndExclusive);
3708
+ const snapshotLines = lines.slice(headerIdx + 1, end);
3709
+ while (snapshotLines.at(-1)?.trim() === "") snapshotLines.pop();
3710
+ return {
3711
+ stepNumber: Number.parseInt(match[1], 10),
3712
+ label: match[2].trim(),
3713
+ snapshot: snapshotLines.join("\n")
3714
+ };
3715
+ });
3716
+ const userTextStart = hasUserTag ? userTagIdx + 1 : legacyUserTextStart;
3717
+ const userLines = userTextStart >= 0 ? lines.slice(userTextStart) : [];
3718
+ while (userLines[0]?.trim() === "") userLines.shift();
3719
+ while (userLines.at(-1)?.trim() === "") userLines.pop();
3720
+ const fromStep = Number.parseInt(headerMatch[1], 10);
3721
+ return {
3722
+ fromStep: Number.isFinite(fromStep) ? fromStep : null,
3723
+ quotes,
3724
+ userText: userLines.join("\n")
3725
+ };
3726
+ }
3727
+
3728
+ // src/components/WhatIfUserBubble.tsx
3655
3729
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3730
+ function WhatIfUserBubble({ parsed, onQuoteClick }) {
3731
+ const { fromStep, quotes, userText } = parsed;
3732
+ return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-end gap-2", children: [
3733
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.5)] px-2.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]", children: [
3734
+ /* @__PURE__ */ jsx14(RefreshCcw, { size: 10 }),
3735
+ /* @__PURE__ */ jsx14("span", { children: fromStep != null ? `\u91CD\u8DD1\u81EA step ${fromStep}` : "\u91CD\u8DD1" })
3736
+ ] }),
3737
+ quotes.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex max-w-[min(72vw,42rem)] flex-col items-stretch gap-2", children: quotes.map((quote, index) => {
3738
+ const clickable = quote.stepNumber != null && !!onQuoteClick;
3739
+ const label = quote.stepNumber != null ? `\u6B65\u9AA4${quote.stepNumber} \xB7 ${quote.label}` : quote.label;
3740
+ return /* @__PURE__ */ jsxs12("div", { className: "rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.8)] px-3 py-2 text-left", children: [
3741
+ /* @__PURE__ */ jsxs12("button", { type: "button", disabled: !clickable, onClick: () => clickable && onQuoteClick(quote.stepNumber), className: "inline-flex max-w-full items-center gap-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] disabled:cursor-default", title: clickable ? "\u8DF3\u8F6C\u5230\u5BF9\u5E94\u6B65\u9AA4\u5361\u7247" : void 0, children: [
3742
+ /* @__PURE__ */ jsx14("span", { children: "\u21B3" }),
3743
+ /* @__PURE__ */ jsx14("span", { className: "truncate", children: label })
3744
+ ] }),
3745
+ quote.snapshot ? /* @__PURE__ */ jsx14("div", { className: "mt-1 border-l-2 border-[hsl(var(--accent-foreground)/0.35)] pl-2 text-xs leading-relaxed text-[hsl(var(--foreground)/0.8)]", children: /* @__PURE__ */ jsx14(MarkdownContent, { className: "blade-chat-prose", children: quote.snapshot }) }) : null
3746
+ ] }, `${quote.stepNumber ?? "x"}-${index}`);
3747
+ }) }),
3748
+ userText && /* @__PURE__ */ jsx14("div", { className: "rounded-2xl border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-sm leading-relaxed text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx14(MarkdownContent, { className: "blade-chat-prose", children: userText }) })
3749
+ ] });
3750
+ }
3751
+
3752
+ // src/components/UserMessageBubble.tsx
3753
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3656
3754
  function isUserMessage(message) {
3657
3755
  return message.role === "user";
3658
3756
  }
@@ -3664,8 +3762,12 @@ function UserMessageBubble({ message, className }) {
3664
3762
  const text = getTextContent2(message.content).trim();
3665
3763
  const fileParts = getFileParts2(message.content);
3666
3764
  const imageParts = getImageParts2(message.content);
3667
- 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: [
3668
- imageParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx14(
3765
+ const whatifParsed = text && imageParts.length === 0 && fileParts.length === 0 ? parseWhatIfPrompt(text) : null;
3766
+ if (whatifParsed) {
3767
+ return /* @__PURE__ */ jsx15("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsx15("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: /* @__PURE__ */ jsx15(WhatIfUserBubble, { parsed: whatifParsed }) }) });
3768
+ }
3769
+ 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: [
3770
+ imageParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx15(
3669
3771
  "img",
3670
3772
  {
3671
3773
  src: part.image_url.url,
@@ -3674,21 +3776,21 @@ function UserMessageBubble({ message, className }) {
3674
3776
  },
3675
3777
  part.image_url.url
3676
3778
  )) }),
3677
- fileParts.length > 0 && /* @__PURE__ */ jsx14("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs12(
3779
+ fileParts.length > 0 && /* @__PURE__ */ jsx15("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs13(
3678
3780
  "div",
3679
3781
  {
3680
3782
  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))]",
3681
3783
  children: [
3682
- /* @__PURE__ */ jsx14(FileText, { size: 12, className: "shrink-0" }),
3683
- /* @__PURE__ */ jsx14("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
3784
+ /* @__PURE__ */ jsx15(FileText, { size: 12, className: "shrink-0" }),
3785
+ /* @__PURE__ */ jsx15("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
3684
3786
  ]
3685
3787
  },
3686
3788
  `${part.name}-${part.data.length}`
3687
3789
  )) }),
3688
- 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 }) }),
3689
- 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: [
3690
- /* @__PURE__ */ jsx14(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
3691
- /* @__PURE__ */ jsx14("span", { children: "\u53D1\u9001\u4E2D" })
3790
+ 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 }) }),
3791
+ 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: [
3792
+ /* @__PURE__ */ jsx15(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
3793
+ /* @__PURE__ */ jsx15("span", { children: "\u53D1\u9001\u4E2D" })
3692
3794
  ] })
3693
3795
  ] }) });
3694
3796
  }
@@ -3697,11 +3799,11 @@ function ErrorMessageBlock({
3697
3799
  className
3698
3800
  }) {
3699
3801
  const text = chatErrorForDisplay(getTextContent2(message.content));
3700
- return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-error-row flex min-w-0 justify-start", className), children: /* @__PURE__ */ jsx14("div", { className: "blade-chat-error-block min-w-0 max-w-full whitespace-pre-wrap break-words border-l-[3px] border-[hsl(var(--border))] px-3 py-1 text-left text-sm leading-7 text-[hsl(var(--muted-foreground))] [overflow-wrap:anywhere]", children: text }) });
3802
+ return /* @__PURE__ */ jsx15("div", { className: cn("blade-chat-error-row flex min-w-0 justify-start", className), children: /* @__PURE__ */ jsx15("div", { className: "blade-chat-error-block min-w-0 max-w-full whitespace-pre-wrap break-words border-l-[3px] border-[hsl(var(--border))] px-3 py-1 text-left text-sm leading-7 text-[hsl(var(--muted-foreground))] [overflow-wrap:anywhere]", children: text }) });
3701
3803
  }
3702
3804
 
3703
3805
  // src/components/MessageList.tsx
3704
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3806
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3705
3807
  function parseModeChange(message) {
3706
3808
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
3707
3809
  return null;
@@ -3827,23 +3929,23 @@ function MessageList({
3827
3929
  }
3828
3930
  return blocks;
3829
3931
  }, [messages, isStreaming]);
3830
- return /* @__PURE__ */ jsxs13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: [
3831
- isStreaming ? /* @__PURE__ */ jsx15("output", { className: "sr-only", children: "\u6B63\u5728\u751F\u6210\u56DE\u590D" }) : null,
3832
- /* @__PURE__ */ jsxs13(
3932
+ return /* @__PURE__ */ jsxs14("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: [
3933
+ isStreaming ? /* @__PURE__ */ jsx16("output", { className: "sr-only", children: "\u6B63\u5728\u751F\u6210\u56DE\u590D" }) : null,
3934
+ /* @__PURE__ */ jsxs14(
3833
3935
  StickToBottom,
3834
3936
  {
3835
3937
  className: "h-full overflow-y-hidden",
3836
3938
  initial: "instant",
3837
3939
  resize: "instant",
3838
3940
  children: [
3839
- /* @__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: [
3840
- renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs13("div", { className: "blade-chat-empty", children: [
3841
- /* @__PURE__ */ jsx15(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3842
- /* @__PURE__ */ jsx15("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3843
- /* @__PURE__ */ jsx15("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3941
+ /* @__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: [
3942
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs14("div", { className: "blade-chat-empty", children: [
3943
+ /* @__PURE__ */ jsx16(MessageSquare, { size: 40, strokeWidth: 1.5 }),
3944
+ /* @__PURE__ */ jsx16("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
3945
+ /* @__PURE__ */ jsx16("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
3844
3946
  ] }) : renderBlocks.map((block) => {
3845
3947
  if (block.type === "message") {
3846
- 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);
3948
+ 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
3949
  }
3848
3950
  if (block.type === "assistant_turn") {
3849
3951
  const blockFeedback = block.messages.map(
@@ -3854,14 +3956,14 @@ function MessageList({
3854
3956
  (message) => message.entry_id === postChatFollowup.assistant_entry_id
3855
3957
  )
3856
3958
  );
3857
- return /* @__PURE__ */ jsx15("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs13(
3959
+ return /* @__PURE__ */ jsx16("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsxs14(
3858
3960
  RenderErrorBoundary,
3859
3961
  {
3860
3962
  label: "\u52A9\u624B\u6D88\u606F",
3861
3963
  details: block.key,
3862
3964
  resetKey: getMessageResetSignature(block.messages),
3863
3965
  children: [
3864
- /* @__PURE__ */ jsx15(
3966
+ /* @__PURE__ */ jsx16(
3865
3967
  AssistantTurnBlock,
3866
3968
  {
3867
3969
  messages: block.messages,
@@ -3873,8 +3975,8 @@ function MessageList({
3873
3975
  sessionId
3874
3976
  }
3875
3977
  ),
3876
- blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx15(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3877
- hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx15(
3978
+ blockFeedback && !hasActiveFollowup ? /* @__PURE__ */ jsx16(HistoricalResultFeedback, { feedback: blockFeedback }) : null,
3979
+ hasActiveFollowup && postChatFollowup ? /* @__PURE__ */ jsx16(
3878
3980
  PostChatFollowupBlock,
3879
3981
  {
3880
3982
  followup: postChatFollowup,
@@ -3891,23 +3993,23 @@ function MessageList({
3891
3993
  ) }, block.key);
3892
3994
  }
3893
3995
  if (block.type === "compaction") {
3894
- return /* @__PURE__ */ jsxs13(
3996
+ return /* @__PURE__ */ jsxs14(
3895
3997
  "div",
3896
3998
  {
3897
3999
  className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
3898
4000
  children: [
3899
- /* @__PURE__ */ jsx15(Layers, { size: 12 }),
3900
- /* @__PURE__ */ jsx15("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
4001
+ /* @__PURE__ */ jsx16(Layers, { size: 12 }),
4002
+ /* @__PURE__ */ jsx16("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
3901
4003
  ]
3902
4004
  },
3903
4005
  block.key
3904
4006
  );
3905
4007
  }
3906
- return /* @__PURE__ */ jsx15(PlanningDivider, { kind: block.kind }, block.key);
4008
+ return /* @__PURE__ */ jsx16(PlanningDivider, { kind: block.kind }, block.key);
3907
4009
  }),
3908
- 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
4010
+ 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
3909
4011
  ] }) }) }),
3910
- /* @__PURE__ */ jsx15(
4012
+ /* @__PURE__ */ jsx16(
3911
4013
  PinLatestUserMessage,
3912
4014
  {
3913
4015
  userMessageCount: userMessages.length,
@@ -3916,7 +4018,7 @@ function MessageList({
3916
4018
  },
3917
4019
  sessionId ?? "no-session"
3918
4020
  ),
3919
- /* @__PURE__ */ jsx15(ScrollToBottomButton, {})
4021
+ /* @__PURE__ */ jsx16(ScrollToBottomButton, {})
3920
4022
  ]
3921
4023
  },
3922
4024
  sessionId ?? "no-session"
@@ -4002,7 +4104,7 @@ function ScrollToBottomButton() {
4002
4104
  scrollToBottom();
4003
4105
  }, [scrollToBottom]);
4004
4106
  if (!visible) return null;
4005
- return /* @__PURE__ */ jsxs13(
4107
+ return /* @__PURE__ */ jsxs14(
4006
4108
  "button",
4007
4109
  {
4008
4110
  type: "button",
@@ -4010,25 +4112,25 @@ function ScrollToBottomButton() {
4010
4112
  "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
4011
4113
  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))]",
4012
4114
  children: [
4013
- /* @__PURE__ */ jsx15(ChevronDown, { size: 14 }),
4014
- /* @__PURE__ */ jsx15("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
4115
+ /* @__PURE__ */ jsx16(ChevronDown, { size: 14 }),
4116
+ /* @__PURE__ */ jsx16("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
4015
4117
  ]
4016
4118
  }
4017
4119
  );
4018
4120
  }
4019
4121
  function PlanningDivider({ kind }) {
4020
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 py-1", children: [
4021
- /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
4022
- /* @__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: [
4023
- /* @__PURE__ */ jsx15(Lightbulb, { size: 12 }),
4024
- /* @__PURE__ */ jsx15("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
4122
+ return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-3 py-1", children: [
4123
+ /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
4124
+ /* @__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: [
4125
+ /* @__PURE__ */ jsx16(Lightbulb, { size: 12 }),
4126
+ /* @__PURE__ */ jsx16("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
4025
4127
  ] }),
4026
- /* @__PURE__ */ jsx15("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
4128
+ /* @__PURE__ */ jsx16("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
4027
4129
  ] });
4028
4130
  }
4029
4131
 
4030
4132
  // src/components/ChatSurface.tsx
4031
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4133
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4032
4134
  function themeAttr(theme) {
4033
4135
  return theme === "dark" ? "dark" : void 0;
4034
4136
  }
@@ -4060,7 +4162,7 @@ function ChatSurface({
4060
4162
  beforeInput,
4061
4163
  banner
4062
4164
  }) {
4063
- return /* @__PURE__ */ jsxs14(
4165
+ return /* @__PURE__ */ jsxs15(
4064
4166
  "div",
4065
4167
  {
4066
4168
  "data-theme": themeAttr(theme),
@@ -4069,14 +4171,14 @@ function ChatSurface({
4069
4171
  classNames?.root
4070
4172
  ),
4071
4173
  children: [
4072
- /* @__PURE__ */ jsx16(ConnectionBanner, { connection, className: classNames?.banner }),
4174
+ /* @__PURE__ */ jsx17(ConnectionBanner, { connection, className: classNames?.banner }),
4073
4175
  banner,
4074
- errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
4075
- /* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
4076
- /* @__PURE__ */ jsx16("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: chatErrorForDisplay2(errorMessage) })
4176
+ errorMessage && /* @__PURE__ */ jsxs15("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
4177
+ /* @__PURE__ */ jsx17(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
4178
+ /* @__PURE__ */ jsx17("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: chatErrorForDisplay2(errorMessage) })
4077
4179
  ] }),
4078
4180
  slots?.header,
4079
- /* @__PURE__ */ jsx16(
4181
+ /* @__PURE__ */ jsx17(
4080
4182
  MessageList,
4081
4183
  {
4082
4184
  messages,
@@ -4097,7 +4199,7 @@ function ChatSurface({
4097
4199
  }
4098
4200
  ),
4099
4201
  beforeInput,
4100
- /* @__PURE__ */ jsx16(
4202
+ /* @__PURE__ */ jsx17(
4101
4203
  ChatInput,
4102
4204
  {
4103
4205
  value: inputText,
@@ -4117,7 +4219,7 @@ function ChatSurface({
4117
4219
  }
4118
4220
 
4119
4221
  // src/components/AgentChat.tsx
4120
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
4222
+ import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4121
4223
  function isUnauthorizedError(error) {
4122
4224
  return error instanceof BladeApiError && error.status === 401;
4123
4225
  }
@@ -4136,11 +4238,11 @@ function LoginCard({ client, onLoggedIn }) {
4136
4238
  setLoggingIn(false);
4137
4239
  }
4138
4240
  };
4139
- 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: [
4140
- /* @__PURE__ */ jsx17(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
4141
- /* @__PURE__ */ jsx17("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
4142
- /* @__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" }),
4143
- /* @__PURE__ */ jsx17(
4241
+ 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: [
4242
+ /* @__PURE__ */ jsx18(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
4243
+ /* @__PURE__ */ jsx18("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
4244
+ /* @__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" }),
4245
+ /* @__PURE__ */ jsx18(
4144
4246
  "button",
4145
4247
  {
4146
4248
  type: "button",
@@ -4150,7 +4252,7 @@ function LoginCard({ client, onLoggedIn }) {
4150
4252
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
4151
4253
  }
4152
4254
  ),
4153
- loginError && /* @__PURE__ */ jsx17("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4255
+ loginError && /* @__PURE__ */ jsx18("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
4154
4256
  ] }) });
4155
4257
  }
4156
4258
  function AgentChat(props) {
@@ -4158,12 +4260,12 @@ function AgentChat(props) {
4158
4260
  const [attempt, setAttempt] = useState13(0);
4159
4261
  const [needLogin, setNeedLogin] = useState13(() => !client.hasToken());
4160
4262
  if (needLogin) {
4161
- return /* @__PURE__ */ jsx17(
4263
+ return /* @__PURE__ */ jsx18(
4162
4264
  "div",
4163
4265
  {
4164
4266
  "data-theme": themeAttr(props.theme),
4165
4267
  className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
4166
- children: /* @__PURE__ */ jsx17(
4268
+ children: /* @__PURE__ */ jsx18(
4167
4269
  LoginCard,
4168
4270
  {
4169
4271
  client,
@@ -4176,7 +4278,7 @@ function AgentChat(props) {
4176
4278
  }
4177
4279
  );
4178
4280
  }
4179
- return /* @__PURE__ */ jsx17(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4281
+ return /* @__PURE__ */ jsx18(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
4180
4282
  }
4181
4283
  function ChatSessionView({
4182
4284
  sessionId,
@@ -4285,7 +4387,7 @@ ${content}`);
4285
4387
  setStopRequested(true);
4286
4388
  void session?.stop();
4287
4389
  };
4288
- return /* @__PURE__ */ jsx17(
4390
+ return /* @__PURE__ */ jsx18(
4289
4391
  ChatSurface,
4290
4392
  {
4291
4393
  theme,
@@ -4295,8 +4397,8 @@ ${content}`);
4295
4397
  slots,
4296
4398
  placeholder,
4297
4399
  connection: state?.connection ?? "connecting",
4298
- banner: /* @__PURE__ */ jsxs15(Fragment3, { children: [
4299
- /* @__PURE__ */ jsx17(
4400
+ banner: /* @__PURE__ */ jsxs16(Fragment3, { children: [
4401
+ /* @__PURE__ */ jsx18(
4300
4402
  ReplayBar,
4301
4403
  {
4302
4404
  isReplay: replay.isReplay,
@@ -4306,7 +4408,7 @@ ${content}`);
4306
4408
  onExit: () => void replay.exitToAutonomous()
4307
4409
  }
4308
4410
  ),
4309
- /* @__PURE__ */ jsx17(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4411
+ /* @__PURE__ */ jsx18(ReplayMismatchPrompt, { mismatch: replay.mismatch })
4310
4412
  ] }),
4311
4413
  errorMessage,
4312
4414
  messages: state?.messages ?? [],
@@ -4339,7 +4441,7 @@ import { useEffect as useEffect12, useMemo as useMemo9, useState as useState15 }
4339
4441
 
4340
4442
  // src/components/LlmAdvancedSettings.tsx
4341
4443
  import { useState as useState14 } from "react";
4342
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
4444
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
4343
4445
  var FIELDS = [
4344
4446
  { id: "baseURL", label: "\u6A21\u578B\u670D\u52A1\u5730\u5740", placeholder: "http://\u5185\u7F51\u5730\u5740/v1" },
4345
4447
  { id: "model", label: "\u6A21\u578B", placeholder: "\u6A21\u578B\u540D\u79F0" },
@@ -4390,8 +4492,8 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4390
4492
  if (!normalized) return null;
4391
4493
  const fields = FIELDS.filter((field) => normalized[field.id]);
4392
4494
  const dirty = Object.keys(override).length > 0;
4393
- return /* @__PURE__ */ jsxs16("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
4394
- /* @__PURE__ */ jsxs16(
4495
+ return /* @__PURE__ */ jsxs17("div", { className: "blade-chat-advanced border-t border-[hsl(var(--border))] px-4 py-2 text-xs", children: [
4496
+ /* @__PURE__ */ jsxs17(
4395
4497
  "button",
4396
4498
  {
4397
4499
  type: "button",
@@ -4401,16 +4503,16 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4401
4503
  },
4402
4504
  className: "flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
4403
4505
  children: [
4404
- /* @__PURE__ */ jsx18(Settings2, { size: 13 }),
4506
+ /* @__PURE__ */ jsx19(Settings2, { size: 13 }),
4405
4507
  "\u9AD8\u7EA7\u8BBE\u7F6E",
4406
- dirty && /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4508
+ dirty && /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--primary))]", children: "\uFF08\u5DF2\u81EA\u5B9A\u4E49\uFF09" })
4407
4509
  ]
4408
4510
  }
4409
4511
  ),
4410
- open && /* @__PURE__ */ jsxs16("div", { className: "mt-2 flex flex-col gap-2", children: [
4411
- fields.map((field) => /* @__PURE__ */ jsxs16("label", { className: "flex flex-col gap-1", children: [
4412
- /* @__PURE__ */ jsx18("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
4413
- /* @__PURE__ */ jsx18(
4512
+ open && /* @__PURE__ */ jsxs17("div", { className: "mt-2 flex flex-col gap-2", children: [
4513
+ fields.map((field) => /* @__PURE__ */ jsxs17("label", { className: "flex flex-col gap-1", children: [
4514
+ /* @__PURE__ */ jsx19("span", { className: "text-[hsl(var(--muted-foreground))]", children: field.label }),
4515
+ /* @__PURE__ */ jsx19(
4414
4516
  "input",
4415
4517
  {
4416
4518
  type: field.secret ? "password" : "text",
@@ -4421,9 +4523,9 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4421
4523
  }
4422
4524
  )
4423
4525
  ] }, field.id)),
4424
- 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" }),
4425
- /* @__PURE__ */ jsxs16("div", { className: "flex gap-2", children: [
4426
- /* @__PURE__ */ jsx18(
4526
+ 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" }),
4527
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
4528
+ /* @__PURE__ */ jsx19(
4427
4529
  "button",
4428
4530
  {
4429
4531
  type: "button",
@@ -4438,7 +4540,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4438
4540
  children: "\u4FDD\u5B58"
4439
4541
  }
4440
4542
  ),
4441
- /* @__PURE__ */ jsx18(
4543
+ /* @__PURE__ */ jsx19(
4442
4544
  "button",
4443
4545
  {
4444
4546
  type: "button",
@@ -4457,7 +4559,7 @@ function LlmAdvancedSettingsBar({ settings, defaults, override, onChange }) {
4457
4559
  }
4458
4560
 
4459
4561
  // src/components/LlmChat.tsx
4460
- import { jsx as jsx19 } from "react/jsx-runtime";
4562
+ import { jsx as jsx20 } from "react/jsx-runtime";
4461
4563
  function LlmChat({
4462
4564
  classNames,
4463
4565
  renderers,
@@ -4486,7 +4588,7 @@ ${text}` : text),
4486
4588
  useEffect12(() => {
4487
4589
  onReady?.(handle);
4488
4590
  }, [handle, onReady]);
4489
- return /* @__PURE__ */ jsx19(
4591
+ return /* @__PURE__ */ jsx20(
4490
4592
  ChatSurface,
4491
4593
  {
4492
4594
  theme,
@@ -4511,7 +4613,7 @@ ${text}` : text),
4511
4613
  setStopRequested(true);
4512
4614
  stop();
4513
4615
  },
4514
- beforeInput: advanced ? /* @__PURE__ */ jsx19(
4616
+ beforeInput: advanced ? /* @__PURE__ */ jsx20(
4515
4617
  LlmAdvancedSettingsBar,
4516
4618
  {
4517
4619
  settings: advanced,
@@ -4529,14 +4631,14 @@ ${text}` : text),
4529
4631
  }
4530
4632
 
4531
4633
  // src/components/ChatView.tsx
4532
- import { jsx as jsx20 } from "react/jsx-runtime";
4634
+ import { jsx as jsx21 } from "react/jsx-runtime";
4533
4635
  function ChatView(props) {
4534
4636
  const { mode, llm, onLlmReady, ...rest } = props;
4535
4637
  if (mode === "llm") {
4536
4638
  if (!llm) {
4537
4639
  throw new Error('ChatView: mode="llm" \u9700\u8981\u540C\u65F6\u4F20 llm={{ baseURL, model }}');
4538
4640
  }
4539
- return /* @__PURE__ */ jsx20(
4641
+ return /* @__PURE__ */ jsx21(
4540
4642
  LlmChat,
4541
4643
  {
4542
4644
  ...llm,
@@ -4549,23 +4651,24 @@ function ChatView(props) {
4549
4651
  }
4550
4652
  );
4551
4653
  }
4552
- return /* @__PURE__ */ jsx20(AgentChat, { ...rest });
4654
+ return /* @__PURE__ */ jsx21(AgentChat, { ...rest });
4553
4655
  }
4554
4656
 
4555
4657
  // src/components/ContextCard.tsx
4556
4658
  import {
4557
- getContextDisplayState
4659
+ getContextDisplayState,
4660
+ getContextGroupDisplayState
4558
4661
  } from "@blade-hq/agent-client";
4559
- import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
4662
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
4560
4663
  function ContextCard({ context, className }) {
4561
4664
  const display = getContextDisplayState(context);
4562
- return /* @__PURE__ */ jsxs17(
4665
+ return /* @__PURE__ */ jsxs18(
4563
4666
  "details",
4564
4667
  {
4565
- className: `blade-chat-context-card group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
4668
+ className: `blade-chat-context-card group/context-card rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`,
4566
4669
  children: [
4567
- /* @__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: [
4568
- /* @__PURE__ */ jsx21(
4670
+ /* @__PURE__ */ jsxs18("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: [
4671
+ /* @__PURE__ */ jsx22(
4569
4672
  Layers,
4570
4673
  {
4571
4674
  size: 15,
@@ -4573,24 +4676,60 @@ function ContextCard({ context, className }) {
4573
4676
  "aria-hidden": "true"
4574
4677
  }
4575
4678
  ),
4576
- /* @__PURE__ */ jsxs17("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
4577
- /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
4578
- /* @__PURE__ */ jsx21("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
4679
+ /* @__PURE__ */ jsxs18("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
4680
+ /* @__PURE__ */ jsx22("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: display.title }),
4681
+ /* @__PURE__ */ jsx22("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: display.summary })
4579
4682
  ] }),
4580
- /* @__PURE__ */ jsx21(
4683
+ /* @__PURE__ */ jsx22(
4581
4684
  ChevronDown,
4582
4685
  {
4583
4686
  size: 14,
4584
- className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open:rotate-180",
4687
+ className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open/context-card:rotate-180",
4585
4688
  "aria-hidden": "true"
4586
4689
  }
4587
4690
  )
4588
4691
  ] }),
4589
- /* @__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 })
4692
+ /* @__PURE__ */ jsx22("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 })
4590
4693
  ]
4591
4694
  }
4592
4695
  );
4593
4696
  }
4697
+ function ContextGroupCard({ contexts, className }) {
4698
+ if (contexts.length === 0) return null;
4699
+ const single = contexts.length === 1 ? getContextDisplayState(contexts[0]) : null;
4700
+ const group = single ? null : getContextGroupDisplayState(contexts);
4701
+ return /* @__PURE__ */ jsxs18("details", { className: `blade-chat-context-card group/context-group rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] text-sm ${className ?? ""}`, children: [
4702
+ /* @__PURE__ */ jsxs18("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: [
4703
+ /* @__PURE__ */ jsx22(
4704
+ Layers,
4705
+ {
4706
+ size: 15,
4707
+ className: "blade-chat-context-icon shrink-0 text-[hsl(var(--muted-foreground))]",
4708
+ "aria-hidden": "true"
4709
+ }
4710
+ ),
4711
+ /* @__PURE__ */ jsxs18("span", { className: "blade-chat-context-copy min-w-0 flex-1", children: [
4712
+ /* @__PURE__ */ jsx22("span", { className: "blade-chat-context-title block font-medium text-[hsl(var(--foreground))]", children: single ? single.title : `${group?.title} \xB7 ${group?.count} \u9879` }),
4713
+ /* @__PURE__ */ jsx22("span", { className: "blade-chat-context-status block truncate text-xs text-[hsl(var(--muted-foreground))]", children: single ? single.summary : group?.summary })
4714
+ ] }),
4715
+ /* @__PURE__ */ jsx22(
4716
+ ChevronDown,
4717
+ {
4718
+ size: 14,
4719
+ className: "blade-chat-context-chevron shrink-0 text-[hsl(var(--muted-foreground))] transition-transform group-open/context-group:rotate-180",
4720
+ "aria-hidden": "true"
4721
+ }
4722
+ )
4723
+ ] }),
4724
+ single ? /* @__PURE__ */ jsx22("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: single.detail }) : /* @__PURE__ */ jsx22("div", { className: "blade-chat-context-group-items flex flex-col gap-1.5 border-t border-[hsl(var(--border))] p-2", children: contexts.map((context) => /* @__PURE__ */ jsx22(
4725
+ ContextCard,
4726
+ {
4727
+ context
4728
+ },
4729
+ `${context.context_kind}:${context.context_key}`
4730
+ )) })
4731
+ ] });
4732
+ }
4594
4733
 
4595
4734
  // src/lib/agent-computer-command.ts
4596
4735
  var COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\n;&|(]\s*)computer\s+launch(?:\s|$)/;
@@ -4641,15 +4780,19 @@ export {
4641
4780
  BladeProvider,
4642
4781
  ChatView,
4643
4782
  ContextCard,
4783
+ ContextGroupCard,
4644
4784
  LlmChat,
4645
4785
  MarkdownContent,
4646
4786
  MemoryRefsHint,
4647
4787
  ReplayBar,
4648
4788
  ReplayMismatchPrompt,
4789
+ WhatIfUserBubble,
4649
4790
  classifyAgentComputerLaunchOutcome,
4650
4791
  collectMemoryRefs,
4651
4792
  isAgentComputerCommand,
4652
4793
  isAgentComputerToolCall,
4794
+ normalizeAdjacentUrlFormatting,
4795
+ parseWhatIfPrompt,
4653
4796
  useAgentSession,
4654
4797
  useBladeClient,
4655
4798
  useLlmChat,
@@ -4683,6 +4826,7 @@ lucide-react/dist/esm/icons/lock-keyhole.js:
4683
4826
  lucide-react/dist/esm/icons/message-square-more.js:
4684
4827
  lucide-react/dist/esm/icons/message-square.js:
4685
4828
  lucide-react/dist/esm/icons/play.js:
4829
+ lucide-react/dist/esm/icons/refresh-ccw.js:
4686
4830
  lucide-react/dist/esm/icons/search.js:
4687
4831
  lucide-react/dist/esm/icons/settings-2.js:
4688
4832
  lucide-react/dist/esm/icons/sparkles.js: