@blade-hq/agent-react 2612.0.0-beta.27 → 2612.0.0-beta.29

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.
Files changed (50) hide show
  1. package/dist/chat/AgentLoopBlock.d.ts +0 -2
  2. package/dist/chat/AssistantTurnBlock.d.ts +0 -8
  3. package/dist/chat/AttachmentPreviewDialog.d.ts +0 -1
  4. package/dist/chat/CurrentPlanPanel.d.ts +0 -3
  5. package/dist/chat/FileDeliveryCards.d.ts +0 -4
  6. package/dist/chat/FinalArtifactCards.d.ts +0 -1
  7. package/dist/chat/LiteMessageList.d.ts +1 -3
  8. package/dist/chat/MessageFileAttachmentList.d.ts +0 -5
  9. package/dist/chat/SessionReplayBar.d.ts +0 -1
  10. package/dist/chat/TextAttachmentPills.d.ts +0 -3
  11. package/dist/chat/TurnNavRail.d.ts +0 -3
  12. package/dist/chat/WorkflowRunBlock.d.ts +0 -2
  13. package/dist/chat/ai-elements/shimmer.d.ts +0 -4
  14. package/dist/chat/message-list-blocks.d.ts +0 -1
  15. package/dist/chat/runtime/actions.d.ts +1 -2
  16. package/dist/chat/runtime/background-task-dismissals.d.ts +0 -1
  17. package/dist/chat/runtime/composer-channels.d.ts +0 -3
  18. package/dist/chat/runtime/input-cache-reset.d.ts +0 -5
  19. package/dist/chat/runtime/session-source.d.ts +0 -5
  20. package/dist/chat/runtime/use-chat-actions.d.ts +0 -4
  21. package/dist/{chat-OCLOVB3H.css → chat-IHPRU35X.css} +5 -18
  22. package/dist/chat.css +5 -18
  23. package/dist/{chunk-66V4EOSO.js → chunk-M5NAFIU4.js} +340 -399
  24. package/dist/chunk-M5NAFIU4.js.map +1 -0
  25. package/dist/{chunk-PAZSK73V.js → chunk-PHWYZP6F.js} +3 -8
  26. package/dist/chunk-PHWYZP6F.js.map +1 -0
  27. package/dist/{chunk-PPREDKQ2.js → chunk-XTYNDVUV.js} +15 -3
  28. package/dist/chunk-XTYNDVUV.js.map +1 -0
  29. package/dist/components/ChatInput.d.ts +1 -15
  30. package/dist/components/LlmAdvancedSettings.d.ts +0 -1
  31. package/dist/components/PlanUpdateBlock.d.ts +0 -1
  32. package/dist/embed/blade-chat-element.d.ts +0 -8
  33. package/dist/embed/entry.d.ts +1 -13
  34. package/dist/hooks/use-message-pin.d.ts +1 -1
  35. package/dist/index.js +2 -2
  36. package/dist/internal.js +4 -6
  37. package/dist/internal.js.map +1 -1
  38. package/dist/lib/message-shortcuts.d.ts +5 -0
  39. package/dist/rich-input/ConnectButton.d.ts +0 -2
  40. package/dist/rich-input/SkillStatusBar.d.ts +0 -6
  41. package/dist/rich-input/lib/reference-candidates.d.ts +0 -1
  42. package/dist/rich-input/voice/VoiceWaveform.d.ts +0 -3
  43. package/dist/rich-input.js +90 -110
  44. package/dist/rich-input.js.map +1 -1
  45. package/dist/style.css +16 -55
  46. package/dist/style.full.css +23 -77
  47. package/package.json +2 -2
  48. package/dist/chunk-66V4EOSO.js.map +0 -1
  49. package/dist/chunk-PAZSK73V.js.map +0 -1
  50. package/dist/chunk-PPREDKQ2.js.map +0 -1
@@ -87,9 +87,11 @@ import {
87
87
  getToolStatusLabel,
88
88
  getToolTone,
89
89
  isPlanUpdateTool,
90
+ isQueueShortcut,
90
91
  notifyChat,
91
92
  parsePlanUpdate,
92
93
  pluginRefsForSend,
94
+ queueShortcutLabel,
93
95
  sendToSession,
94
96
  useBladeClient,
95
97
  useBladeHost,
@@ -112,7 +114,7 @@ import {
112
114
  useSessionSource,
113
115
  useSessionState,
114
116
  useSingleSessionSource
115
- } from "./chunk-PPREDKQ2.js";
117
+ } from "./chunk-XTYNDVUV.js";
116
118
  import {
117
119
  __export
118
120
  } from "./chunk-PR4QN5HX.js";
