@opengeni/react 0.45.0 → 0.48.0

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 (141) hide show
  1. package/README.md +68 -12
  2. package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
  3. package/dist/chunk-FK6VG4LL.js.map +1 -0
  4. package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
  5. package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
  6. package/dist/chunk-I4MPFDRP.js.map +1 -0
  7. package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
  8. package/dist/chunk-KZ73RL76.js.map +1 -0
  9. package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
  10. package/dist/chunk-LHLYWG5R.js.map +1 -0
  11. package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
  12. package/dist/chunk-NJ7M2B6Z.js.map +1 -0
  13. package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
  14. package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
  15. package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
  16. package/dist/chunk-OL6QVXGF.js.map +1 -0
  17. package/dist/chunk-VZTQ73XT.js +86 -0
  18. package/dist/chunk-VZTQ73XT.js.map +1 -0
  19. package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
  20. package/dist/chunk-WYA65Y3F.js.map +1 -0
  21. package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
  22. package/dist/chunk-XCNTXWBB.js.map +1 -0
  23. package/dist/client.d.ts +1 -1
  24. package/dist/components/chat-composer.d.ts +7 -2
  25. package/dist/components/composer-transcription-control.d.ts +2 -0
  26. package/dist/components/composer.d.ts +14 -0
  27. package/dist/components/machines/machine-detail.d.ts +3 -1
  28. package/dist/components/machines-dashboard.d.ts +3 -3
  29. package/dist/components/message-timeline.d.ts +12 -2
  30. package/dist/components/sandbox-files.d.ts +2 -2
  31. package/dist/components/sandbox-terminal.d.ts +29 -0
  32. package/dist/components/sandbox-workspace.d.ts +5 -1
  33. package/dist/components/workspace-dock.d.ts +3 -1
  34. package/dist/composer.d.ts +2 -2
  35. package/dist/composer.js +6 -6
  36. package/dist/hooks/internal.d.ts +6 -0
  37. package/dist/hooks/use-codex-accounts.d.ts +1 -1
  38. package/dist/hooks/use-environments.d.ts +10 -4
  39. package/dist/hooks/use-machines.d.ts +7 -0
  40. package/dist/hooks/use-sandbox-files.d.ts +19 -0
  41. package/dist/hooks/use-sandbox-git.d.ts +7 -0
  42. package/dist/hooks/use-transcription.d.ts +2 -2
  43. package/dist/hooks/use-voice-input.d.ts +13 -4
  44. package/dist/index.d.ts +6 -5
  45. package/dist/index.js +904 -538
  46. package/dist/index.js.map +1 -1
  47. package/dist/lib/composer-responsive-context.d.ts +9 -0
  48. package/dist/lib/use-portal-token-style.d.ts +14 -3
  49. package/dist/machines.js +2 -2
  50. package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
  51. package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
  52. package/dist/realtime/realtime-control.d.ts +9 -0
  53. package/dist/realtime.js +29 -32
  54. package/dist/realtime.js.map +1 -1
  55. package/dist/session-ui.js +5 -5
  56. package/dist/session.js +4 -4
  57. package/dist/timeline/activity-rail.d.ts +3 -2
  58. package/dist/timeline/index.d.ts +2 -2
  59. package/dist/timeline/parsers.d.ts +3 -3
  60. package/dist/timeline/registry.d.ts +3 -0
  61. package/dist/timeline/screenshot-lightbox.d.ts +1 -1
  62. package/dist/timeline/types.d.ts +4 -0
  63. package/dist/voice-recording-store.d.ts +8 -2
  64. package/package.json +20 -4
  65. package/src/client.ts +3 -0
  66. package/src/components/chat-composer.tsx +12 -2
  67. package/src/components/code-editor.tsx +1 -1
  68. package/src/components/command-palette.tsx +1 -1
  69. package/src/components/composer-transcription-control.tsx +41 -16
  70. package/src/components/composer.tsx +52 -26
  71. package/src/components/copy-button.tsx +2 -2
  72. package/src/components/desktop-viewer.tsx +2 -2
  73. package/src/components/file-browser.tsx +39 -17
  74. package/src/components/human-input-form.tsx +2 -2
  75. package/src/components/machine-card.tsx +1 -1
  76. package/src/components/machines/machine-detail.tsx +39 -15
  77. package/src/components/machines-dashboard.tsx +7 -6
  78. package/src/components/message-timeline.tsx +44 -11
  79. package/src/components/model-picker.tsx +2 -2
  80. package/src/components/model-policy-picker.tsx +16 -15
  81. package/src/components/queue-surface-implementation.tsx +20 -16
  82. package/src/components/queue-surface-state.tsx +2 -2
  83. package/src/components/sandbox-files.tsx +140 -60
  84. package/src/components/sandbox-terminal.tsx +24 -5
  85. package/src/components/sandbox-workspace.tsx +180 -142
  86. package/src/components/session-chrome.tsx +14 -14
  87. package/src/components/tooltip.tsx +13 -16
  88. package/src/components/user-message-body.tsx +1 -1
  89. package/src/components/workbench-changes.tsx +4 -4
  90. package/src/components/workspace-dock.tsx +13 -5
  91. package/src/composer.ts +3 -0
  92. package/src/hooks/internal.ts +132 -38
  93. package/src/hooks/use-codex-accounts.ts +4 -4
  94. package/src/hooks/use-environments.ts +24 -5
  95. package/src/hooks/use-file-attachments.ts +70 -32
  96. package/src/hooks/use-goal.ts +17 -5
  97. package/src/hooks/use-machines.ts +47 -1
  98. package/src/hooks/use-sandbox-files.ts +310 -59
  99. package/src/hooks/use-sandbox-git.ts +148 -41
  100. package/src/hooks/use-session-capabilities.ts +35 -24
  101. package/src/hooks/use-session-events.ts +18 -4
  102. package/src/hooks/use-transcription.ts +4 -14
  103. package/src/hooks/use-turn-queue.ts +17 -5
  104. package/src/hooks/use-voice-input.ts +481 -36
  105. package/src/hooks/use-windowed-sections.ts +9 -7
  106. package/src/index.ts +11 -6
  107. package/src/lib/composer-responsive-context.ts +15 -0
  108. package/src/lib/use-portal-token-style.ts +60 -15
  109. package/src/provider.tsx +52 -7
  110. package/src/realtime/dropdown-menu.tsx +15 -19
  111. package/src/realtime/realtime-control.tsx +18 -7
  112. package/src/timeline/activity-rail.tsx +15 -6
  113. package/src/timeline/index.ts +1 -1
  114. package/src/timeline/parsers.ts +33 -20
  115. package/src/timeline/projection.ts +23 -0
  116. package/src/timeline/registry.ts +7 -0
  117. package/src/timeline/screenshot-lightbox.tsx +15 -4
  118. package/src/timeline/shared.tsx +8 -8
  119. package/src/timeline/tool-renderers.tsx +166 -22
  120. package/src/timeline/turn-summary.tsx +6 -6
  121. package/src/timeline/types.ts +4 -0
  122. package/src/voice-recording-store.ts +15 -0
  123. package/styles/compiled.css +5065 -0
  124. package/styles/compiled.d.ts +2 -0
  125. package/styles/effective-tokens.css +27 -0
  126. package/styles/index.css +3 -0
  127. package/styles/responsive.css +196 -0
  128. package/styles/responsive.d.ts +2 -0
  129. package/styles/tokens.css +50 -17
  130. package/dist/chunk-6EDV6YFE.js.map +0 -1
  131. package/dist/chunk-EB67J347.js.map +0 -1
  132. package/dist/chunk-EHSYZ4KP.js.map +0 -1
  133. package/dist/chunk-FD72GJMK.js.map +0 -1
  134. package/dist/chunk-JB5725BI.js +0 -48
  135. package/dist/chunk-JB5725BI.js.map +0 -1
  136. package/dist/chunk-L3EWO3UK.js.map +0 -1
  137. package/dist/chunk-LWR4MXSS.js.map +0 -1
  138. package/dist/chunk-SRFUT2ZU.js.map +0 -1
  139. package/dist/chunk-U3CSCMWA.js.map +0 -1
  140. package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
  141. /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
