@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.
- package/README.md +15 -0
- package/dist/accounts.d.ts +64 -0
- package/dist/accounts.js +746 -0
- package/dist/accounts.js.map +1 -0
- package/dist/{browser-viewer-GXUICIAG.js → browser-viewer-AEFHUYZK.js} +3 -3
- package/dist/{chunk-MXJGO7LE.js → chunk-D3UIAJKY.js} +52 -2
- package/dist/chunk-D3UIAJKY.js.map +1 -0
- package/dist/{chunk-QGBJ6GHG.js → chunk-ELIYWBZR.js} +4 -4
- package/dist/{chunk-6H6S5V4Z.js → chunk-HQVCKCLG.js} +758 -871
- package/dist/chunk-HQVCKCLG.js.map +1 -0
- package/dist/{chunk-T7VAYG2I.js → chunk-MZ2G2XBA.js} +54 -2
- package/dist/chunk-MZ2G2XBA.js.map +1 -0
- package/dist/{chunk-X4JAFD5R.js → chunk-OAM4WAAM.js} +4 -4
- package/dist/{chunk-KSDXER4X.js → chunk-RGALCTWO.js} +64 -15
- package/dist/chunk-RGALCTWO.js.map +1 -0
- package/dist/chunk-YFKJ7VZH.js +268 -0
- package/dist/chunk-YFKJ7VZH.js.map +1 -0
- package/dist/{chunk-ATQJEWCA.js → chunk-YJFGAFBD.js} +124 -50
- package/dist/chunk-YJFGAFBD.js.map +1 -0
- package/dist/components/composer.d.ts +8 -0
- package/dist/components/file-browser.d.ts +4 -1
- package/dist/components/sandbox-files.d.ts +4 -1
- package/dist/components/sandbox-workspace.d.ts +5 -0
- package/dist/composer.js +3 -3
- package/dist/{computer-viewer-ZOP4Q7A7.js → computer-viewer-FWEZISW4.js} +3 -3
- package/dist/embedded-session-client.d.ts +23 -0
- package/dist/file-node-visibility.d.ts +15 -0
- package/dist/hooks/use-file-attachments.d.ts +9 -2
- package/dist/human-input.d.ts +3 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +139 -53
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +3 -3
- package/dist/session-ui.js +4 -4
- package/dist/session.d.ts +2 -0
- package/dist/session.js +7 -5
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/screenshot-lightbox.d.ts +16 -1
- package/package.json +6 -2
- package/src/accounts.tsx +970 -0
- package/src/components/chat-composer.tsx +88 -84
- package/src/components/composer.tsx +61 -9
- package/src/components/file-browser.tsx +33 -20
- package/src/components/human-input-surface.tsx +10 -6
- package/src/components/message-timeline.tsx +37 -9
- package/src/components/sandbox-files.tsx +42 -2
- package/src/components/sandbox-workspace.tsx +10 -0
- package/src/embedded-session-client.ts +104 -0
- package/src/file-node-visibility.ts +66 -0
- package/src/hooks/use-composer.ts +64 -2
- package/src/hooks/use-file-attachments.ts +38 -6
- package/src/hooks/use-human-input.ts +31 -4
- package/src/human-input.ts +12 -1
- package/src/index.ts +12 -0
- package/src/session.ts +5 -0
- package/src/timeline/index.ts +1 -0
- package/src/timeline/screenshot-lightbox.tsx +93 -29
- package/styles/compiled.css +11 -1
- package/styles/tokens.css +3 -1
- package/dist/chunk-6H6S5V4Z.js.map +0 -1
- package/dist/chunk-ATQJEWCA.js.map +0 -1
- package/dist/chunk-FK6VG4LL.js +0 -90
- package/dist/chunk-FK6VG4LL.js.map +0 -1
- package/dist/chunk-KSDXER4X.js.map +0 -1
- package/dist/chunk-MXJGO7LE.js.map +0 -1
- package/dist/chunk-T7VAYG2I.js.map +0 -1
- /package/dist/{browser-viewer-GXUICIAG.js.map → browser-viewer-AEFHUYZK.js.map} +0 -0
- /package/dist/{chunk-QGBJ6GHG.js.map → chunk-ELIYWBZR.js.map} +0 -0
- /package/dist/{chunk-X4JAFD5R.js.map → chunk-OAM4WAAM.js.map} +0 -0
- /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":";;;;;;;;;AASA,SAAS,WAAW,wBAAwB;AAC5C,SAAS,eAAe,kBAA2D;AAgB1E,cAgDH,YAhDG;AANT,IAAM,uBAAuB,cAAgD,IAAI;AAEjF,SAAS,gBAAgB;AAAA,EACvB,gBAAgB;AAAA,EAChB,GAAG;AACL,GAAqD;AACnD,SAAO,oBAAC,iBAAiB,UAAjB,EAA0B,eAA+B,GAAG,OAAO;AAC7E;AAEA,SAAS,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAiD;AACrF,QAAM,SAAS,qBAAkC;AACjD,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAAO,QACpC,8BAAC,iBAAiB,MAAjB,EAAsB,aAAU,WAAW,GAAG,OAC5C,UACH,GACF;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB,UAAU;AAAA,EACV,GAAG;AACL,GAAoD;AAClD,QAAM,YAAY,WAAW,oBAAoB;AACjD,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,KAAK,CAAC,SAAS;AACb,mBAAW,IAAI,IAAI;AAAA,MACrB;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAM,sBAAqC;AAAA,EACzC,iBAAiB;AAAA,EACjB,OAAO;AACT;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoD;AAClD,QAAM,SAAS,WAAW,oBAAoB;AAC9C,QAAM,cAAc,oBAAoB,QAAQ,UAAU,IAAI;AAE9D,SACE,oBAAC,iBAAiB,QAAjB,EACC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,EAAE,GAAG,aAAa,GAAG,qBAAqB,GAAG,MAAM;AAAA,MACzD,GAAG;AAAA,MAEH;AAAA;AAAA,QACD;AAAA,UAAC,iBAAiB;AAAA,UAAjB;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,iBAAiB;AAAA,cACjB,MAAM;AAAA,YACR;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;;;ACjGA,SAAS,cAAc,aAAa;AACpC,SAAS,iBAAiB,cAAc;AACxC;AAAA,EACE,iBAAAA;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,cAAc;AAkFZ,0BAAAC,MA0GS,QAAAC,aA1GT;AAhDX,IAAM,kBAAkBC,eAAyC,IAAI;AAG9D,SAAS,cAAkC;AAChD,SAAOC,YAAW,eAAe,KAAK;AACxC;AAOO,SAAS,sBAAiD;AAC/D,SAAOA,YAAW,eAAe;AACnC;AAEA,IAAM,OAA2B,EAAE,MAAM,MAAM;AAAC,EAAE;AAG3C,SAAS,4BAA4B;AAC1C,MAAI,iBAAsC;AAC1C,SAAO;AAAA,IACL,QAAQ,SAAoC;AAC1C,YAAM,WAAW;AACjB,uBAAiB,WAAW;AAC5B,iBAAW;AAAA,IACb;AAAA,IACA,UAAU;AACR,YAAM,UAAU;AAChB,uBAAiB;AACjB,gBAAU;AAAA,IACZ;AAAA,EACF;AACF;AAYO,SAAS,iBAAiB,EAAE,SAAS,GAA4B;AACtE,QAAM,WAAWA,YAAW,eAAe;AAC3C,MAAI,UAAU;AACZ,WAAO,gBAAAH,KAAA,YAAG,UAAS;AAAA,EACrB;AACA,SAAO,gBAAAA,KAAC,gBAAc,UAAS;AACjC;AAEA,SAAS,aAAa,EAAE,SAAS,GAA4B;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAMhB,IAAI;AACd,QAAM,CAAC,aAAa,cAAc,IAAI,SAA6B,IAAI;AACvE,QAAM,cAAc,QAAQ,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACjE,QAAM,cAAc,oBAAoB,WAAW;AAEnD,QAAM,uBAAuB,YAAY,MAAM;AAC7C,gBAAY,QAAQ;AAAA,EACtB,GAAG,CAAC,WAAW,CAAC;AAEhB,YAAU,MAAM,sBAAsB,CAAC,oBAAoB,CAAC;AAE5D,QAAM,OAAO;AAAA,IACX,CACE,KACA,SACA,QACA,QAAQ,cACR,kBACA,eACA,kBACG;AACH,kBAAY,QAAQ,aAAa;AACjC,qBAAe,UAAU,IAAI;AAC7B,eAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC7B,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,QAC/C,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,QAAQ,YAAY,MAAM;AAC9B,yBAAqB;AACrB,aAAS,IAAI;AACb,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,oBAAoB,CAAC;AAEzB,QAAM,aAAa,QAA4B,OAAO,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;AAEvE,SACE,gBAAAC,MAAC,gBAAgB,UAAhB,EAAyB,OAAO,YAC9B;AAAA;AAAA,IACD,gBAAAD,KAAC,OAAO,MAAP,EAAY,MAAM,UAAU,MAAM,cAAc,CAAC,SAAS,CAAC,QAAQ,MAAM,GACxE,0BAAAA,KAAC,mBACE,oBAAU,OACT,gBAAAC,MAAC,OAAO,QAAP,EAAc,YAAU,MACvB;AAAA,sBAAAD,KAAC,OAAO,SAAP,EAAe,SAAO,MAAC,YAAU,MAChC,0BAAAA;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,MAAM,EAAE,SAAS,EAAE;AAAA,UACnB,YAAY,EAAE,UAAU,KAAK;AAAA,UAC7B,WAAU;AAAA,UACV,OAAO;AAAA;AAAA,MACT,GACF;AAAA,MACA,gBAAAA;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,SAAO;AAAA,UACP,YAAU;AAAA,UACV,cAAY,MAAM;AAAA,UAClB,iBAAiB,CAAC,UAAU,MAAM,eAAe;AAAA,UAEjD,0BAAAC;AAAA,YAAC,OAAO;AAAA,YAAP;AAAA,cACC,SAAS,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,cACnC,SAAS,EAAE,SAAS,GAAG,OAAO,EAAE;AAAA,cAChC,MAAM,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,cAChC,YAAY,EAAE,UAAU,MAAM,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE;AAAA,cAOtD,SAAS,CAAC,UAAU;AAClB,oBAAI,MAAM,WAAW,MAAM,eAAe;AACxC,wBAAM;AAAA,gBACR;AAAA,cACF;AAAA,cACA,WAAU;AAAA,cACV,OAAO;AAAA,cAEP;AAAA,gCAAAD,KAAC,OAAO,OAAP,EAAa,WAAU,WAAW,gBAAM,OAAM;AAAA,gBAC/C,gBAAAA,KAAC,OAAO,aAAP,EAAmB,WAAU,WAC3B,gBAAM,WAAW,YAAY,MAAM,MAAM,YAAY,CAAC,IACzD;AAAA,gBAMA,gBAAAC,MAAC,YAAO,WAAU,6DAChB;AAAA,kCAAAA,MAAC,SAAI,WAAU,0CAEb;AAAA,oCAAAD;AAAA,sBAAC;AAAA;AAAA,wBACC,KAAK,MAAM;AAAA,wBACX,KAAK,MAAM,WAAW,MAAM;AAAA,wBAC5B,WAAU;AAAA;AAAA,oBACZ;AAAA,oBACA,gBAAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,KAAK,MAAM;AAAA,wBACX,kBAAkB,MAAM;AAAA,wBACxB,eAAe,MAAM;AAAA;AAAA,oBACvB;AAAA,qBACF;AAAA,kBACC,MAAM,UACL,gBAAAA,KAAC,gBAAW,WAAU,+DACnB,gBAAM,SACT,IAEA,gBAAAA,KAAC,gBAAW,WAAU,oEAAmE,2CAEzF;AAAA,mBAEJ;AAAA;AAAA;AAAA,UACF;AAAA;AAAA,MACF;AAAA,OACF,IACE,MACN,GACF;AAAA,KACF;AAEJ;AAGO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,gBAAAC,MAAC,SAAI,WAAU,oDACZ;AAAA,uBACC,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,UAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,cAAY,eAAe,YAAY,YAAY,gBAAgB;AAAA,QAEnE,0BAAAA,KAAC,gBAAa,WAAU,UAAS;AAAA;AAAA,IACnC,IACE;AAAA,IACJ,gBAAAA;AAAA,MAAC,OAAO;AAAA,MAAP;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,cAAY,eAAe,SAAS;AAAA,QAEpC,0BAAAA,KAAC,SAAM,WAAU,UAAS;AAAA;AAAA,IAC5B;AAAA,KACF;AAEJ;","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-
|
|
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
|
|
1090
|
-
|
|
1091
|
-
|
|
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-
|
|
2337
|
+
//# sourceMappingURL=chunk-YJFGAFBD.js.map
|