@@ -576,276 +578,268 @@ function SessionQueuePanel({
576
578
  next.splice(edge === "after" ? target + 1 : target, 0, sourceId);
577
579
  onReorder(next);
578
580
  };
579
- return (
580
- // 外层左右留白必须跟输入框一致:两边各自 mx-auto 居中,padding 不同的话
581
- // 即使 max-width 相同也会整体错开,看起来就是"没对齐"。
582
- // 用变量而不是写死 px:SDK 输入框用 --blade-chat-gutter(默认 1rem,
583
- // 容器查询下还会变),内置 Web 输入框外层是 px-5(20px);调用方按
584
- // .blade-chat-queue 覆盖 --blade-chat-queue-gutter 即可对齐,两边共用
585
- // 同一套机制。
586
- /* @__PURE__ */ jsx3("section", { part: "queue", className: cn("blade-chat-queue shrink-0 pt-2", rootClassName), "aria-label": "\u5F85\u6267\u884C\u6D88\u606F", children: /* @__PURE__ */ jsxs3("div", { className: cn("mx-auto", contentWidthClassName), children: [
587
- snapshot.paused || collapsible ? /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-0.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
588
- /* @__PURE__ */ jsxs3("span", { className: "font-medium", children: [
589
- "\u5F85\u6267\u884C \xB7 ",
590
- items.length
591
- ] }),
592
- snapshot.paused && /* @__PURE__ */ jsxs3(Fragment, { children: [
593
- /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--destructive))]", children: [
594
- /* @__PURE__ */ jsx3(CirclePause, { size: 12 }),
595
- pauseLabel
596
- ] }),
597
- /* @__PURE__ */ jsx3(
598
- "button",
599
- {
600
- type: "button",
601
- onClick: onResume,
602
- className: "h-6 rounded-md border border-[hsl(var(--border))] px-2 font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
603
- children: "\u7EE7\u7EED\u6267\u884C"
604
- }
605
- )
581
+ return /* @__PURE__ */ jsx3("section", { part: "queue", className: cn("blade-chat-queue shrink-0 pt-2", rootClassName), "aria-label": "\u5F85\u6267\u884C\u6D88\u606F", children: /* @__PURE__ */ jsxs3("div", { className: cn("mx-auto", contentWidthClassName), children: [
582
+ snapshot.paused || collapsible ? /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-0.5 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
583
+ /* @__PURE__ */ jsxs3("span", { className: "font-medium", children: [
584
+ "\u5F85\u6267\u884C \xB7 ",
585
+ items.length
586
+ ] }),
587
+ snapshot.paused && /* @__PURE__ */ jsxs3(Fragment, { children: [
588
+ /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--destructive))]", children: [
589
+ /* @__PURE__ */ jsx3(CirclePause, { size: 12 }),
590
+ pauseLabel
606
591
  ] }),
607
- collapsible && /* @__PURE__ */ jsxs3(
592
+ /* @__PURE__ */ jsx3(
608
593
  "button",
609
594
  {
610
595
  type: "button",
611
- onClick: () => setCollapsed((value) => !value),
612
- "aria-expanded": !collapsed,
613
- className: "ml-auto inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
614
- children: [
615
- collapsed ? "\u5C55\u5F00" : "\u6298\u53E0",
616
- /* @__PURE__ */ jsx3(ChevronDown, { size: 12, className: cn(!collapsed && "rotate-180") })
617
- ]
596
+ onClick: onResume,
597
+ className: "h-6 rounded-md border border-[hsl(var(--border))] px-2 font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
598
+ children: "\u7EE7\u7EED\u6267\u884C"
618
599
  }
619
600
  )
620
- ] }) : null,
621
- notice && /* @__PURE__ */ jsxs3("div", { className: "blade-chat-queue-notice mt-2 flex items-start gap-1.5 text-xs text-[hsl(var(--destructive))]", children: [
622
- /* @__PURE__ */ jsx3(CircleAlert, { size: 13, className: "mt-0.5 shrink-0" }),
623
- /* @__PURE__ */ jsx3("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: notice })
624
- ] }),
625
- detachedEdit && /* @__PURE__ */ jsxs3("div", { className: "mt-2 flex flex-col gap-2 text-xs", children: [
626
- /* @__PURE__ */ jsx3("span", { children: "\u539F\u6D88\u606F\u5DF2\u53D8\u5316\uFF0C\u4FEE\u6539\u5185\u5BB9\u5DF2\u4FDD\u7559" }),
627
- /* @__PURE__ */ jsx3(
628
- "textarea",
629
- {
630
- "aria-label": "\u4FDD\u7559\u7684\u4FEE\u6539\u5185\u5BB9",
631
- value: detachedEdit.text,
632
- onChange: (event) => setEditing((current) => current ? { ...current, text: event.target.value } : current),
633
- rows: 2,
634
- className: "w-full rounded border border-[hsl(var(--border))] bg-transparent p-2"
635
- }
636
- ),
637
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
638
- /* @__PURE__ */ jsx3("button", { type: "button", className: "rounded border border-[hsl(var(--border))] px-2 py-1", disabled: requeueing, onClick: stopEdit, children: "\u653E\u5F03\u4FEE\u6539" }),
639
- onRequeue && /* @__PURE__ */ jsx3("button", { type: "button", className: "rounded bg-[hsl(var(--primary))] px-2 py-1 text-[hsl(var(--primary-foreground))] disabled:opacity-40", disabled: requeueing || !detachedEdit.text.trim(), onClick: async () => {
640
- if (requeuePending.current) return;
641
- requeuePending.current = true;
642
- setRequeueing(true);
643
- const submitted = editing;
644
- try {
645
- if (await onRequeue(detachedEdit.text.trim())) {
646
- setEditing((current) => current === submitted ? null : current);
647
- }
648
- } finally {
649
- requeuePending.current = false;
650
- setRequeueing(false);
651
- }
652
- }, children: "\u4F5C\u4E3A\u65B0\u6D88\u606F\u6392\u961F" })
653
- ] })
654
601
  ] }),
602
+ collapsible && /* @__PURE__ */ jsxs3(
603
+ "button",
604
+ {
605
+ type: "button",
606
+ onClick: () => setCollapsed((value) => !value),
607
+ "aria-expanded": !collapsed,
608
+ className: "ml-auto inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
609
+ children: [
610
+ collapsed ? "\u5C55\u5F00" : "\u6298\u53E0",
611
+ /* @__PURE__ */ jsx3(ChevronDown, { size: 12, className: cn(!collapsed && "rotate-180") })
612
+ ]
613
+ }
614
+ )
615
+ ] }) : null,
616
+ notice && /* @__PURE__ */ jsxs3("div", { className: "blade-chat-queue-notice mt-2 flex items-start gap-1.5 text-xs text-[hsl(var(--destructive))]", children: [
617
+ /* @__PURE__ */ jsx3(CircleAlert, { size: 13, className: "mt-0.5 shrink-0" }),
618
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: notice })
619
+ ] }),
620
+ detachedEdit && /* @__PURE__ */ jsxs3("div", { className: "mt-2 flex flex-col gap-2 text-xs", children: [
621
+ /* @__PURE__ */ jsx3("span", { children: "\u539F\u6D88\u606F\u5DF2\u53D8\u5316\uFF0C\u4FEE\u6539\u5185\u5BB9\u5DF2\u4FDD\u7559" }),
655
622
  /* @__PURE__ */ jsx3(
656
- "ul",
623
+ "textarea",
657
624
  {
658
- className: cn(
659
- QUEUE_INSET_CLASS,
660
- "flex max-h-56 flex-col overflow-y-auto rounded-t-[22px] border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-1.5 py-1.5",
661
- !mergesWithInputBelow && "rounded-b-[22px]"
662
- ),
663
- children: visibleItems.map((item) => {
664
- const position2 = items.indexOf(item) + 1;
665
- const pending = canEditQueuedMessage(item);
666
- const busy = pendingItemId === item.id;
667
- const isEditing = activeEdit?.id === item.id;
668
- const pendingIndex = pendingIds.indexOf(item.id);
669
- const statusLabel = item.status === "pending" ? null : queuedMessageStatusLabel(item.status);
670
- const deliverable = canDeliver && canDeliverQueuedMessage(item);
671
- return /* @__PURE__ */ jsx3(
672
- "li",
673
- {
674
- draggable: pending && !busy && !isEditing,
675
- onDragStart: (event) => {
676
- draggingRef.current = item.id;
677
- setDraggingId(item.id);
678
- const text4 = event.currentTarget.querySelector("[data-queue-text]");
679
- if (text4 && event.dataTransfer) {
680
- const rect = text4.getBoundingClientRect();
681
- event.dataTransfer.setDragImage(
682
- text4,
683
- event.clientX - rect.left,
684
- event.clientY - rect.top
685
- );
686
- }
687
- },
688
- onDragEnd: () => {
689
- draggingRef.current = null;
690
- dropRef.current = null;
691
- setDraggingId(null);
692
- setDropAt(null);
693
- },
694
- onDragOver: (event) => {
695
- if (!pending) return;
696
- event.preventDefault();
697
- if (!draggingRef.current || draggingRef.current === item.id) return;
698
- const rect = event.currentTarget.getBoundingClientRect();
699
- const edge = event.clientY > rect.top + rect.height / 2 ? "after" : "before";
700
- dropRef.current = { id: item.id, edge };
701
- setDropAt(
702
- (current) => current?.id === item.id && current.edge === edge ? current : { id: item.id, edge }
625
+ "aria-label": "\u4FDD\u7559\u7684\u4FEE\u6539\u5185\u5BB9",
626
+ value: detachedEdit.text,
627
+ onChange: (event) => setEditing((current) => current ? { ...current, text: event.target.value } : current),
628
+ rows: 2,
629
+ className: "w-full rounded border border-[hsl(var(--border))] bg-transparent p-2"
630
+ }
631
+ ),
632
+ /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
633
+ /* @__PURE__ */ jsx3("button", { type: "button", className: "rounded border border-[hsl(var(--border))] px-2 py-1", disabled: requeueing, onClick: stopEdit, children: "\u653E\u5F03\u4FEE\u6539" }),
634
+ onRequeue && /* @__PURE__ */ jsx3("button", { type: "button", className: "rounded bg-[hsl(var(--primary))] px-2 py-1 text-[hsl(var(--primary-foreground))] disabled:opacity-40", disabled: requeueing || !detachedEdit.text.trim(), onClick: async () => {
635
+ if (requeuePending.current) return;
636
+ requeuePending.current = true;
637
+ setRequeueing(true);
638
+ const submitted = editing;
639
+ try {
640
+ if (await onRequeue(detachedEdit.text.trim())) {
641
+ setEditing((current) => current === submitted ? null : current);
642
+ }
643
+ } finally {
644
+ requeuePending.current = false;
645
+ setRequeueing(false);
646
+ }
647
+ }, children: "\u4F5C\u4E3A\u6392\u961F\u6D88\u606F\u53D1\u9001" })
648
+ ] })
649
+ ] }),
650
+ /* @__PURE__ */ jsx3(
651
+ "ul",
652
+ {
653
+ className: cn(
654
+ QUEUE_INSET_CLASS,
655
+ "flex max-h-56 flex-col overflow-y-auto rounded-t-[22px] border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-1.5 py-1.5",
656
+ !mergesWithInputBelow && "rounded-b-[22px]"
657
+ ),
658
+ children: visibleItems.map((item) => {
659
+ const position2 = items.indexOf(item) + 1;
660
+ const pending = canEditQueuedMessage(item);
661
+ const busy = pendingItemId === item.id;
662
+ const isEditing = activeEdit?.id === item.id;
663
+ const pendingIndex = pendingIds.indexOf(item.id);
664
+ const statusLabel = item.status === "pending" ? null : queuedMessageStatusLabel(item.status);
665
+ const deliverable = canDeliver && canDeliverQueuedMessage(item);
666
+ return /* @__PURE__ */ jsx3(
667
+ "li",
668
+ {
669
+ draggable: pending && !busy && !isEditing,
670
+ onDragStart: (event) => {
671
+ draggingRef.current = item.id;
672
+ setDraggingId(item.id);
673
+ const text4 = event.currentTarget.querySelector("[data-queue-text]");
674
+ if (text4 && event.dataTransfer) {
675
+ const rect = text4.getBoundingClientRect();
676
+ event.dataTransfer.setDragImage(
677
+ text4,
678
+ event.clientX - rect.left,
679
+ event.clientY - rect.top
703
680
  );
704
- },
705
- onDragLeave: () => {
706
- if (dropRef.current?.id === item.id) dropRef.current = null;
707
- setDropAt((current) => current?.id === item.id ? null : current);
708
- },
709
- onDrop: (event) => {
710
- event.preventDefault();
711
- const landed = dropRef.current;
712
- if (pending) handleDrop(item.id, landed?.id === item.id ? landed.edge : "before");
713
- },
714
- className: cn(
715
- "blade-chat-queue-item group relative flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[11px]",
716
- pending && !isEditing && "cursor-grab active:cursor-grabbing",
717
- busy && "opacity-60",
718
- draggingId === item.id && "opacity-40"
681
+ }
682
+ },
683
+ onDragEnd: () => {
684
+ draggingRef.current = null;
685
+ dropRef.current = null;
686
+ setDraggingId(null);
687
+ setDropAt(null);
688
+ },
689
+ onDragOver: (event) => {
690
+ if (!pending) return;
691
+ event.preventDefault();
692
+ if (!draggingRef.current || draggingRef.current === item.id) return;
693
+ const rect = event.currentTarget.getBoundingClientRect();
694
+ const edge = event.clientY > rect.top + rect.height / 2 ? "after" : "before";
695
+ dropRef.current = { id: item.id, edge };
696
+ setDropAt(
697
+ (current) => current?.id === item.id && current.edge === edge ? current : { id: item.id, edge }
698
+ );
699
+ },
700
+ onDragLeave: () => {
701
+ if (dropRef.current?.id === item.id) dropRef.current = null;
702
+ setDropAt((current) => current?.id === item.id ? null : current);
703
+ },
704
+ onDrop: (event) => {
705
+ event.preventDefault();
706
+ const landed = dropRef.current;
707
+ if (pending) handleDrop(item.id, landed?.id === item.id ? landed.edge : "before");
708
+ },
709
+ className: cn(
710
+ "blade-chat-queue-item group relative flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[11px]",
711
+ pending && !isEditing && "cursor-grab active:cursor-grabbing",
712
+ busy && "opacity-60",
713
+ draggingId === item.id && "opacity-40"
714
+ ),
715
+ children: isEditing ? /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
716
+ /* @__PURE__ */ jsx3(
717
+ "textarea",
718
+ {
719
+ value: activeEdit?.text ?? "",
720
+ onChange: (event) => setEditing(
721
+ (current) => current ? { ...current, text: event.target.value } : current
722
+ ),
723
+ rows: 2,
724
+ "aria-label": `\u7F16\u8F91\u7B2C ${position2} \u6761\u6D88\u606F`,
725
+ className: "w-full resize-none rounded-md border border-[hsl(var(--border))] bg-transparent px-2 py-1.5 text-sm leading-5 text-[hsl(var(--foreground))] outline-none"
726
+ }
719
727
  ),
720
- children: isEditing ? /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
728
+ /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-1.5", children: [
721
729
  /* @__PURE__ */ jsx3(
722
- "textarea",
730
+ "button",
723
731
  {
724
- value: activeEdit?.text ?? "",
725
- onChange: (event) => setEditing(
726
- (current) => current ? { ...current, text: event.target.value } : current
727
- ),
728
- rows: 2,
729
- "aria-label": `\u7F16\u8F91\u7B2C ${position2} \u6761\u6D88\u606F`,
730
- className: "w-full resize-none rounded-md border border-[hsl(var(--border))] bg-transparent px-2 py-1.5 text-sm leading-5 text-[hsl(var(--foreground))] outline-none"
732
+ type: "button",
733
+ onClick: stopEdit,
734
+ className: "h-7 rounded-md border border-[hsl(var(--border))] px-2 text-xs text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
735
+ children: "\u53D6\u6D88"
731
736
  }
732
737
  ),
733
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-1.5", children: [
734
- /* @__PURE__ */ jsx3(
735
- "button",
736
- {
737
- type: "button",
738
- onClick: stopEdit,
739
- className: "h-7 rounded-md border border-[hsl(var(--border))] px-2 text-xs text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
740
- children: "\u53D6\u6D88"
741
- }
742
- ),
743
- /* @__PURE__ */ jsx3(
744
- "button",
745
- {
746
- type: "button",
747
- onClick: () => commitEdit(item),
748
- disabled: busy || !activeEdit?.text.trim(),
749
- className: "h-7 rounded-md bg-[hsl(var(--primary))] px-2 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-40",
750
- children: "\u4FDD\u5B58"
751
- }
738
+ /* @__PURE__ */ jsx3(
739
+ "button",
740
+ {
741
+ type: "button",
742
+ onClick: () => commitEdit(item),
743
+ disabled: busy || !activeEdit?.text.trim(),
744
+ className: "h-7 rounded-md bg-[hsl(var(--primary))] px-2 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-40",
745
+ children: "\u4FDD\u5B58"
746
+ }
747
+ )
748
+ ] })
749
+ ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
750
+ dropAt?.id === item.id ? /* @__PURE__ */ jsx3(
751
+ "span",
752
+ {
753
+ "aria-hidden": "true",
754
+ style: { background: "var(--resize-line-hover, hsl(var(--foreground) / 0.55))" },
755
+ className: cn(
756
+ "pointer-events-none absolute inset-x-1 h-[2px] rounded-full",
757
+ dropAt.edge === "before" ? "top-0" : "bottom-0"
752
758
  )
753
- ] })
754
- ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
755
- dropAt?.id === item.id ? /* @__PURE__ */ jsx3(
756
- "span",
759
+ }
760
+ ) : null,
761
+ /* @__PURE__ */ jsx3(
762
+ "button",
763
+ {
764
+ type: "button",
765
+ disabled: !pending || busy,
766
+ "aria-label": `\u8C03\u6574\u7B2C ${position2} \u6761\u7684\u987A\u5E8F\uFF08\u62D6\u52A8\uFF0C\u6216\u6309 Alt+\u4E0A/\u4E0B\uFF09`,
767
+ title: "\u62D6\u52A8\u8C03\u6574\u987A\u5E8F\uFF08Alt+\u4E0A/\u4E0B \u4E5F\u884C\uFF09",
768
+ onKeyDown: (event) => {
769
+ if (!event.altKey) return;
770
+ if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
771
+ event.preventDefault();
772
+ const delta = event.key === "ArrowUp" ? -1 : 1;
773
+ if (pendingIndex < 0) return;
774
+ if (delta < 0 && pendingIndex === 0) return;
775
+ if (delta > 0 && pendingIndex === pendingIds.length - 1) return;
776
+ onMove(item, delta);
777
+ },
778
+ className: "-ml-0.5 flex h-5 w-4 shrink-0 cursor-grab items-center justify-center rounded text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] active:cursor-grabbing disabled:cursor-default disabled:opacity-60 disabled:hover:bg-transparent",
779
+ children: /* @__PURE__ */ jsx3(Menu, { size: 14, "aria-hidden": "true" })
780
+ }
781
+ ),
782
+ /* @__PURE__ */ jsx3(
783
+ "span",
784
+ {
785
+ "data-queue-text": true,
786
+ className: "min-w-0 flex-1 truncate pt-px text-[hsl(var(--foreground))]",
787
+ children: item.content
788
+ }
789
+ ),
790
+ item.error ? /* @__PURE__ */ jsx3("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--destructive))]", children: item.error }) : busy ? /* @__PURE__ */ jsxs3("span", { className: "mt-0.5 inline-flex shrink-0 items-center gap-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
791
+ /* @__PURE__ */ jsx3(LoaderCircle, { size: 11, className: "animate-spin" }),
792
+ "\u5904\u7406\u4E2D"
793
+ ] }) : statusLabel ? /* @__PURE__ */ jsx3("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: statusLabel }) : null,
794
+ /* @__PURE__ */ jsxs3("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 [@media(hover:none)]:opacity-100 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", children: [
795
+ /* @__PURE__ */ jsxs3(
796
+ "button",
757
797
  {
758
- "aria-hidden": "true",
759
- style: { background: "var(--resize-line-hover, hsl(var(--foreground) / 0.55))" },
760
- className: cn(
761
- "pointer-events-none absolute inset-x-1 h-[2px] rounded-full",
762
- dropAt.edge === "before" ? "top-0" : "bottom-0"
763
- )
798
+ type: "button",
799
+ "aria-label": `\u7ACB\u523B\u53D1\u9001\u7B2C ${position2} \u6761`,
800
+ title: deliverable ? "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F" : "\u5F53\u524D\u6CA1\u6709\u53EF\u63A5\u6536\u8865\u5145\u7684\u4EFB\u52A1",
801
+ disabled: busy || !deliverable,
802
+ onClick: () => onDeliver(item),
803
+ className: LABEL_BUTTON,
804
+ children: [
805
+ /* @__PURE__ */ jsx3(Send, { size: 13, "aria-hidden": "true" }),
806
+ "\u7ACB\u523B\u53D1\u9001"
807
+ ]
764
808
  }
765
- ) : null,
809
+ ),
766
810
  /* @__PURE__ */ jsx3(
767
811
  "button",
768
812
  {
769
813
  type: "button",
770
- disabled: !pending || busy,
771
- "aria-label": `\u8C03\u6574\u7B2C ${position2} \u6761\u7684\u987A\u5E8F\uFF08\u62D6\u52A8\uFF0C\u6216\u6309 Alt+\u4E0A/\u4E0B\uFF09`,
772
- title: "\u62D6\u52A8\u8C03\u6574\u987A\u5E8F\uFF08Alt+\u4E0A/\u4E0B \u4E5F\u884C\uFF09",
773
- onKeyDown: (event) => {
774
- if (!event.altKey) return;
775
- if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
776
- event.preventDefault();
777
- const delta = event.key === "ArrowUp" ? -1 : 1;
778
- if (pendingIndex < 0) return;
779
- if (delta < 0 && pendingIndex === 0) return;
780
- if (delta > 0 && pendingIndex === pendingIds.length - 1) return;
781
- onMove(item, delta);
782
- },
783
- className: "-ml-0.5 flex h-5 w-4 shrink-0 cursor-grab items-center justify-center rounded text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] active:cursor-grabbing disabled:cursor-default disabled:opacity-60 disabled:hover:bg-transparent",
784
- children: /* @__PURE__ */ jsx3(Menu, { size: 14, "aria-hidden": "true" })
814
+ "aria-label": `\u7F16\u8F91\u7B2C ${position2} \u6761`,
815
+ title: "\u7F16\u8F91",
816
+ disabled: busy || !pending,
817
+ onClick: () => startEdit(item),
818
+ className: ICON_BUTTON,
819
+ children: /* @__PURE__ */ jsx3(Pencil, { size: 13, "aria-hidden": "true" })
785
820
  }
786
821
  ),
787
822
  /* @__PURE__ */ jsx3(
788
- "span",
823
+ "button",
789
824
  {
790
- "data-queue-text": true,
791
- className: "min-w-0 flex-1 truncate pt-px text-[hsl(var(--foreground))]",
792
- children: item.content
825
+ type: "button",
826
+ "aria-label": `\u5220\u9664\u7B2C ${position2} \u6761`,
827
+ title: "\u5220\u9664",
828
+ disabled: busy || !canCancelQueuedMessage(item),
829
+ onClick: () => onCancel(item),
830
+ className: ICON_BUTTON,
831
+ children: /* @__PURE__ */ jsx3(Trash2, { size: 13, "aria-hidden": "true" })
793
832
  }
794
- ),
795
- item.error ? /* @__PURE__ */ jsx3("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--destructive))]", children: item.error }) : busy ? /* @__PURE__ */ jsxs3("span", { className: "mt-0.5 inline-flex shrink-0 items-center gap-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: [
796
- /* @__PURE__ */ jsx3(LoaderCircle, { size: 11, className: "animate-spin" }),
797
- "\u5904\u7406\u4E2D"
798
- ] }) : statusLabel ? /* @__PURE__ */ jsx3("span", { className: "shrink-0 pt-1 text-[11px] text-[hsl(var(--muted-foreground))]", children: statusLabel }) : null,
799
- /* @__PURE__ */ jsxs3("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 [@media(hover:none)]:opacity-100 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", children: [
800
- /* @__PURE__ */ jsxs3(
801
- "button",
802
- {
803
- type: "button",
804
- "aria-label": `\u7ACB\u523B\u53D1\u9001\u7B2C ${position2} \u6761`,
805
- title: deliverable ? "\u7ACB\u523B\u53D1\u9001" : "\u5F53\u524D\u6CA1\u6709\u53EF\u63A5\u6536\u8865\u5145\u7684\u4EFB\u52A1",
806
- disabled: busy || !deliverable,
807
- onClick: () => onDeliver(item),
808
- className: LABEL_BUTTON,
809
- children: [
810
- /* @__PURE__ */ jsx3(Send, { size: 13, "aria-hidden": "true" }),
811
- "\u7ACB\u523B\u53D1\u9001"
812
- ]
813
- }
814
- ),
815
- /* @__PURE__ */ jsx3(
816
- "button",
817
- {
818
- type: "button",
819
- "aria-label": `\u7F16\u8F91\u7B2C ${position2} \u6761`,
820
- title: "\u7F16\u8F91",
821
- disabled: busy || !pending,
822
- onClick: () => startEdit(item),
823
- className: ICON_BUTTON,
824
- children: /* @__PURE__ */ jsx3(Pencil, { size: 13, "aria-hidden": "true" })
825
- }
826
- ),
827
- /* @__PURE__ */ jsx3(
828
- "button",
829
- {
830
- type: "button",
831
- "aria-label": `\u5220\u9664\u7B2C ${position2} \u6761`,
832
- title: "\u5220\u9664",
833
- disabled: busy || !canCancelQueuedMessage(item),
834
- onClick: () => onCancel(item),
835
- className: ICON_BUTTON,
836
- children: /* @__PURE__ */ jsx3(Trash2, { size: 13, "aria-hidden": "true" })
837
- }
838
- )
839
- ] })
833
+ )
840
834
  ] })
