@tangle-network/sandbox-ui 0.3.7 → 0.3.10

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 (39) hide show
  1. package/dist/active-sessions-store-CeOmXgv5.d.ts +85 -0
  2. package/dist/artifact-pane-Bh45Ssco.d.ts +24 -0
  3. package/dist/{chat-container-B34uj-J1.d.ts → chat-container-Dn1jWtWo.d.ts} +15 -3
  4. package/dist/chat.d.ts +16 -4
  5. package/dist/chat.js +2 -2
  6. package/dist/{chunk-PXRPYAMM.js → chunk-6H3EFUUC.js} +96 -74
  7. package/dist/{chunk-WUR652Y3.js → chunk-72UEKFZ2.js} +113 -89
  8. package/dist/{chunk-5LV6DZZF.js → chunk-FOQTE67I.js} +278 -21
  9. package/dist/chunk-MGCVTFKB.js +10910 -0
  10. package/dist/chunk-OEX7NZE3.js +321 -0
  11. package/dist/chunk-Q56BYXQF.js +61 -0
  12. package/dist/{chunk-ZSNOGOUX.js → chunk-RQOX5JRR.js} +541 -76
  13. package/dist/{chunk-PDV7W4NY.js → chunk-SULQQJPB.js} +1 -56
  14. package/dist/chunk-W4LM3QYZ.js +54 -0
  15. package/dist/{chunk-JF6E2DS5.js → chunk-ZYGWTIWO.js} +171 -155
  16. package/dist/document-editor-pane-Bk-9MQmw.d.ts +116 -0
  17. package/dist/document-editor-pane-GRIQOJHB.js +11 -0
  18. package/dist/editor.d.ts +7 -84
  19. package/dist/editor.js +18 -699
  20. package/dist/{expanded-tool-detail-BDi_h_dZ.d.ts → expanded-tool-detail-DM5M_T9h.d.ts} +10 -2
  21. package/dist/{file-tabs-CmaoDVBI.d.ts → file-tabs-BLfxfmAH.d.ts} +1 -22
  22. package/dist/files.d.ts +25 -3
  23. package/dist/files.js +2 -1
  24. package/dist/hooks.d.ts +3 -1
  25. package/dist/hooks.js +6 -1
  26. package/dist/index.d.ts +12 -6
  27. package/dist/index.js +21 -8
  28. package/dist/pages.js +4 -2
  29. package/dist/primitives.js +4 -2
  30. package/dist/run.d.ts +1 -1
  31. package/dist/run.js +1 -1
  32. package/dist/sdk-hooks.d.ts +32 -1
  33. package/dist/sdk-hooks.js +6 -1
  34. package/dist/stores.d.ts +1 -0
  35. package/dist/stores.js +60 -1
  36. package/dist/types.d.ts +2 -0
  37. package/dist/workspace.d.ts +84 -6
  38. package/dist/workspace.js +10 -4
  39. package/package.json +17 -6
