@opengeni/react 2.5.0-canary.1 → 3.0.0-canary.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 (70) hide show
  1. package/README.md +15 -0
  2. package/dist/accounts.d.ts +64 -0
  3. package/dist/accounts.js +746 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/{browser-viewer-GXUICIAG.js → browser-viewer-AEFHUYZK.js} +3 -3
  6. package/dist/{chunk-MXJGO7LE.js → chunk-D3UIAJKY.js} +52 -2
  7. package/dist/chunk-D3UIAJKY.js.map +1 -0
  8. package/dist/{chunk-QGBJ6GHG.js → chunk-ELIYWBZR.js} +4 -4
  9. package/dist/{chunk-6H6S5V4Z.js → chunk-HQVCKCLG.js} +758 -871
  10. package/dist/chunk-HQVCKCLG.js.map +1 -0
  11. package/dist/{chunk-T7VAYG2I.js → chunk-MZ2G2XBA.js} +54 -2
  12. package/dist/chunk-MZ2G2XBA.js.map +1 -0
  13. package/dist/{chunk-X4JAFD5R.js → chunk-OAM4WAAM.js} +4 -4
  14. package/dist/{chunk-KSDXER4X.js → chunk-RGALCTWO.js} +64 -15
  15. package/dist/chunk-RGALCTWO.js.map +1 -0
  16. package/dist/chunk-YFKJ7VZH.js +268 -0
  17. package/dist/chunk-YFKJ7VZH.js.map +1 -0
  18. package/dist/{chunk-ATQJEWCA.js → chunk-YJFGAFBD.js} +124 -50
  19. package/dist/chunk-YJFGAFBD.js.map +1 -0
  20. package/dist/components/composer.d.ts +8 -0
  21. package/dist/components/file-browser.d.ts +4 -1
  22. package/dist/components/sandbox-files.d.ts +4 -1
  23. package/dist/components/sandbox-workspace.d.ts +5 -0
  24. package/dist/composer.js +3 -3
  25. package/dist/{computer-viewer-ZOP4Q7A7.js → computer-viewer-FWEZISW4.js} +3 -3
  26. package/dist/embedded-session-client.d.ts +23 -0
  27. package/dist/file-node-visibility.d.ts +15 -0
  28. package/dist/hooks/use-file-attachments.d.ts +9 -2
  29. package/dist/human-input.d.ts +3 -1
  30. package/dist/index.d.ts +5 -1
  31. package/dist/index.js +139 -53
  32. package/dist/index.js.map +1 -1
  33. package/dist/interaction.js +3 -3
  34. package/dist/session-ui.js +4 -4
  35. package/dist/session.d.ts +2 -0
  36. package/dist/session.js +7 -5
  37. package/dist/timeline/index.d.ts +1 -0
  38. package/dist/timeline/screenshot-lightbox.d.ts +16 -1
  39. package/package.json +6 -2
  40. package/src/accounts.tsx +970 -0
  41. package/src/components/chat-composer.tsx +88 -84
  42. package/src/components/composer.tsx +61 -9
  43. package/src/components/file-browser.tsx +33 -20
  44. package/src/components/human-input-surface.tsx +10 -6
  45. package/src/components/message-timeline.tsx +37 -9
  46. package/src/components/sandbox-files.tsx +42 -2
  47. package/src/components/sandbox-workspace.tsx +10 -0
  48. package/src/embedded-session-client.ts +104 -0
  49. package/src/file-node-visibility.ts +66 -0
  50. package/src/hooks/use-composer.ts +64 -2
  51. package/src/hooks/use-file-attachments.ts +38 -6
  52. package/src/hooks/use-human-input.ts +31 -4
  53. package/src/human-input.ts +12 -1
  54. package/src/index.ts +12 -0
  55. package/src/session.ts +5 -0
  56. package/src/timeline/index.ts +1 -0
  57. package/src/timeline/screenshot-lightbox.tsx +93 -29
  58. package/styles/compiled.css +11 -1
  59. package/styles/tokens.css +3 -1
  60. package/dist/chunk-6H6S5V4Z.js.map +0 -1
  61. package/dist/chunk-ATQJEWCA.js.map +0 -1
  62. package/dist/chunk-FK6VG4LL.js +0 -90
  63. package/dist/chunk-FK6VG4LL.js.map +0 -1
  64. package/dist/chunk-KSDXER4X.js.map +0 -1
  65. package/dist/chunk-MXJGO7LE.js.map +0 -1
  66. package/dist/chunk-T7VAYG2I.js.map +0 -1
  67. /package/dist/{browser-viewer-GXUICIAG.js.map → browser-viewer-AEFHUYZK.js.map} +0 -0
  68. /package/dist/{chunk-QGBJ6GHG.js.map → chunk-ELIYWBZR.js.map} +0 -0
  69. /package/dist/{chunk-X4JAFD5R.js.map → chunk-OAM4WAAM.js.map} +0 -0
  70. /package/dist/{computer-viewer-ZOP4Q7A7.js.map → computer-viewer-FWEZISW4.js.map} +0 -0