841
- },
842
- item.id
843
- );
844
- })
845
- }
846
- )
847
- ] }) })
848
- );
835
+ ] })
836
+ },
837
+ item.id
838
+ );
839
+ })
840
+ }
841
+ )
842
+ ] }) });
849
843
  }
850
844
 
851
845
  // src/components/McpAppCard.tsx
@@ -26215,13 +26209,13 @@ function ChatInput({
26215
26209
  const [isSending2, setIsSending] = useState6(false);
26216
26210
  void queueKey;
26217
26211
  const canSend = !isSending2 && (trimmed.length > 0 || hasAttachments) && (!isStreaming || queueWhileRunning && !hasAttachments && !isStopping);
26218
- const handleSend = async () => {
26212
+ const handleSend = async (queueWhenRunning = false) => {
26219
26213
  if (!canSend || sending.current) return;
26220
26214
  sending.current = true;
26221
26215
  setIsSending(true);
26222
26216
  const submitted = value;
26223
26217
  try {
26224
- const accepted = await onSend(trimmed);
26218
+ const accepted = await onSend(trimmed, queueWhenRunning);
26225
26219
  if (accepted === false) return;
26226
26220
  if (latestValue.current === submitted) onValueChange("");
26227
26221
  } finally {
@@ -26239,10 +26233,10 @@ function ChatInput({
26239
26233
  keyCode: event.nativeEvent.keyCode
26240
26234
  }, false)) {
26241
26235
  event.preventDefault();
26242
- void handleSend();
26236
+ void handleSend(isQueueShortcut(event));
26243
26237
  }
26244
26238
  };
26245
- return /* @__PURE__ */ jsx7(
26239
+ return /* @__PURE__ */ jsxs7(
26246
26240
  "div",
26247
26241
  {
26248
26242
  style: mergesWithPanelAbove ? { "--blade-chat-input-top-border": "0" } : void 0,
@@ -26254,55 +26248,61 @@ function ChatInput({
26254
26248
  mergesWithPanelAbove && "pt-0",
26255
26249
  className
26256
26250
  ),
26257
- children: /* @__PURE__ */ jsxs7(
26258
- "div",
26259
- {
26260
- part: "input-inner",
26261
- className: cn(
26262
- "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2",
26263
- mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-2xl",
26264
- innerClassName
26265
- ),
26266
- children: [
26267
- /* @__PURE__ */ jsx7(
26268
- "textarea",
26269
- {
26270
- value,
26271
- onChange: (event) => onValueChange(event.target.value),
26272
- onKeyDown: handleKeyDown,
26273
- onInput: (event) => {
26274
- const el = event.currentTarget;
26275
- el.style.height = "auto";
26276
- el.style.height = `${Math.min(el.scrollHeight, 192)}px`;
26277
- },
26278
- rows: 1,
26279
- placeholder,
26280
- "aria-label": "\u804A\u5929\u8F93\u5165",
26281
- part: "textarea",
26282
- className: cn(
26283
- "blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]",
26284
- textareaClassName
26285
- )
26286
- }
26251
+ children: [
26252
+ /* @__PURE__ */ jsxs7(
26253
+ "div",
26254
+ {
26255
+ part: "input-inner",
26256
+ className: cn(
26257
+ "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2",
26258
+ mergesWithPanelAbove ? "rounded-b-[22px]" : "rounded-2xl",
26259
+ innerClassName
26287
26260
  ),
26288
- /* @__PURE__ */ jsx7("div", { part: "input-toolbar", className: cn("blade-chat-input-toolbar flex shrink-0 items-center gap-2", toolbarClassName), children: isStreaming ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
26289
- queueWhileRunning ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: handleSend, disabled: !canSend, "aria-label": "\u52A0\u5165\u6392\u961F", title: "\u52A0\u5165\u6392\u961F", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] disabled:opacity-40", children: /* @__PURE__ */ jsx7(ArrowUp, { size: 15 }) }) : null,
26290
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: onStop, disabled: isStopping, "aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60", children: isStopping ? /* @__PURE__ */ jsx7(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx7(Square, { size: 12, fill: "currentColor" }) })
26291
- ] }) : /* @__PURE__ */ jsx7(
26292
- "button",
26293
- {
26294
- type: "button",
26295
- onClick: handleSend,
26296
- disabled: !canSend,
26297
- "aria-label": "\u53D1\u9001\u6D88\u606F",
26298
- title: "\u53D1\u9001\u6D88\u606F",
26299
- className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40",
26300
- children: /* @__PURE__ */ jsx7(ArrowUp, { size: 15 })
26301
- }
26302
- ) })
26303
- ]
26304
- }
26305
- )
26261
+ children: [
26262
+ /* @__PURE__ */ jsx7(
26263
+ "textarea",
26264
+ {
26265
+ value,
26266
+ onChange: (event) => onValueChange(event.target.value),
26267
+ onKeyDown: handleKeyDown,
26268
+ onInput: (event) => {
26269
+ const el = event.currentTarget;
26270
+ el.style.height = "auto";
26271
+ el.style.height = `${Math.min(el.scrollHeight, 192)}px`;
26272
+ },
26273
+ rows: 1,
26274
+ placeholder,
26275
+ "aria-label": "\u804A\u5929\u8F93\u5165",
26276
+ part: "textarea",
26277
+ className: cn(
26278
+ "blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]",
26279
+ textareaClassName
26280
+ )
26281
+ }
26282
+ ),
26283
+ /* @__PURE__ */ jsx7("div", { part: "input-toolbar", className: cn("blade-chat-input-toolbar flex shrink-0 items-center gap-2", toolbarClassName), children: isStreaming ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
26284
+ queueWhileRunning ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => void handleSend(), disabled: !canSend, "aria-label": "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F", title: "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] disabled:opacity-40", children: /* @__PURE__ */ jsx7(ArrowUp, { size: 15 }) }) : null,
26285
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: onStop, disabled: isStopping, "aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", title: isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u56DE\u590D", className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60", children: isStopping ? /* @__PURE__ */ jsx7(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx7(Square, { size: 12, fill: "currentColor" }) })
26286
+ ] }) : /* @__PURE__ */ jsx7(
26287
+ "button",
26288
+ {
26289
+ type: "button",
26290
+ onClick: () => void handleSend(),
26291
+ disabled: !canSend,
26292
+ "aria-label": "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
26293
+ title: "\u53D1\u9001\u5F15\u5BFC\u6D88\u606F",
26294
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40",
26295
+ children: /* @__PURE__ */ jsx7(ArrowUp, { size: 15 })
26296
+ }
26297
+ ) })
26298
+ ]
26299
+ }
26300
+ ),
26301
+ trimmed && canSend && !hasAttachments && /* @__PURE__ */ jsxs7("div", { className: "mx-auto mt-1 max-w-[748px] text-right text-[11px] text-[hsl(var(--muted-foreground))]", children: [
26302
+ queueShortcutLabel(),
26303
+ " \xB7 \u6392\u961F\u6D88\u606F"
26304
+ ] })
26305
+ ]
26306
26306
  }