@@ -759,7 +759,8 @@ var InlineToolItem = memo9(
759
759
  renderToolDetail,
760
760
  groupPosition = "single",
761
761
  className,
762
- contentClassName
762
+ contentClassName,
763
+ actions
763
764
  }) => {
764
765
  const [open, setOpen] = useState3(false);
765
766
  const meta = getToolDisplayMetadata(part);
@@ -780,49 +781,59 @@ var InlineToolItem = memo9(
780
781
  last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
781
782
  }[groupPosition];
782
783
  return /* @__PURE__ */ jsxs10(Collapsible.Root, { open, onOpenChange: setOpen, children: [
783
- /* @__PURE__ */ jsx11(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
784
- "button",
785
- {
786
- className: cn(
787
- "w-full border text-left transition-colors",
788
- "border-[var(--border-subtle)] bg-[var(--bg-card)] hover:border-[var(--border-accent-hover)] hover:bg-[var(--bg-hover)]/35",
789
- open && "border-[var(--border-accent)] bg-[var(--bg-hover)]/30",
790
- shapeClass,
791
- className
792
- ),
793
- children: [
794
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 px-3 py-3", children: [
795
- /* @__PURE__ */ jsx11(
796
- "div",
797
- {
798
- className: cn(
799
- "flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
800
- isRunning && "border-[var(--border-accent)] bg-[var(--brand-cool)]/12 text-[var(--brand-cool)]",
801
- isComplete && "border-emerald-500/30 bg-emerald-500/12 text-emerald-200",
802
- isError && "border-red-500/30 bg-red-500/10 text-red-200",
803
- !isRunning && !isComplete && !isError && "border-[var(--border-subtle)] bg-[var(--bg-section)] text-[var(--text-muted)]"
804
- ),
805
- children: isRunning ? /* @__PURE__ */ jsx11(Loader24, { className: "h-4 w-4 animate-spin" }) : isComplete ? /* @__PURE__ */ jsx11(CheckCircle2, { className: "h-4 w-4" }) : isError ? /* @__PURE__ */ jsx11(AlertCircle2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx11(DefaultIcon, { className: "h-4 w-4" })
806
- }
807
- ),
808
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
809
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
810
- /* @__PURE__ */ jsx11("span", { className: "truncate text-sm font-medium text-[var(--text-primary)]", children: meta.title }),
811
- isError ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-red-500/30 bg-red-500/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-red-200", children: "Failed" }) : null,
812
- isRunning ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-[var(--border-accent)] bg-[var(--brand-cool)]/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-[var(--brand-cool)]", children: "Running" }) : null
784
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-2", children: [
785
+ /* @__PURE__ */ jsx11(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
786
+ "button",
787
+ {
788
+ className: cn(
789
+ "w-full border text-left transition-colors",
790
+ "border-[var(--border-subtle)] bg-[var(--bg-card)] hover:border-[var(--border-accent-hover)] hover:bg-[var(--bg-hover)]/35",
791
+ open && "border-[var(--border-accent)] bg-[var(--bg-hover)]/30",
792
+ shapeClass,
793
+ className
794
+ ),
795
+ children: [
796
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 px-3 py-3", children: [
797
+ /* @__PURE__ */ jsx11(
798
+ "div",
799
+ {
800
+ className: cn(
801
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
802
+ isRunning && "border-[var(--border-accent)] bg-[var(--brand-cool)]/12 text-[var(--brand-cool)]",
803
+ isComplete && "border-emerald-500/30 bg-emerald-500/12 text-emerald-200",
804
+ isError && "border-red-500/30 bg-red-500/10 text-red-200",
805
+ !isRunning && !isComplete && !isError && "border-[var(--border-subtle)] bg-[var(--bg-section)] text-[var(--text-muted)]"
806
+ ),
807
+ children: isRunning ? /* @__PURE__ */ jsx11(Loader24, { className: "h-4 w-4 animate-spin" }) : isComplete ? /* @__PURE__ */ jsx11(CheckCircle2, { className: "h-4 w-4" }) : isError ? /* @__PURE__ */ jsx11(AlertCircle2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx11(DefaultIcon, { className: "h-4 w-4" })
808
+ }
809
+ ),
810
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
811
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
812
+ /* @__PURE__ */ jsx11("span", { className: "truncate text-sm font-medium text-[var(--text-primary)]", children: meta.title }),
813
+ isError ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-red-500/30 bg-red-500/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-red-200", children: "Failed" }) : null,
814
+ isRunning ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-[var(--border-accent)] bg-[var(--brand-cool)]/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-[var(--brand-cool)]", children: "Running" }) : null
815
+ ] }),
816
+ meta.description ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs font-[var(--font-mono)] text-[var(--text-muted)]", children: meta.description }) : null
813
817
  ] }),
814
- meta.description ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs font-[var(--font-mono)] text-[var(--text-muted)]", children: meta.description }) : null
818
+ /* @__PURE__ */ jsxs10("div", { className: "flex shrink-0 items-center gap-2", children: [
819
+ isRunning && startTime ? /* @__PURE__ */ jsx11(LiveDuration, { startTime }) : null,
820
+ !isRunning && durationMs != null ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-[var(--border-subtle)] bg-[var(--bg-section)] px-2 py-0.5 text-[11px] font-[var(--font-mono)] text-[var(--text-muted)]", children: formatDuration(durationMs) }) : null,
821
+ open ? /* @__PURE__ */ jsx11(ChevronDown2, { className: "h-3.5 w-3.5 text-[var(--text-muted)]" }) : /* @__PURE__ */ jsx11(ChevronRight2, { className: "h-3.5 w-3.5 text-[var(--text-muted)]" })
822
+ ] })
815
823
  ] }),
816
- /* @__PURE__ */ jsxs10("div", { className: "flex shrink-0 items-center gap-2", children: [
817
- isRunning && startTime ? /* @__PURE__ */ jsx11(LiveDuration, { startTime }) : null,
818
- !isRunning && durationMs != null ? /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-[var(--border-subtle)] bg-[var(--bg-section)] px-2 py-0.5 text-[11px] font-[var(--font-mono)] text-[var(--text-muted)]", children: formatDuration(durationMs) }) : null,
819
- open ? /* @__PURE__ */ jsx11(ChevronDown2, { className: "h-3.5 w-3.5 text-[var(--text-muted)]" }) : /* @__PURE__ */ jsx11(ChevronRight2, { className: "h-3.5 w-3.5 text-[var(--text-muted)]" })
820
- ] })
821
- ] }),
822
- errorText && !open ? /* @__PURE__ */ jsx11("div", { className: "border-t border-[var(--border-subtle)] px-3 py-2 text-xs text-red-200", children: errorText }) : null
823
- ]
824
- }
825
- ) }),
824
+ errorText && !open ? /* @__PURE__ */ jsx11("div", { className: "border-t border-[var(--border-subtle)] px-3 py-2 text-xs text-red-200", children: errorText }) : null
825
+ ]
826
+ }
827
+ ) }),
828
+ actions ? /* @__PURE__ */ jsx11(
829
+ "div",
830
+ {
831
+ className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
832
+ onClick: (event) => event.stopPropagation(),
833
+ children: actions
834
+ }
835
+ ) : null
836
+ ] }),
826
837
  /* @__PURE__ */ jsx11(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx11("div", { className: cn("mt-2 pl-4", contentClassName), children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx11(ExpandedToolDetail, { part }) }) })
827
838
  ] });
828
839
  }
@@ -967,14 +978,17 @@ function CategoryBadges({ categories }) {
967
978
  [categories]
968
979
  );
969
980
  if (sorted.length === 0) return null;
970
- return /* @__PURE__ */ jsx13("div", { className: "flex items-center gap-1", children: sorted.map((cat) => {
981
+ return /* @__PURE__ */ jsx13("div", { className: "flex items-center gap-1.5", children: sorted.map((cat) => {
971
982
  const Icon = CATEGORY_ICON_MAP[cat] ?? Settings2;
972
- return /* @__PURE__ */ jsx13(
983
+ return /* @__PURE__ */ jsxs12(
973
984
  "span",
974
985
  {
975
986
  title: cat,
976
- className: "flex h-6 w-6 items-center justify-center rounded-full border border-[var(--border-subtle)] bg-[var(--bg-section)] text-[var(--text-muted)]",
977
- children: /* @__PURE__ */ jsx13(Icon, { className: "h-3.5 w-3.5" })
987
+ className: "flex h-7 items-center gap-1 rounded-full border border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.04),transparent)] px-2 text-[11px] uppercase tracking-[0.12em] text-[var(--text-muted)]",
988
+ children: [
989
+ /* @__PURE__ */ jsx13(Icon, { className: "h-3.5 w-3.5" }),
990
+ /* @__PURE__ */ jsx13("span", { children: cat })
991
+ ]
978
992
  },
979
993
  cat
980
994
  );
@@ -1010,7 +1024,9 @@ var RunGroup = memo11(
1010
1024
  collapsed,
1011
1025
  onToggle,
1012
1026
  branding = DEFAULT_BRANDING,
1013
- renderToolDetail
1027
+ renderToolDetail,
1028
+ headerActions,
1029
+ renderToolActions
1014
1030
  }) => {
1015
1031
  const allParts = useMemo5(() => {
1016
1032
  const parts = [];
@@ -1033,53 +1049,56 @@ var RunGroup = memo11(
1033
1049
  return null;
1034
1050
  }
1035
1051
  return /* @__PURE__ */ jsxs12(Collapsible3.Root, { open: !collapsed, onOpenChange: () => onToggle(), children: [
1036
- /* @__PURE__ */ jsx13(Collapsible3.Trigger, { asChild: true, children: /* @__PURE__ */ jsx13(
1037
- "button",
1038
- {
1039
- className: cn(
1040
- "w-full rounded-[var(--radius-xl)] border px-4 py-3 text-left transition-colors",
1041
- "bg-[var(--bg-card)] hover:bg-[var(--bg-hover)]/28",
1042
- collapsed ? branding.borderClass : "border-[var(--border-subtle)]",
1043
- branding.bgClass
1044
- ),
1045
- children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3", children: [
1046
- /* @__PURE__ */ jsx13(
1047
- "div",
1048
- {
1049
- className: cn(
1050
- "flex h-10 w-10 shrink-0 items-center justify-center rounded-[var(--radius-lg)] border bg-[var(--bg-section)]",
1051
- branding.borderClass
1052
- ),
1053
- children: /* @__PURE__ */ jsx13(Bot2, { className: cn("h-4 w-4", branding.accentClass) })
1054
- }
1052
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-start gap-3", children: [
1053
+ /* @__PURE__ */ jsx13(Collapsible3.Trigger, { asChild: true, children: /* @__PURE__ */ jsx13(
1054
+ "button",
1055
+ {
1056
+ className: cn(
1057
+ "w-full rounded-[calc(var(--radius-xl)+2px)] border px-4 py-3.5 text-left transition-colors shadow-[var(--shadow-card)] backdrop-blur-sm",
1058
+ "bg-[radial-gradient(circle_at_top_left,rgba(96,165,250,0.12),transparent_34%),linear-gradient(180deg,rgba(255,255,255,0.03),transparent_30%),var(--bg-card)] hover:bg-[radial-gradient(circle_at_top_left,rgba(96,165,250,0.16),transparent_34%),linear-gradient(180deg,rgba(255,255,255,0.04),transparent_30%),var(--bg-card)]",
1059
+ collapsed ? branding.borderClass : "border-[var(--border-subtle)]",
1060
+ branding.bgClass
1055
1061
  ),
1056
- /* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
1057
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
1058
- /* @__PURE__ */ jsx13("span", { className: cn("text-sm font-semibold", branding.textClass), children: branding.label }),
1059
- isStreaming ? /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-accent)] bg-[var(--brand-cool)]/10 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--brand-cool)]", children: [
1060
- /* @__PURE__ */ jsx13(Loader25, { className: "h-3 w-3 animate-spin" }),
1061
- "Running"
1062
- ] }) : /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-subtle)] bg-[var(--bg-section)] px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-muted)]", children: [
1063
- /* @__PURE__ */ jsx13(Sparkles, { className: "h-3 w-3" }),
1064
- "Complete"
1062
+ children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3", children: [
1063
+ /* @__PURE__ */ jsx13(
1064
+ "div",
1065
+ {
1066
+ className: cn(
1067
+ "flex h-11 w-11 shrink-0 items-center justify-center rounded-[calc(var(--radius-lg)+2px)] border bg-[linear-gradient(135deg,rgba(82,164,255,0.22),rgba(82,164,255,0.06))] shadow-[var(--shadow-accent)]",
1068
+ branding.borderClass
1069
+ ),
1070
+ children: /* @__PURE__ */ jsx13(Bot2, { className: cn("h-4 w-4", branding.accentClass) })
1071
+ }
1072
+ ),
1073
+ /* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
1074
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
1075
+ /* @__PURE__ */ jsx13("span", { className: cn("text-sm font-semibold tracking-[0.01em]", branding.textClass), children: branding.label }),
1076
+ isStreaming ? /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(82,164,255,0.22),rgba(82,164,255,0.08))] px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--brand-cool)]", children: [
1077
+ /* @__PURE__ */ jsx13(Loader25, { className: "h-3 w-3 animate-spin" }),
1078
+ "Running"
1079
+ ] }) : /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1 rounded-full border border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.04),transparent)] px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-muted)]", children: [
1080
+ /* @__PURE__ */ jsx13(Sparkles, { className: "h-3 w-3" }),
1081
+ "Complete"
1082
+ ] })
1083
+ ] }),
1084
+ /* @__PURE__ */ jsxs12("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-[var(--text-muted)]", children: [
1085
+ renderSummary(run) ? /* @__PURE__ */ jsx13("span", { children: renderSummary(run) }) : null,
1086
+ collapsed && run.summaryText ? /* @__PURE__ */ jsx13("span", { className: "min-w-0 truncate text-[var(--text-secondary)]", children: run.summaryText }) : null
1065
1087
  ] })