@@ -0,0 +1,9 @@
1
+ import { type RefObject } from "react";
2
+ /** The measurement surface used by responsive composer chrome. */
3
+ export type ResponsiveBasis = "viewport" | "container";
4
+ export type ComposerResponsiveContextValue = {
5
+ responsiveBasis: ResponsiveBasis;
6
+ rootRef: RefObject<HTMLDivElement | null>;
7
+ };
8
+ export declare const ComposerResponsiveContext: import("react").Context<ComposerResponsiveContextValue | null>;
9
+ export declare function useComposerResponsiveContext(): ComposerResponsiveContextValue | null;
@@ -1,9 +1,20 @@
1
- import { type CSSProperties, type RefObject } from "react";
2
- export type PortalTokenStyle = CSSProperties & Record<`--${string}`, string>;
1
+ import { type CSSProperties, type RefCallback, type RefObject } from "react";
2
+ export type PortalTokenStyle = Pick<CSSProperties, "colorScheme"> & Partial<Record<`--${string}`, string>>;
3
+ export declare const PORTAL_SOURCE_INLINE_SIZE = "--og-portal-source-inline-size";
4
+ /**
5
+ * A callback ref that publishes the currently mounted source element through
6
+ * React state. Unlike a bare mutable ref, late mounts and replacements cause
7
+ * consumers to render and restart their observers without polling.
8
+ */
9
+ export declare function usePortalTokenSource<T extends HTMLElement>(): {
10
+ source: T | null;
11
+ currentRef: RefObject<T | null>;
12
+ ref: RefCallback<T>;
13
+ };
3
14
  /**
4
15
  * Copy the effective SDK tokens across a portal boundary. A locally themed or
5
16
  * rebranded embed cannot rely on CSS inheritance once a portal mounts under
6
17
  * `<body>`. Ancestor theme/class/style mutations and OS color-scheme changes
7
18
  * keep the copied values live.
8
19
  */
9
- export declare function usePortalTokenStyle(sourceRef: RefObject<HTMLElement | null>): PortalTokenStyle;
20
+ export declare function usePortalTokenStyle(source: HTMLElement | null): PortalTokenStyle;
package/dist/machines.js CHANGED
@@ -24,8 +24,8 @@ import {
24
24
  healthPulses,
25
25
  pointsFor,
26
26
  useMachines
27
- } from "./chunk-6EDV6YFE.js";
28
- import "./chunk-EB67J347.js";
27
+ } from "./chunk-OL6QVXGF.js";
28
+ import "./chunk-KZ73RL76.js";
29
29
  import "./chunk-EKZH6IDG.js";
30
30
  import "./chunk-LAKLF4PA.js";
31
31
  import "./chunk-22KP6LR5.js";
@@ -2,10 +2,11 @@ import {
2
2
  QueueErrorAlert,
3
3
  QueueStoppingStatus,
4
4
  requestQueueDraftEdit
5
- } from "./chunk-VCBFUSUZ.js";
5
+ } from "./chunk-O4VXOBGF.js";
6
6
  import {
7
+ usePortalTokenSource,
7
8
  usePortalTokenStyle
8
- } from "./chunk-JB5725BI.js";
9
+ } from "./chunk-VZTQ73XT.js";
9
10
 
10
11
  // src/components/queue-surface-implementation.tsx