26307
26307
  );
26308
26308
  }
@@ -26408,7 +26408,7 @@ ${content3}`);
26408
26408
  {
26409
26409
  value,
26410
26410
  onValueChange: setValue,
26411
- onSend: (text4) => onSend(text4 || refs.map((ref) => `@${ref.label}`).join(" "), { refs: pluginRefsForSend(refs, session?.getState().turns) }),
26411
+ onSend: (text4, queueWhenRunning) => onSend(text4 || refs.map((ref) => `@${ref.label}`).join(" "), { queueWhenRunning, refs: pluginRefsForSend(refs, session?.getState().turns) }),
26412
26412
  hasAttachments: refs.length > 0,
26413
26413
  onKeyDown: (event) => {
26414
26414
  if (query === null || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;
@@ -35345,12 +35345,6 @@ function renderNode(node3, context, key) {
35345
35345
  renderIntrinsic(
35346
35346
  context,
35347
35347
  "code",
35348
- // 用字符偏移量而不是行号:增量解析里冻结前缀和尾部是分两次单独
35349
- // 解析的(`incremental.ts` 的 `shiftPositions` 只搬移了 offset,
35350
- // 没有跟着搬移 line/column),尾部重新解析出来的节点 line 永远从
35351
- // 1 数起,冻结边界一推进这个值就会变,两个不同位置的代码块也
35352
- // 可能撞上同一个相对行号——offset 全程是相对整篇输入的绝对值,
35353
- // 才是跨帧稳定、真正唯一的标识。
35354
35348
  { className, "data-block-offset": code2.position?.start.offset },
35355
35349
  "code",
35356
35350
  `${code2.value}
