@opengeni/react 3.8.0-canary.1 → 4.0.1-canary.1

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 (63) hide show
  1. package/README.md +10 -24
  2. package/dist/artifacts.js +7 -7
  3. package/dist/{browser-viewer-SS46LUAC.js → browser-viewer-NTD6UIPR.js} +3 -3
  4. package/dist/{chunk-VEPNNDNG.js → chunk-24M4YBCL.js} +4 -4
  5. package/dist/{chunk-ELIYWBZR.js → chunk-BV5A4OTE.js} +4 -4
  6. package/dist/{chunk-7W6PVVTK.js → chunk-CQG7YUJB.js} +2582 -1037
  7. package/dist/chunk-CQG7YUJB.js.map +1 -0
  8. package/dist/{chunk-BXJOQFCD.js → chunk-HUMIRRYI.js} +84 -221
  9. package/dist/chunk-HUMIRRYI.js.map +1 -0
  10. package/dist/{chunk-7BWFU6H4.js → chunk-Z7WBDB4E.js} +395 -287
  11. package/dist/chunk-Z7WBDB4E.js.map +1 -0
  12. package/dist/components/human-input-form.d.ts +3 -1
  13. package/dist/components/human-input-surface.d.ts +3 -2
  14. package/dist/components/markdown-table-layout.d.ts +9 -0
  15. package/dist/components/session-conversation.d.ts +2 -0
  16. package/dist/composer.js +2 -3
  17. package/dist/{computer-viewer-FWEZISW4.js → computer-viewer-7TEZC6Y2.js} +3 -3
  18. package/dist/hooks/use-codex-accounts.d.ts +11 -1
  19. package/dist/hooks/use-session-events.d.ts +2 -2
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +44 -34
  22. package/dist/index.js.map +1 -1
  23. package/dist/interaction.js +3 -3
  24. package/dist/markdown-table-layout-3Z3AWBY7.js +71 -0
  25. package/dist/markdown-table-layout-3Z3AWBY7.js.map +1 -0
  26. package/dist/older-history.d.ts +3 -2
  27. package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-27LKAWZD.js} +2 -2
  28. package/dist/platform-activity-row-27LKAWZD.js.map +1 -0
  29. package/dist/realtime.js +3 -3
  30. package/dist/session-ui.js +6 -9
  31. package/dist/session.js +1 -1
  32. package/dist/timeline/types.d.ts +3 -0
  33. package/package.json +2 -6
  34. package/src/components/human-input-form.tsx +185 -53
  35. package/src/components/human-input-surface.tsx +3 -0
  36. package/src/components/markdown-table-layout.ts +85 -0
  37. package/src/components/markdown.tsx +20 -2
  38. package/src/components/message-timeline.tsx +47 -7
  39. package/src/components/session-commands-panel.tsx +7 -1
  40. package/src/components/session-conversation.tsx +4 -1
  41. package/src/hooks/use-codex-accounts.ts +32 -5
  42. package/src/hooks/use-session-events.ts +16 -277
  43. package/src/index.ts +0 -1
  44. package/src/older-history.ts +22 -4
  45. package/src/timeline/platform-activity-row.tsx +4 -1
  46. package/src/timeline/projection.ts +99 -9
  47. package/src/timeline/types.ts +3 -0
  48. package/dist/chat.d.ts +0 -37
  49. package/dist/chat.js +0 -315
  50. package/dist/chat.js.map +0 -1
  51. package/dist/chunk-7BWFU6H4.js.map +0 -1
  52. package/dist/chunk-7W6PVVTK.js.map +0 -1
  53. package/dist/chunk-BXJOQFCD.js.map +0 -1
  54. package/dist/chunk-HQV2I5HV.js +0 -124
  55. package/dist/chunk-HQV2I5HV.js.map +0 -1
  56. package/dist/chunk-YAIPFO5D.js +0 -1416
  57. package/dist/chunk-YAIPFO5D.js.map +0 -1
  58. package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
  59. package/src/chat.tsx +0 -393
  60. /package/dist/{browser-viewer-SS46LUAC.js.map → browser-viewer-NTD6UIPR.js.map} +0 -0
  61. /package/dist/{chunk-VEPNNDNG.js.map → chunk-24M4YBCL.js.map} +0 -0
  62. /package/dist/{chunk-ELIYWBZR.js.map → chunk-BV5A4OTE.js.map} +0 -0
  63. /package/dist/{computer-viewer-FWEZISW4.js.map → computer-viewer-7TEZC6Y2.js.map} +0 -0