1066
1088
  ] }),
1067
- /* @__PURE__ */ jsxs12("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-[var(--text-muted)]", children: [
1068
- renderSummary(run) ? /* @__PURE__ */ jsx13("span", { children: renderSummary(run) }) : null,
1069
- collapsed && run.summaryText ? /* @__PURE__ */ jsx13("span", { className: "min-w-0 truncate text-[var(--text-secondary)]", children: run.summaryText }) : null
1070
- ] })
1071
- ] }),
1072
- /* @__PURE__ */ jsx13(CategoryBadges, { categories: stats.toolCategories }),
1073
- !collapsed ? /* @__PURE__ */ jsx13(ChevronDown4, { className: "h-4 w-4 shrink-0 text-[var(--text-muted)]" }) : /* @__PURE__ */ jsx13(ChevronRight4, { className: "h-4 w-4 shrink-0 text-[var(--text-muted)]" })
1074
- ] })
1075
- }
1076
- ) }),
1077
- collapsed && run.summaryText && /* @__PURE__ */ jsx13("div", { className: "px-4 py-2 text-sm text-[var(--text-muted)] line-clamp-2", children: run.summaryText }),
1089
+ /* @__PURE__ */ jsx13(CategoryBadges, { categories: stats.toolCategories }),
1090
+ !collapsed ? /* @__PURE__ */ jsx13(ChevronDown4, { className: "h-4 w-4 shrink-0 text-[var(--text-muted)]" }) : /* @__PURE__ */ jsx13(ChevronRight4, { className: "h-4 w-4 shrink-0 text-[var(--text-muted)]" })
1091
+ ] })
1092
+ }
1093
+ ) }),
1094
+ headerActions ? /* @__PURE__ */ jsx13("div", { className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1", children: headerActions }) : null
1095
+ ] }),
1096
+ collapsed && run.summaryText && /* @__PURE__ */ jsx13("div", { className: "px-4 py-2 text-sm leading-6 text-[var(--text-muted)] line-clamp-2", children: run.summaryText }),
1078
1097
  /* @__PURE__ */ jsx13(Collapsible3.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx13(
1079
1098
  "div",
1080
1099
  {
1081
1100
  className: cn(
1082
- "mt-2 space-y-2 rounded-[var(--radius-xl)] border border-[var(--border-subtle)] p-3",
1101
+ "mt-2 space-y-3 rounded-[calc(var(--radius-xl)+2px)] border border-[var(--border-subtle)] p-3.5 shadow-[var(--shadow-card)]",
1083
1102
  branding.containerBgClass
1084
1103
  ),
1085
1104
  children: allParts.map(({ part, msgId, index }, partIndex) => {
@@ -1090,7 +1109,12 @@ var RunGroup = memo11(
1090
1109
  {
1091
1110
  part,
1092
1111
  renderToolDetail,
1093
- groupPosition: getToolGroupPosition(partIndex, allParts)
1112
+ groupPosition: getToolGroupPosition(partIndex, allParts),
1113
+ actions: renderToolActions?.(part, {
1114
+ run,
1115
+ messageId: msgId,
1116
+ partIndex: index
1117
+ })
1094
1118
  },
1095
1119
  key
1096
1120
  );
@@ -1109,7 +1133,7 @@ var RunGroup = memo11(
1109
1133
  return /* @__PURE__ */ jsx13(
1110
1134
  "div",
1111
1135
  {
1112
- className: "rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-4 py-4",
1136
+ className: "rounded-[calc(var(--radius-lg)+2px)] border border-[var(--border-subtle)] bg-[radial-gradient(circle_at_top_left,rgba(96,165,250,0.08),transparent_36%),linear-gradient(180deg,rgba(255,255,255,0.03),transparent_30%),var(--bg-card)] px-4 py-4",
1113
1137
  children: /* @__PURE__ */ jsx13(Markdown, { children: part.text })
1114
1138
  },
1115
1139
  key
@@ -1,6 +1,17 @@
1
1
  import {
2
2
  parseToolEvent
3
3
  } from "./chunk-CCKNIAS7.js";
4
+ import {
5
+ bumpActiveSessionActivity,
6
+ registerActiveSession,
7
+ setActiveSessionAttention,
8
+ setActiveSessionConnection,
9
+ setActiveSessionError,
10
+ setActiveSessionRunning,
11
+ setForegroundActiveSession,
12
+ unregisterActiveSession,
13
+ updateActiveSessionMeta
14
+ } from "./chunk-OEX7NZE3.js";
4
15
 
5
16
  // src/hooks/use-tool-call-stream.ts
6
17
  import { useState, useCallback, useRef } from "react";
@@ -744,8 +755,252 @@ function useSdkSession({
744
755
  };
745
756
  }
746
757
 
758
+ // src/hooks/use-realtime-session.ts
759
+ import { createElement, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
760
+ function parseEvent(message) {
761
+ try {
762
+ const parsed = JSON.parse(message);
763
+ return typeof parsed?.type === "string" ? parsed : null;
764
+ } catch {
765
+ return null;
766
+ }
767
+ }
768
+ function eventTimestamp(event) {
769
+ const rootTimestamp = event.timestamp;
770
+ if (typeof rootTimestamp === "number" && Number.isFinite(rootTimestamp)) {
771
+ return rootTimestamp;
772
+ }
773
+ const raw = event.data?.timestamp ?? event.data?.ts ?? event.data?.time ?? event.data?.eventAt;
774
+ if (typeof raw === "number" && Number.isFinite(raw)) return raw;
775
+ return null;
776
+ }
777
+ function resolveErrorMessage(event) {
778
+ const message = event.data?.message;
779
+ return typeof message === "string" && message.length > 0 ? message : null;
780
+ }
781
+ function updateStoreFromEvent(sessionId, event) {
782
+ const lastEventAt = eventTimestamp(event) ?? Date.now();
783
+ bumpActiveSessionActivity(sessionId, { lastEventAt });
784
+ if (event.type === "session.run.started") {
785
+ setActiveSessionRunning(sessionId, true, { lastEventAt });
786
+ return;
787
+ }
788
+ if (event.type === "session.run.completed" || event.type === "done" || event.type === "result") {
789
+ setActiveSessionRunning(sessionId, false, { lastEventAt });
790
+ return;
791
+ }
792
+ if (event.type === "session.attention") {
793
+ setActiveSessionAttention(sessionId, true, { lastEventAt });
794
+ return;
795
+ }
796
+ if (event.type === "error" || event.type === "session.run.failed") {
797
+ setActiveSessionError(sessionId, resolveErrorMessage(event) ?? "Session error");
798
+ return;
799
+ }
800
+ }
801
+ function useRealtimeSession({
802
+ sessionId,
803
+ projectId = null,
804
+ projectLabel,
805
+ title,
806
+ href,
807
+ metadata,
808
+ connectUrl,
809
+ enabled = true,
810
+ foreground = true,
811
+ keepRegistered = true,
812
+ reconnect = true,
813
+ reconnectIntervalMs = 1500,
814
+ maxReconnectAttempts = Infinity,
815
+ transportMode = "websocket",
816
+ onEvent,
817
+ onOpen,
818
+ onClose,
819
+ onError
820
+ }) {
821
+ const [connectionState, setConnectionState] = useState4("disconnected");
822
+ const [lastError, setLastError] = useState4(null);
823
+ const [reconnectAttempts, setReconnectAttempts] = useState4(0);
824
+ const socketRef = useRef4(null);
825
+ const timerRef = useRef4(null);
826
+ const reconnectAttemptsRef = useRef4(0);
827
+ const shouldReconnectRef = useRef4(true);
828
+ const registration = useMemo2(
829
+ () => ({
830
+ sessionId,
831
+ projectId,
832
+ projectLabel,
833
+ title,
834
+ href,
835
+ metadata
836
+ }),
837
+ [href, metadata, projectId, projectLabel, sessionId, title]
838
+ );
839
+ useEffect2(() => {
840
+ if (!sessionId || !keepRegistered) return void 0;
841
+ registerActiveSession(registration);
842
+ return () => {
843
+ unregisterActiveSession(sessionId);
844
+ };
845
+ }, [keepRegistered, registration, sessionId]);
846
+ useEffect2(() => {
847
+ if (!sessionId || !keepRegistered) return;
848
+ updateActiveSessionMeta(sessionId, {
849
+ projectId,
850
+ projectLabel,
851
+ title,
852
+ href,
853
+ metadata
854
+ });
855
+ }, [href, keepRegistered, metadata, projectId, projectLabel, sessionId, title]);
856
+ useEffect2(() => {
857
+ if (!sessionId || !foreground) return void 0;
858
+ setForegroundActiveSession(sessionId);
859
+ return () => {
860
+ setForegroundActiveSession(null);
861
+ };
862
+ }, [foreground, sessionId]);
863
+ useEffect2(() => {
864
+ if (!enabled || !sessionId || !connectUrl || typeof window === "undefined") {
865
+ setConnectionState("disconnected");
866
+ if (sessionId) {
867
+ setActiveSessionConnection(sessionId, {
868
+ connectionState: "disconnected",
869
+ reconnectState: "idle",
870
+ transportMode
871
+ });
872
+ }
873
+ return void 0;
874
+ }
875
+ shouldReconnectRef.current = true;
876
+ const clearReconnectTimer = () => {
877
+ if (timerRef.current != null) {
878
+ window.clearTimeout(timerRef.current);
879
+ timerRef.current = null;
880
+ }
881
+ };
882
+ const connect = () => {
883
+ clearReconnectTimer();
884
+ setConnectionState(reconnectAttemptsRef.current > 0 ? "reconnecting" : "connecting");
885
+ setActiveSessionConnection(sessionId, {
886
+ connectionState: reconnectAttemptsRef.current > 0 ? "reconnecting" : "connecting",
887
+ reconnectState: reconnectAttemptsRef.current > 0 ? "reconnecting" : "idle",
888
+ transportMode,
889
+ lastError: null
890
+ });
891
+ const socket = new window.WebSocket(connectUrl);
892
+ socketRef.current = socket;
893
+ socket.onopen = () => {
894
+ reconnectAttemptsRef.current = 0;
895
+ setReconnectAttempts(0);
896
+ setLastError(null);
897
+ setConnectionState("connected");
898
+ registerActiveSession(registration);
899
+ setActiveSessionConnection(sessionId, {
900
+ connectionState: "connected",
901
+ reconnectState: "idle",
902
+ transportMode,
903
+ lastError: null,
904
+ lastEventAt: Date.now()
905
+ });
906
+ onOpen?.();
907
+ };
908
+ socket.onmessage = (message) => {
909
+ const event = parseEvent(message.data);
910
+ if (!event) return;
911
+ registerActiveSession(registration);
912
+ updateStoreFromEvent(sessionId, event);
913
+ onEvent?.(event);
914
+ };
915
+ socket.onerror = () => {
916
+ const nextError = "Realtime session connection error";
917
+ setLastError(nextError);
918
+ setConnectionState("error");
919
+ setActiveSessionConnection(sessionId, {
920
+ connectionState: "error",
921
+ reconnectState: reconnect ? "reconnecting" : "failed",
922
+ transportMode,
923
+ lastError: nextError
924
+ });
925
+ onError?.(new Error(nextError));
926
+ };
927
+ socket.onclose = () => {
928
+ socketRef.current = null;
929
+ onClose?.();
930
+ if (!shouldReconnectRef.current || !reconnect) {
931
+ setConnectionState("disconnected");
932
+ setActiveSessionConnection(sessionId, {
933
+ connectionState: "disconnected",
934
+ reconnectState: "idle",
935
+ transportMode
936
+ });
937
+ return;
938
+ }
939
+ reconnectAttemptsRef.current += 1;
940
+ setReconnectAttempts(reconnectAttemptsRef.current);
941
+ if (reconnectAttemptsRef.current > maxReconnectAttempts) {
942
+ setConnectionState("error");
943
+ setActiveSessionConnection(sessionId, {
944
+ connectionState: "error",
945
+ reconnectState: "failed",
946
+ transportMode,
947
+ lastError: "Unable to reconnect to realtime session"
948
+ });
949
+ return;
950
+ }
951
+ setConnectionState("reconnecting");
952
+ timerRef.current = window.setTimeout(connect, reconnectIntervalMs);
953
+ };
954
+ };
955
+ connect();
956
+ return () => {
957
+ shouldReconnectRef.current = false;
958
+ clearReconnectTimer();
959
+ const socket = socketRef.current;
960
+ socketRef.current = null;
961
+ if (socket && socket.readyState < WebSocket.CLOSING) {
962
+ socket.close();
963
+ }
964
+ };
965
+ }, [
966
+ connectUrl,
967
+ enabled,
968
+ maxReconnectAttempts,
969
+ onClose,
970
+ onError,
971
+ onEvent,
972
+ onOpen,
973
+ reconnect,
974
+ reconnectIntervalMs,
975
+ registration,
976
+ sessionId,
977
+ transportMode
978
+ ]);
979
+ return {
980
+ connectionState,
981
+ lastError,
982
+ reconnectAttempts,
983
+ isConnected: connectionState === "connected"
984
+ };
985
+ }
986
+ function RealtimeSessionRegistryItem(props) {
987
+ useRealtimeSession({
988
+ ...props,
989
+ foreground: props.foreground ?? false
990
+ });
991
+ return null;
992
+ }
993
+ function RealtimeSessionRegistry({ sessions }) {
994
+ return sessions.map(
995
+ (session) => createElement(RealtimeSessionRegistryItem, {
996
+ key: session.key ?? session.sessionId,
997
+ ...session
998
+ })
999
+ );
1000
+ }
1001
+
747
1002
  // src/hooks/use-session-stream.ts
748
- import { useCallback as useCallback4, useEffect as useEffect2, useRef as useRef4, useState as useState4 } from "react";
1003
+ import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef5, useState as useState5 } from "react";
749
1004
  var _insertionCounter = 0;
750
1005
  function mapApiMessage(msg) {
751
1006
  const created = msg.info.timestamp ? new Date(msg.info.timestamp).getTime() : Date.now();
@@ -795,13 +1050,13 @@ function useSessionStream({
795
1050
  sessionId,
796
1051
  enabled = true
797
1052
  }) {
798
- const [messages, setMessages] = useState4([]);
799
- const [partMap, setPartMap] = useState4({});
800
- const [isStreaming, setIsStreaming] = useState4(false);
801
- const [error, setError] = useState4(null);
802
- const [connected, setConnected] = useState4(false);
803
- const abortRef = useRef4(null);
804
- const streamingMsgIdRef = useRef4(null);
1053
+ const [messages, setMessages] = useState5([]);
1054
+ const [partMap, setPartMap] = useState5({});
1055
+ const [isStreaming, setIsStreaming] = useState5(false);
1056
+ const [error, setError] = useState5(null);
1057
+ const [connected, setConnected] = useState5(false);
1058
+ const abortRef = useRef5(null);
1059
+ const streamingMsgIdRef = useRef5(null);
805
1060
  const refetch = useCallback4(async () => {
806
1061
  if (!token || !sessionId || !apiUrl) return;
807
1062
  try {
@@ -988,7 +1243,7 @@ function useSessionStream({
988
1243
  setError(msg);
989
1244
  }
990
1245
  }, [apiUrl, token, sessionId]);
991
- useEffect2(() => {
1246
+ useEffect3(() => {
992
1247
  if (!enabled || !token || !sessionId) return;
993
1248
  refetch();
994
1249
  connectSSE();
@@ -1001,12 +1256,12 @@ function useSessionStream({
1001
1256
  }
1002
1257
 
1003
1258
  // src/hooks/use-dropdown-menu.ts
1004
- import { useEffect as useEffect3, useRef as useRef5, useState as useState5 } from "react";
1259
+ import { useEffect as useEffect4, useRef as useRef6, useState as useState6 } from "react";
1005
1260
  function useDropdownMenu(options) {
1006
1261
  const closeOnEsc = options?.closeOnEsc ?? true;
1007
- const [open, setOpen] = useState5(false);
1008
- const ref = useRef5(null);
1009
- useEffect3(() => {
1262
+ const [open, setOpen] = useState6(false);
1263
+ const ref = useRef6(null);
1264
+ useEffect4(() => {
1010
1265
  function handleClick(e) {
1011
1266
  if (ref.current && !ref.current.contains(e.target)) {
1012
1267
  setOpen(false);
@@ -1017,7 +1272,7 @@ function useDropdownMenu(options) {
1017
1272
  }
1018
1273
  return () => document.removeEventListener("mousedown", handleClick);
1019
1274
  }, [open]);
1020
- useEffect3(() => {
1275
+ useEffect4(() => {
1021
1276
  if (!open || !closeOnEsc) return;
1022
1277
  function handleKey(e) {
1023
1278
  if (e.key === "Escape") setOpen(false);
@@ -1035,7 +1290,7 @@ function useDropdownMenu(options) {
1035
1290
  }
1036
1291
 
1037
1292
  // src/hooks/use-sidecar-auth.ts
1038
- import { useState as useState6, useCallback as useCallback5, useEffect as useEffect4, useRef as useRef6 } from "react";
1293
+ import { useState as useState7, useCallback as useCallback5, useEffect as useEffect5, useRef as useRef7 } from "react";
1039
1294
  function storageKey(resourceId, apiUrl) {
1040
1295
  return `sidecar_session_${resourceId}__${apiUrl}`;
1041
1296
  }
@@ -1067,11 +1322,11 @@ function clearSession(resourceId, apiUrl) {
1067
1322
  }
1068
1323
  function useSidecarAuth({ resourceId, apiUrl, signMessage }) {
1069
1324
  const cached = loadSession(resourceId, apiUrl);
1070
- const [token, setToken] = useState6(cached?.token ?? null);
1071
- const [expiresAt, setExpiresAt] = useState6(cached?.expiresAt ?? 0);
1072
- const [isAuthenticating, setIsAuthenticating] = useState6(false);
1073
- const [error, setError] = useState6(null);
1074
- const refreshTimerRef = useRef6(void 0);
1325
+ const [token, setToken] = useState7(cached?.token ?? null);
1326
+ const [expiresAt, setExpiresAt] = useState7(cached?.expiresAt ?? 0);
1327
+ const [isAuthenticating, setIsAuthenticating] = useState7(false);
1328
+ const [error, setError] = useState7(null);
1329
+ const refreshTimerRef = useRef7(void 0);
1075
1330
  const clearCachedToken = useCallback5(() => {
1076
1331
  setToken(null);
1077
1332
  setExpiresAt(0);
@@ -1112,7 +1367,7 @@ function useSidecarAuth({ resourceId, apiUrl, signMessage }) {
1112
1367
  setIsAuthenticating(false);
1113
1368
  }
1114
1369
  }, [resourceId, apiUrl, signMessage, clearCachedToken]);
1115
- useEffect4(() => {
1370
+ useEffect5(() => {
1116
1371
  if (refreshTimerRef.current) {
1117
1372
  clearTimeout(refreshTimerRef.current);
1118
1373
  }
@@ -1147,6 +1402,8 @@ export {
1147
1402
  useToolCallStream,
1148
1403
  useSSEStream,
1149
1404
  useSdkSession,
1405
+ useRealtimeSession,
1406
+ RealtimeSessionRegistry,
1150
1407
  useSessionStream,
1151
1408
  useDropdownMenu,
1152
1409
  useSidecarAuth