@@ -35981,7 +35975,6 @@ function CodeBlockPre({ children, ...props }) {
35981
35975
  className: cn(
35982
35976
  "blade-chat-codeblock-body",
35983
35977
  props.className,
35984
- // 原型:13.5px/1.7 等宽、浅底;覆盖 prose 的继承字号与主题里手写的 pre 样式。
35985
35978
  "m-0! overflow-x-auto! rounded-none! border-0! bg-[hsl(var(--muted))/0.25]! px-4! py-3.5! font-mono text-[13.5px]! leading-[1.7]! [&_code]:bg-transparent! [&_code]:p-0! [&_code]:font-mono [&_code]:text-[13.5px]! [&_code]:text-[hsl(var(--foreground))]"
35986
35979
  ),
35987
35980
  children
@@ -38057,7 +38050,6 @@ function parseWebResults(result) {
38057
38050
  const value = parseJsonValue(result);
38058
38051
  const items = isPlainObject3(value) ? toRecordArray(value.results) : toRecordArray(value);
38059
38052
  return items.map((item) => ({
38060
- // text 是当前字段;description 只为读旧会话保留,那时的结果没有正文片段。
38061
38053
  description: typeof item.text === "string" ? item.text : typeof item.description === "string" ? item.description : null,
38062
38054
  publishedDate: typeof item.published_date === "string" ? item.published_date : null,
38063
38055
  title: typeof item.title === "string" ? item.title : null,
@@ -38681,14 +38673,12 @@ function renderContent({
38681
38673
 
38682
38674
  // src/chat/lib/preview-dispatch.ts
38683
38675
  var IMAGE_EXTS = [
38684
- // 静态
38685
38676
  ".png",
38686
38677
  ".jpg",
38687
38678
  ".jpeg",
38688
38679
  ".bmp",
38689
38680
  ".svg",
38690
38681
  ".heic",
38691
- // 动图(<img> 原生播放)
38692
38682
  ".gif",
38693
38683
  ".webp",
38694
38684
  ".apng",
@@ -39116,32 +39106,25 @@ function UserMessageBubble({ message, className }) {
39116
39106
  pluginPills,
39117
39107
  topicAssetPills,
39118
39108
  /* @__PURE__ */ jsx36(ContextAttachmentPills, { attachments: message.context_attachments }),
39119
- trimmedClean && // 原型:不对称圆角(指向发送侧的一角收窄),无边框、无内阴影。
39120
- (customBubble != null ? customBubble : /* @__PURE__ */ jsx36(
39109
+ trimmedClean && (customBubble != null ? customBubble : /* @__PURE__ */ jsx36(
39121
39110
  "div",
39122
39111
  {
39123
39112
  part: "user-bubble",
39124
- 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))]",
39113
+ className: cn(
39114
+ "blade-chat-user-bubble max-w-full rounded-[24px] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-base leading-[1.7] transition-colors duration-200",
39115
+ isSending(message) ? "text-[hsl(var(--muted-foreground))]" : "text-[hsl(var(--user-msg-fg))]"
39116
+ ),
39125
39117
  children: /* @__PURE__ */ jsx36(
39126
39118
  MarkdownContent,
39127
39119
  {
39128
- className: USER_MESSAGE_MARKDOWN_CLASS,
39120
+ className: cn(USER_MESSAGE_MARKDOWN_CLASS, "text-inherit [&_strong]:text-inherit [&_p]:text-inherit"),
39129
39121
  controls: { code: true },
39130
39122
  children: cleanText
39131
39123
  }
39132
39124
  )
39133
39125
  }
39134
39126
  )),
39135
- trimmedClean && (isSending(message) ? /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
39136
- /* @__PURE__ */ jsx36(LoaderCircle, { size: 12, className: "animate-spin", "aria-hidden": "true" }),
39137
- /* @__PURE__ */ jsx36("span", { children: "\u53D1\u9001\u4E2D" })
39138
- ] }) : /* @__PURE__ */ jsx36(
39139
- MessageActions,
39140
- {
39141
- content: cleanText,
39142
- className: "opacity-0 [@media(hover:none)]:opacity-100 transition-opacity group-hover:opacity-100"
39143
- }
39144
- ))
39127
+ trimmedClean && !isSending(message) && /* @__PURE__ */ jsx36(MessageActions, { content: cleanText, className: "opacity-0 transition-opacity group-hover:opacity-100 [@media(hover:none)]:opacity-100" })
39145
39128
  ] }) });
39146
39129
  }
39147
39130
  function ErrorMessageBlock({
@@ -39574,7 +39557,6 @@ function synthToolCall(loopName, info, desc) {
39574
39557
  id: loopName,
39575
39558
  name: "Agent",
39576
39559
  arguments: JSON.stringify({ description: desc || info.description }),
39577
- // error/cancelled/awaiting_answer 原样透传:失败的步骤卡不能渲染成绿色完成态
39578
39560
  status: info.status === "running" ? "pending" : info.status === "error" || info.status === "cancelled" || info.status === "awaiting_answer" ? info.status : "done"
39579
39561
  };
39580
39562
  }
@@ -39819,8 +39801,7 @@ function WorkflowRunBlock({ toolCall, sessionId }) {
39819
39801
  /* @__PURE__ */ jsx38("summary", { className: "cursor-pointer select-none text-xs text-[hsl(var(--muted-foreground))]", children: "\u6700\u7EC8\u8F93\u51FA" }),
39820
39802
  /* @__PURE__ */ jsx38("pre", { className: "mt-1.5 max-h-48 overflow-y-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-[1.5] text-[hsl(var(--muted-foreground))]", children: finalOutput })
39821
39803
  ] }),
39822
- status === "done" && hasStepContent && // 统一的终止行:正常跑完(不管是 end 节点还是自然走完)都有,观感一致
39823
- /* @__PURE__ */ jsx38("div", { className: "py-0.5 text-center text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u23F9 \u6D41\u7A0B\u5230\u6B64\u7ED3\u675F" })
39804
+ status === "done" && hasStepContent && /* @__PURE__ */ jsx38("div", { className: "py-0.5 text-center text-[11px] text-[hsl(var(--muted-foreground))]", children: "\u23F9 \u6D41\u7A0B\u5230\u6B64\u7ED3\u675F" })
39824
39805
  ] })
39825
39806
  ] });
39826
39807
  }
@@ -40058,8 +40039,7 @@ function AssistantTurnBlockBase({
40058
40039
  const allToolCalls = useMemo11(() => messages.flatMap((m2) => m2.tool_calls ?? []), [messages]);
40059
40040
  const detailToolCalls = useMemo11(
40060
40041
  () => allToolCalls.filter(
40061
- (toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !isPlanUpdateTool(toolCall) && // 工作流运行由折叠区外的 WorkflowRunBlock 承载,折叠区内不再计入/展示
40062
- !isWorkflowRunToolName2(toolCall.name)
40042
+ (toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion" && !isPlanUpdateTool(toolCall) && !isWorkflowRunToolName2(toolCall.name)
40063
40043
  ),
40064
40044
  [allToolCalls]
40065
40045
  );
@@ -40151,8 +40131,7 @@ function AssistantTurnBlockBase({
40151
40131
  () => finalMessage ? getOrderedMessageParts(
40152
40132
  finalMessage,
40153
40133
  (finalMessage.tool_calls ?? []).filter(
40154
- (toolCall) => !isPlanUpdateTool(toolCall) && formatToolName(toolCall.name) !== "AskUserQuestion" && // 工作流运行由 WorkflowRunBlock 独占渲染,compact 内联再画一遍会重复
40155
- !isWorkflowRunToolName2(toolCall.name)
40134
+ (toolCall) => !isPlanUpdateTool(toolCall) && formatToolName(toolCall.name) !== "AskUserQuestion" && !isWorkflowRunToolName2(toolCall.name)
40156
40135
  )
40157
40136
  ) : [],
40158
40137
  [finalMessage]
@@ -40175,8 +40154,6 @@ function AssistantTurnBlockBase({
40175
40154
  const hasExecutionProcess = detailToolCalls.length > 0 || workflowRunToolCalls.length > 0 || persistentAskUserQuestions.length > 0 || messages.some((message) => Boolean(message.reasoning)) || resourceBlocks.length > 0;
40176
40155
  const client = useOptionalBladeClient();
40177
40156
  const executionDurationMs = getExecutionDurationMs({
40178
- // 根消息的 duration 已覆盖等待子智能体的墙钟时间,不能再累计 turnMessages
40179
- // 里收集到的子循环,否则嵌套和并行 Agent 都会重复计时。
40180
40157
  messages,
40181
40158
  isStreaming
40182
40159
  });
@@ -40189,7 +40166,6 @@ function AssistantTurnBlockBase({
40189
40166
  const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({
40190
40167
  messages,
40191
40168
  isStreaming,
40192
- // Direct LLM mode has no Blade session and generates its own local timestamps.
40193
40169
  now: sessionId ? getServerTime(client, clock) : Date.now()
40194
40170
  }) : executionDurationMs;
40195
40171
  const observedMemoryRefs = useMemo11(() => collectMemoryRefs(messages), [messages]);
@@ -40351,12 +40327,8 @@ function AssistantTurnBlockBase({
40351
40327
  customization
40352
40328
  }
40353
40329
  ),
40354
- SHOW_FILE_DELIVERY_CARDS && level === 1 && // 用合并后的轮次消息:子智能体(fork Agent)写入的文件也要出交付卡片。
40355
- /* @__PURE__ */ jsx39(FileDeliveryCards, { toolCalls: turnToolCalls, sessionId }),
40356
- level === 1 && !isStreaming && finalMessageText ? (
40357
- // 反馈行(原型):轮次底部的复制入口。
40358
- /* @__PURE__ */ jsx39(MessageActions, { content: finalMessageText, className: "-mt-1.5" })
40359
- ) : null
40330
+ SHOW_FILE_DELIVERY_CARDS && level === 1 && /* @__PURE__ */ jsx39(FileDeliveryCards, { toolCalls: turnToolCalls, sessionId }),
40331
+ level === 1 && !isStreaming && finalMessageText ? /* @__PURE__ */ jsx39(MessageActions, { content: finalMessageText, className: "-mt-1.5" }) : null
40360
40332
  ]
40361
40333
  }
40362
40334
  );
@@ -40834,11 +40806,6 @@ function useMessagePin({
40834
40806
  getSpacerHeight,
40835
40807
  setSpacerHeight,
40836
40808
  stopAutoScroll,
40837
- // 不再内部调用(见下面 reposition 里的说明),但这是公开的 SDK hook 参数,
40838
- // 删掉会让已经传这个 prop 的调用方在 TS 严格类型下编译不过——留着接口
40839
- // 不动,只是这里不再用它。
40840
- // biome-ignore lint/correctness/noUnusedVariables: 保留公开 API 形状
40841
- scrollToBottom,
40842
40809
  margin = DEFAULT_MARGIN_PX
40843
40810
  }) {
40844
40811
  const pinActiveRef = useRef17(false);
@@ -41189,7 +41156,6 @@ function buildMessageListBlocks({
41189
41156
  }
41190
41157
  ],
41191
41158
  key: pendingKey,
41192
- // pending 的 ID 只在前端临时存在,不能进入虚拟器的持久 key。
41193
41159
  persistentId: null,
41194
41160
  anchorId: `chat-turn-${assistantTurnCount}`,
41195
41161
  isStreaming: true,
@@ -41565,6 +41531,7 @@ function buildLiteRows({
41565
41531
  type: "text",
41566
41532
  key: block.message.render_id ?? block.key,
41567
41533
  role,
41534
+ sending: role === "user" && block.message.status === "streaming",
41568
41535
  text: text4,
41569
41536
  entryIds: block.message.entry_id ? [block.message.entry_id] : []
41570
41537
  };
@@ -41907,7 +41874,7 @@ function PlainTextMessage({
41907
41874
  }
41908
41875
  );
41909
41876
  if (row.role === "user") {
41910
- return /* @__PURE__ */ jsx42("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx42("div", { className: "max-w-[82%] rounded-[18px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-4 py-3 text-sm leading-6 text-[hsl(var(--user-msg-fg))]", children: markdown }) });
41877
+ return /* @__PURE__ */ jsx42("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx42("div", { className: `max-w-[82%] rounded-[24px] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-base leading-[1.7] transition-colors duration-200 ${row.sending ? "text-[hsl(var(--muted-foreground))]" : "text-[hsl(var(--user-msg-fg))]"}`, children: markdown }) });
41911
41878
  }
41912
41879
  return /* @__PURE__ */ jsxs36(
41913
41880
  "div",
@@ -46543,37 +46510,32 @@ function TurnNavRail({
46543
46510
  ]
46544
46511
  }
46545
46512
  ) : loadingTurnId ? /* @__PURE__ */ jsx47("output", { className: "absolute right-full top-1/2 mr-2 -translate-y-1/2 whitespace-nowrap rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--popover))] px-2.5 py-1 text-xs text-[hsl(var(--popover-foreground))] shadow-[var(--swf-shadow-overlay)]", children: "\u6B63\u5728\u5B9A\u4F4D\u5230\u8FD9\u6761\u53D1\u8A00\u2026" }) : null,
46546
- panelOpen ? (
46547
- // pr-2 让刻度与列表之间的空隙也算悬停区域,鼠标横穿时面板不会关闭。
46548
- // 与刻度轨同心:顶对齐会让接近上限高度的面板整条往下长,聊天区是 overflow: hidden,
46549
- // 视口矮一点下面的条目就被裁掉、滚也滚不到。高度同时受视口约束。
46550
- /* @__PURE__ */ jsx47("div", { className: "absolute right-full top-1/2 -translate-y-1/2 pr-2", children: /* @__PURE__ */ jsx47(
46551
- "div",
46552
- {
46553
- ref: listRef,
46554
- className: "flex max-h-[min(28rem,60vh)] w-80 flex-col overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]",
46555
- children: items.map((item, index2) => {
46556
- const isActive = item.id === activeTurnId;
46557
- const isHovered = item.id === hoveredTurnId;
46558
- return /* @__PURE__ */ jsx47(
46559
- "button",
46560
- {
46561
- type: "button",
46562
- "data-turn-id": item.id,
46563
- onClick: () => onSelectTurn(item.id),
46564
- onMouseEnter: () => setHoveredTurnId(item.id),
46565
- className: cn(
46566
- "shrink-0 truncate px-3 py-1.5 text-left text-xs text-[hsl(var(--popover-foreground))] transition-colors",
46567
- isHovered ? "bg-[hsl(var(--accent))]" : isActive ? "bg-[hsl(var(--accent)/0.5)]" : "hover:bg-[hsl(var(--accent))]"
46568
- ),
46569
- children: item.title || `\u7B2C ${index2 + 1} \u8F6E`
46570
- },
46571
- item.id
46572
- );
46573
- })
46574
- }
46575
- ) })
46576
- ) : null
46513
+ panelOpen ? /* @__PURE__ */ jsx47("div", { className: "absolute right-full top-1/2 -translate-y-1/2 pr-2", children: /* @__PURE__ */ jsx47(
46514
+ "div",
46515
+ {
46516
+ ref: listRef,
46517
+ className: "flex max-h-[min(28rem,60vh)] w-80 flex-col overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-[var(--swf-shadow-overlay)]",
46518
+ children: items.map((item, index2) => {
46519
+ const isActive = item.id === activeTurnId;
46520
+ const isHovered = item.id === hoveredTurnId;
46521
+ return /* @__PURE__ */ jsx47(
46522
+ "button",
46523
+ {
46524
+ type: "button",
46525
+ "data-turn-id": item.id,
46526
+ onClick: () => onSelectTurn(item.id),
46527
+ onMouseEnter: () => setHoveredTurnId(item.id),
46528
+ className: cn(
46529
+ "shrink-0 truncate px-3 py-1.5 text-left text-xs text-[hsl(var(--popover-foreground))] transition-colors",
46530
+ isHovered ? "bg-[hsl(var(--accent))]" : isActive ? "bg-[hsl(var(--accent)/0.5)]" : "hover:bg-[hsl(var(--accent))]"
46531
+ ),
46532
+ children: item.title || `\u7B2C ${index2 + 1} \u8F6E`
46533
+ },
46534
+ item.id
46535
+ );
46536
+ })
46537
+ }
46538
+ ) }) : null
46577
46539
  ] })
46578
46540
  }
46579
46541
  );
@@ -46764,10 +46726,6 @@ function MessageListBody({
46764
46726
  const blocks = buildMessageListBlocks({
46765
46727
  messages: messages.filter((message) => message.kind !== "compaction"),
46766
46728
  agentLoopNames: agentLoopNameSet,
46767
- // 服务端可能已经说完了(sessionIsStreaming 变 false),但打字机节流
46768
- // 还没把最后这点内容追平——block.isStreaming 驱动一大批"完成态"展示
46769
- // 逻辑(折叠/展开、思考过程是否显示等),提前关掉会出现"字还没打完,
46770
- // 这堆状态已经按完成态收起来了"这种跟视觉进度对不上的观感。
46771
46729
  sessionIsStreaming: sessionIsStreaming || isRevealingAny,
46772
46730
  showContexts: false
46773
46731
  });
@@ -46917,22 +46875,16 @@ function MessageListBody({
46917
46875
  selectEntry: selectNavEntry
46918
46876
  } = useTurnNavigation({
46919
46877
  sessionId,
46920
- // 目录只在最新一条用户发言变化时重拉:往上翻页补进更早的发言、助手继续输出都
46921
- // 不改目录,却会把正在进行的定位误判成过期。窗口被整段替换是另一回事,见 rewriteKey。
46922
46878
  reloadKey: latestUserSpeechEntryId(messages),
46923
46879
  rewriteKey: historyRewriteRevision,
46924
46880
  loadTurnIndex: isSharedSession ? void 0 : session ? () => session.loadTurnIndex() : void 0,
46925
46881
  fallbackItems: sharedNavItems,
46926
- // 会话实例还没建好时没有历史窗口可换,定位按失败处理
46927
46882
  locateEntry: (entryId) => session?.locateEntry(entryId) ?? Promise.resolve(false),
46928
- // 改选一条已加载的发言时不发定位请求,前一次在途的定位得在这里作废。
46929
46883
  cancelPendingLocate: () => session?.cancelPendingLocate(),
46930
46884
  getLoadedEntryElement: (entryId) => {
46931
46885
  const root = containerRef.current;
46932
46886
  return root ? findEntryAnchor(root, entryId) : null;
46933
46887
  },
46934
- // 已加载窗口里有这条发言就算"已加载",哪怕它的行还在虚拟前缀的挂载范围之外:
46935
- // 那些发言该由宿主挂出来再滚,不该发定位请求(分享页更没有定位接口)。
46936
46888
  isEntryLoaded: (entryId) => entryIdToBlockIndex.has(entryId),
46937
46889
  revealEntry: (entryId) => {
46938
46890
  const blockIndex = entryIdToBlockIndex.get(entryId);
@@ -46956,8 +46908,7 @@ function MessageListBody({
46956
46908
  }, [activeTurnId, renderBlocks, turnIdToBlockIndex]);
46957
46909
  const lastNavTurnId = turnNavItems.at(-1)?.id ?? null;
46958
46910
  const layoutSignature = useMemo16(
46959
- () => `${getMessagesMeasureSignature(messages)}|${postChatFollowup ? `${postChatFollowup.assistant_entry_id}:${postChatFollowup.recaption ?? ""}:${postChatFollowup.suggestions.join("")}` : ""}|${// 产物卡片也占高度:漏了它,卡片出现后虚拟列表不会重新测量这一行。
46960
- (postChatFollowup?.final_artifacts ?? []).map((artifact) => artifact.target).join(",")}|${[...resultFeedbackByEntry.values()].map((feedback) => `${feedback.assistant_entry_id}:${feedback.updated_at}`).join(",")}`,
46911
+ () => `${getMessagesMeasureSignature(messages)}|${postChatFollowup ? `${postChatFollowup.assistant_entry_id}:${postChatFollowup.recaption ?? ""}:${postChatFollowup.suggestions.join("")}` : ""}|${(postChatFollowup?.final_artifacts ?? []).map((artifact) => artifact.target).join(",")}|${[...resultFeedbackByEntry.values()].map((feedback) => `${feedback.assistant_entry_id}:${feedback.updated_at}`).join(",")}`,
46961
46912
  [messages, postChatFollowup, resultFeedbackByEntry]
46962
46913
  );
46963
46914
  const followupTurnId = useMemo16(() => {
@@ -48050,10 +48001,7 @@ function useChatActions(sessionId) {
48050
48001
  const [pendingQueueItemId, setPendingQueueItemId] = useState33(null);
48051
48002
  const previousSessionIdRef = useRef28(sessionId);
48052
48003
  const send = useCallback15(
48053
- (msg, targetMode, askuserAnswer, options) => (
48054
- // 等会话就绪再发:等待回答时要按最新状态把输入当作作答
48055
- source.whenReady ? source.whenReady(sessionId, (ready) => sendToSession(ready, msg, targetMode, askuserAnswer, options)) : session ? sendToSession(session, msg, targetMode, askuserAnswer, options) : Promise.resolve(false)
48056
- ),
48004
+ (msg, targetMode, askuserAnswer, options) => source.whenReady ? source.whenReady(sessionId, (ready) => sendToSession(ready, msg, targetMode, askuserAnswer, options)) : session ? sendToSession(session, msg, targetMode, askuserAnswer, options) : Promise.resolve(false),
48057
48005
  [session, sessionId, source]
48058
48006
  );
48059
48007
  const withQueue = useCallback15(
@@ -48380,8 +48328,7 @@ function ChatPanel({
48380
48328
  [sendUserMessage]
48381
48329
  );
48382
48330
  const sendNewUserMessage = useCallback17(
48383
- // 输入框提交走服务端排队;这个面板渲染了队列面板,等待消息看得见。
48384
- (message, options) => sendUserMessage(message, mode, void 0, { ...options, queueWhenRunning: true }),
48331
+ (message, options) => sendUserMessage(message, mode, void 0, options),
48385
48332
  [mode, sendUserMessage]
48386
48333
  );
48387
48334
  const answerQuestion = useCallback17(
@@ -48433,12 +48380,6 @@ function ChatPanel({
48433
48380
  canShareSession,
48434
48381
  planPanel: !lite ? /* @__PURE__ */ jsx50(CurrentPlanPanel, { sessionId, className: "border-b border-[hsl(var(--border))] px-4" }) : null,
48435
48382
  maxWidthClassName: cn("max-w-3xl", classNames?.chatInputInner),
48436
- // 队列面板此刻占位时,输入框上两角改直角,跟它拼成一条完整轮廓。
48437
- // 用面板自己上报的状态,不在宿主侧复算。
48438
- //
48439
- // 必须真的**相邻**才算:`composerBanner`(走 statusBarAddon)渲染在
48440
- // 面板与圆角框之间,两张卡片并不挨着,这时去掉圆角只会让输入框看起来
48441
- // 缺了个角,却没有东西跟它对上。
48442
48383
  mergesWithPanelAbove: queuePanelVisible && !composerBanner,
48443
48384
  className: classNames?.chatInputRoot,
48444
48385
  innerClassName: classNames?.chatInputInner,
@@ -49562,4 +49503,4 @@ use-stick-to-bottom/dist/StickToBottom.js:
49562
49503
  js-yaml/dist/js-yaml.mjs:
49563
49504
  (*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT *)
49564
49505
  */
49565
- //# sourceMappingURL=chunk-66V4EOSO.js.map
49506
+ //# sourceMappingURL=chunk-M5NAFIU4.js.map