@@ -1,1416 +0,0 @@
1
- import {
2
- copyTextToClipboard,
3
- tableElementToTsv
4
- } from "./chunk-JVYQRRC4.js";
5
- import {
6
- Tooltip,
7
- TooltipContent,
8
- TooltipProvider,
9
- TooltipTrigger
10
- } from "./chunk-HQV2I5HV.js";
11
- import {
12
- cn
13
- } from "./chunk-22KP6LR5.js";
14
-
15
- // src/components/human-input-form.tsx
16
- import { ChevronDownIcon, ChevronUpIcon, MessageCircleQuestionIcon } from "lucide-react";
17
- import { useEffect, useId, useRef, useState } from "react";
18
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
- var defaultHumanInputFormMessages = {
20
- title: "Input required",
21
- /** Multi-question chrome has no default subtitle; hosts may still override. */
22
- description: "",
23
- submit: "Send answers",
24
- skip: "Skip",
25
- submitting: "Submitting\u2026",
26
- other: "Other",
27
- deadlineLabel: "Expires",
28
- formatDeadline,
29
- required: "This question is required.",
30
- otherRequired: "Enter a value for Other.",
31
- minSelections: (count) => `Choose at least ${count} option${count === 1 ? "" : "s"}.`,
32
- maxSelections: (count) => `Choose no more than ${count} option${count === 1 ? "" : "s"}.`,
33
- optional: "Optional",
34
- moreBelow: "More below",
35
- questionCount: (count) => `${count} questions`,
36
- collapse: "Collapse",
37
- expand: "Expand",
38
- selectionHint: (min, max) => {
39
- if (min != null && max != null) return `Choose ${min}\u2013${max}.`;
40
- if (min != null) return `Choose at least ${min}.`;
41
- if (max != null) return `Choose up to ${max}.`;
42
- return null;
43
- }
44
- };
45
- function HumanInputForm(props) {
46
- return /* @__PURE__ */ jsx(HumanInputRequestForm, { ...props }, props.request.id);
47
- }
48
- function HumanInputRequestForm({
49
- request,
50
- onSubmit,
51
- submitting = false,
52
- error,
53
- title,
54
- description,
55
- progressLabel,
56
- submitLabel,
57
- skipLabel,
58
- messages: messageOverrides,
59
- autoFocus = true,
60
- defaultCollapsed = false,
61
- className
62
- }) {
63
- const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
64
- const singleQuestion = request.questions.length === 1 ? request.questions[0] : null;
65
- const resolvedTitle = title === void 0 ? singleQuestion ? singleQuestion.label ?? singleQuestion.prompt : messages.title : title;
66
- const resolvedDescription = description === void 0 ? singleQuestion ? singleQuestion.label ? singleQuestion.prompt : singleQuestion.helpText ?? null : messages.description || null : description;
67
- const resolvedSubmitLabel = submitLabel ?? messages.submit;
68
- const resolvedSkipLabel = skipLabel ?? messages.skip;
69
- const formId = useId();
70
- const titleId = useId();
71
- const scrollRef = useRef(null);
72
- const [drafts, setDrafts] = useState(
73
- () => initialDrafts(request.questions)
74
- );
75
- const [validationErrors, setValidationErrors] = useState({});
76
- const [submissionError, setSubmissionError] = useState(null);
77
- const [submittingInternally, setSubmittingInternally] = useState(false);
78
- const [overflowBelow, setOverflowBelow] = useState(false);
79
- const [collapsed, setCollapsed] = useState(defaultCollapsed);
80
- const submissionInFlight = useRef(false);
81
- const submissionGeneration = useRef(0);
82
- const busy = submitting || submittingInternally;
83
- useEffect(() => {
84
- if (collapsed) {
85
- setOverflowBelow(false);
86
- return;
87
- }
88
- const node = scrollRef.current;
89
- if (!node) return;
90
- const sync = () => {
91
- const { scrollTop, scrollHeight, clientHeight } = node;
92
- setOverflowBelow(
93
- scrollHeight > clientHeight + 2 && scrollTop + clientHeight < scrollHeight - 4
94
- );
95
- };
96
- const frame = requestAnimationFrame(sync);
97
- node.addEventListener("scroll", sync, { passive: true });
98
- const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(sync) : null;
99
- observer?.observe(node);
100
- const content = node.firstElementChild;
101
- if (content) observer?.observe(content);
102
- return () => {
103
- cancelAnimationFrame(frame);
104
- node.removeEventListener("scroll", sync);
105
- observer?.disconnect();
106
- };
107
- }, [request.id, request.questions, collapsed]);
108
- const update = (questionId, apply) => {
109
- setDrafts((current) => ({
110
- ...current,
111
- [questionId]: apply(current[questionId] ?? emptyDraft())
112
- }));
113
- setValidationErrors((current) => {
114
- if (!(questionId in current)) return current;
115
- const next = { ...current };
116
- delete next[questionId];
117
- return next;
118
- });
119
- };
120
- const submitResponse = async (response) => {
121
- if (busy || submissionInFlight.current) return;
122
- const generation = submissionGeneration.current;
123
- submissionInFlight.current = true;
124
- setSubmissionError(null);
125
- setSubmittingInternally(true);
126
- try {
127
- await onSubmit(response);
128
- } catch (cause) {
129
- if (generation === submissionGeneration.current) {
130
- setSubmissionError(cause instanceof Error ? cause.message : String(cause));
131
- }
132
- } finally {
133
- if (generation === submissionGeneration.current) {
134
- submissionInFlight.current = false;
135
- setSubmittingInternally(false);
136
- }
137
- }
138
- };
139
- const focusQuestion = (questionId) => {
140
- const root = scrollRef.current;
141
- if (!root) return;
142
- const block = Array.from(
143
- root.querySelectorAll("[data-human-input-question]")
144
- ).find((node) => node.getAttribute("data-human-input-question") === questionId);
145
- block?.scrollIntoView({ block: "nearest", behavior: "smooth" });
146
- const focusable = block?.querySelector(
147
- "input:not([type='hidden']):not([disabled]), textarea:not([disabled])"
148
- );
149
- focusable?.focus({ preventScroll: true });
150
- };
151
- const submit = async (event) => {
152
- event.preventDefault();
153
- const result = answersFromDrafts(request.questions, drafts, messages);
154
- if (Object.keys(result.errors).length > 0) {
155
- setValidationErrors(result.errors);
156
- const firstInvalid = request.questions.find((question) => question.id in result.errors);
157
- if (firstInvalid) {
158
- requestAnimationFrame(() => focusQuestion(firstInvalid.id));
159
- }
160
- return;
161
- }
162
- await submitResponse({ outcome: "answered", answers: result.answers });
163
- };
164
- const metaBits = [
165
- progressLabel,
166
- !singleQuestion ? messages.questionCount(request.questions.length) : null,
167
- request.expiresAt ? /* @__PURE__ */ jsxs(Fragment, { children: [
168
- messages.deadlineLabel,
169
- " ",
170
- /* @__PURE__ */ jsx("time", { dateTime: request.expiresAt, title: new Date(request.expiresAt).toLocaleString(), children: messages.formatDeadline(request.expiresAt) })
171
- ] }) : null
172
- ].filter(Boolean);
173
- if (collapsed) {
174
- return /* @__PURE__ */ jsxs(
175
- "div",
176
- {
177
- "data-human-input-request": request.id,
178
- "data-human-input-collapsed": "",
179
- "aria-labelledby": titleId,
180
- className: cn(
181
- "og-root flex w-full items-center gap-3 rounded-og-lg border border-og-status-waiting/35 bg-og-status-waiting/5 px-3 py-2.5 shadow-og-sm",
182
- className
183
- ),
184
- children: [
185
- /* @__PURE__ */ jsx("span", { className: "inline-flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-status-waiting/12 text-og-status-waiting", children: /* @__PURE__ */ jsx(MessageCircleQuestionIcon, { "aria-hidden": "true", className: "size-4" }) }),
186
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
187
- /* @__PURE__ */ jsx("h2", { id: titleId, className: "truncate text-og-sm font-semibold text-og-fg", children: resolvedTitle }),
188
- metaBits.length > 0 ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 truncate text-og-xs text-og-fg-subtle", children: metaBits.join(" \xB7 ") }) : null
189
- ] }),
190
- /* @__PURE__ */ jsxs(
191
- "button",
192
- {
193
- type: "button",
194
- onClick: () => setCollapsed(false),
195
- className: "inline-flex min-h-8 shrink-0 items-center gap-1 rounded-og-md border border-og-border px-2.5 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg",
196
- children: [
197
- messages.expand,
198
- /* @__PURE__ */ jsx(ChevronDownIcon, { "aria-hidden": "true", className: "size-3.5" })
199
- ]
200
- }
201
- )
202
- ]
203
- }
204
- );
205
- }
206
- return /* @__PURE__ */ jsxs(
207
- "form",
208
- {
209
- "data-human-input-request": request.id,
210
- onSubmit: (event) => void submit(event),
211
- "aria-labelledby": titleId,
212
- className: cn(
213
- // Multi-question: pin height at the cap so the flex body gets a real
214
- // box and overflow-y engages. max-height alone + percentage/`h-full`
215
- // children often sizes to content and clips with no scroll.
216
- "og-root flex min-h-0 w-full flex-col overflow-hidden rounded-og-lg border border-og-status-waiting/35 bg-og-status-waiting/5 shadow-og-sm",
217
- singleQuestion ? "max-h-[min(28rem,50dvh)]" : "h-[min(28rem,50dvh)] max-h-[min(28rem,50dvh)]",
218
- className
219
- ),
220
- children: [
221
- /* @__PURE__ */ jsx("header", { className: "shrink-0 border-b border-og-status-waiting/20 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
222
- /* @__PURE__ */ jsx("span", { className: "mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-status-waiting/12 text-og-status-waiting", children: /* @__PURE__ */ jsx(MessageCircleQuestionIcon, { "aria-hidden": "true", className: "size-4" }) }),
223
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
224
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [
225
- /* @__PURE__ */ jsxs("h2", { id: titleId, className: "text-og-md font-semibold text-og-fg", children: [
226
- resolvedTitle,
227
- singleQuestion?.required && !request.allowSkip ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "ml-1 text-og-status-failed", children: "*" }) : null
228
- ] }),
229
- progressLabel ? /* @__PURE__ */ jsx("span", { className: "text-og-xs font-medium text-og-status-waiting", children: progressLabel }) : null,
230
- !singleQuestion ? /* @__PURE__ */ jsx("span", { className: "text-og-xs font-medium text-og-fg-subtle", children: messages.questionCount(request.questions.length) }) : null
231
- ] }),
232
- resolvedDescription ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-og-sm text-og-fg-muted", children: resolvedDescription }) : null,
233
- request.expiresAt ? /* @__PURE__ */ jsxs("p", { className: "mt-1 text-og-xs text-og-fg-subtle", children: [
234
- messages.deadlineLabel,
235
- " ",
236
- /* @__PURE__ */ jsx(
237
- "time",
238
- {
239
- dateTime: request.expiresAt,
240
- title: new Date(request.expiresAt).toLocaleString(),
241
- children: messages.formatDeadline(request.expiresAt)
242
- }
243
- )
244
- ] }) : null,
245
- request.allowSkip && singleQuestion ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-og-xs text-og-fg-subtle", children: "Or skip and let the agent decide." }) : null
246
- ] }),
247
- /* @__PURE__ */ jsx(
248
- "button",
249
- {
250
- type: "button",
251
- onClick: () => setCollapsed(true),
252
- "aria-label": messages.collapse,
253
- title: messages.collapse,
254
- className: "inline-flex size-8 shrink-0 items-center justify-center rounded-og-md text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg",
255
- children: /* @__PURE__ */ jsx(ChevronUpIcon, { "aria-hidden": "true", className: "size-4" })
256
- }
257
- )
258
- ] }) }),
259
- /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col overflow-hidden", children: [
260
- /* @__PURE__ */ jsx(
261
- "div",
262
- {
263
- ref: scrollRef,
264
- className: "min-h-0 flex-1 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]",
265
- children: /* @__PURE__ */ jsx("fieldset", { disabled: busy, className: "min-w-0 space-y-4 px-4 py-3", children: request.questions.map((question, index) => {
266
- if (singleQuestion) {
267
- return /* @__PURE__ */ jsx("div", { "data-human-input-question": question.id, children: /* @__PURE__ */ jsx(
268
- QuestionControls,
269
- {
270
- question,
271
- questionNumber: null,
272
- labelledBy: titleId,
273
- draft: drafts[question.id] ?? emptyDraft(),
274
- fieldId: `${formId}-${index}`,
275
- error: validationErrors[question.id],
276
- messages,
277
- autoFocus,
278
- firstOption: true,
279
- showPromptChrome: false,
280
- allowSkip: request.allowSkip,
281
- busy,
282
- onUpdate: (apply) => update(question.id, apply)
283
- }
284
- ) }, question.id);
285
- }
286
- return /* @__PURE__ */ jsx(
287
- "div",
288
- {
289
- "data-human-input-question": question.id,
290
- className: "flex flex-col gap-1.5",
291
- children: /* @__PURE__ */ jsx(
292
- QuestionControls,
293
- {
294
- question,
295
- questionNumber: index + 1,
296
- labelledBy: void 0,
297
- draft: drafts[question.id] ?? emptyDraft(),
298
- fieldId: `${formId}-${index}`,
299
- error: validationErrors[question.id],
300
- messages,
301
- autoFocus: autoFocus && index === 0,
302
- firstOption: index === 0,
303
- showPromptChrome: true,
304
- allowSkip: request.allowSkip,
305
- busy,
306
- onUpdate: (apply) => update(question.id, apply)
307
- }
308
- )
309
- },
310
- question.id
311
- );
312
- }) })
313
- }
314
- ),
315
- overflowBelow ? /* @__PURE__ */ jsxs(
316
- "div",
317
- {
318
- className: "pointer-events-none absolute inset-x-0 bottom-0 z-[1] flex flex-col items-center",
319
- "aria-hidden": "true",
320
- children: [
321
- /* @__PURE__ */ jsx("div", { className: "h-10 w-full bg-gradient-to-t from-og-surface-1 via-og-surface-1/85 to-transparent" }),
322
- /* @__PURE__ */ jsx("span", { className: "-mt-5 mb-1 rounded-og-full bg-og-surface-1 px-2.5 py-0.5 text-og-xs font-medium text-og-fg-muted shadow-og-sm ring-1 ring-og-border/60", children: messages.moreBelow })
323
- ]
324
- }
325
- ) : null
326
- ] }),
327
- error ?? submissionError ? /* @__PURE__ */ jsx(
328
- "p",
329
- {
330
- role: "alert",
331
- className: "relative z-10 shrink-0 px-4 pb-1 text-og-sm text-og-status-failed",
332
- children: error ?? submissionError
333
- }
334
- ) : null,
335
- /* @__PURE__ */ jsxs("footer", { className: "relative z-10 flex shrink-0 items-center justify-end gap-2 border-t border-og-status-waiting/20 bg-og-surface-1/95 px-4 py-3 backdrop-blur-[2px]", children: [
336
- request.allowSkip ? /* @__PURE__ */ jsx(
337
- "button",
338
- {
339
- type: "button",
340
- disabled: busy,
341
- onClick: () => void submitResponse({ outcome: "skipped" }),
342
- className: "inline-flex min-h-9 items-center rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg disabled:opacity-50",
343
- children: resolvedSkipLabel
344
- }
345
- ) : null,
346
- /* @__PURE__ */ jsx(
347
- "button",
348
- {
349
- type: "submit",
350
- disabled: busy,
351
- className: "inline-flex min-h-9 items-center rounded-og-md bg-og-accent-deep px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition hover:brightness-110 disabled:opacity-50",
352
- children: busy ? messages.submitting : resolvedSubmitLabel
353
- }
354
- )
355
- ] })
356
- ]
357
- }
358
- );
359
- }
360
- function QuestionControls({
361
- question,
362
- questionNumber,
363
- labelledBy,
364
- draft,
365
- fieldId,
366
- error,
367
- messages,
368
- autoFocus,
369
- firstOption,
370
- showPromptChrome,
371
- allowSkip,
372
- busy,
373
- onUpdate
374
- }) {
375
- const errorId = `${fieldId}-error`;
376
- const helpId = `${fieldId}-help`;
377
- const labelId = `${fieldId}-label`;
378
- const promptId = `${fieldId}-prompt`;
379
- const otherChoiceId = `${fieldId}-other-choice`;
380
- const otherLabelId = `${fieldId}-other-label`;
381
- const otherTextId = `${fieldId}-other-text`;
382
- const visibleLabel = question.label ?? question.prompt;
383
- const controlLabelId = showPromptChrome ? labelId : labelledBy;
384
- const hint = question.kind === "multi_select" ? messages.selectionHint(
385
- question.validation?.minSelections,
386
- question.validation?.maxSelections
387
- ) : null;
388
- const describedBy = [
389
- question.label && showPromptChrome ? promptId : null,
390
- question.helpText && showPromptChrome ? helpId : null,
391
- hint ? `${fieldId}-hint` : null,
392
- error ? errorId : null
393
- ].filter(Boolean).join(" ") || void 0;
394
- const selectOtherDraft = (current) => ({
395
- ...current,
396
- otherSelected: true,
397
- ...question.kind === "single_select" ? { values: [] } : {}
398
- });
399
- return /* @__PURE__ */ jsxs(Fragment, { children: [
400
- showPromptChrome ? /* @__PURE__ */ jsxs(Fragment, { children: [
401
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-baseline gap-x-2", children: /* @__PURE__ */ jsxs(
402
- "label",
403
- {
404
- id: labelId,
405
- htmlFor: question.kind === "text" ? fieldId : void 0,
406
- className: "text-og-sm font-medium text-og-fg",
407
- children: [
408
- questionNumber === null ? null : /* @__PURE__ */ jsxs("span", { className: "mr-1.5 tabular-nums text-og-fg-muted", children: [
409
- questionNumber,
410
- "."
411
- ] }),
412
- questionNumber === null ? null : " ",
413
- visibleLabel,
414
- question.required && !allowSkip ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "ml-1 text-og-status-failed", children: "*" }) : !question.required ? /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-og-xs font-normal text-og-fg-subtle", children: messages.optional }) : null
415
- ]
416
- }
417
- ) }),
418
- question.label ? /* @__PURE__ */ jsx("p", { id: promptId, className: "text-og-sm text-og-fg-muted", children: question.prompt }) : null,
419
- question.helpText ? /* @__PURE__ */ jsx("p", { id: helpId, className: "text-og-xs text-og-fg-subtle", children: question.helpText }) : null,
420
- hint ? /* @__PURE__ */ jsx("p", { id: `${fieldId}-hint`, className: "text-og-xs text-og-fg-subtle", children: hint }) : null
421
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
422
- !question.required && allowSkip === false ? /* @__PURE__ */ jsx("p", { className: "text-og-xs text-og-fg-subtle", children: messages.optional }) : null,
423
- question.helpText && question.label ? /* @__PURE__ */ jsx("p", { id: helpId, className: "mb-1.5 text-og-xs text-og-fg-subtle", children: question.helpText }) : null,
424
- hint ? /* @__PURE__ */ jsx("p", { id: `${fieldId}-hint`, className: "mb-1.5 text-og-xs text-og-fg-subtle", children: hint }) : null
425
- ] }),
426
- question.kind === "text" ? /* @__PURE__ */ jsx(
427
- "textarea",
428
- {
429
- id: fieldId,
430
- value: draft.values[0] ?? "",
431
- onChange: (event) => onUpdate((current) => ({
432
- ...current,
433
- values: event.target.value ? [event.target.value] : []
434
- })),
435
- "aria-invalid": Boolean(error),
436
- "aria-labelledby": controlLabelId,
437
- "aria-describedby": describedBy,
438
- autoFocus,
439
- rows: 2,
440
- className: "min-h-14 w-full resize-y rounded-og-md border border-og-border bg-og-surface-1 px-3 py-2 text-og-sm text-og-fg outline-hidden placeholder:text-og-fg-subtle focus:border-og-accent"
441
- }
442
- ) : /* @__PURE__ */ jsxs(
443
- "div",
444
- {
445
- role: question.kind === "single_select" ? "radiogroup" : "group",
446
- "aria-labelledby": controlLabelId,
447
- "aria-describedby": describedBy,
448
- className: "flex flex-col gap-0.5",
449
- children: [
450
- question.options.map((option, optionIndex) => {
451
- const checked = draft.values.includes(option.id);
452
- return /* @__PURE__ */ jsxs(
453
- "label",
454
- {
455
- className: cn(
456
- "flex cursor-pointer items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
457
- checked ? "bg-og-status-waiting/12 text-og-fg" : "text-og-fg hover:bg-og-surface-1/80"
458
- ),
459
- children: [
460
- /* @__PURE__ */ jsx(
461
- "input",
462
- {
463
- type: question.kind === "single_select" ? "radio" : "checkbox",
464
- name: question.kind === "single_select" ? fieldId : void 0,
465
- autoFocus: autoFocus && firstOption && optionIndex === 0,
466
- checked,
467
- onChange: (event) => onUpdate((current) => ({
468
- ...current,
469
- values: question.kind === "single_select" ? event.target.checked ? [option.id] : [] : event.target.checked ? [...current.values, option.id] : current.values.filter((value) => value !== option.id),
470
- ...question.kind === "single_select" && event.target.checked ? { otherSelected: false } : {}
471
- })),
472
- className: "mt-0.5 accent-og-accent"
473
- }
474
- ),
475
- /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
476
- /* @__PURE__ */ jsx("span", { className: "block text-og-sm font-medium", children: option.label }),
477
- option.description ? /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-og-xs text-og-fg-muted", children: option.description }) : null
478
- ] })
479
- ]
480
- },
481
- option.id
482
- );
483
- }),
484
- /* @__PURE__ */ jsxs(
485
- "div",
486
- {
487
- className: cn(
488
- "flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
489
- draft.otherSelected ? "bg-og-status-waiting/12 text-og-fg" : "text-og-fg hover:bg-og-surface-1/80"
490
- ),
491
- children: [
492
- /* @__PURE__ */ jsx(
493
- "input",
494
- {
495
- id: otherChoiceId,
496
- type: question.kind === "single_select" ? "radio" : "checkbox",
497
- name: question.kind === "single_select" ? fieldId : void 0,
498
- "aria-labelledby": otherLabelId,
499
- checked: draft.otherSelected,
500
- autoFocus: autoFocus && firstOption && question.options.length === 0,
501
- onChange: (event) => onUpdate((current) => ({
502
- ...current,
503
- otherSelected: event.target.checked,
504
- ...question.kind === "single_select" && event.target.checked ? { values: [] } : {}
505
- })),
506
- className: "mt-2 accent-og-accent"
507
- }
508
- ),
509
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
510
- /* @__PURE__ */ jsx(
511
- "label",
512
- {
513
- id: otherLabelId,
514
- htmlFor: otherChoiceId,
515
- className: "block text-og-sm font-medium",
516
- children: messages.other
517
- }
518
- ),
519
- /* @__PURE__ */ jsxs("label", { htmlFor: otherTextId, className: "sr-only", children: [
520
- messages.other,
521
- " answer for ",
522
- visibleLabel
523
- ] }),
524
- /* @__PURE__ */ jsx(
525
- "input",
526
- {
527
- id: otherTextId,
528
- type: "text",
529
- value: draft.other,
530
- disabled: busy,
531
- placeholder: "Type a value\u2026",
532
- onClick: () => onUpdate(selectOtherDraft),
533
- onFocus: () => onUpdate(selectOtherDraft),
534
- onChange: (event) => {
535
- const other = event.target.value;
536
- onUpdate((current) => ({
537
- ...selectOtherDraft(current),
538
- other
539
- }));
540
- },
541
- className: "mt-1.5 w-full rounded-og-sm border border-og-border bg-og-surface-1 px-2 py-1.5 text-og-sm text-og-fg outline-hidden focus:border-og-accent disabled:opacity-50"
542
- }
543
- )
544
- ] })
545
- ]
546
- }
547
- )
548
- ]
549
- }
550
- ),
551
- error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-og-xs text-og-status-failed", children: error }) : null
552
- ] });
553
- }
554
- function answersFromDrafts(questions, drafts, messageOverrides = {}) {
555
- const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
556
- const answers = [];
557
- const errors = {};
558
- for (const question of questions) {
559
- const draft = drafts[question.id] ?? emptyDraft();
560
- const values = question.kind === "text" ? draft.values.filter(Boolean) : draft.values;
561
- const other = draft.otherSelected ? draft.other : "";
562
- const hasOther = Boolean(other.trim());
563
- const supplied = values.length + (hasOther ? 1 : 0);
564
- if (question.kind !== "text" && draft.otherSelected && !hasOther) {
565
- errors[question.id] = messages.otherRequired;
566
- continue;
567
- }
568
- if (question.required && supplied === 0) {
569
- errors[question.id] = messages.required;
570
- continue;
571
- }
572
- if (question.kind !== "text") {
573
- const min = question.validation?.minSelections;
574
- const max = question.kind === "single_select" ? 1 : question.validation?.maxSelections;
575
- if (min != null && supplied < min) {
576
- errors[question.id] = messages.minSelections(min);
577
- continue;
578
- }
579
- if (max != null && supplied > max) {
580
- errors[question.id] = messages.maxSelections(max);
581
- continue;
582
- }
583
- }
584
- if (supplied > 0) {
585
- answers.push({
586
- questionId: question.id,
587
- values,
588
- ...hasOther ? { other } : {}
589
- });
590
- }
591
- }
592
- return { answers, errors };
593
- }
594
- function initialDrafts(questions) {
595
- return Object.fromEntries(questions.map((question) => [question.id, emptyDraft()]));
596
- }
597
- function emptyDraft() {
598
- return { values: [], other: "", otherSelected: false };
599
- }
600
- function formatDeadline(value) {
601
- const date = new Date(value);
602
- if (Number.isNaN(date.getTime())) return value;
603
- const ms = date.getTime() - Date.now();
604
- if (ms <= 0) return "deadline passed";
605
- const minutes = Math.round(ms / 6e4);
606
- if (minutes < 1) return "in under a minute";
607
- if (minutes < 60) return `in ${minutes}m`;
608
- const hours = Math.round(minutes / 60);
609
- if (hours < 48) return `in ${hours}h`;
610
- return date.toLocaleString();
611
- }
612
-
613
- // src/components/copy-button.tsx
614
- import { CheckIcon, CopyIcon } from "lucide-react";
615
- import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
616
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
617
- var COPIED_MS = 1600;
618
- function CopyButton({
619
- text,
620
- label = "Copy",
621
- className,
622
- reveal = "group-hover"
623
- }) {
624
- const [copied, setCopied] = useState2(false);
625
- const [tipOpen, setTipOpen] = useState2(false);
626
- const timerRef = useRef2(null);
627
- useEffect2(() => {
628
- return () => {
629
- if (timerRef.current !== null) {
630
- clearTimeout(timerRef.current);
631
- }
632
- };
633
- }, []);
634
- const onClick = async (event) => {
635
- event.preventDefault();
636
- event.stopPropagation();
637
- const button = event.currentTarget;
638
- const pointerActivated = event.detail > 0;
639
- const value = typeof text === "function" ? text() : text;
640
- const ok = await copyTextToClipboard(value);
641
- if (!ok) {
642
- return;
643
- }
644
- setCopied(true);
645
- setTipOpen(true);
646
- if (timerRef.current !== null) {
647
- clearTimeout(timerRef.current);
648
- }
649
- timerRef.current = setTimeout(() => {
650
- timerRef.current = null;
651
- setCopied(false);
652
- setTipOpen(false);
653
- }, COPIED_MS);
654
- if (pointerActivated) {
655
- button.blur();
656
- }
657
- };
658
- const tip = copied ? "Copied" : label;
659
- return /* @__PURE__ */ jsxs2(
660
- Tooltip,
661
- {
662
- open: copied ? true : tipOpen,
663
- onOpenChange: (next) => {
664
- if (!copied) {
665
- setTipOpen(next);
666
- }
667
- },
668
- children: [
669
- /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
670
- "button",
671
- {
672
- type: "button",
673
- "data-og-copy": "",
674
- "data-state": copied ? "copied" : "idle",
675
- "aria-label": tip,
676
- onClick,
677
- className: cn(
678
- "inline-flex size-7 shrink-0 items-center justify-center rounded-og-sm pointer-coarse:size-11",
679
- "text-og-fg-subtle transition-[opacity,color,background-color] duration-150",
680
- "hover:bg-og-surface-2/80 hover:text-og-fg",
681
- "focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent/40",
682
- reveal === "group-hover" && "opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 pointer-coarse:opacity-70",
683
- copied && "opacity-100 text-og-accent",
684
- className
685
- ),
686
- children: copied ? /* @__PURE__ */ jsx2(CheckIcon, { className: "size-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx2(CopyIcon, { className: "size-3.5", "aria-hidden": true })
687
- }
688
- ) }),
689
- /* @__PURE__ */ jsx2(TooltipContent, { side: "top", children: tip })
690
- ]
691
- }
692
- );
693
- }
694
- function CopyHoverFrame({
695
- children,
696
- className,
697
- copyText,
698
- label,
699
- align = "end",
700
- trailing
701
- }) {
702
- if (copyText.trim().length === 0) {
703
- return /* @__PURE__ */ jsx2("div", { className, children });
704
- }
705
- return /* @__PURE__ */ jsxs2("div", { className: cn("group/copy", className), children: [
706
- children,
707
- /* @__PURE__ */ jsxs2(
708
- "div",
709
- {
710
- "data-og-annotation-chrome": "",
711
- className: cn(
712
- "mt-1 flex h-7 items-center gap-1.5",
713
- align === "end" ? "justify-end" : "justify-start"
714
- ),
715
- children: [
716
- /* @__PURE__ */ jsx2(CopyButton, { text: copyText, label, reveal: "group-hover" }),
717
- trailing
718
- ]
719
- }
720
- )
721
- ] });
722
- }
723
-
724
- // src/components/markdown.tsx
725
- import {
726
- Children,
727
- isValidElement,
728
- memo,
729
- useEffect as useEffect3,
730
- useMemo,
731
- useReducer,
732
- useRef as useRef3,
733
- useState as useState3
734
- } from "react";
735
- import ReactMarkdown, {
736
- defaultUrlTransform
737
- } from "react-markdown";
738
- import remarkGfm from "remark-gfm";
739
-
740
- // src/lib/motion.ts
741
- import { flushSync } from "react-dom";
742
- var query;
743
- function prefersReducedMotion() {
744
- if (query === void 0) {
745
- query = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
746
- }
747
- return query?.matches ?? false;
748
- }
749
-
750
- // src/lib/motion-inspect.ts
751
- var MOTION_INSPECT_SCALE = 1;
752
-
753
- // src/components/soften-streaming-markdown.ts
754
- function softenStreamingMarkdown(source) {
755
- if (source.length === 0) {
756
- return source;
757
- }
758
- let text = source;
759
- if (countFences(text) % 2 === 1) {
760
- text += text.endsWith("\n") ? "```" : "\n```";
761
- }
762
- const segments = splitByFences(text);
763
- for (const segment of segments) {
764
- if (segment.kind === "fence") {
765
- continue;
766
- }
767
- segment.value = closeInlineMarkers(segment.value);
768
- }
769
- let result = segments.map((segment) => segment.value).join("");
770
- if (text.endsWith("\n") && !result.endsWith("\n")) {
771
- result += "\n";
772
- }
773
- return result;
774
- }
775
- function countFences(text) {
776
- let count = 0;
777
- for (const line of text.split("\n")) {
778
- if (/^ {0,3}```/.test(line)) {
779
- count += 1;
780
- }
781
- }
782
- return count;
783
- }
784
- function splitByFences(text) {
785
- const segments = [];
786
- const lines = text.split("\n");
787
- let buf = [];
788
- let inFence = false;
789
- const flush = (kind, mode) => {
790
- if (buf.length === 0) {
791
- return;
792
- }
793
- let value = buf.join("\n");
794
- if (mode === "boundary") {
795
- value += "\n";
796
- }
797
- segments.push({ kind, value });
798
- buf = [];
799
- };
800
- for (const line of lines) {
801
- const isFence = /^ {0,3}```/.test(line);
802
- if (isFence) {
803
- if (inFence) {
804
- buf.push(line);
805
- flush("fence", "end");
806
- inFence = false;
807
- } else {
808
- flush("prose", "boundary");
809
- buf.push(line);
810
- inFence = true;
811
- }
812
- continue;
813
- }
814
- buf.push(line);
815
- }
816
- flush(inFence ? "fence" : "prose", "end");
817
- return segments;
818
- }
819
- function closeInlineMarkers(prose) {
820
- let text = prose;
821
- text = closeDelimiter(text, "~~");
822
- text = closeDelimiter(text, "**");
823
- text = closeDelimiter(text, "__");
824
- text = closeSingleBackticks(text);
825
- text = closeSingleAsterisks(text);
826
- text = closeUnfinishedLink(text);
827
- return text;
828
- }
829
- function closeDelimiter(text, delimiter) {
830
- let count = 0;
831
- let i = 0;
832
- while (i < text.length) {
833
- if (text[i] === "\\" && i + 1 < text.length) {
834
- i += 2;
835
- continue;
836
- }
837
- if (text.startsWith(delimiter, i)) {
838
- count += 1;
839
- i += delimiter.length;
840
- continue;
841
- }
842
- i += 1;
843
- }
844
- return count % 2 === 1 ? insertBeforeTrailingNewlines(text, delimiter) : text;
845
- }
846
- function insertBeforeTrailingNewlines(text, suffix) {
847
- let end = text.length;
848
- while (end > 0 && text[end - 1] === "\n") {
849
- end -= 1;
850
- }
851
- return text.slice(0, end) + suffix + text.slice(end);
852
- }
853
- function closeSingleBackticks(text) {
854
- let count = 0;
855
- for (let i = 0; i < text.length; i += 1) {
856
- if (text[i] === "\\" && i + 1 < text.length) {
857
- i += 1;
858
- continue;
859
- }
860
- if (text[i] === "`") {
861
- if (text.startsWith("```", i)) {
862
- i += 2;
863
- continue;
864
- }
865
- count += 1;
866
- }
867
- }
868
- return count % 2 === 1 ? insertBeforeTrailingNewlines(text, "`") : text;
869
- }
870
- function closeSingleAsterisks(text) {
871
- let count = 0;
872
- for (let i = 0; i < text.length; i += 1) {
873
- if (text[i] === "\\" && i + 1 < text.length) {
874
- i += 1;
875
- continue;
876
- }
877
- if (text[i] === "*" && text[i + 1] === "*") {
878
- i += 1;
879
- continue;
880
- }
881
- if (text[i] === "*") {
882
- count += 1;
883
- }
884
- }
885
- return count % 2 === 1 ? insertBeforeTrailingNewlines(text, "*") : text;
886
- }
887
- function closeUnfinishedLink(text) {
888
- const open = text.lastIndexOf("](");
889
- if (open === -1) {
890
- return text;
891
- }
892
- const after = text.slice(open + 2);
893
- if (after.includes(")")) {
894
- return text;
895
- }
896
- if (after.includes("[")) {
897
- return text;
898
- }
899
- return insertBeforeTrailingNewlines(text, ")");
900
- }
901
-
902
- // src/components/stream-reveal.ts
903
- var INK_FADE_MS = 420 * MOTION_INSPECT_SCALE;
904
- var INITIAL_ANIMATED_LIMIT = 400;
905
- function createStreamReveal() {
906
- let batches = [];
907
- let revealedChars = -1;
908
- return {
909
- observe(text, now) {
910
- if (revealedChars === -1) {
911
- revealedChars = text.length > INITIAL_ANIMATED_LIMIT ? text.length : 0;
912
- }
913
- if (text.length <= revealedChars) {
914
- revealedChars = Math.max(revealedChars, text.length);
915
- return;
916
- }
917
- batches.push({ start: revealedChars, end: text.length, birth: now });
918
- revealedChars = text.length;
919
- batches = batches.filter((batch) => batch.birth + INK_FADE_MS > now);
920
- },
921
- delayFor(offset, now) {
922
- const batch = findBatch(batches, offset);
923
- if (!batch) {
924
- return null;
925
- }
926
- const delay = batch.birth - now;
927
- return delay + INK_FADE_MS <= 0 ? null : delay;
928
- },
929
- hasActive(now) {
930
- const last = batches[batches.length - 1];
931
- return last !== void 0 && last.birth + INK_FADE_MS > now;
932
- }
933
- };
934
- }
935
- function findBatch(batches, offset) {
936
- let low = 0;
937
- let high = batches.length - 1;
938
- while (low <= high) {
939
- const mid = low + high >> 1;
940
- const batch = batches[mid];
941
- if (offset < batch.start) {
942
- high = mid - 1;
943
- } else if (offset >= batch.end) {
944
- low = mid + 1;
945
- } else {
946
- return batch;
947
- }
948
- }
949
- return null;
950
- }
951
- function rehypeStreamReveal(options) {
952
- const { reveal, now } = options;
953
- return (tree) => {
954
- walk(tree, false);
955
- };
956
- function walk(node, insideVerbatim) {
957
- if (!node.children) {
958
- return;
959
- }
960
- const verbatim = insideVerbatim || node.tagName === "code" || node.tagName === "pre";
961
- const next = [];
962
- for (const child of node.children) {
963
- if (child.type === "text" && !verbatim) {
964
- next.push(...splitTextNode(child));
965
- continue;
966
- }
967
- walk(child, verbatim);
968
- next.push(child);
969
- }
970
- node.children = next;
971
- }
972
- function splitTextNode(node) {
973
- const sourceOffset = node.position?.start?.offset;
974
- if (sourceOffset === void 0) {
975
- return [node];
976
- }
977
- const value = node.value;
978
- const out = [];
979
- let plain = "";
980
- const flushPlain = () => {
981
- if (plain.length > 0) {
982
- out.push({ type: "text", value: plain });
983
- plain = "";
984
- }
985
- };
986
- let i = 0;
987
- while (i < value.length) {
988
- const delay = reveal.delayFor(sourceOffset + i, now);
989
- let j = i + 1;
990
- while (j < value.length) {
991
- const nextDelay = reveal.delayFor(sourceOffset + j, now);
992
- if (nextDelay !== delay) {
993
- break;
994
- }
995
- j += 1;
996
- }
997
- const slice = value.slice(i, j);
998
- if (delay === null) {
999
- plain += slice;
1000
- } else {
1001
- flushPlain();
1002
- out.push({
1003
- type: "element",
1004
- tagName: "span",
1005
- properties: {
1006
- className: ["og-stream-ink"],
1007
- style: `animation-delay:${Math.round(delay)}ms`
1008
- },
1009
- children: [{ type: "text", value: slice }]
1010
- });
1011
- }
1012
- i = j;
1013
- }
1014
- flushPlain();
1015
- return out.length > 0 ? out : [node];
1016
- }
1017
- }
1018
-
1019
- // src/components/markdown.tsx
1020
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1021
- var baseComponents = {
1022
- h1: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1023
- "h1",
1024
- {
1025
- className: "mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0",
1026
- ...props,
1027
- children
1028
- }
1029
- ),
1030
- h2: ({ children, ...props }) => /* @__PURE__ */ jsx3("h2", { className: "mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
1031
- h3: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1032
- "h3",
1033
- {
1034
- className: "mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0",
1035
- ...props,
1036
- children
1037
- }
1038
- ),
1039
- h4: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1040
- "h4",
1041
- {
1042
- className: "mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0",
1043
- ...props,
1044
- children
1045
- }
1046
- ),
1047
- p: ({ children, ...props }) => /* @__PURE__ */ jsx3("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
1048
- strong: ({ children, ...props }) => /* @__PURE__ */ jsx3("strong", { className: "font-semibold text-og-fg", ...props, children }),
1049
- em: ({ children, ...props }) => /* @__PURE__ */ jsx3("em", { className: "italic", ...props, children }),
1050
- ul: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1051
- "ul",
1052
- {
1053
- className: "my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0",
1054
- ...props,
1055
- children
1056
- }
1057
- ),
1058
- ol: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1059
- "ol",
1060
- {
1061
- className: "my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0",
1062
- ...props,
1063
- children
1064
- }
1065
- ),
1066
- // GFM task-list items carry a leading checkbox <input>; `list-none` + a
1067
- // negative margin pull the checkbox back to the bullet column so it aligns
1068
- // with the text.
1069
- li: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1070
- "li",
1071
- {
1072
- className: "leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5",
1073
- ...props,
1074
- children
1075
- }
1076
- ),
1077
- input: ({ type, ...props }) => type === "checkbox" ? /* @__PURE__ */ jsx3(
1078
- "input",
1079
- {
1080
- ...props,
1081
- type: "checkbox",
1082
- disabled: true,
1083
- className: "mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline"
1084
- }
1085
- ) : /* @__PURE__ */ jsx3("input", { type, ...props }),
1086
- blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1087
- "blockquote",
1088
- {
1089
- className: "my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0",
1090
- ...props,
1091
- children
1092
- }
1093
- ),
1094
- hr: (props) => /* @__PURE__ */ jsx3("hr", { className: "my-4 border-0 border-t border-og-border", ...props }),
1095
- // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an
1096
- // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by
1097
- // the `pre` renderer), so a `code` reaching here is treated as inline.
1098
- code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx3(
1099
- "code",
1100
- {
1101
- className: "rounded-og-xs bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg",
1102
- ...props,
1103
- children
1104
- }
1105
- ),
1106
- // Fenced code — quiet mono block (no card / no nested vertical scroll).
1107
- pre: ({ children }) => /* @__PURE__ */ jsx3(MarkdownCodeBlock, { children }),
1108
- // Tables stay unboxed (hairline rules); hover reveals a TSV copy control.
1109
- table: ({ children, ...props }) => /* @__PURE__ */ jsx3(MarkdownTable, { ...props, children }),
1110
- thead: ({ children, ...props }) => /* @__PURE__ */ jsx3("thead", { ...props, children }),
1111
- th: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1112
- "th",
1113
- {
1114
- className: "border-b border-og-border px-0 py-1.5 pr-4 text-left font-medium text-og-fg first:pl-0",
1115
- ...props,
1116
- children
1117
- }
1118
- ),
1119
- td: ({ children, ...props }) => /* @__PURE__ */ jsx3(
1120
- "td",
1121
- {
1122
- className: "border-b border-og-border/70 px-0 py-1.5 pr-4 align-top text-og-fg-muted [tr:last-child>&]:border-b-0",
1123
- ...props,
1124
- children
1125
- }
1126
- ),
1127
- img: ({ alt, src, ...props }) => src ? /* @__PURE__ */ jsx3(
1128
- "img",
1129
- {
1130
- alt: alt ?? "",
1131
- src,
1132
- className: "my-3 max-w-full rounded-og-md border border-og-border",
1133
- ...props
1134
- }
1135
- ) : alt ? /* @__PURE__ */ jsx3("span", { className: "text-og-fg-subtle", "aria-disabled": "true", children: alt }) : null
1136
- };
1137
- var MARKDOWN_LINK_CLASS = "break-words font-medium text-og-accent-strong underline-offset-2 hover:underline";
1138
- function markdownComponents(onSandboxFile) {
1139
- return {
1140
- ...baseComponents,
1141
- a: ({ children, href, ...props }) => {
1142
- const location = sandboxFileLocationFromHref(href);
1143
- if (location !== null) {
1144
- return /* @__PURE__ */ jsx3(SandboxMarkdownLink, { location, onSandboxFile, children });
1145
- }
1146
- if (isSandboxHref(href) || !href) {
1147
- return /* @__PURE__ */ jsx3(
1148
- "span",
1149
- {
1150
- className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
1151
- "aria-disabled": "true",
1152
- title: isSandboxHref(href) ? "This sandbox file reference is invalid" : "This link is unavailable",
1153
- children
1154
- }
1155
- );
1156
- }
1157
- return /* @__PURE__ */ jsx3(
1158
- "a",
1159
- {
1160
- className: MARKDOWN_LINK_CLASS,
1161
- target: "_blank",
1162
- rel: "noreferrer noopener",
1163
- href,
1164
- ...props,
1165
- children
1166
- }
1167
- );
1168
- }
1169
- };
1170
- }
1171
- function SandboxMarkdownLink({
1172
- location,
1173
- onSandboxFile,
1174
- children
1175
- }) {
1176
- const [state, setState] = useState3("idle");
1177
- const { path, line } = location;
1178
- if (!onSandboxFile) {
1179
- return /* @__PURE__ */ jsx3(
1180
- "span",
1181
- {
1182
- className: "break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2",
1183
- "aria-disabled": "true",
1184
- title: "This sandbox file requires a session-aware handler",
1185
- children
1186
- }
1187
- );
1188
- }
1189
- const idleTitle = line !== null ? `Open ${path} at line ${line}` : `Open ${path}`;
1190
- return /* @__PURE__ */ jsxs3(
1191
- "button",
1192
- {
1193
- type: "button",
1194
- className: cn(
1195
- MARKDOWN_LINK_CLASS,
1196
- "inline-flex min-h-7 cursor-pointer items-center disabled:cursor-wait disabled:opacity-70 pointer-coarse:min-h-11"
1197
- ),
1198
- disabled: state === "loading",
1199
- "aria-busy": state === "loading",
1200
- title: state === "error" ? "Couldn't open this file. Select to retry." : idleTitle,
1201
- onClick: () => {
1202
- setState("loading");
1203
- void Promise.resolve(onSandboxFile(path, line ?? void 0)).then(
1204
- () => setState("idle"),
1205
- () => setState("error")
1206
- );
1207
- },
1208
- children: [
1209
- children,
1210
- state === "loading" ? " (opening\u2026)" : state === "error" ? " (retry)" : null
1211
- ]
1212
- }
1213
- );
1214
- }
1215
- var SANDBOX_SCHEME = "sandbox:";
1216
- var LEGACY_WORKSPACE_PREFIX = "/workspace/";
1217
- var TRAILING_LINE = /:([0-9]+)$/u;
1218
- var TRAILING_INVALID_LINE = /:-(?:[0-9]+)$|:[0-9]+-[0-9]+$/u;
1219
- var CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/u;
1220
- function isSandboxHref(href) {
1221
- return href?.startsWith(SANDBOX_SCHEME) ?? false;
1222
- }
1223
- function sandboxFileLocationFromHref(href) {
1224
- if (!href) return null;
1225
- const encodedLocation = isSandboxHref(href) ? href.slice(SANDBOX_SCHEME.length) : href.startsWith(LEGACY_WORKSPACE_PREFIX) ? href : null;
1226
- if (!encodedLocation || encodedLocation.includes("?") || encodedLocation.includes("#")) {
1227
- return null;
1228
- }
1229
- if (TRAILING_INVALID_LINE.test(encodedLocation)) return null;
1230
- const lineMatch = TRAILING_LINE.exec(encodedLocation);
1231
- const encodedPath = lineMatch ? encodedLocation.slice(0, -lineMatch[0].length) : encodedLocation;
1232
- const line = lineMatch?.[1] ? Number(lineMatch[1]) : null;
1233
- if (line !== null && (!Number.isSafeInteger(line) || line < 1)) return null;
1234
- if (!encodedPath) return null;
1235
- try {
1236
- const path = decodeURIComponent(encodedPath);
1237
- return path && !CONTROL_CHARACTER.test(path) ? { path, line } : null;
1238
- } catch {
1239
- return null;
1240
- }
1241
- }
1242
- function sandboxFilePathFromHref(href) {
1243
- return sandboxFileLocationFromHref(href)?.path ?? null;
1244
- }
1245
- var markdownUrlTransform = (url, key, node) => key === "href" && node.tagName === "a" && isSandboxHref(url) ? url : defaultUrlTransform(url);
1246
- var REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;
1247
- var MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;
1248
- function nodeText(node) {
1249
- if (node == null || typeof node === "boolean") {
1250
- return "";
1251
- }
1252
- if (typeof node === "string" || typeof node === "number") {
1253
- return String(node);
1254
- }
1255
- if (Array.isArray(node)) {
1256
- return node.map(nodeText).join("");
1257
- }
1258
- if (isValidElement(node)) {
1259
- return nodeText(node.props.children);
1260
- }
1261
- return "";
1262
- }
1263
- function fenceLanguage(children) {
1264
- let found = null;
1265
- Children.forEach(children, (child) => {
1266
- if (found || !isValidElement(child)) {
1267
- return;
1268
- }
1269
- const match = /language-([a-zA-Z0-9_+-]+)/.exec(child.props.className ?? "");
1270
- if (match?.[1]) {
1271
- found = match[1];
1272
- }
1273
- });
1274
- return found;
1275
- }
1276
- function MarkdownCodeBlock({ children }) {
1277
- const code = nodeText(children).replace(/\n$/, "");
1278
- const language = fenceLanguage(children);
1279
- return /* @__PURE__ */ jsxs3("div", { className: "group/copy relative mt-3 first:mt-0", children: [
1280
- /* @__PURE__ */ jsxs3("div", { className: "pointer-events-none absolute top-1.5 right-1.5 z-10 flex items-center gap-1", children: [
1281
- language ? /* @__PURE__ */ jsx3("span", { className: "rounded px-1 py-0.5 font-og-mono text-[10px] uppercase tracking-wide text-og-fg-subtle/80 opacity-0 transition-opacity group-hover/copy:opacity-100 pointer-coarse:opacity-70", children: language }) : null,
1282
- /* @__PURE__ */ jsx3("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx3(CopyButton, { text: code, label: "Copy code", reveal: "group-hover" }) })
1283
- ] }),
1284
- /* @__PURE__ */ jsx3(
1285
- "pre",
1286
- {
1287
- tabIndex: 0,
1288
- className: "overflow-x-auto overflow-y-hidden rounded-og-md bg-og-surface-1/70 px-3 py-2.5 font-og-mono text-og-sm leading-5 text-og-fg-muted [scrollbar-gutter:stable] [&>code]:block [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:leading-5 [&>code]:text-inherit",
1289
- children
1290
- }
1291
- )
1292
- ] });
1293
- }
1294
- function MarkdownTable({ children, className, ...props }) {
1295
- const tableRef = useRef3(null);
1296
- return /* @__PURE__ */ jsxs3("div", { className: "group/copy relative mt-3 max-w-full first:mt-0", children: [
1297
- /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute top-0 right-0 z-10", children: /* @__PURE__ */ jsx3("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx3(
1298
- CopyButton,
1299
- {
1300
- text: () => tableElementToTsv(tableRef.current),
1301
- label: "Copy table",
1302
- reveal: "group-hover"
1303
- }
1304
- ) }) }),
1305
- /* @__PURE__ */ jsx3("div", { className: "overflow-x-auto", tabIndex: 0, children: /* @__PURE__ */ jsx3(
1306
- "table",
1307
- {
1308
- ref: tableRef,
1309
- className: cn("w-full min-w-0 border-collapse text-og-base", className),
1310
- ...props,
1311
- children
1312
- }
1313
- ) })
1314
- ] });
1315
- }
1316
- function MarkdownImpl({ children, className, streaming = false, onSandboxFile }) {
1317
- const revealRef = useRef3(null);
1318
- const bodyRef = useRef3(null);
1319
- const [, bump] = useReducer((n) => n + 1, 0);
1320
- const [settling, setSettling] = useState3(false);
1321
- const hadRevealRef = useRef3(false);
1322
- const now = typeof performance !== "undefined" ? performance.now() : Date.now();
1323
- const crystallize = (mutate) => {
1324
- mutate();
1325
- setSettling(true);
1326
- bump();
1327
- return setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);
1328
- };
1329
- if (streaming && revealRef.current === null && !prefersReducedMotion()) {
1330
- revealRef.current = createStreamReveal();
1331
- }
1332
- const reveal = revealRef.current;
1333
- if (reveal !== null && streaming) {
1334
- reveal.observe(children, now);
1335
- }
1336
- if (reveal !== null) {
1337
- hadRevealRef.current = true;
1338
- }
1339
- const revealActive = reveal !== null && (streaming || reveal.hasActive(now));
1340
- const rehypePlugins = revealActive && reveal !== null ? [[rehypeStreamReveal, { reveal, now }]] : void 0;
1341
- useEffect3(() => {
1342
- if (streaming || revealRef.current === null) {
1343
- return;
1344
- }
1345
- let clearSettle;
1346
- const timer = setTimeout(() => {
1347
- const shouldSettle = hadRevealRef.current && !prefersReducedMotion();
1348
- if (shouldSettle) {
1349
- hadRevealRef.current = false;
1350
- }
1351
- if (shouldSettle) {
1352
- clearSettle = crystallize(() => {
1353
- revealRef.current = null;
1354
- });
1355
- } else {
1356
- revealRef.current = null;
1357
- bump();
1358
- }
1359
- }, REVEAL_LINGER_MS);
1360
- return () => {
1361
- clearTimeout(timer);
1362
- if (clearSettle !== void 0) {
1363
- clearTimeout(clearSettle);
1364
- }
1365
- };
1366
- }, [streaming]);
1367
- const wasStreamingRef = useRef3(streaming);
1368
- useEffect3(() => {
1369
- const ended = wasStreamingRef.current && !streaming;
1370
- wasStreamingRef.current = streaming;
1371
- if (!ended || revealRef.current !== null || prefersReducedMotion()) {
1372
- return;
1373
- }
1374
- setSettling(true);
1375
- const timer = setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);
1376
- return () => clearTimeout(timer);
1377
- }, [streaming]);
1378
- const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;
1379
- const components = useMemo(() => markdownComponents(onSandboxFile), [onSandboxFile]);
1380
- return /* @__PURE__ */ jsx3(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx3(
1381
- "div",
1382
- {
1383
- ref: bodyRef,
1384
- className: cn(
1385
- "og-markdown-body min-w-0 break-words",
1386
- settling && "og-markdown-settle",
1387
- className
1388
- ),
1389
- children: /* @__PURE__ */ jsx3(
1390
- ReactMarkdown,
1391
- {
1392
- remarkPlugins: [remarkGfm],
1393
- rehypePlugins,
1394
- components,
1395
- urlTransform: markdownUrlTransform,
1396
- children: parseText
1397
- }
1398
- )
1399
- }
1400
- ) });
1401
- }
1402
- var Markdown = memo(MarkdownImpl);
1403
-
1404
- export {
1405
- defaultHumanInputFormMessages,
1406
- HumanInputForm,
1407
- answersFromDrafts,
1408
- prefersReducedMotion,
1409
- MOTION_INSPECT_SCALE,
1410
- CopyButton,
1411
- CopyHoverFrame,
1412
- sandboxFileLocationFromHref,
1413
- sandboxFilePathFromHref,
1414
- Markdown
1415
- };
1416
- //# sourceMappingURL=chunk-YAIPFO5D.js.map