@@ -0,0 +1,268 @@
1
+ import {
2
+ usePortalTokenSource,
3
+ usePortalTokenStyle
4
+ } from "./chunk-VZTQ73XT.js";
5
+ import {
6
+ cn
7
+ } from "./chunk-22KP6LR5.js";
8
+
9
+ // src/components/tooltip.tsx
10
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
11
+ import { createContext, useContext } from "react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var TooltipSourceContext = createContext(null);
14
+ function TooltipProvider({
15
+ delayDuration = 300,
16
+ ...props
17
+ }) {
18
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, ...props });
19
+ }
20
+ function Tooltip({ children, ...props }) {
21
+ const source = usePortalTokenSource();
22
+ return /* @__PURE__ */ jsx(TooltipSourceContext.Provider, { value: source, children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props, children }) });
23
+ }
24
+ function TooltipTrigger({
25
+ asChild = true,
26
+ ...props
27
+ }) {
28
+ const sourceRef = useContext(TooltipSourceContext);
29
+ return /* @__PURE__ */ jsx(
30
+ TooltipPrimitive.Trigger,
31
+ {
32
+ "data-slot": "tooltip-trigger",
33
+ asChild,
34
+ ref: (node) => {
35
+ sourceRef?.ref(node);
36
+ },
37
+ ...props
38
+ }
39
+ );
40
+ }
41
+ var tooltipSurfaceStyle = {
42
+ backgroundColor: "var(--og-color-fg)",
43
+ color: "var(--og-color-bg)"
44
+ };
45
+ function TooltipContent({
46
+ className,
47
+ sideOffset = 6,
48
+ children,
49
+ style,
50
+ ...props
51
+ }) {
52
+ const source = useContext(TooltipSourceContext);
53
+ const portalStyle = usePortalTokenStyle(source?.source ?? null);
54
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
55
+ TooltipPrimitive.Content,
56
+ {
57
+ "data-slot": "tooltip-content",
58
+ sideOffset,
59
+ className: cn(
60
+ "og-root z-50 w-fit max-w-xs origin-[var(--radix-tooltip-content-transform-origin)]",
61
+ "rounded-og-md px-2.5 py-1.5 text-og-xs leading-4 text-balance shadow-og-md",
62
+ "animate-og-enter data-[state=closed]:opacity-0 data-[state=closed]:transition-opacity",
63
+ className
64
+ ),
65
+ style: { ...portalStyle, ...tooltipSurfaceStyle, ...style },
66
+ ...props,
67
+ children: [
68
+ children,
69
+ /* @__PURE__ */ jsx(
70
+ TooltipPrimitive.Arrow,
71
+ {
72
+ className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]",
73
+ style: {
74
+ backgroundColor: "var(--og-color-fg)",
75
+ fill: "var(--og-color-fg)"
76
+ }
77
+ }
78
+ )
79
+ ]
80
+ }
81
+ ) });
82
+ }
83
+
84
+ // src/timeline/screenshot-lightbox.tsx
85
+ import { DownloadIcon, XIcon } from "lucide-react";
86
+ import { AnimatePresence, motion } from "motion/react";
87
+ import {
88
+ createContext as createContext2,
89
+ useCallback,
90
+ useContext as useContext2,
91
+ useEffect,
92
+ useMemo,
93
+ useState
94
+ } from "react";
95
+ import { Dialog } from "radix-ui";
96
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
97
+ var LightboxContext = createContext2(null);
98
+ function useLightbox() {
99
+ return useContext2(LightboxContext) ?? NOOP;
100
+ }
101
+ function useLightboxOptional() {
102
+ return useContext2(LightboxContext);
103
+ }
104
+ var NOOP = { open: () => {
105
+ } };
106
+ function createLightboxSourceOwner() {
107
+ let releaseCurrent = null;
108
+ return {
109
+ replace(release) {
110
+ const previous = releaseCurrent;
111
+ releaseCurrent = release ?? null;
112
+ previous?.();
113
+ },
114
+ release() {
115
+ const release = releaseCurrent;
116
+ releaseCurrent = null;
117
+ release?.();
118
+ }
119
+ };
120
+ }
121
+ function LightboxProvider({ children }) {
122
+ const ancestor = useContext2(LightboxContext);
123
+ if (ancestor) {
124
+ return /* @__PURE__ */ jsx2(Fragment, { children });
125
+ }
126
+ return /* @__PURE__ */ jsx2(LightboxRoot, { children });
127
+ }
128
+ function LightboxRoot({ children }) {
129
+ const [state, setState] = useState(null);
130
+ const [tokenSource, setTokenSource] = useState(null);
131
+ const sourceOwner = useMemo(() => createLightboxSourceOwner(), []);
132
+ const portalStyle = usePortalTokenStyle(tokenSource);
133
+ const releaseCurrentSource = useCallback(() => {
134
+ sourceOwner.release();
135
+ }, [sourceOwner]);
136
+ useEffect(() => releaseCurrentSource, [releaseCurrentSource]);
137
+ const open = useCallback(
138
+ (src, caption, source, label = "Screenshot", downloadFilename, controlLabels, releaseSource) => {
139
+ sourceOwner.replace(releaseSource);
140
+ setTokenSource(source ?? null);
141
+ setState({
142
+ src,
143
+ label,
144
+ ...caption ? { caption } : {},
145
+ ...downloadFilename ? { downloadFilename } : {},
146
+ ...controlLabels ? { controlLabels } : {}
147
+ });
148
+ },
149
+ [sourceOwner]
150
+ );
151
+ const close = useCallback(() => {
152
+ releaseCurrentSource();
153
+ setState(null);
154
+ setTokenSource(null);
155
+ }, [releaseCurrentSource]);
156
+ const controller = useMemo(() => ({ open }), [open]);
157
+ return /* @__PURE__ */ jsxs2(LightboxContext.Provider, { value: controller, children: [
158
+ children,
159
+ /* @__PURE__ */ jsx2(Dialog.Root, { open: state !== null, onOpenChange: (next) => !next && close(), children: /* @__PURE__ */ jsx2(AnimatePresence, { children: state !== null ? /* @__PURE__ */ jsxs2(Dialog.Portal, { forceMount: true, children: [
160
+ /* @__PURE__ */ jsx2(Dialog.Overlay, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx2(
161
+ motion.div,
162
+ {
163
+ initial: { opacity: 0 },
164
+ animate: { opacity: 1 },
165
+ exit: { opacity: 0 },
166
+ transition: { duration: 0.15 },
167
+ className: "og-root fixed inset-0 z-50 bg-black/90 backdrop-blur-md",
168
+ style: portalStyle
169
+ }
170
+ ) }),
171
+ /* @__PURE__ */ jsx2(
172
+ Dialog.Content,
173
+ {
174
+ asChild: true,
175
+ forceMount: true,
176
+ "aria-label": state.label,
177
+ onOpenAutoFocus: (event) => event.preventDefault(),
178
+ children: /* @__PURE__ */ jsxs2(
179
+ motion.div,
180
+ {
181
+ initial: { opacity: 0, scale: 0.98 },
182
+ animate: { opacity: 1, scale: 1 },
183
+ exit: { opacity: 0, scale: 0.98 },
184
+ transition: { duration: 0.18, ease: [0.16, 1, 0.3, 1] },
185
+ onClick: (event) => {
186
+ if (event.target === event.currentTarget) {
187
+ close();
188
+ }
189
+ },
190
+ className: "og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12",
191
+ style: portalStyle,
192
+ children: [
193
+ /* @__PURE__ */ jsx2(Dialog.Title, { className: "sr-only", children: state.label }),
194
+ /* @__PURE__ */ jsx2(Dialog.Description, { className: "sr-only", children: state.caption ?? `Expanded ${state.label.toLowerCase()}` }),
195
+ /* @__PURE__ */ jsxs2("figure", { className: "m-0 flex max-h-full max-w-5xl flex-col items-center gap-3", children: [
196
+ /* @__PURE__ */ jsxs2("div", { className: "relative flex min-h-0 w-fit max-w-full", children: [
197
+ /* @__PURE__ */ jsx2(
198
+ "img",
199
+ {
200
+ src: state.src,
201
+ alt: state.caption ?? state.label,
202
+ className: "min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg"
203
+ }
204
+ ),
205
+ /* @__PURE__ */ jsx2(
206
+ ScreenshotLightboxControls,
207
+ {
208
+ src: state.src,
209
+ downloadFilename: state.downloadFilename,
210
+ controlLabels: state.controlLabels
211
+ }
212
+ )
213
+ ] }),
214
+ state.caption ? /* @__PURE__ */ jsx2("figcaption", { className: "max-w-2xl text-center font-og-mono text-og-xs text-white/55", children: state.caption }) : /* @__PURE__ */ jsx2("figcaption", { className: "font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35", children: "Esc or click outside to close" })
215
+ ] })
216
+ ]
217
+ }
218
+ )
219
+ }
220
+ )
221
+ ] }) : null }) })
222
+ ] });
223
+ }
224
+ function ScreenshotLightboxControls({
225
+ src,
226
+ downloadFilename,
227
+ controlLabels
228
+ }) {
229
+ return /* @__PURE__ */ jsxs2("div", { className: "absolute -right-3 -top-3 flex items-center gap-2", children: [
230
+ downloadFilename ? /* @__PURE__ */ jsx2(
231
+ "a",
232
+ {
233
+ href: src,
234
+ download: downloadFilename,
235
+ className: cn(
236
+ "inline-flex size-9 items-center justify-center rounded-full",
237
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
238
+ "transition-colors hover:border-white/30 hover:text-white"
239
+ ),
240
+ "aria-label": controlLabels?.download ?? `Download ${downloadFilename}`,
241
+ children: /* @__PURE__ */ jsx2(DownloadIcon, { className: "size-4" })
242
+ }
243
+ ) : null,
244
+ /* @__PURE__ */ jsx2(
245
+ Dialog.Close,
246
+ {
247
+ className: cn(
248
+ "inline-flex size-9 items-center justify-center rounded-full",
249
+ "border border-white/15 bg-black/60 text-white/70 backdrop-blur",
250
+ "transition-colors hover:border-white/30 hover:text-white"
251
+ ),
252
+ "aria-label": controlLabels?.close ?? "Close",
253
+ children: /* @__PURE__ */ jsx2(XIcon, { className: "size-4" })
254
+ }
255
+ )
256
+ ] });
257
+ }
258
+
259
+ export {
260
+ TooltipProvider,
261
+ Tooltip,
262
+ TooltipTrigger,
263
+ TooltipContent,
264
+ useLightbox,
265
+ useLightboxOptional,
266
+ LightboxProvider
267
+ };
268
+ //# sourceMappingURL=chunk-YFKJ7VZH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/tooltip.tsx","../src/timeline/screenshot-lightbox.tsx"],"sourcesContent":["/**\n * Token-styled Radix tooltip — SDK counterpart to apps/web `components/ui/tooltip`.\n * Portals copy `--og-*` tokens so embeds keep the host theme outside `.og-root`.\n *\n * Background/foreground are applied as inline styles (not only Tailwind\n * utilities): `.og-root` sets `color: var(--og-color-fg)` after utilities in the\n * consumer CSS cascade, which would otherwise paint light-on-light inverted\n * tips and look like a blank white bubble.\n */\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport { createContext, useContext, type ComponentProps, type CSSProperties } from \"react\";\n\nimport { cn } from \"../lib/cn\";\nimport { usePortalTokenSource, usePortalTokenStyle } from \"../lib/use-portal-token-style\";\n\ntype TooltipSourceContextValue = {\n source: HTMLElement | null;\n ref: (node: HTMLElement | null) => void;\n};\n\nconst TooltipSourceContext = createContext<TooltipSourceContextValue | null>(null);\n\nfunction TooltipProvider({\n delayDuration = 300,\n ...props\n}: ComponentProps<typeof TooltipPrimitive.Provider>) {\n return <TooltipPrimitive.Provider delayDuration={delayDuration} {...props} />;\n}\n\nfunction Tooltip({ children, ...props }: ComponentProps<typeof TooltipPrimitive.Root>) {\n const source = usePortalTokenSource<HTMLElement>();\n return (\n <TooltipSourceContext.Provider value={source}>\n <TooltipPrimitive.Root data-slot=\"tooltip\" {...props}>\n {children}\n </TooltipPrimitive.Root>\n </TooltipSourceContext.Provider>\n );\n}\n\nfunction TooltipTrigger({\n asChild = true,\n ...props\n}: ComponentProps<typeof TooltipPrimitive.Trigger>) {\n const sourceRef = useContext(TooltipSourceContext);\n return (\n <TooltipPrimitive.Trigger\n data-slot=\"tooltip-trigger\"\n asChild={asChild}\n ref={(node) => {\n sourceRef?.ref(node);\n }}\n {...props}\n />\n );\n}\n\nconst tooltipSurfaceStyle: CSSProperties = {\n backgroundColor: \"var(--og-color-fg)\",\n color: \"var(--og-color-bg)\",\n};\n\nfunction TooltipContent({\n className,\n sideOffset = 6,\n children,\n style,\n ...props\n}: ComponentProps<typeof TooltipPrimitive.Content>) {\n const source = useContext(TooltipSourceContext);\n const portalStyle = usePortalTokenStyle(source?.source ?? null);\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n data-slot=\"tooltip-content\"\n sideOffset={sideOffset}\n className={cn(\n \"og-root z-50 w-fit max-w-xs origin-[var(--radix-tooltip-content-transform-origin)]\",\n \"rounded-og-md px-2.5 py-1.5 text-og-xs leading-4 text-balance shadow-og-md\",\n \"animate-og-enter data-[state=closed]:opacity-0 data-[state=closed]:transition-opacity\",\n className,\n )}\n style={{ ...portalStyle, ...tooltipSurfaceStyle, ...style }}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow\n className=\"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]\"\n style={{\n backgroundColor: \"var(--og-color-fg)\",\n fill: \"var(--og-color-fg)\",\n }}\n />\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n}\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n","import { DownloadIcon, XIcon } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from \"react\";\nimport { Dialog } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\n\n/* ----------------------------------------------------------------------------\n Screenshot lightbox\n\n A single, app-level lightbox the computer_call / view_image renderers open by\n `src`. Built on Radix Dialog so it is focus-trapped, ESC-closable, and\n scroll-locked — fixing the v1 mockup's broken expand (an absolutely-positioned\n <img> that overflowed its row). The image is centered, constrained to the\n viewport (`max-w/max-h` + `object-contain`), and sits on a dimmed backdrop.\n\n Consumers render `<LightboxProvider>` once near the timeline; renderers call\n `useLightbox().open(src)`.\n -------------------------------------------------------------------------- */\n\ntype LightboxController = {\n open: (\n src: string,\n caption?: string,\n source?: HTMLElement | null,\n label?: string,\n downloadFilename?: string,\n controlLabels?: LightboxControlLabels,\n releaseSource?: () => void,\n ) => void;\n};\n\nexport type LightboxControlLabels = {\n download?: string | undefined;\n close?: string | undefined;\n};\n\nconst LightboxContext = createContext<LightboxController | null>(null);\n\n/** Open the app-level screenshot lightbox. No-op outside a `LightboxProvider`. */\nexport function useLightbox(): LightboxController {\n return useContext(LightboxContext) ?? NOOP;\n}\n\n/**\n * The lightbox controller when one is mounted, or `null` outside a\n * `LightboxProvider`. Lets a media primitive degrade to a non-interactive image\n * (rather than a dead \"Expand\" button that announces an action it cannot do).\n */\nexport function useLightboxOptional(): LightboxController | null {\n return useContext(LightboxContext);\n}\n\nconst NOOP: LightboxController = { open: () => {} };\n\n/** @internal Owns one optional retained lightbox source and releases it exactly once. */\nexport function createLightboxSourceOwner() {\n let releaseCurrent: (() => void) | null = null;\n return {\n replace(release?: (() => void) | undefined) {\n const previous = releaseCurrent;\n releaseCurrent = release ?? null;\n previous?.();\n },\n release() {\n const release = releaseCurrent;\n releaseCurrent = null;\n release?.();\n },\n };\n}\n\n/**\n * The app-level screenshot lightbox. Render once near the timeline; renderers\n * call `useLightbox().open(src)`.\n *\n * Idempotent by design: when an ancestor `LightboxProvider` already exists (e.g.\n * a `MessageTimeline` mounted inside an app that already wraps its shell), this\n * one becomes a pass-through and does NOT mount a second focus-trapping Dialog.\n * That keeps `MessageTimeline` self-sufficient (it owns its own provider) while\n * composing cleanly when nested.\n */\nexport function LightboxProvider({ children }: { children: ReactNode }) {\n const ancestor = useContext(LightboxContext);\n if (ancestor) {\n return <>{children}</>;\n }\n return <LightboxRoot>{children}</LightboxRoot>;\n}\n\nfunction LightboxRoot({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{\n src: string;\n caption?: string;\n label: string;\n downloadFilename?: string;\n controlLabels?: LightboxControlLabels;\n } | null>(null);\n const [tokenSource, setTokenSource] = useState<HTMLElement | null>(null);\n const sourceOwner = useMemo(() => createLightboxSourceOwner(), []);\n const portalStyle = usePortalTokenStyle(tokenSource);\n\n const releaseCurrentSource = useCallback(() => {\n sourceOwner.release();\n }, [sourceOwner]);\n\n useEffect(() => releaseCurrentSource, [releaseCurrentSource]);\n\n const open = useCallback(\n (\n src: string,\n caption?: string,\n source?: HTMLElement | null,\n label = \"Screenshot\",\n downloadFilename?: string,\n controlLabels?: LightboxControlLabels,\n releaseSource?: () => void,\n ) => {\n sourceOwner.replace(releaseSource);\n setTokenSource(source ?? null);\n setState({\n src,\n label,\n ...(caption ? { caption } : {}),\n ...(downloadFilename ? { downloadFilename } : {}),\n ...(controlLabels ? { controlLabels } : {}),\n });\n },\n [sourceOwner],\n );\n\n const close = useCallback(() => {\n releaseCurrentSource();\n setState(null);\n setTokenSource(null);\n }, [releaseCurrentSource]);\n\n const controller = useMemo<LightboxController>(() => ({ open }), [open]);\n\n return (\n <LightboxContext.Provider value={controller}>\n {children}\n <Dialog.Root open={state !== null} onOpenChange={(next) => !next && close()}>\n <AnimatePresence>\n {state !== null ? (\n <Dialog.Portal forceMount>\n <Dialog.Overlay asChild forceMount>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n className=\"og-root fixed inset-0 z-50 bg-black/90 backdrop-blur-md\"\n style={portalStyle}\n />\n </Dialog.Overlay>\n <Dialog.Content\n asChild\n forceMount\n aria-label={state.label}\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.98 }}\n transition={{ duration: 0.18, ease: [0.16, 1, 0.3, 1] }}\n // Content is a full-inset centering wrapper layered above the\n // Overlay, so Radix's own click-outside (which fires on the\n // Overlay) can never see a backdrop click — every click lands on\n // Content. We make Content's own backdrop dismiss: a click whose\n // target is the wrapper itself (not the figure) closes it, so the\n // figcaption's \"click outside to close\" affordance is real.\n onClick={(event) => {\n if (event.target === event.currentTarget) {\n close();\n }\n }}\n className=\"og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12\"\n style={portalStyle}\n >\n <Dialog.Title className=\"sr-only\">{state.label}</Dialog.Title>\n <Dialog.Description className=\"sr-only\">\n {state.caption ?? `Expanded ${state.label.toLowerCase()}`}\n </Dialog.Description>\n {/* The figure is one self-contained object: image, caption, and\n its own close control. The close button anchors to a wrapper\n sized to the IMAGE (w-fit), so it hugs the real top-right\n corner regardless of aspect ratio — never floating into the\n empty space of a wide figure column. */}\n <figure className=\"m-0 flex max-h-full max-w-5xl flex-col items-center gap-3\">\n <div className=\"relative flex min-h-0 w-fit max-w-full\">\n {/* A plain <img>: this SDK is framework-agnostic, with no host Image component. */}\n <img\n src={state.src}\n alt={state.caption ?? state.label}\n className=\"min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg\"\n />\n <ScreenshotLightboxControls\n src={state.src}\n downloadFilename={state.downloadFilename}\n controlLabels={state.controlLabels}\n />\n </div>\n {state.caption ? (\n <figcaption className=\"max-w-2xl text-center font-og-mono text-og-xs text-white/55\">\n {state.caption}\n </figcaption>\n ) : (\n <figcaption className=\"font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35\">\n Esc or click outside to close\n </figcaption>\n )}\n </figure>\n </motion.div>\n </Dialog.Content>\n </Dialog.Portal>\n ) : null}\n </AnimatePresence>\n </Dialog.Root>\n </LightboxContext.Provider>\n );\n}\n\n/** @internal Exact controls rendered by an open screenshot lightbox. */\nexport function ScreenshotLightboxControls({\n src,\n downloadFilename,\n controlLabels,\n}: {\n src: string;\n downloadFilename?: string | undefined;\n controlLabels?: LightboxControlLabels | undefined;\n}) {\n return (\n <div className=\"absolute -right-3 -top-3 flex items-center gap-2\">\n {downloadFilename ? (\n <a\n href={src}\n download={downloadFilename}\n className={cn(\n \"inline-flex size-9 items-center justify-center rounded-full\",\n \"border border-white/15 bg-black/60 text-white/70 backdrop-blur\",\n \"transition-colors hover:border-white/30 hover:text-white\",\n )}\n aria-label={controlLabels?.download ?? `Download ${downloadFilename}`}\n >\n <DownloadIcon className=\"size-4\" />\n </a>\n ) : null}\n <Dialog.Close\n className={cn(\n \"inline-flex size-9 items-center justify-center rounded-full\",\n \"border border-white/15 bg-black/60 text-white/70 backdrop-blur\",\n \"transition-colors hover:border-white/30 hover:text-white\",\n )}\n aria-label={controlLabels?.close ?? \"Close\"}\n >\n <XIcon className=\"size-4\" />\n </Dialog.Close>\n </div>\n );\n}\n"],"mappings":"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","names":["createContext","useContext","jsx","jsxs","createContext","useContext"]}
@@ -2,8 +2,9 @@ import {
2
2
  buildTimeline,
3
3
  createOlderHistoryLoadReceipt,
4
4
  groupTimeline,
5
+ isActionableHumanInputRequest,
5
6
  sessionStatusFromEvents
6
- } from "./chunk-MXJGO7LE.js";
7
+ } from "./chunk-D3UIAJKY.js";
7
8
  import {
8
9
  useDebouncedCallback,
9
10
  useMutationRunner,
@@ -21,6 +22,73 @@ import {
21
22
  useEmbeddedSessionRead
22
23
  } from "./chunk-NEXLLTP4.js";
23
24
 
25
+ // src/embedded-session-client.ts
26
+ var requiredMethods = [
27
+ "getSession",
28
+ "listEvents",
29
+ "streamEvents",
30
+ "getComposerDraft",
31
+ "saveComposerDraft",
32
+ "submitComposerDraft",
33
+ "sendMessage",
34
+ "steerMessage",
35
+ "getQueue",
36
+ "moveQueueItem",
37
+ "editQueueItem",
38
+ "steerQueueItem",
39
+ "deleteQueueItem",
40
+ "pauseSession",
41
+ "resumeSession",
42
+ "sendApprovalDecision"
43
+ ];
44
+ function createEmbeddedSessionClient(base, options = {}) {
45
+ const overrides = options.overrides ?? {};
46
+ const client = {};
47
+ for (const key of requiredMethods) {
48
+ const override = overrides[key];
49
+ const method = override ?? base[key];
50
+ if (typeof method !== "function") {
51
+ throw new TypeError(`Embedded session client method is required: ${key}`);
52
+ }
53
+ client[key] = method.bind(override === void 0 ? base : overrides);
54
+ }
55
+ const inferenceOverride = overrides.setWorkspaceInferenceState;
56
+ const inferenceBase = base.setWorkspaceInferenceState;
57
+ const inferenceMethod = inferenceOverride ?? inferenceBase;
58
+ if (typeof inferenceMethod === "function") {
59
+ client.setWorkspaceInferenceState = inferenceMethod.bind(
60
+ inferenceOverride === void 0 ? base : overrides
61
+ );
62
+ }
63
+ const mapDraft = options.mapComposerDraft;
64
+ if (!mapDraft) return client;
65
+ const getComposerDraft = client.getComposerDraft;
66
+ client.getComposerDraft = async (workspaceId, sessionId) => mapDraft(await getComposerDraft(workspaceId, sessionId), {
67
+ operation: "read",
68
+ workspaceId,
69
+ sessionId
70
+ });
71
+ const saveComposerDraft = client.saveComposerDraft;
72
+ client.saveComposerDraft = async (workspaceId, sessionId, request) => mapDraft(await saveComposerDraft(workspaceId, sessionId, request), {
73
+ operation: "save",
74
+ workspaceId,
75
+ sessionId
76
+ });
77
+ const submitComposerDraft = client.submitComposerDraft;
78
+ client.submitComposerDraft = async (workspaceId, sessionId, request) => {
79
+ const response = await submitComposerDraft(workspaceId, sessionId, request);
80
+ return {
81
+ ...response,
82
+ draft: mapDraft(response.draft, {
83
+ operation: "submit",
84
+ workspaceId,
85
+ sessionId
86
+ })
87
+ };
88
+ };
89
+ return client;
90
+ }
91
+
24
92
  // src/hooks/use-session.ts
25
93
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
26
94
  function isTitleEvent(event) {
@@ -1079,17 +1147,41 @@ function useFileAttachments(options = {}) {
1079
1147
  const [attachments, setAttachments] = useState3([]);
1080
1148
  const sources = useRef3(/* @__PURE__ */ new Map());
1081
1149
  const previewUrls = useRef3(/* @__PURE__ */ new Map());
1150
+ const previewRetainers = useRef3(/* @__PURE__ */ new Map());
1151
+ const pendingPreviewRevocations = useRef3(/* @__PURE__ */ new Set());
1082
1152
  const revokePreview = useCallback3((id) => {
1083
1153
  const previewUrl = previewUrls.current.get(id);
1084
1154
  if (!previewUrl) return;
1155
+ if ((previewRetainers.current.get(id) ?? 0) > 0) {
1156
+ pendingPreviewRevocations.current.add(id);
1157
+ return;
1158
+ }
1085
1159
  previewUrls.current.delete(id);
1160
+ pendingPreviewRevocations.current.delete(id);
1086
1161
  URL.revokeObjectURL(previewUrl);
1087
1162
  }, []);
1088
1163
  const revokeAllPreviews = useCallback3(() => {
1089
- const urls = [...previewUrls.current.values()];
1090
- previewUrls.current.clear();
1091
- for (const previewUrl of urls) URL.revokeObjectURL(previewUrl);
1092
- }, []);
1164
+ for (const id of previewUrls.current.keys()) revokePreview(id);
1165
+ }, [revokePreview]);
1166
+ const retainPreview = useCallback3(
1167
+ (id) => {
1168
+ if (!previewUrls.current.has(id)) return void 0;
1169
+ previewRetainers.current.set(id, (previewRetainers.current.get(id) ?? 0) + 1);
1170
+ let released = false;
1171
+ return () => {
1172
+ if (released) return;
1173
+ released = true;
1174
+ const remaining = (previewRetainers.current.get(id) ?? 1) - 1;
1175
+ if (remaining > 0) {
1176
+ previewRetainers.current.set(id, remaining);
1177
+ return;
1178
+ }
1179
+ previewRetainers.current.delete(id);
1180
+ if (pendingPreviewRevocations.current.has(id)) revokePreview(id);
1181
+ };
1182
+ },
1183
+ [revokePreview]
1184
+ );
1093
1185
  const committedAttachmentIds = useRef3(/* @__PURE__ */ new Set());
1094
1186
  useEffect3(() => {
1095
1187
  const currentIds = new Set(attachments.map((attachment) => attachment.id));
@@ -1280,6 +1372,7 @@ function useFileAttachments(options = {}) {
1280
1372
  addFromPaste,
1281
1373
  restoreReadyFiles,
1282
1374
  retry,
1375
+ retainPreview,
1283
1376
  remove,
1284
1377
  removeReadyFiles,
1285
1378
  clear
@@ -2124,47 +2217,6 @@ function projectPendingApprovals(events) {
2124
2217
  return pending;
2125
2218
  }
2126
2219
 
2127
- // src/human-input.ts
2128
- function humanInputRequestFromEvent(event) {
2129
- if (event.type !== "session.humanInput.requested" || !isRecord(event.payload)) return null;
2130
- const request = event.payload.request;
2131
- if (!isRecord(request) || typeof request.id !== "string" || !Array.isArray(request.questions)) {
2132
- return null;
2133
- }
2134
- return {
2135
- id: request.id,
2136
- turnId: event.turnId ?? null,
2137
- questions: request.questions,
2138
- allowSkip: request.allowSkip === true,
2139
- expiresAt: typeof request.expiresAt === "string" ? request.expiresAt : null
2140
- };
2141
- }
2142
- function projectPendingHumanInputRequests(events) {
2143
- const pending = /* @__PURE__ */ new Map();
2144
- for (const event of events) {
2145
- const requested = humanInputRequestFromEvent(event);
2146
- if (requested) {
2147
- pending.set(requested.id, requested);
2148
- continue;
2149
- }
2150
- if (event.type === "user.humanInputResponse" && isRecord(event.payload)) {
2151
- if (typeof event.payload.requestId === "string") pending.delete(event.payload.requestId);
2152
- continue;
2153
- }
2154
- if (event.type === "turn.completed" || event.type === "turn.failed" || event.type === "turn.cancelled") {
2155
- for (const [id, request] of pending) {
2156
- if (request.turnId === null || event.turnId === null || event.turnId === void 0 || request.turnId === event.turnId) {
2157
- pending.delete(id);
2158
- }
2159
- }
2160
- }
2161
- }
2162
- return [...pending.values()];
2163
- }
2164
- function isRecord(value) {
2165
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2166
- }
2167
-
2168
2220
  // src/hooks/use-human-input.ts
2169
2221
  import { useCallback as useCallback9, useEffect as useEffect8, useRef as useRef9, useState as useState7 } from "react";
2170
2222
  function isHumanInputEvent(event) {
@@ -2181,8 +2233,11 @@ function useHumanInputRequests(sessionId, options = {}) {
2181
2233
  enabled,
2182
2234
  pollIntervalMs: options.pollIntervalMs
2183
2235
  });
2236
+ const loadedRequests = state.data;
2237
+ const refreshRequests = state.refresh;
2184
2238
  const mutation = useMutationRunner(`${workspaceId}\0${sessionId ?? ""}`);
2185
2239
  const [respondingRequestId, setRespondingRequestId] = useState7(null);
2240
+ const [deadlineVersion, setDeadlineVersion] = useState7(0);
2186
2241
  const respondingRequestRef = useRef9(null);
2187
2242
  useEffect8(() => {
2188
2243
  respondingRequestRef.current = null;
@@ -2197,6 +2252,24 @@ function useHumanInputRequests(sessionId, options = {}) {
2197
2252
  enabled,
2198
2253
  ...options.events !== void 0 ? { events: options.events } : {}
2199
2254
  });
2255
+ useEffect8(() => {
2256
+ const now2 = Date.now();
2257
+ const nextDeadline = (loadedRequests ?? []).reduce((next, request) => {
2258
+ if (request.status !== "pending" || !request.expiresAt) return next;
2259
+ const deadline = Date.parse(request.expiresAt);
2260
+ if (!Number.isFinite(deadline) || deadline <= now2) return next;
2261
+ return next === null ? deadline : Math.min(next, deadline);
2262
+ }, null);
2263
+ if (nextDeadline === null) return;
2264
+ const timer = globalThis.setTimeout(
2265
+ () => {
2266
+ setDeadlineVersion((current) => current + 1);
2267
+ void refreshRequests();
2268
+ },
2269
+ Math.min(2147483647, Math.max(0, nextDeadline - now2 + 1))
2270
+ );
2271
+ return () => globalThis.clearTimeout(timer);
2272
+ }, [loadedRequests, refreshRequests]);
2200
2273
  const respond = useCallback9(
2201
2274
  async (requestId, response) => {
2202
2275
  if (!sessionId || respondingRequestRef.current !== null) return null;
@@ -2219,8 +2292,10 @@ function useHumanInputRequests(sessionId, options = {}) {
2219
2292
  },
2220
2293
  [client, mutation, sessionId, state, workspaceId]
2221
2294
  );
2295
+ const now = Date.now();
2296
+ void deadlineVersion;
2222
2297
  return {
2223
- requests: [...state.data ?? []].sort(
2298
+ requests: [...state.data ?? []].filter((request) => isActionableHumanInputRequest(request, now)).sort(
2224
2299
  (left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id)
2225
2300
  ),
2226
2301
  loading: state.loading,
@@ -2234,6 +2309,7 @@ function useHumanInputRequests(sessionId, options = {}) {
2234
2309
  }
2235
2310
 
2236
2311
  export {
2312
+ createEmbeddedSessionClient,
2237
2313
  isTitleEvent,
2238
2314
  useSession,
2239
2315
  SESSION_EVENT_BROWSER_MAX_BYTES,
@@ -2255,9 +2331,7 @@ export {
2255
2331
  useSessionLineage,
2256
2332
  approvalsFromRequiresAction,
2257
2333
  projectPendingApprovals,
2258
- humanInputRequestFromEvent,
2259
- projectPendingHumanInputRequests,
2260
2334
  isHumanInputEvent,
2261
2335
  useHumanInputRequests
2262
2336
  };
2263
- //# sourceMappingURL=chunk-ATQJEWCA.js.map
2337
+ //# sourceMappingURL=chunk-YJFGAFBD.js.map