11
12
  import {
@@ -38,7 +39,6 @@ import {
38
39
  useCallback,
39
40
  useId,
40
41
  useMemo,
41
- useRef,
42
42
  useState
43
43
  } from "react";
44
44
  import { DropdownMenu } from "radix-ui";
@@ -56,8 +56,9 @@ function QueueSurface({
56
56
  const [replaceDraftFor, setReplaceDraftFor] = useState(null);
57
57
  const [announcement, setAnnouncement] = useState("");
58
58
  const [draggedTurnId, setDraggedTurnId] = useState(null);
59
- const surfaceRef = useRef(null);
60
- const portalTokenStyle = usePortalTokenStyle(surfaceRef);
59
+ const surface = usePortalTokenSource();
60
+ const surfaceRef = surface.currentRef;
61
+ const portalTokenStyle = usePortalTokenStyle(surface.source);
61
62
  const [keyboardDrag, setKeyboardDrag] = useState(null);
62
63
  const count = queue.queue.length;
63
64
  const pendingInputCount = queue.pendingInputs.length;
@@ -97,7 +98,7 @@ function QueueSurface({
97
98
  );
98
99
  if (moved) focusQueueTurn(surfaceRef.current, turnId);
99
100
  },
100
- [queue]
101
+ [queue, surfaceRef]
101
102
  );
102
103
  const onDragEnd = useCallback(
103
104
  (event) => {
@@ -204,7 +205,7 @@ function QueueSurface({
204
205
  return /* @__PURE__ */ jsxs(
205
206
  "div",
206
207
  {
207
- ref: surfaceRef,
208
+ ref: surface.ref,
208
209
  className: "og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6",
209
210
  "data-testid": "queue-surface",
210
211
  children: [
@@ -214,7 +215,7 @@ function QueueSurface({
214
215
  "button",
215
216
  {
216
217
  type: "button",
217
- className: "flex w-full min-w-0 flex-wrap items-center gap-2 px-3 py-2 text-left outline-none transition-colors hover:bg-surface-2/60 focus-visible:bg-surface-2/60 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]",
218
+ className: "flex w-full min-w-0 flex-wrap items-center gap-2 px-3 py-2 text-left outline-hidden transition-colors hover:bg-surface-2/60 focus-visible:bg-surface-2/60 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]",
218
219
  onClick: () => setOpen((value) => !value),
219
220
  "aria-description": !open && totalCount > 0 ? collapsedPreview.summary : void 0,
220
221
  "aria-expanded": open,
@@ -640,7 +641,7 @@ function QueuePrompt({
640
641
  "aria-controls": fullContentId,
641
642
  "aria-expanded": expanded,
642
643
  "aria-label": `${expanded ? "Hide" : "Show"} full content for queued prompt ${index + 1}`,
643
- className: "mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-none focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]",
644
+ className: "mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-hidden focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]",
644
645
  "data-testid": `queue-prompt-disclosure-${index + 1}`,
645
646
  onClick: () => {
646
647
  const next = !expanded;
@@ -780,7 +781,7 @@ function SortableQueueRow({
780
781
  onClick: onSteer,
781
782
  "aria-label": `Steer queued prompt ${index + 1}`,
782
783
  title: "Steer \u2014 interrupt the current turn and send this message now",
783
- className: "inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-og-control font-medium text-fg outline-none transition-[background-color] hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:min-h-[44px] pointer-coarse:min-w-[44px]",
784
+ className: "inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-og-control font-medium text-fg outline-hidden transition-[background-color] hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:min-h-[44px] pointer-coarse:min-w-[44px]",
784
785
  children: [
785
786
  pending === "steer" ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(ZapIcon, { className: "size-3.5" }),
786
787
  /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Steer" })
@@ -795,7 +796,7 @@ function SortableQueueRow({
795
796
  onClick: onDelete,
796
797
  "aria-label": `Delete queued prompt ${index + 1}`,
797
798
  title: "Delete this queued prompt",
798
- className: "inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-none transition-colors hover:bg-surface-2 hover:text-status-failed focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]",
799
+ className: "inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-hidden transition-colors hover:bg-surface-2 hover:text-status-failed focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]",
799
800
  children: pending === "delete" ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Trash2Icon, { className: "size-3.5" })
800
801
  }
801
802
  ),
@@ -806,7 +807,7 @@ function SortableQueueRow({
806
807
  type: "button",
807
808
  disabled: pending !== null,
808
809
  "aria-label": `More actions for queued prompt ${index + 1}`,
809
- className: "inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-none transition-colors hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]",
810
+ className: "inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-hidden transition-colors hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]",
810
811
  children: pending && pending !== "steer" && pending !== "delete" ? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(EllipsisIcon, { className: "size-3.5" })
811
812
  }
812
813
  ) }),
@@ -823,7 +824,7 @@ function SortableQueueRow({
823
824
  /* @__PURE__ */ jsxs(
824
825
  DropdownMenu.Item,
825
826
  {
826
- className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-none focus:bg-surface-2 pointer-coarse:min-h-[44px]",
827
+ className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 pointer-coarse:min-h-[44px]",
827
828
  onSelect: onEdit,
828
829
  children: [
829
830
  /* @__PURE__ */ jsx(PencilIcon, { className: "size-3.5" }),
@@ -836,7 +837,7 @@ function SortableQueueRow({
836
837
  /* @__PURE__ */ jsxs(
837
838
  DropdownMenu.Item,
838
839
  {
839
- className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-none focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
840
+ className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
840
841
  disabled: index === 0,
841
842
  onSelect: () => onMove(0),
842
843
  children: [
@@ -848,7 +849,7 @@ function SortableQueueRow({
848
849
  /* @__PURE__ */ jsx(
849
850
  DropdownMenu.Item,
850
851
  {
851
- className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-none focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
852
+ className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
852
853
  disabled: index === 0,
853
854
  onSelect: () => onMove(index - 1),
854
855
  children: "Move up"
@@ -857,7 +858,7 @@ function SortableQueueRow({
857
858
  /* @__PURE__ */ jsx(
858
859
  DropdownMenu.Item,
859
860
  {
860
- className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-none focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
861
+ className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
861
862
  disabled: index === count - 1,
862
863
  onSelect: () => onMove(index + 1),
863
864
  children: "Move down"
@@ -866,7 +867,7 @@ function SortableQueueRow({
866
867
  /* @__PURE__ */ jsxs(
867
868
  DropdownMenu.Item,
868
869
  {
869
- className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-none focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
870
+ className: "flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]",
870
871
  disabled: index === count - 1,
871
872
  onSelect: () => onMove(count - 1),
872
873
  children: [
@@ -934,4 +935,4 @@ export {
934
935
  QueueSurface,
935
936
  queueComposerCheckoutEnabled
936
937
  };
937
- //# sourceMappingURL=queue-surface-implementation-J4XJFKRW.js.map
938
+ //# sourceMappingURL=queue-surface-implementation-U5JFG7HT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/queue-surface-implementation.tsx"],"sourcesContent":["import {\n DndContext,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragStartEvent,\n type Modifier,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n arrayMove,\n useSortable,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport type { SessionPendingInputPreview, SessionTurn } from \"@opengeni/sdk\";\nimport {\n ArrowDownToLineIcon,\n ArrowUpToLineIcon,\n ChevronDownIcon,\n EllipsisIcon,\n GripVerticalIcon,\n Loader2Icon,\n PencilIcon,\n Trash2Icon,\n ZapIcon,\n} from \"lucide-react\";\nimport {\n useCallback,\n useId,\n useMemo,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n} from \"react\";\n\nimport { DropdownMenu } from \"radix-ui\";\nimport type { ComposerState } from \"../hooks/use-composer\";\nimport type { QueueMutationKind, UseTurnQueueResult } from \"../hooks/use-turn-queue\";\nimport {\n type PortalTokenStyle,\n usePortalTokenSource,\n usePortalTokenStyle,\n} from \"../lib/use-portal-token-style\";\nimport { requestQueueDraftEdit } from \"./queue-draft-policy\";\nimport { QueueErrorAlert, QueueStoppingStatus } from \"./queue-surface-state\";\n\n/** The sole pending-input surface: compact above Goal, Agents, and composer. */\ntype QueueSurfaceCommonProps = {\n /** Focus the composer owned by this queue after checkout/removal. */\n onRequestComposerFocus?: (() => void) | undefined;\n};\n\nexport type QueueSurfaceProps =\n | (QueueSurfaceCommonProps & {\n queue: UseTurnQueueResult;\n composer: ComposerState;\n readOnly?: false | undefined;\n })\n | (QueueSurfaceCommonProps & {\n queue: UseTurnQueueResult;\n composer?: undefined;\n readOnly: true;\n });\n\n/** @internal Pure policy seam for queue/composer embedding tests. */\nexport function queueComposerCheckoutEnabled(\n composer: ComposerState | undefined,\n readOnly: boolean,\n): boolean {\n return !readOnly && composer !== undefined && composer.draftPersistence !== \"disabled\";\n}\n\nexport function QueueSurface({\n queue,\n composer,\n readOnly = false,\n onRequestComposerFocus,\n}: QueueSurfaceProps) {\n const [open, setOpen] = useState(false);\n const [replaceDraftFor, setReplaceDraftFor] = useState<string | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n const [draggedTurnId, setDraggedTurnId] = useState<string | null>(null);\n const surface = usePortalTokenSource<HTMLDivElement>();\n const surfaceRef = surface.currentRef;\n const portalTokenStyle = usePortalTokenStyle(surface.source);\n const [keyboardDrag, setKeyboardDrag] = useState<{\n turnId: string;\n projectedIndex: number;\n } | null>(null);\n const count = queue.queue.length;\n const pendingInputCount = queue.pendingInputs.length;\n const totalCount = count + pendingInputCount;\n const attachedInputIds = queue.pendingInputAttachment?.inputIds ?? [];\n const attachedInputs = queue.pendingInputs.filter((input) => attachedInputIds.includes(input.id));\n const standaloneInputs = queue.pendingInputs.filter(\n (input) => !attachedInputIds.includes(input.id),\n );\n const canEditInComposer = queueComposerCheckoutEnabled(composer, readOnly);\n const collapsedPreview = useMemo(\n () =>\n queuePromptPreview(\n queue.queue[0]?.prompt ?? queue.pendingInputs[0]?.summary ?? \"\",\n QUEUE_COLLAPSED_PREVIEW_CHARACTERS,\n ),\n [queue.pendingInputs, queue.queue],\n );\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));\n\n const displayedQueue = useMemo(() => {\n if (!keyboardDrag) return queue.queue;\n const oldIndex = queue.queue.findIndex((turn) => turn.id === keyboardDrag.turnId);\n if (oldIndex < 0) return queue.queue;\n return arrayMove(queue.queue, oldIndex, keyboardDrag.projectedIndex);\n }, [keyboardDrag, queue.queue]);\n\n const ids = useMemo(() => displayedQueue.map((turn) => turn.id), [displayedQueue]);\n const moveToIndex = useCallback(\n async (turnId: string, nextIndex: number): Promise<void> => {\n const oldIndex = queue.queue.findIndex((turn) => turn.id === turnId);\n if (oldIndex < 0) return;\n const boundedIndex = Math.max(0, Math.min(nextIndex, queue.queue.length - 1));\n if (oldIndex === boundedIndex) return;\n const ordered = arrayMove(queue.queue, oldIndex, boundedIndex);\n const beforeTurnId = ordered[boundedIndex + 1]?.id ?? null;\n const moved = await queue.moveTurn(turnId, beforeTurnId);\n setAnnouncement(\n moved\n ? `Queued prompt moved to position ${boundedIndex + 1}.`\n : \"The queue changed before that prompt could be moved. Refreshed server order.\",\n );\n if (moved) focusQueueTurn(surfaceRef.current, turnId);\n },\n [queue, surfaceRef],\n );\n\n const onDragEnd = useCallback(\n (event: DragEndEvent) => {\n setDraggedTurnId(null);\n const activeId = String(event.active.id);\n const overId = event.over ? String(event.over.id) : null;\n if (!overId || activeId === overId) {\n setAnnouncement(\"Queued prompt returned to its original position.\");\n return;\n }\n const nextIndex = queue.queue.findIndex((turn) => turn.id === overId);\n if (nextIndex >= 0) void moveToIndex(activeId, nextIndex);\n },\n [moveToIndex, queue.queue],\n );\n\n const onDragStart = useCallback(\n (event: DragStartEvent) => {\n setKeyboardDrag(null);\n const turnId = String(event.active.id);\n const position = queue.queue.findIndex((turn) => turn.id === turnId) + 1;\n setDraggedTurnId(turnId);\n setAnnouncement(`Dragging queued prompt ${position} of ${queue.queue.length}.`);\n },\n [queue.queue],\n );\n\n const onHandleKeyDown = useCallback(\n (event: ReactKeyboardEvent<HTMLButtonElement>, turnId: string) => {\n const canonicalIndex = queue.queue.findIndex((turn) => turn.id === turnId);\n if (canonicalIndex < 0) return;\n\n if (!keyboardDrag) {\n if (event.key !== \" \") return;\n event.preventDefault();\n setKeyboardDrag({ turnId, projectedIndex: canonicalIndex });\n setAnnouncement(\n `Lifted queued prompt ${canonicalIndex + 1} of ${count}. Use arrow keys to move it, then press Space to drop.`,\n );\n return;\n }\n if (keyboardDrag.turnId !== turnId) return;\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n setKeyboardDrag(null);\n setAnnouncement(\"Queue reorder cancelled.\");\n return;\n }\n if (event.key === \" \") {\n event.preventDefault();\n const targetIndex = keyboardDrag.projectedIndex;\n setAnnouncement(`Moving queued prompt to position ${targetIndex + 1}.`);\n void moveToIndex(turnId, targetIndex).finally(() => setKeyboardDrag(null));\n return;\n }\n\n const direction = event.key === \"ArrowUp\" ? -1 : event.key === \"ArrowDown\" ? 1 : 0;\n const edge = event.key === \"Home\" ? 0 : event.key === \"End\" ? count - 1 : null;\n if (direction === 0 && edge === null) return;\n event.preventDefault();\n const projectedIndex = Math.max(\n 0,\n Math.min(edge ?? keyboardDrag.projectedIndex + direction, count - 1),\n );\n setKeyboardDrag({ turnId, projectedIndex });\n setAnnouncement(`Queued prompt projected to position ${projectedIndex + 1} of ${count}.`);\n },\n [count, keyboardDrag, moveToIndex, queue.queue],\n );\n\n const edit = useCallback(\n async (turn: SessionTurn, replaceDraft: boolean) => {\n if (!composer || !canEditInComposer) return;\n const restored = await queue.editTurn(turn.id, {\n expectedDraftRevision: composer.draftRevision,\n replaceDraft,\n });\n if (!restored) return;\n composer.applyDraft(restored);\n setReplaceDraftFor(null);\n setAnnouncement(\"Queued prompt moved back to the composer for editing.\");\n window.requestAnimationFrame(() => {\n if (onRequestComposerFocus) {\n onRequestComposerFocus();\n return;\n }\n const input = document.querySelector<HTMLTextAreaElement>(\n 'textarea[aria-label=\"Message the agent\"]',\n );\n input?.scrollIntoView({ block: \"nearest\", behavior: \"smooth\" });\n input?.focus();\n });\n },\n [canEditInComposer, composer, onRequestComposerFocus, queue],\n );\n\n const requestEdit = useCallback(\n (turn: SessionTurn) => {\n if (!composer || !canEditInComposer) return;\n requestQueueDraftEdit(\n composer,\n () => setReplaceDraftFor(turn.id),\n () => void edit(turn, false),\n );\n },\n [canEditInComposer, composer, edit],\n );\n\n if (totalCount === 0 && !queue.stoppingPreviousAttempt && !queue.error && !queue.mutationError)\n return null;\n\n return (\n <div\n ref={surface.ref}\n className=\"og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6\"\n data-testid=\"queue-surface\"\n >\n <div className=\"overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm\">\n {queue.stoppingPreviousAttempt ? <QueueStoppingStatus queue={queue} dividerAfter /> : null}\n <button\n type=\"button\"\n className=\"flex w-full min-w-0 flex-wrap items-center gap-2 px-3 py-2 text-left outline-hidden transition-colors hover:bg-surface-2/60 focus-visible:bg-surface-2/60 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]\"\n onClick={() => setOpen((value) => !value)}\n aria-description={!open && totalCount > 0 ? collapsedPreview.summary : undefined}\n aria-expanded={open}\n aria-label={`${count} queued prompt${count === 1 ? \"\" : \"s\"}${\n pendingInputCount > 0\n ? ` and ${pendingInputCount} pending machine input${pendingInputCount === 1 ? \"\" : \"s\"}`\n : \"\"\n }${readOnly ? \" Read-only\" : \"\"}`}\n >\n <ChevronDownIcon\n aria-hidden=\"true\"\n className={`size-3.5 shrink-0 text-fg-subtle transition-transform ${open ? \"rotate-180\" : \"\"}`}\n />\n <span className=\"text-og-control font-medium text-fg\">\n {count > 0 ? `${count} queued prompt${count === 1 ? \"\" : \"s\"}` : null}\n {count > 0 && pendingInputCount > 0 ? \" · \" : null}\n {pendingInputCount > 0\n ? `${pendingInputCount} incoming update${pendingInputCount === 1 ? \"\" : \"s\"}`\n : null}\n </span>\n {readOnly ? (\n <span className=\"shrink-0 rounded border border-border px-1.5 py-0.5 text-og-xs text-fg-subtle\">\n Read-only\n </span>\n ) : null}\n {!open && totalCount > 0 ? (\n <span\n aria-hidden=\"true\"\n className={`max-w-full truncate text-fg-muted ${\n collapsedPreview.collapsedVisual === collapsedPreview.summary\n ? \"min-w-0 flex-1 text-og-control\"\n : \"shrink-0 text-[10px]\"\n }`}\n data-testid=\"queue-collapsed-preview\"\n dir=\"auto\"\n >\n {collapsedPreview.collapsedVisual}\n </span>\n ) : null}\n {queue.loading ? <Loader2Icon className=\"ml-auto size-3.5 animate-spin\" /> : null}\n </button>\n\n {open && standaloneInputs.length > 0 ? (\n <PendingMachineInputs inputs={standaloneInputs} />\n ) : null}\n\n {open && count > 0 && readOnly ? (\n <ol\n className=\"max-h-[min(30rem,60dvh)] divide-y divide-border overflow-y-auto overscroll-contain border-t border-border\"\n aria-label=\"Queued prompts\"\n data-testid=\"queue-list\"\n >\n {queue.queue.map((turn, index) => (\n <ReadOnlyQueueRow\n key={turn.id}\n turn={turn}\n index={index}\n attachedInputs={\n turn.id === queue.pendingInputAttachment?.turnId ? attachedInputs : []\n }\n onDisclosureChange={(expanded) =>\n setAnnouncement(\n `Full content for queued prompt ${index + 1} ${expanded ? \"shown\" : \"hidden\"}.`,\n )\n }\n />\n ))}\n </ol>\n ) : null}\n\n {open && count > 0 && !readOnly ? (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={[verticalOnly]}\n onDragStart={onDragStart}\n onDragCancel={() => {\n setDraggedTurnId(null);\n setAnnouncement(\"Queue reorder cancelled.\");\n }}\n onDragEnd={onDragEnd}\n >\n <SortableContext items={ids} strategy={verticalListSortingStrategy}>\n <ol\n className=\"max-h-[min(30rem,60dvh)] divide-y divide-border overflow-y-auto overscroll-contain border-t border-border\"\n aria-label=\"Queued prompts\"\n data-testid=\"queue-list\"\n >\n {displayedQueue.map((turn, index) => (\n <SortableQueueRow\n key={turn.id}\n turn={turn}\n index={index}\n count={count}\n attachedInputs={\n turn.id === queue.pendingInputAttachment?.turnId ? attachedInputs : []\n }\n pending={queue.mutationFor(turn.id)}\n confirmingReplace={replaceDraftFor === turn.id}\n keyboardDragging={keyboardDrag?.turnId === turn.id}\n portalTokenStyle={portalTokenStyle}\n onHandleKeyDown={(event) => onHandleKeyDown(event, turn.id)}\n onMove={(nextIndex) => void moveToIndex(turn.id, nextIndex)}\n onEdit={canEditInComposer ? () => requestEdit(turn) : undefined}\n onConfirmReplace={() => void edit(turn, true)}\n onCancelReplace={() => setReplaceDraftFor(null)}\n onSteer={() => {\n void queue.steerTurn(turn.id).then((steered) => {\n setAnnouncement(\n steered\n ? \"Queued prompt is now the next direction.\"\n : \"That prompt changed before it could be steered.\",\n );\n if (steered) {\n focusAfterQueueRemoval(surfaceRef.current, index, onRequestComposerFocus);\n }\n });\n }}\n onDelete={() => {\n void queue.removeTurn(turn.id).then((removed) => {\n setAnnouncement(\n removed\n ? \"Queued prompt deleted.\"\n : \"That prompt changed before it could be deleted.\",\n );\n if (removed) {\n focusAfterQueueRemoval(surfaceRef.current, index, onRequestComposerFocus);\n }\n });\n }}\n onDisclosureChange={(expanded) =>\n setAnnouncement(\n `Full content for queued prompt ${index + 1} ${expanded ? \"shown\" : \"hidden\"}.`,\n )\n }\n />\n ))}\n </ol>\n </SortableContext>\n <DragOverlay modifiers={[verticalOnly]}>\n {draggedTurnId ? (\n <div\n className=\"max-h-20 w-[min(36rem,calc(100vw-2rem))] max-w-[calc(100vw-2rem)] overflow-hidden rounded-md border border-brand/40 bg-surface px-3 py-2 text-og-control text-fg shadow-lg\"\n data-testid=\"queue-drag-overlay\"\n >\n <p\n aria-hidden=\"true\"\n className=\"line-clamp-3 break-all whitespace-pre-wrap [unicode-bidi:plaintext]\"\n dir=\"auto\"\n >\n {\n queuePromptPreview(\n queue.queue.find((turn) => turn.id === draggedTurnId)?.prompt ?? \"\",\n QUEUE_ROW_PREVIEW_CHARACTERS,\n ).summary\n }\n </p>\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n ) : null}\n\n {queue.error || queue.mutationError ? (\n <QueueErrorAlert queue={queue} dividerBefore />\n ) : null}\n </div>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcement}\n </p>\n </div>\n );\n}\n\nfunction PendingMachineInputs({\n inputs,\n attached = false,\n}: {\n inputs: SessionPendingInputPreview[];\n attached?: boolean;\n}) {\n return (\n <section className=\"border-t border-border px-3 py-2\">\n <p className=\"text-og-xs font-medium text-fg-subtle\">\n {attached\n ? `${inputs.length} update${inputs.length === 1 ? \"\" : \"s\"} will join this prompt`\n : \"Incoming updates waiting to run\"}\n </p>\n <ol className=\"mt-1 space-y-1\">\n {inputs.map((input) => (\n <li\n key={input.id}\n className=\"line-clamp-3 break-words text-og-control text-fg\"\n dir=\"auto\"\n >\n <strong className=\"capitalize text-fg-muted\">\n {input.kind.replace(\"_terminal\", \"\").replaceAll(\"_\", \" \")}\n </strong>{\" \"}\n · {input.sourceId}\n {input.summary ? ` — ${input.summary}` : \"\"}\n </li>\n ))}\n </ol>\n </section>\n );\n}\n\nconst QUEUE_ROW_PREVIEW_CHARACTERS = 360;\nconst QUEUE_COLLAPSED_PREVIEW_CHARACTERS = 180;\nconst QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS = 32;\nconst QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS = 32;\nconst QUEUE_VISIBLE_END_IDENTITY_CHARACTERS = 18;\nconst QUEUE_PREVIEW_SEPARATOR = \" … \";\nconst queuePreviewSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\nconst queuePromptNonRenderingCodePoint =\n /[\\p{White_Space}\\p{Control}\\p{Default_Ignorable_Code_Point}]/u;\n\ntype BoundedPromptSample = {\n value: string;\n characters: number;\n truncated: boolean;\n};\n\ntype QueuePromptPreview = {\n summary: string;\n collapsedVisual: string;\n visibleStart: string;\n visibleIdentity: string | null;\n visibleIdentityLabel: \"End\" | \"Safe boundary\" | null;\n isFallback: boolean;\n};\n\n/**\n * Build a bounded head/tail summary of an arbitrary queued prompt. Sampling\n * both ends distinguishes prompts with equal long prefixes. Each sampled edge\n * has a small amount of grapheme context so ordinary emoji/combining sequences\n * can be retained whole. A cluster that exceeds that context is omitted rather\n * than fragmented, and malformed UTF-16 is replaced only in the summary. The\n * durable prompt remains exact and no operation scans or copies it in full.\n */\nfunction queuePromptPreview(prompt: string, maxCharacters: number): QueuePromptPreview {\n const wholePromptProbe = samplePromptStart(prompt, maxCharacters + 1);\n if (!wholePromptProbe.truncated && wholePromptProbe.characters <= maxCharacters) {\n const summary = replaceLoneSurrogates(wholePromptProbe.value);\n return hasVisiblePromptContent(summary)\n ? {\n summary,\n collapsedVisual: summary,\n visibleStart: summary,\n visibleIdentity: null,\n visibleIdentityLabel: null,\n isFallback: false,\n }\n : fallbackPromptPreview(prompt.length, wholePromptProbe.value, wholePromptProbe.value);\n }\n\n const suffixCharacters = Math.min(Math.floor(maxCharacters / 3), 120);\n const prefixCharacters =\n maxCharacters - codePointLength(QUEUE_PREVIEW_SEPARATOR) - suffixCharacters;\n const prefixSample = samplePromptStart(\n prompt,\n prefixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,\n );\n const suffixSample = samplePromptEnd(\n prompt,\n suffixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,\n );\n const prefixSegments = segmentPromptSample(prefixSample.value);\n const suffixSegments = segmentPromptSample(suffixSample.value);\n\n // A cluster at a truncated sampling edge may continue outside the sample.\n // Prefix sampling starts at the true source start, so only its last segment\n // is ambiguous. Suffix sampling ends at the true source end, so its first is.\n if (prefixSample.truncated) prefixSegments.pop();\n if (suffixSample.truncated) {\n let ambiguousSegment = suffixSegments.shift();\n // A locally segmented leading fragment ending in ZWJ can join the next\n // pictographic segment when omitted left context supplies its base. Keep\n // backing off until that uncertainty no longer propagates to the right.\n while (ambiguousSegment?.endsWith(\"\\u200d\") && suffixSegments.length > 0) {\n ambiguousSegment = suffixSegments.shift();\n }\n // Regional Indicator pairing depends on the parity of the preceding run.\n // If that run reaches the unknown sample boundary, omit all of its visible\n // leading segments rather than potentially recombining halves of flags.\n while (suffixSegments[0] && startsWithRegionalIndicator(suffixSegments[0])) {\n suffixSegments.shift();\n }\n }\n\n const prefix = takeWholeGraphemesFromStart(prefixSegments, prefixCharacters);\n const suffix = takeWholeGraphemesFromEnd(suffixSegments, suffixCharacters);\n const reference = boundedPromptSampleReference(\n prompt.length,\n prefixSample.value,\n suffixSample.value,\n );\n\n if (!hasVisiblePromptContent(prefix) && !hasVisiblePromptContent(suffix)) {\n return fallbackPromptPreview(prompt.length, prefixSample.value, suffixSample.value);\n }\n\n const safeSuffix = hasVisiblePromptContent(suffix)\n ? suffix\n : promptPreviewFallbackLabel(reference);\n const summary = `${prefix}${QUEUE_PREVIEW_SEPARATOR}${safeSuffix}`;\n if (!hasVisiblePromptContent(prefix)) {\n return {\n summary,\n collapsedVisual: summary,\n visibleStart: safeSuffix,\n visibleIdentity: null,\n visibleIdentityLabel: null,\n isFallback: false,\n };\n }\n\n const endIdentity = takeWholeGraphemesFromEnd(\n suffixSegments,\n QUEUE_VISIBLE_END_IDENTITY_CHARACTERS,\n );\n return {\n summary,\n collapsedVisual: summary,\n visibleStart: prefix,\n visibleIdentity: hasVisiblePromptContent(endIdentity) ? endIdentity : `ref ${reference}`,\n visibleIdentityLabel: hasVisiblePromptContent(endIdentity) ? \"End\" : \"Safe boundary\",\n isFallback: false,\n };\n}\n\nfunction fallbackPromptPreview(\n promptLength: number,\n startSample: string,\n endSample: string,\n): QueuePromptPreview {\n const reference = boundedPromptSampleReference(promptLength, startSample, endSample);\n const summary = promptPreviewFallbackLabel(reference);\n return {\n summary,\n collapsedVisual: `Omitted · ${reference}`,\n // The complete fallback remains the canonical accessible summary. Narrow\n // collapsed/row layouts paint the bounded reference in a compact truthful\n // form so ellipsis cannot hide the only identifying portion.\n visibleStart: `Omitted · ${reference}`,\n visibleIdentity: null,\n visibleIdentityLabel: null,\n isFallback: true,\n };\n}\n\nfunction promptPreviewFallbackLabel(reference: string): string {\n return `Content omitted at safe boundary · ref ${reference}`;\n}\n\nfunction boundedPromptSampleReference(\n promptLength: number,\n startSample: string,\n endSample: string,\n): string {\n const head = samplePromptStart(startSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;\n const tail = samplePromptEnd(endSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;\n let hash = 0x811c9dc5;\n for (const value of [String(promptLength), head, tail]) {\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193);\n }\n hash ^= 0xffff;\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\").toUpperCase();\n}\n\nfunction hasVisiblePromptContent(value: string): boolean {\n // Callers pass only the already-bounded whole/head/tail preview samples.\n // Default-ignorables and controls can survive trim() while painting no row\n // identity at all (for example ZWJ, VS16, bidi controls, and tag characters).\n for (const character of value) {\n if (!queuePromptNonRenderingCodePoint.test(character)) return true;\n }\n return false;\n}\n\nfunction samplePromptStart(prompt: string, maxCharacters: number): BoundedPromptSample {\n let end = 0;\n let characters = 0;\n while (end < prompt.length && characters < maxCharacters) {\n const first = prompt.charCodeAt(end);\n end +=\n isHighSurrogate(first) &&\n end + 1 < prompt.length &&\n isLowSurrogate(prompt.charCodeAt(end + 1))\n ? 2\n : 1;\n characters += 1;\n }\n return { value: prompt.slice(0, end), characters, truncated: end < prompt.length };\n}\n\nfunction samplePromptEnd(prompt: string, maxCharacters: number): BoundedPromptSample {\n let start = prompt.length;\n let characters = 0;\n while (start > 0 && characters < maxCharacters) {\n start -= 1;\n if (\n isLowSurrogate(prompt.charCodeAt(start)) &&\n start > 0 &&\n isHighSurrogate(prompt.charCodeAt(start - 1))\n ) {\n start -= 1;\n }\n characters += 1;\n }\n return { value: prompt.slice(start), characters, truncated: start > 0 };\n}\n\nfunction segmentPromptSample(sample: string): string[] {\n return Array.from(\n queuePreviewSegmenter.segment(replaceLoneSurrogates(sample)),\n ({ segment }) => segment,\n );\n}\n\nfunction replaceLoneSurrogates(value: string): string {\n let sanitized = \"\";\n for (let index = 0; index < value.length; index += 1) {\n const current = value.charCodeAt(index);\n if (\n isHighSurrogate(current) &&\n index + 1 < value.length &&\n isLowSurrogate(value.charCodeAt(index + 1))\n ) {\n sanitized += value.slice(index, index + 2);\n index += 1;\n } else if (isHighSurrogate(current) || isLowSurrogate(current)) {\n sanitized += \"�\";\n } else {\n sanitized += value[index];\n }\n }\n return sanitized;\n}\n\nfunction takeWholeGraphemesFromStart(segments: string[], maxCharacters: number): string {\n const selected: string[] = [];\n let characters = 0;\n for (const segment of segments) {\n const segmentCharacters = codePointLength(segment);\n if (characters + segmentCharacters > maxCharacters) break;\n selected.push(segment);\n characters += segmentCharacters;\n }\n while (selected.at(-1)?.trim().length === 0) selected.pop();\n return selected.join(\"\");\n}\n\nfunction takeWholeGraphemesFromEnd(segments: string[], maxCharacters: number): string {\n const selected: string[] = [];\n let characters = 0;\n for (let index = segments.length - 1; index >= 0; index -= 1) {\n const segment = segments[index];\n if (!segment) continue;\n const segmentCharacters = codePointLength(segment);\n if (characters + segmentCharacters > maxCharacters) break;\n selected.unshift(segment);\n characters += segmentCharacters;\n }\n while (selected[0]?.trim().length === 0) selected.shift();\n while (selected.at(-1)?.trim().length === 0) selected.pop();\n return selected.join(\"\");\n}\n\nfunction codePointLength(value: string): number {\n let characters = 0;\n for (const _character of value) characters += 1;\n return characters;\n}\n\nfunction startsWithRegionalIndicator(value: string): boolean {\n const codePoint = value.codePointAt(0);\n return codePoint !== undefined && codePoint >= 0x1f1e6 && codePoint <= 0x1f1ff;\n}\n\nfunction isHighSurrogate(codeUnit: number): boolean {\n return codeUnit >= 0xd800 && codeUnit <= 0xdbff;\n}\n\nfunction isLowSurrogate(codeUnit: number): boolean {\n return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;\n}\n\nfunction QueuePrompt({\n prompt,\n index,\n onDisclosureChange,\n}: {\n prompt: string;\n index: number;\n onDisclosureChange: (expanded: boolean) => void;\n}) {\n const [expanded, setExpanded] = useState(false);\n const fullContentId = useId();\n const preview = useMemo(() => queuePromptPreview(prompt, QUEUE_ROW_PREVIEW_CHARACTERS), [prompt]);\n\n return (\n <div className=\"w-full min-w-0 max-w-full\">\n <div\n aria-label={`Queued prompt ${index + 1} summary: ${preview.summary}`}\n className=\"max-w-full overflow-hidden text-og-control leading-5 text-fg\"\n data-testid={`queue-prompt-preview-${index + 1}`}\n dir=\"auto\"\n role=\"note\"\n >\n <span aria-hidden=\"true\" className=\"flex min-w-0 max-w-full items-baseline gap-2 sm:block\">\n <span\n className={`${preview.isFallback ? \"\" : \"line-clamp-1 sm:line-clamp-2\"} min-w-0 flex-1 whitespace-pre-wrap break-all [unicode-bidi:plaintext]`}\n data-testid={`queue-prompt-start-${index + 1}`}\n dir=\"auto\"\n >\n {preview.visibleStart}\n </span>\n {preview.visibleIdentity && preview.visibleIdentityLabel ? (\n <span\n className=\"flex min-w-0 max-w-[70%] shrink-0 items-center gap-1 text-og-xs leading-4 text-fg-muted sm:mt-0.5 sm:max-w-full\"\n data-testid={`queue-prompt-identity-row-${index + 1}`}\n >\n <span className=\"shrink-0 font-medium text-fg-subtle\">\n {preview.visibleIdentityLabel}\n </span>\n <span\n className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-mono [unicode-bidi:plaintext]\"\n data-testid={`queue-prompt-identity-${index + 1}`}\n dir=\"auto\"\n >\n {preview.visibleIdentity}\n </span>\n </span>\n ) : null}\n </span>\n </div>\n <button\n type=\"button\"\n aria-controls={fullContentId}\n aria-expanded={expanded}\n aria-label={`${expanded ? \"Hide\" : \"Show\"} full content for queued prompt ${index + 1}`}\n className=\"mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-hidden focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]\"\n data-testid={`queue-prompt-disclosure-${index + 1}`}\n onClick={() => {\n const next = !expanded;\n setExpanded(next);\n onDisclosureChange(next);\n }}\n >\n <ChevronDownIcon\n aria-hidden=\"true\"\n className={`size-3 shrink-0 transition-transform ${expanded ? \"rotate-180\" : \"\"}`}\n />\n {expanded ? \"Hide full prompt\" : \"View full prompt\"}\n </button>\n {expanded ? (\n <pre\n id={fullContentId}\n role=\"region\"\n aria-label={`Full content for queued prompt ${index + 1}`}\n className=\"mt-1.5 max-h-64 w-full min-w-0 max-w-full overflow-auto overscroll-contain rounded-md border border-border bg-surface-2/60 p-2 whitespace-pre-wrap break-all font-mono text-og-control leading-5 text-fg [unicode-bidi:plaintext]\"\n data-testid={`queue-prompt-full-${index + 1}`}\n dir=\"auto\"\n tabIndex={0}\n >\n {prompt}\n </pre>\n ) : null}\n </div>\n );\n}\n\nfunction ReadOnlyQueueRow({\n turn,\n index,\n attachedInputs,\n onDisclosureChange,\n}: {\n turn: SessionTurn;\n index: number;\n attachedInputs: SessionPendingInputPreview[];\n onDisclosureChange: (expanded: boolean) => void;\n}) {\n return (\n <li className=\"flex min-w-0 items-start gap-2 bg-surface px-3 py-2\">\n <span className=\"mt-1 shrink-0 font-mono text-og-xs text-fg-subtle\">{index + 1}</span>\n <div className=\"min-w-0 flex-1\">\n <QueuePrompt prompt={turn.prompt} index={index} onDisclosureChange={onDisclosureChange} />\n {attachedInputs.length > 0 ? (\n <PendingMachineInputs inputs={attachedInputs} attached />\n ) : null}\n <div className=\"mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-og-xs text-fg-subtle\">\n {turn.resources.length > 0 ? (\n <span className=\"shrink-0\">\n {turn.resources.length} resource{turn.resources.length === 1 ? \"\" : \"s\"}\n </span>\n ) : null}\n {turn.tools.length > 0 ? (\n <span className=\"shrink-0\">\n {turn.tools.length} tool{turn.tools.length === 1 ? \"\" : \"s\"}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{turn.model}</span>\n <span className=\"shrink-0\">{turn.reasoningEffort}</span>\n </div>\n </div>\n </li>\n );\n}\n\nfunction SortableQueueRow({\n turn,\n index,\n count,\n attachedInputs,\n pending,\n confirmingReplace,\n keyboardDragging,\n portalTokenStyle,\n onHandleKeyDown,\n onMove,\n onEdit,\n onConfirmReplace,\n onCancelReplace,\n onSteer,\n onDelete,\n onDisclosureChange,\n}: {\n turn: SessionTurn;\n index: number;\n count: number;\n attachedInputs: SessionPendingInputPreview[];\n pending: QueueMutationKind | null;\n confirmingReplace: boolean;\n keyboardDragging: boolean;\n portalTokenStyle: PortalTokenStyle;\n onHandleKeyDown: (event: ReactKeyboardEvent<HTMLButtonElement>) => void;\n onMove: (index: number) => void;\n onEdit?: (() => void) | undefined;\n onConfirmReplace: () => void;\n onCancelReplace: () => void;\n onSteer: () => void;\n onDelete: () => void;\n onDisclosureChange: (expanded: boolean) => void;\n}) {\n const sortable = useSortable({\n id: turn.id,\n disabled: pending !== null || keyboardDragging,\n });\n return (\n <li\n data-queue-turn-id={turn.id}\n ref={sortable.setNodeRef}\n style={{\n transform: CSS.Transform.toString(sortable.transform),\n transition: sortable.transition,\n }}\n className={`bg-surface ${sortable.isDragging || keyboardDragging ? \"relative z-10 shadow-lg ring-1 ring-brand/40\" : \"\"}`}\n >\n <div className=\"grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-start gap-x-1.5 px-2 py-1.5 sm:grid-cols-[auto_auto_minmax(0,1fr)_auto] sm:gap-x-2 sm:px-3 sm:py-2\">\n <button\n data-queue-handle\n ref={sortable.setActivatorNodeRef}\n type=\"button\"\n {...sortable.attributes}\n {...sortable.listeners}\n onKeyDown={onHandleKeyDown}\n disabled={pending !== null}\n className=\"col-start-1 row-start-1 mt-0.5 inline-flex size-7 shrink-0 touch-none items-center justify-center rounded-md text-fg-subtle hover:bg-surface-2 hover:text-fg focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:size-[44px]\"\n aria-label={`Reorder queued prompt ${index + 1}`}\n title=\"Drag to reorder. Press Space, arrows, then Space to drop.\"\n >\n <GripVerticalIcon className=\"size-3.5\" />\n </button>\n <span className=\"col-start-2 row-start-1 mt-1 shrink-0 font-mono text-og-xs text-fg-subtle\">\n {index + 1}\n </span>\n <div className=\"col-span-full row-start-2 min-w-0 sm:col-span-1 sm:col-start-3 sm:row-start-1\">\n <QueuePrompt prompt={turn.prompt} index={index} onDisclosureChange={onDisclosureChange} />\n {attachedInputs.length > 0 ? (\n <PendingMachineInputs inputs={attachedInputs} attached />\n ) : null}\n <div className=\"mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-og-xs text-fg-subtle\">\n {turn.resources.length > 0 ? (\n <span className=\"shrink-0\">\n {turn.resources.length} resource{turn.resources.length === 1 ? \"\" : \"s\"}\n </span>\n ) : null}\n {turn.tools.length > 0 ? (\n <span className=\"shrink-0\">\n {turn.tools.length} tool{turn.tools.length === 1 ? \"\" : \"s\"}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{turn.model}</span>\n <span className=\"shrink-0\">{turn.reasoningEffort}</span>\n </div>\n </div>\n <div className=\"col-span-full row-start-3 flex min-w-0 items-start justify-end gap-1.5 sm:col-span-1 sm:col-start-4 sm:row-start-1 sm:gap-2\">\n <button\n type=\"button\"\n disabled={pending !== null}\n onClick={onSteer}\n aria-label={`Steer queued prompt ${index + 1}`}\n title=\"Steer — interrupt the current turn and send this message now\"\n className=\"inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-og-control font-medium text-fg outline-hidden transition-[background-color] hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:min-h-[44px] pointer-coarse:min-w-[44px]\"\n >\n {pending === \"steer\" ? (\n <Loader2Icon className=\"size-3.5 animate-spin\" />\n ) : (\n <ZapIcon className=\"size-3.5\" />\n )}\n <span className=\"hidden sm:inline\">Steer</span>\n </button>\n <button\n type=\"button\"\n disabled={pending !== null}\n onClick={onDelete}\n aria-label={`Delete queued prompt ${index + 1}`}\n title=\"Delete this queued prompt\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-hidden transition-colors hover:bg-surface-2 hover:text-status-failed focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]\"\n >\n {pending === \"delete\" ? (\n <Loader2Icon className=\"size-3.5 animate-spin\" />\n ) : (\n <Trash2Icon className=\"size-3.5\" />\n )}\n </button>\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n disabled={pending !== null}\n aria-label={`More actions for queued prompt ${index + 1}`}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-md outline-hidden transition-colors hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:size-[44px]\"\n >\n {pending && pending !== \"steer\" && pending !== \"delete\" ? (\n <Loader2Icon className=\"size-3.5 animate-spin\" />\n ) : (\n <EllipsisIcon className=\"size-3.5\" />\n )}\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align=\"end\"\n sideOffset={4}\n className=\"og-root z-50 w-48 max-w-[calc(100vw-16px)] rounded-md border border-border bg-surface p-1 text-og-control text-fg shadow-lg\"\n style={portalTokenStyle}\n data-testid={`queue-actions-menu-${index + 1}`}\n >\n {onEdit ? (\n <>\n <DropdownMenu.Item\n className=\"flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 pointer-coarse:min-h-[44px]\"\n onSelect={onEdit}\n >\n <PencilIcon className=\"size-3.5\" /> Edit in composer\n </DropdownMenu.Item>\n <DropdownMenu.Separator className=\"my-1 h-px bg-border\" />\n </>\n ) : null}\n <DropdownMenu.Item\n className=\"flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]\"\n disabled={index === 0}\n onSelect={() => onMove(0)}\n >\n <ArrowUpToLineIcon className=\"size-3.5\" /> Move to top\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className=\"flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]\"\n disabled={index === 0}\n onSelect={() => onMove(index - 1)}\n >\n Move up\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className=\"flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]\"\n disabled={index === count - 1}\n onSelect={() => onMove(index + 1)}\n >\n Move down\n </DropdownMenu.Item>\n <DropdownMenu.Item\n className=\"flex min-w-0 cursor-default items-center gap-2 whitespace-normal break-words rounded-sm px-2 py-1.5 outline-hidden focus:bg-surface-2 data-[disabled]:opacity-50 pointer-coarse:min-h-[44px]\"\n disabled={index === count - 1}\n onSelect={() => onMove(count - 1)}\n >\n <ArrowDownToLineIcon className=\"size-3.5\" /> Move to bottom\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n </div>\n </div>\n {confirmingReplace ? (\n <div className=\"mx-3 mb-2 rounded-md border border-status-waiting/30 bg-status-waiting/10 p-2 text-og-control text-fg\">\n <p>Your composer already has a draft. Replace it with this queued prompt?</p>\n <p className=\"mt-0.5 text-fg-muted\">\n The current draft will be permanently discarded; this queued prompt is preserved until\n you confirm.\n </p>\n <div className=\"mt-2 flex justify-end gap-1.5\">\n <button\n type=\"button\"\n className=\"rounded-md px-2 py-1 font-medium hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40\"\n onClick={onCancelReplace}\n >\n Keep current draft\n </button>\n <button\n type=\"button\"\n className=\"rounded-md bg-brand px-2 py-1 font-medium text-white hover:bg-brand/90 focus-visible:ring-2 focus-visible:ring-ring/40\"\n onClick={onConfirmReplace}\n >\n Replace and edit\n </button>\n </div>\n </div>\n ) : null}\n </li>\n );\n}\n\nconst verticalOnly: Modifier = ({ transform }) => ({ ...transform, x: 0 });\n\nfunction focusQueueTurn(surface: HTMLElement | null, turnId: string): void {\n window.requestAnimationFrame(() => {\n surface\n ?.querySelector<HTMLElement>(`[data-queue-turn-id=\"${turnId}\"] [data-queue-handle]`)\n ?.focus();\n });\n}\n\nfunction focusAfterQueueRemoval(\n surface: HTMLElement | null,\n previousIndex: number,\n onRequestComposerFocus?: (() => void) | undefined,\n): void {\n window.requestAnimationFrame(() => {\n const handles = surface?.querySelectorAll<HTMLElement>(\"[data-queue-handle]\") ?? [];\n const nearest = handles[Math.min(previousIndex, Math.max(0, handles.length - 1))];\n if (nearest) {\n nearest.focus();\n return;\n }\n if (onRequestComposerFocus) {\n onRequestComposerFocus();\n return;\n }\n document\n .querySelector<HTMLTextAreaElement>('textarea[aria-label=\"Message the agent\"]')\n ?.focus();\n });\n}\n"],"mappings":"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","names":["summary"]}
@@ -67,6 +67,13 @@ export declare function SessionRealtimeControl(props: {
67
67
  onRealtimeAutostartConsumed?: (() => void) | undefined;
68
68
  /** Host hides dictate (and can choreograph layout) while realtime voice is live. */
69
69
  onVoiceActiveChange?: ((active: boolean) => void) | undefined;
70
+ /**
71
+ * `split` attaches the model chevron at every breakpoint (public default).
72
+ * `split-desktop` hides it below `sm` when the host owns mobile selection.
73
+ * Inside a container-responsive Composer.Root, `sm` follows that composer.
74
+ * `none` never attaches a model menu to the bar button.
75
+ */
76
+ modelMenu?: "split" | "split-desktop" | "none" | undefined;
70
77
  /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */
71
78
  controllerFactory?: SessionRealtimeControllerFactory | undefined;
72
79
  }): import("react/jsx-runtime").JSX.Element;
@@ -94,6 +101,7 @@ export declare function NewSessionRealtimeControl(props: {
94
101
  /**
95
102
  * `split` attaches the model chevron at every breakpoint (public default).
96
103
  * `split-desktop` hides it below `sm` when the host owns mobile selection (e.g. “+”).
104
+ * Inside a container-responsive Composer.Root, `sm` follows that composer.
97
105
  * `none` never attaches a model menu to the bar button.
98
106
  */
99
107
  modelMenu?: "split" | "split-desktop" | "none" | undefined;
@@ -109,6 +117,7 @@ export declare function RealtimeVoiceControl(props: {
109
117
  /**
110
118
  * `split` = start + model chevron at every breakpoint (public SDK default).
111
119
  * `split-desktop` = chevron from `sm` up; below that the host owns selection.
120
+ * Inside a container-responsive Composer.Root, `sm` follows that composer.
112
121
  * `none` = start button only.
113
122
  */
114
123
  modelMenu?: "split" | "split-desktop" | "none" | undefined;
package/dist/realtime.js CHANGED
@@ -3,14 +3,15 @@ import {
3
3
  PickerAnimatedPage,
4
4
  PickerBackHeader,
5
5
  PickerNavRow
6
- } from "./chunk-EHSYZ4KP.js";
6
+ } from "./chunk-WYA65Y3F.js";
7
7
  import {
8
8
  useEmbeddedRealtimeSession
9
9
  } from "./chunk-EKZH6IDG.js";
10
10
  import "./chunk-23EJ676W.js";
11
11
  import {
12
+ usePortalTokenSource,
12
13
  usePortalTokenStyle
13
- } from "./chunk-JB5725BI.js";
14
+ } from "./chunk-VZTQ73XT.js";
14
15
  import {
15
16
  cn
16
17
  } from "./chunk-22KP6LR5.js";
@@ -38,18 +39,14 @@ import {
38
39
  useCallback,
39
40
  useEffect,
40
41
  useMemo,
41
- useRef as useRef2,
42
+ useRef,
42
43
  useState
43
44
  } from "react";
44
45
 
45
46
  // src/realtime/dropdown-menu.tsx
46
47
  import { ChevronRightIcon } from "lucide-react";
47
48
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
48
- import {
49
- createContext,
50
- useContext,
51
- useRef
52
- } from "react";
49
+ import { createContext, useContext } from "react";
53
50
  import { jsx, jsxs } from "react/jsx-runtime";
54
51
  var DropdownMenuSourceContext = createContext(null);
55
52
  function assignRef(ref, value) {
@@ -57,8 +54,8 @@ function assignRef(ref, value) {
57
54
  else if (ref) ref.current = value;
58
55
  }
59
56
  function DropdownMenu(props) {
60
- const sourceRef = useRef(null);
61
- return /* @__PURE__ */ jsx(DropdownMenuSourceContext.Provider, { value: sourceRef, children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props }) });
57
+ const source = usePortalTokenSource();
58
+ return /* @__PURE__ */ jsx(DropdownMenuSourceContext.Provider, { value: source, children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props }) });
62
59
  }
63
60
  function DropdownMenuTrigger({
64
61
  ref,
@@ -70,7 +67,7 @@ function DropdownMenuTrigger({
70
67
  {
71
68
  "data-slot": "dropdown-menu-trigger",
72
69
  ref: (node) => {
73
- if (sourceRef) sourceRef.current = node;
70
+ sourceRef?.ref(node);
74
71
  assignRef(ref, node);
75
72
  },
76
73
  ...props
@@ -83,9 +80,8 @@ function DropdownMenuContent({
83
80
  style,
84
81
  ...props
85
82
  }) {
86
- const sourceRef = useContext(DropdownMenuSourceContext);
87
- const fallbackRef = useRef(null);
88
- const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);
83
+ const source = useContext(DropdownMenuSourceContext);
84
+ const portalStyle = usePortalTokenStyle(source?.source ?? null);
89
85
  return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
90
86
  DropdownMenuPrimitive.Content,
91
87
  {
@@ -164,9 +160,8 @@ function DropdownMenuSubContent({
164
160
  style,
165
161
  ...props
166
162
  }) {
167
- const sourceRef = useContext(DropdownMenuSourceContext);
168
- const fallbackRef = useRef(null);
169
- const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);
163
+ const source = useContext(DropdownMenuSourceContext);
164
+ const portalStyle = usePortalTokenStyle(source?.source ?? null);
170
165
  return /* @__PURE__ */ jsx(
171
166
  DropdownMenuPrimitive.SubContent,
172
167
  {
@@ -219,9 +214,9 @@ function useSessionRealtime(options) {
219
214
  workspaceId: options.workspaceId
220
215
  });
221
216
  const model = options.model ?? CODEX_LIVE_MODEL.id;
222
- const audioRef = useRef2(null);
223
- const controllerRef = useRef2(null);
224
- const controllerModelRef = useRef2(null);
217
+ const audioRef = useRef(null);
218
+ const controllerRef = useRef(null);
219
+ const controllerModelRef = useRef(null);
225
220
  const [snapshot, setSnapshot] = useState(() => ({
226
221
  status: hasStoredSessionRealtimeOwnerProof({ workspaceId, sessionId: options.sessionId, model }) ? "recovering" : "idle",
227
222
  realtimeId: null,
@@ -240,8 +235,8 @@ function useSessionRealtime(options) {
240
235
  () => projectSessionRealtimeLifecycle(options.events),
241
236
  [options.events]
242
237
  );
243
- const lifecycleRef = useRef2(lifecycle);
244
- const eventsReadyRef = useRef2(options.eventsReady);
238
+ const lifecycleRef = useRef(lifecycle);
239
+ const eventsReadyRef = useRef(options.eventsReady);
245
240
  lifecycleRef.current = lifecycle;
246
241
  eventsReadyRef.current = options.eventsReady;
247
242
  const lifecycleActive = lifecycle?.state === "active";
@@ -363,8 +358,8 @@ function SessionRealtimeControl(props) {
363
358
  modelAvailable: selectedModel.available,
364
359
  modelUnavailableReason: selectedModel.unavailableReason
365
360
  });
366
- const autostartModelRef = useRef2(props.realtimeAutostartModel ?? null);
367
- const autostartStartedRef = useRef2(false);
361
+ const autostartModelRef = useRef(props.realtimeAutostartModel ?? null);
362
+ const autostartStartedRef = useRef(false);
368
363
  const { models, selectedModel: selectedRealtimeModel, selectModel } = selection;
369
364
  const { canStart, start } = realtime;
370
365
  const onRealtimeAutostartConsumed = props.onRealtimeAutostartConsumed;
@@ -409,6 +404,7 @@ function SessionRealtimeControl(props) {
409
404
  admissionBlocker: realtime.admissionBlocker,
410
405
  modelAvailable: selectedModel.available,
411
406
  menuSide: "top",
407
+ modelMenu: props.modelMenu ?? "split",
412
408
  audioRef: realtime.audioRef,
413
409
  selectedModel,
414
410
  models: selection.models,
@@ -499,7 +495,7 @@ function NewSessionRealtimeControl(props) {
499
495
  selectedModel: props.selectedModel,
500
496
  selectModel: props.onSelectModel
501
497
  } : internalSelection;
502
- const audioRef = useRef2(null);
498
+ const audioRef = useRef(null);
503
499
  const [starting, setStarting] = useState(false);
504
500
  const [error, setError] = useState(null);
505
501
  const snapshot = useMemo(
@@ -585,7 +581,8 @@ function RealtimeVoiceControl(props) {
585
581
  role: "group",
586
582
  "aria-label": "Realtime voice",
587
583
  "data-picker-side": props.menuSide ?? "top",
588
- className: "inline-flex shrink-0 items-center",
584
+ "data-model-menu": modelMenu,
585
+ className: "og-realtime-control inline-flex shrink-0 items-center",
589
586
  children: [
590
587
  /* @__PURE__ */ jsx2("audio", { ref: props.audioRef, autoPlay: true, className: "hidden", "aria-hidden": "true" }),
591
588
  /* @__PURE__ */ jsx2(RealtimeComposerGlow, { phase: status.phase, reduceMotion: reduceMotion === true }),
@@ -672,7 +669,7 @@ function RealtimeVoiceControl(props) {
672
669
  // Match transcription mic: ghost icon when idle; filled only when live.
673
670
  // Public contract: coarse pointers keep a 44px target; split menu uses
674
671
  // left-only rounding at `sm+` where the chevron attaches.
675
- "relative inline-flex size-8 items-center justify-center outline-none",
672
+ "og-realtime-primary relative inline-flex size-8 items-center justify-center outline-hidden",
676
673
  "rounded-og-md transition-[background-color,border-color,color,box-shadow] duration-200 ease-og-out",
677
674
  "focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45",
678
675
  "disabled:cursor-not-allowed disabled:opacity-45 pointer-coarse:size-11",
@@ -698,11 +695,11 @@ function RealtimeVoiceControl(props) {
698
695
  title: `Voice model: ${selectedModel.label}`,
699
696
  disabled: props.selectionDisabled,
700
697
  className: cn(
701
- // ≥24px wide so WCAG 2.2 target-size passes when the chevron is shown.
702
- "inline-flex h-8 w-6 items-center justify-center rounded-r-og-md outline-none",
698
+ // Keep the split trigger compact on desktop while preserving a
699
+ // full 44px mobile target independent of pointer-media support.
700
+ "og-realtime-model-trigger inline-flex h-11 w-11 items-center justify-center rounded-r-og-md outline-hidden sm:h-8 sm:w-6",
703
701
  "transition-[background-color,border-color,color] duration-200 ease-og-out",
704
702
  "focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45",
705
- "pointer-coarse:h-11 pointer-coarse:w-7",
706
703
  desktopOnlyModelMenu && "hidden sm:inline-flex",
707
704
  voiceChevronTone(status.phase)
708
705
  ),
@@ -716,7 +713,7 @@ function RealtimeVoiceControl(props) {
716
713
  align: "end",
717
714
  sideOffset: 8,
718
715
  collisionPadding: 12,
719
- className: "flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden rounded-xl border-border bg-surface p-1.5 shadow-xl",
716
+ className: "og-realtime-menu flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden rounded-xl border-border bg-surface p-1.5 shadow-xl",
720
717
  onCloseAutoFocus: (event) => event.preventDefault(),
721
718
  children: [
722
719
  /* @__PURE__ */ jsx2("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: /* @__PURE__ */ jsx2(
@@ -855,7 +852,7 @@ function RealtimeMuteButton(props) {
855
852
  ...props.reduceMotion ? {} : { whileTap: { scale: 0.92 } },
856
853
  onClick: props.onToggle,
857
854
  className: cn(
858
- "inline-flex size-8 shrink-0 items-center justify-center rounded-og-md outline-none",
855
+ "inline-flex size-8 shrink-0 items-center justify-center rounded-og-md outline-hidden",
859
856
  "transition-[background-color,border-color,color] duration-150 ease-og-out",
860
857
  "focus-visible:ring-2 focus-visible:ring-og-accent/45 pointer-coarse:size-11",
861
858
  props.muted ? "border border-og-accent/35 bg-og-accent-soft text-og-accent" : "text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg"