@opengeni/react 3.8.0-canary.1 → 4.0.1-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 +5 -24
- package/dist/artifacts.js +7 -7
- package/dist/{browser-viewer-SS46LUAC.js → browser-viewer-NTD6UIPR.js} +3 -3
- package/dist/{chunk-VEPNNDNG.js → chunk-24M4YBCL.js} +4 -4
- package/dist/{chunk-ELIYWBZR.js → chunk-BV5A4OTE.js} +4 -4
- package/dist/{chunk-7W6PVVTK.js → chunk-HO6X4FHG.js} +2559 -1037
- package/dist/chunk-HO6X4FHG.js.map +1 -0
- package/dist/{chunk-BXJOQFCD.js → chunk-HUMIRRYI.js} +84 -221
- package/dist/chunk-HUMIRRYI.js.map +1 -0
- package/dist/{chunk-7BWFU6H4.js → chunk-Z7WBDB4E.js} +395 -287
- package/dist/chunk-Z7WBDB4E.js.map +1 -0
- package/dist/components/human-input-form.d.ts +3 -1
- package/dist/components/human-input-surface.d.ts +3 -2
- package/dist/components/session-conversation.d.ts +2 -0
- package/dist/composer.js +2 -3
- package/dist/{computer-viewer-FWEZISW4.js → computer-viewer-7TEZC6Y2.js} +3 -3
- package/dist/hooks/use-codex-accounts.d.ts +11 -1
- package/dist/hooks/use-session-events.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -34
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +8 -8
- package/dist/older-history.d.ts +3 -2
- package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-27LKAWZD.js} +2 -2
- package/dist/platform-activity-row-27LKAWZD.js.map +1 -0
- package/dist/realtime.js +3 -3
- package/dist/session-ui.js +6 -9
- package/dist/session.js +1 -1
- package/dist/timeline/types.d.ts +3 -0
- package/package.json +2 -6
- package/src/components/human-input-form.tsx +185 -53
- package/src/components/human-input-surface.tsx +3 -0
- package/src/components/message-timeline.tsx +41 -6
- package/src/components/session-commands-panel.tsx +7 -1
- package/src/components/session-conversation.tsx +4 -1
- package/src/hooks/use-codex-accounts.ts +32 -5
- package/src/hooks/use-session-events.ts +16 -277
- package/src/index.ts +0 -1
- package/src/older-history.ts +22 -4
- package/src/timeline/platform-activity-row.tsx +4 -1
- package/src/timeline/projection.ts +99 -9
- package/src/timeline/types.ts +3 -0
- package/dist/chat.d.ts +0 -37
- package/dist/chat.js +0 -315
- package/dist/chat.js.map +0 -1
- package/dist/chunk-7BWFU6H4.js.map +0 -1
- package/dist/chunk-7W6PVVTK.js.map +0 -1
- package/dist/chunk-BXJOQFCD.js.map +0 -1
- package/dist/chunk-HQV2I5HV.js +0 -124
- package/dist/chunk-HQV2I5HV.js.map +0 -1
- package/dist/chunk-YAIPFO5D.js +0 -1416
- package/dist/chunk-YAIPFO5D.js.map +0 -1
- package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
- package/src/chat.tsx +0 -393
- /package/dist/{browser-viewer-SS46LUAC.js.map → browser-viewer-NTD6UIPR.js.map} +0 -0
- /package/dist/{chunk-VEPNNDNG.js.map → chunk-24M4YBCL.js.map} +0 -0
- /package/dist/{chunk-ELIYWBZR.js.map → chunk-BV5A4OTE.js.map} +0 -0
- /package/dist/{computer-viewer-FWEZISW4.js.map → computer-viewer-7TEZC6Y2.js.map} +0 -0
package/dist/interaction.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComputerViewer,
|
|
3
|
+
useComputerFrameStream,
|
|
4
|
+
useComputerSession,
|
|
5
|
+
useComputerSessions
|
|
6
|
+
} from "./chunk-BV5A4OTE.js";
|
|
1
7
|
import {
|
|
2
8
|
BrowserViewer,
|
|
3
9
|
useAttachedBrowsers,
|
|
@@ -7,19 +13,14 @@ import {
|
|
|
7
13
|
useBrowserSession,
|
|
8
14
|
useBrowserSessions,
|
|
9
15
|
useSiteAuthConnections
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import {
|
|
12
|
-
ComputerViewer,
|
|
13
|
-
useComputerFrameStream,
|
|
14
|
-
useComputerSession,
|
|
15
|
-
useComputerSessions
|
|
16
|
-
} from "./chunk-ELIYWBZR.js";
|
|
16
|
+
} from "./chunk-24M4YBCL.js";
|
|
17
17
|
import {
|
|
18
18
|
useInteractionInterventions,
|
|
19
19
|
useInteractionInvalidation
|
|
20
20
|
} from "./chunk-H5YGYNXS.js";
|
|
21
21
|
import "./chunk-4MDLEHXL.js";
|
|
22
22
|
import "./chunk-5YK2ZDIG.js";
|
|
23
|
+
import "./chunk-JVYQRRC4.js";
|
|
23
24
|
import "./chunk-PLYRL5ER.js";
|
|
24
25
|
import "./chunk-KZ73RL76.js";
|
|
25
26
|
import {
|
|
@@ -28,7 +29,6 @@ import {
|
|
|
28
29
|
useEmbeddedInteraction,
|
|
29
30
|
useEmbeddedInterventions
|
|
30
31
|
} from "./chunk-NEXLLTP4.js";
|
|
31
|
-
import "./chunk-JVYQRRC4.js";
|
|
32
32
|
import "./chunk-22KP6LR5.js";
|
|
33
33
|
|
|
34
34
|
// src/hooks/use-network-routes.ts
|
package/dist/older-history.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export type OlderHistoryLoadReceipt = Promise<boolean> & {
|
|
10
10
|
readonly committed: boolean;
|
|
11
|
+
readonly tailPreserved?: boolean;
|
|
11
12
|
};
|
|
12
13
|
/**
|
|
13
14
|
* Source-compatible public callback accepted by MessageTimeline.
|
|
@@ -20,10 +21,10 @@ export type OlderHistoryLoadReceipt = Promise<boolean> & {
|
|
|
20
21
|
export type OlderHistoryLoader = () => unknown;
|
|
21
22
|
type OlderHistoryReceiptCapture = (receipt: OlderHistoryLoadReceipt) => void;
|
|
22
23
|
/** Bind a receipt before a synchronous forwarding stack can publish state. */
|
|
23
|
-
export declare function invokeOlderHistoryLoaderWithReceiptCapture(load: OlderHistoryLoader, capture: OlderHistoryReceiptCapture): unknown;
|
|
24
|
+
export declare function invokeOlderHistoryLoaderWithReceiptCapture(load: OlderHistoryLoader, capture: OlderHistoryReceiptCapture, preserveTail?: boolean): unknown;
|
|
24
25
|
/**
|
|
25
26
|
* Build an await-compatible older-history receipt for custom timeline hosts.
|
|
26
27
|
* Call `markCommitted` immediately before publishing an accepted older window.
|
|
27
28
|
*/
|
|
28
|
-
export declare function createOlderHistoryLoadReceipt(load: (markCommitted: () => void) => boolean | Promise<boolean>): OlderHistoryLoadReceipt;
|
|
29
|
+
export declare function createOlderHistoryLoadReceipt(load: (markCommitted: () => void, preserveTail: boolean, markTailPreserved: () => void) => boolean | Promise<boolean>): OlderHistoryLoadReceipt;
|
|
29
30
|
export {};
|
|
@@ -47,7 +47,7 @@ function PlatformActivityRow({
|
|
|
47
47
|
return j(ActivityDisclosure, {
|
|
48
48
|
icon: j(BotIcon, { className: "size-3.5" }),
|
|
49
49
|
iconTone: failed ? "failed" : running ? "running" : "muted",
|
|
50
|
-
title: startupPhaseTitle(item.phase, item.status, item.outcome),
|
|
50
|
+
title: item.blockedReason === "rotation_in_progress" ? "Waiting for sandbox rotation" : startupPhaseTitle(item.phase, item.status, item.outcome),
|
|
51
51
|
preview: item.phase === "model_preparation" ? "Includes overlapping sandbox, rig, repository, and runtime setup shown below." : void 0,
|
|
52
52
|
running,
|
|
53
53
|
failed,
|
|
@@ -166,4 +166,4 @@ function startupDuration(durationMs) {
|
|
|
166
166
|
export {
|
|
167
167
|
PlatformActivityRow as default
|
|
168
168
|
};
|
|
169
|
-
//# sourceMappingURL=platform-activity-row-
|
|
169
|
+
//# sourceMappingURL=platform-activity-row-27LKAWZD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/timeline/platform-activity-row.tsx"],"sourcesContent":["import type { ReasoningItem, SandboxItem, StartupPhaseItem } from \"./types\";\n\ntype RowJsx = typeof import(\"react/jsx-runtime\").jsx;\ntype RowJsxs = typeof import(\"react/jsx-runtime\").jsxs;\n\nexport default function PlatformActivityRow({\n item,\n d: ActivityDisclosure,\n p: PayloadBlock,\n t: displayName,\n b: BotIcon,\n m: Markdown,\n r: truncate,\n j,\n s,\n}: {\n item: ReasoningItem | SandboxItem | StartupPhaseItem;\n d: typeof import(\"./shared\").ActivityDisclosure;\n p: typeof import(\"./shared\").PayloadBlock;\n t: (name: string) => string;\n b: typeof import(\"lucide-react\").BotIcon;\n m: typeof import(\"../components/markdown\").Markdown;\n r: typeof import(\"../lib/format\").truncate;\n j: RowJsx;\n s: RowJsxs;\n}) {\n if (item.kind === \"reasoning\") {\n return j(ActivityDisclosure, {\n icon: brainIcon(j, s),\n iconTone: \"muted\",\n title: item.streaming\n ? \"Thinking\"\n : j(\"span\", {\n className: \"font-normal italic text-og-fg-subtle\",\n children: \"Thought\",\n }),\n running: item.streaming,\n preview: truncate(item.text, 110),\n children: j(\"div\", {\n className: \"text-og-base leading-6 text-og-fg-muted [&_strong]:text-og-fg-muted\",\n children: j(Markdown, { streaming: item.streaming, children: item.text }),\n }),\n });\n }\n if (item.kind === \"sandbox\") {\n return s(ActivityDisclosure, {\n icon: terminalIcon(j, s),\n iconTone:\n item.status === \"failed\" ? \"failed\" : item.status === \"running\" ? \"running\" : \"muted\",\n title: sandboxRowTitle(item, displayName),\n running: item.status === \"running\",\n failed: item.status === \"failed\",\n cancelled: item.status === \"cancelled\",\n preview: item.command ?? undefined,\n children: [\n item.command ? j(PayloadBlock, { label: \"Command\", value: item.command }, \"command\") : null,\n item.output ? j(PayloadBlock, { label: \"Output\", value: item.output }, \"output\") : null,\n ],\n });\n }\n\n const failed = item.status === \"failed\";\n const running = item.status === \"running\";\n const duration = startupDuration(item.durationMs);\n return j(ActivityDisclosure, {\n icon: j(BotIcon, { className: \"size-3.5\" }),\n iconTone: failed ? \"failed\" : running ? \"running\" : \"muted\",\n title:\n item.blockedReason === \"rotation_in_progress\"\n ? \"Waiting for sandbox rotation\"\n : startupPhaseTitle(item.phase, item.status, item.outcome),\n preview:\n item.phase === \"model_preparation\"\n ? \"Includes overlapping sandbox, rig, repository, and runtime setup shown below.\"\n : undefined,\n running,\n failed,\n cancelled: item.status === \"cancelled\",\n chip: duration ? { tone: failed ? \"bad\" : \"muted\", text: duration } : undefined,\n expandable: false,\n });\n}\n\nfunction brainIcon(j: RowJsx, s: RowJsxs) {\n return lucideIcon(j, s, \"brain\", [\n j(\"path\", { d: \"M 12 18V5\" }, \"spine\"),\n j(\"path\", { d: \"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4\" }, \"center\"),\n j(\"path\", { d: \"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5\" }, \"top\"),\n j(\"path\", { d: \"M17.997 5.125a4 4 0 0 1 2.526 5.77\" }, \"upper-right\"),\n j(\"path\", { d: \"M18 18a4 4 0 0 0 2-7.464\" }, \"right\"),\n j(\"path\", { d: \"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517\" }, \"base\"),\n j(\"path\", { d: \"M6 18a4 4 0 0 1-2-7.464\" }, \"left\"),\n j(\"path\", { d: \"M6.003 5.125a4 4 0 0 0-2.526 5.77\" }, \"upper-left\"),\n ]);\n}\n\nfunction terminalIcon(j: RowJsx, s: RowJsxs) {\n return lucideIcon(j, s, \"square-terminal\", [\n j(\"path\", { d: \"m7 11 2-2-2-2\" }, \"prompt\"),\n j(\"path\", { d: \"M11 13h4\" }, \"cursor\"),\n j(\"rect\", { width: 18, height: 18, x: 3, y: 3, rx: 2, ry: 2 }, \"frame\"),\n ]);\n}\n\nfunction lucideIcon(j: RowJsx, s: RowJsxs, name: string, children: ReturnType<RowJsx>[]) {\n return s(\"svg\", {\n \"aria-hidden\": \"true\",\n className: `lucide lucide-${name} size-3.5`,\n fill: \"none\",\n height: 24,\n stroke: \"currentColor\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeWidth: 2,\n viewBox: \"0 0 24 24\",\n width: 24,\n children,\n });\n}\n\nfunction sandboxRowTitle(item: SandboxItem, displayName: (name: string) => string): string {\n if (item.name === \"sandbox.provision\") {\n return startupPhaseTitle(\n \"sandbox\",\n item.status === \"cancelled\" ? \"complete\" : item.status,\n item.origin ?? null,\n );\n }\n return displayName(item.name);\n}\n\nfunction startupPhaseTitle(\n phase: StartupPhaseItem[\"phase\"],\n status: StartupPhaseItem[\"status\"],\n outcome: StartupPhaseItem[\"outcome\"],\n): string {\n if (status === \"complete\" && phase === \"sandbox\" && outcome && outcome !== \"skipped\") {\n return `Sandbox ${outcome === \"resumed\" ? \"reattached\" : outcome}`;\n }\n if (status === \"complete\" && phase === \"rig\" && outcome === \"skipped\") {\n return \"Rig already ready\";\n }\n const statusIndex =\n status === \"running\" ? 0 : status === \"failed\" ? 1 : status === \"cancelled\" ? 2 : 3;\n return STARTUP_PHASE_TITLES[phase][statusIndex];\n}\n\nconst STARTUP_PHASE_TITLES: Record<\n StartupPhaseItem[\"phase\"],\n readonly [string, string, string, string]\n> = {\n queue: [\n \"Waiting for a worker\",\n \"Worker startup failed\",\n \"Worker wait interrupted\",\n \"Worker started\",\n ],\n sandbox: [\n \"Starting sandbox\",\n \"Sandbox didn’t start\",\n \"Sandbox startup interrupted\",\n \"Sandbox ready\",\n ],\n rig: [\"Setting up rig\", \"Rig setup failed\", \"Rig setup interrupted\", \"Rig ready\"],\n repository: [\n \"Preparing repository\",\n \"Repository preparation failed\",\n \"Repository preparation interrupted\",\n \"Repository ready\",\n ],\n files: [\n \"Preparing files\",\n \"File preparation failed\",\n \"File preparation interrupted\",\n \"Files ready\",\n ],\n tools: [\n \"Connecting tools\",\n \"Tool connection failed\",\n \"Tool connection interrupted\",\n \"Tools ready\",\n ],\n model_preparation: [\n \"Preparing runtime and model request\",\n \"Runtime/model preparation failed\",\n \"Runtime/model preparation interrupted\",\n \"Model request dispatched\",\n ],\n provider_first_byte: [\n \"Waiting for model\",\n \"Model didn’t respond\",\n \"Model wait interrupted\",\n \"Model started responding\",\n ],\n};\n\nfunction startupDuration(durationMs: number | null): string | null {\n if (durationMs === null || !Number.isFinite(durationMs) || durationMs < 0) return null;\n if (durationMs < 1_000) return `${Math.round(durationMs)}ms`;\n if (durationMs < 60_000) return `${(durationMs / 1_000).toFixed(1)}s`;\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1_000);\n return `${minutes}m ${String(seconds).padStart(2, \"0\")}s`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/realtime.js
CHANGED
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
PickerBackHeader,
|
|
5
5
|
PickerNavRow
|
|
6
6
|
} from "./chunk-R4KRSFGA.js";
|
|
7
|
-
import {
|
|
8
|
-
useEmbeddedRealtimeSession
|
|
9
|
-
} from "./chunk-NEXLLTP4.js";
|
|
10
7
|
import {
|
|
11
8
|
usePortalTokenSource,
|
|
12
9
|
usePortalTokenStyle
|
|
13
10
|
} from "./chunk-VZTQ73XT.js";
|
|
11
|
+
import {
|
|
12
|
+
useEmbeddedRealtimeSession
|
|
13
|
+
} from "./chunk-NEXLLTP4.js";
|
|
14
14
|
import "./chunk-VRBL3F5E.js";
|
|
15
15
|
import {
|
|
16
16
|
cn
|
package/dist/session-ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BUILT_IN_TURN_SUMMARY_FACET_IDS,
|
|
3
|
+
HumanInputForm,
|
|
3
4
|
HumanInputSurface,
|
|
4
5
|
MessageTimeline,
|
|
5
6
|
QueueSurface,
|
|
@@ -12,27 +13,23 @@ import {
|
|
|
12
13
|
sessionChromeGoalPillLabel,
|
|
13
14
|
sessionChromeGoalPillState,
|
|
14
15
|
userMessageLikelyNeedsDisclosure
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-HO6X4FHG.js";
|
|
16
17
|
import "./chunk-YBM6CQRU.js";
|
|
17
18
|
import "./chunk-5M6VTFJ5.js";
|
|
18
19
|
import "./chunk-ZYRGEKWS.js";
|
|
19
20
|
import "./chunk-NOSYBS2D.js";
|
|
20
21
|
import "./chunk-PAJU5KKL.js";
|
|
21
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-JVYQRRC4.js";
|
|
23
|
+
import "./chunk-Z7WBDB4E.js";
|
|
22
24
|
import "./chunk-R4KRSFGA.js";
|
|
25
|
+
import "./chunk-VZTQ73XT.js";
|
|
23
26
|
import {
|
|
24
27
|
createOlderHistoryLoadReceipt
|
|
25
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-HUMIRRYI.js";
|
|
26
29
|
import "./chunk-6J56T3MG.js";
|
|
27
30
|
import "./chunk-PLYRL5ER.js";
|
|
28
31
|
import "./chunk-KZ73RL76.js";
|
|
29
32
|
import "./chunk-NEXLLTP4.js";
|
|
30
|
-
import {
|
|
31
|
-
HumanInputForm
|
|
32
|
-
} from "./chunk-YAIPFO5D.js";
|
|
33
|
-
import "./chunk-JVYQRRC4.js";
|
|
34
|
-
import "./chunk-HQV2I5HV.js";
|
|
35
|
-
import "./chunk-VZTQ73XT.js";
|
|
36
33
|
import "./chunk-VRBL3F5E.js";
|
|
37
34
|
import "./chunk-22KP6LR5.js";
|
|
38
35
|
export {
|
package/dist/session.js
CHANGED
package/dist/timeline/types.d.ts
CHANGED
|
@@ -173,6 +173,7 @@ export type StartupPhaseItem = {
|
|
|
173
173
|
durationMs: number | null;
|
|
174
174
|
/** Sandbox origin and rig marker outcomes refine the settled label only. */
|
|
175
175
|
outcome: "created" | "restored" | "resumed" | "skipped" | null;
|
|
176
|
+
blockedReason?: "rotation_in_progress" | undefined;
|
|
176
177
|
occurredAt: string;
|
|
177
178
|
};
|
|
178
179
|
/**
|
|
@@ -352,6 +353,8 @@ export type AuthNeededItem = {
|
|
|
352
353
|
export type TurnOutcome = "complete" | "failed" | "cancelled";
|
|
353
354
|
export type TurnEndItem = {
|
|
354
355
|
kind: "turn-end";
|
|
356
|
+
/** Keep an existing answer visible when a recorded input wait ends without final output. */
|
|
357
|
+
preserveWaitResponse?: true;
|
|
355
358
|
id: string;
|
|
356
359
|
turnId: string | null;
|
|
357
360
|
outcome: TurnOutcome;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1-canary.0",
|
|
4
4
|
"description": "React hooks and styled components for OpenGeni: live session streaming, chat composer, message timeline, session status, and fleet views — token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -78,10 +78,6 @@
|
|
|
78
78
|
"types": "./dist/clipboard.d.ts",
|
|
79
79
|
"import": "./dist/clipboard.js"
|
|
80
80
|
},
|
|
81
|
-
"./chat": {
|
|
82
|
-
"types": "./dist/chat.tsx",
|
|
83
|
-
"import": "./dist/chat.tsx"
|
|
84
|
-
},
|
|
85
81
|
"./styles.css": {
|
|
86
82
|
"types": "./styles/index.d.ts",
|
|
87
83
|
"style": "./styles/index.css",
|
|
@@ -124,7 +120,7 @@
|
|
|
124
120
|
"@dnd-kit/utilities": "3.2.2",
|
|
125
121
|
"@fontsource-variable/noto-sans-arabic": "5.2.10",
|
|
126
122
|
"@fontsource-variable/noto-sans-jp": "5.2.10",
|
|
127
|
-
"@opengeni/sdk": "^
|
|
123
|
+
"@opengeni/sdk": "^4.0.1-canary.0",
|
|
128
124
|
"clsx": "^2.1.1",
|
|
129
125
|
"dequal": "2.0.3",
|
|
130
126
|
"lucide-react": "^1.8.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
HumanInputAnswer,
|
|
3
3
|
HumanInputQuestion,
|
|
4
|
+
SkillRecord,
|
|
4
5
|
SessionHumanInputRequest,
|
|
5
6
|
SubmitHumanInputResponseRequest,
|
|
6
7
|
} from "@opengeni/sdk";
|
|
@@ -64,6 +65,10 @@ export const defaultHumanInputFormMessages: HumanInputFormMessages = {
|
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
export type HumanInputFormProps = {
|
|
68
|
+
/** Scoped immutable revision reader. Saving a Skill fails closed without its full preview. */
|
|
69
|
+
loadSkillReview?:
|
|
70
|
+
| ((reference: NonNullable<HumanInputQuestion["skillReview"]>) => Promise<SkillRecord>)
|
|
71
|
+
| undefined;
|
|
67
72
|
request: Pick<SessionHumanInputRequest, "id" | "questions" | "allowSkip" | "expiresAt">;
|
|
68
73
|
onSubmit: (response: SubmitHumanInputResponseRequest) => void | Promise<void>;
|
|
69
74
|
submitting?: boolean | undefined;
|
|
@@ -98,6 +103,7 @@ export function HumanInputForm(props: HumanInputFormProps) {
|
|
|
98
103
|
function HumanInputRequestForm({
|
|
99
104
|
request,
|
|
100
105
|
onSubmit,
|
|
106
|
+
loadSkillReview,
|
|
101
107
|
submitting = false,
|
|
102
108
|
error,
|
|
103
109
|
title,
|
|
@@ -142,6 +148,116 @@ function HumanInputRequestForm({
|
|
|
142
148
|
const submissionInFlight = useRef(false);
|
|
143
149
|
const submissionGeneration = useRef(0);
|
|
144
150
|
const busy = submitting || submittingInternally;
|
|
151
|
+
const reviewIdentity = JSON.stringify(
|
|
152
|
+
request.questions
|
|
153
|
+
.filter((question) => question.skillReview)
|
|
154
|
+
.map((question) => ({
|
|
155
|
+
id: question.id,
|
|
156
|
+
reference: {
|
|
157
|
+
sourceOperationId: question.skillReview!.sourceOperationId,
|
|
158
|
+
skillId: question.skillReview!.skillId,
|
|
159
|
+
revisionId: question.skillReview!.revisionId,
|
|
160
|
+
expectedRevisionId: question.skillReview!.expectedRevisionId,
|
|
161
|
+
expectedScopeVersion: question.skillReview!.expectedScopeVersion,
|
|
162
|
+
},
|
|
163
|
+
})),
|
|
164
|
+
);
|
|
165
|
+
const [reviewReload, setReviewReload] = useState(0);
|
|
166
|
+
const [reviews, setReviews] = useState<{
|
|
167
|
+
loader: typeof loadSkillReview;
|
|
168
|
+
identity: string;
|
|
169
|
+
records: Record<string, SkillRecord>;
|
|
170
|
+
error: string | null;
|
|
171
|
+
} | null>(null);
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
let current = true;
|
|
174
|
+
const questions = JSON.parse(reviewIdentity) as Array<{
|
|
175
|
+
id: string;
|
|
176
|
+
reference: NonNullable<HumanInputQuestion["skillReview"]>;
|
|
177
|
+
}>;
|
|
178
|
+
if (!questions.length) return;
|
|
179
|
+
setReviews(null);
|
|
180
|
+
void Promise.all(
|
|
181
|
+
questions.map(async (question) => {
|
|
182
|
+
if (!loadSkillReview)
|
|
183
|
+
throw new Error(
|
|
184
|
+
"This client cannot preview Skill files. Open this request in OpenGeni to review it.",
|
|
185
|
+
);
|
|
186
|
+
const reference = question.reference;
|
|
187
|
+
const record = await loadSkillReview(reference);
|
|
188
|
+
if (
|
|
189
|
+
record.id !== reference.skillId ||
|
|
190
|
+
record.revisionId !== reference.revisionId ||
|
|
191
|
+
!record.files.some((file) => file.path === "SKILL.md")
|
|
192
|
+
) {
|
|
193
|
+
throw new Error("The requested Skill revision could not be verified.");
|
|
194
|
+
}
|
|
195
|
+
return [question.id, record] as const;
|
|
196
|
+
}),
|
|
197
|
+
)
|
|
198
|
+
.then((records) => {
|
|
199
|
+
if (current)
|
|
200
|
+
setReviews({
|
|
201
|
+
loader: loadSkillReview,
|
|
202
|
+
identity: reviewIdentity,
|
|
203
|
+
records: Object.fromEntries(records),
|
|
204
|
+
error: null,
|
|
205
|
+
});
|
|
206
|
+
})
|
|
207
|
+
.catch((cause) => {
|
|
208
|
+
if (current)
|
|
209
|
+
setReviews({
|
|
210
|
+
loader: loadSkillReview,
|
|
211
|
+
identity: reviewIdentity,
|
|
212
|
+
records: {},
|
|
213
|
+
error: cause instanceof Error ? cause.message : "Could not load the Skill files.",
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
return () => {
|
|
217
|
+
current = false;
|
|
218
|
+
};
|
|
219
|
+
}, [loadSkillReview, reviewIdentity, reviewReload]);
|
|
220
|
+
const visibleReviews =
|
|
221
|
+
reviews?.loader === loadSkillReview && reviews?.identity === reviewIdentity ? reviews : null;
|
|
222
|
+
const preview = (question: HumanInputQuestion) => {
|
|
223
|
+
if (!question.skillReview) return null;
|
|
224
|
+
const record = visibleReviews?.records[question.id];
|
|
225
|
+
return (
|
|
226
|
+
<div className="mb-3 min-w-0 space-y-2" data-skill-review="">
|
|
227
|
+
{record ? (
|
|
228
|
+
<>
|
|
229
|
+
<p className="text-og-sm">
|
|
230
|
+
{record.title ?? "Skill"} · {record.scope} · {record.files.length} files
|
|
231
|
+
</p>
|
|
232
|
+
<p className="text-og-xs text-og-fg-muted">
|
|
233
|
+
Saving activates these exact files. No additional review is required.
|
|
234
|
+
</p>
|
|
235
|
+
{record.files.map((file) => (
|
|
236
|
+
<details key={file.path} open={file.path === "SKILL.md"}>
|
|
237
|
+
<summary className="cursor-pointer break-all text-og-sm">{file.path}</summary>
|
|
238
|
+
<pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-og-md bg-og-surface-1 p-2 text-og-xs">
|
|
239
|
+
{file.content}
|
|
240
|
+
</pre>
|
|
241
|
+
</details>
|
|
242
|
+
))}
|
|
243
|
+
</>
|
|
244
|
+
) : visibleReviews?.error ? (
|
|
245
|
+
<>
|
|
246
|
+
<p role="alert" className="text-og-sm">
|
|
247
|
+
{visibleReviews.error}
|
|
248
|
+
</p>
|
|
249
|
+
<button type="button" onClick={() => setReviewReload((value) => value + 1)}>
|
|
250
|
+
Retry preview
|
|
251
|
+
</button>
|
|
252
|
+
</>
|
|
253
|
+
) : (
|
|
254
|
+
<p role="status" className="text-og-sm">
|
|
255
|
+
Loading the exact Skill files…
|
|
256
|
+
</p>
|
|
257
|
+
)}
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
145
261
|
|
|
146
262
|
useEffect(() => {
|
|
147
263
|
if (collapsed) {
|
|
@@ -232,6 +348,18 @@ function HumanInputRequestForm({
|
|
|
232
348
|
}
|
|
233
349
|
return;
|
|
234
350
|
}
|
|
351
|
+
const unreviewedSave = request.questions.find(
|
|
352
|
+
(question) =>
|
|
353
|
+
question.skillReview &&
|
|
354
|
+
!visibleReviews?.records[question.id] &&
|
|
355
|
+
result.answers.some(
|
|
356
|
+
(answer) => answer.questionId === question.id && answer.values.includes("save"),
|
|
357
|
+
),
|
|
358
|
+
);
|
|
359
|
+
if (unreviewedSave) {
|
|
360
|
+
setValidationErrors({ [unreviewedSave.id]: "Load the exact Skill files before saving." });
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
235
363
|
await submitResponse({ outcome: "answered", answers: result.answers });
|
|
236
364
|
};
|
|
237
365
|
|
|
@@ -365,6 +493,7 @@ function HumanInputRequestForm({
|
|
|
365
493
|
// Title already carries the question; only render the control + help extras.
|
|
366
494
|
return (
|
|
367
495
|
<div key={question.id} data-human-input-question={question.id}>
|
|
496
|
+
{preview(question)}
|
|
368
497
|
<QuestionControls
|
|
369
498
|
question={question}
|
|
370
499
|
questionNumber={null}
|
|
@@ -389,6 +518,7 @@ function HumanInputRequestForm({
|
|
|
389
518
|
data-human-input-question={question.id}
|
|
390
519
|
className="flex flex-col gap-1.5"
|
|
391
520
|
>
|
|
521
|
+
{preview(question)}
|
|
392
522
|
<QuestionControls
|
|
393
523
|
question={question}
|
|
394
524
|
questionNumber={index + 1}
|
|
@@ -643,62 +773,64 @@ function QuestionControls({
|
|
|
643
773
|
</label>
|
|
644
774
|
);
|
|
645
775
|
})}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
id={otherChoiceId}
|
|
656
|
-
type={question.kind === "single_select" ? "radio" : "checkbox"}
|
|
657
|
-
name={question.kind === "single_select" ? fieldId : undefined}
|
|
658
|
-
aria-labelledby={otherLabelId}
|
|
659
|
-
checked={draft.otherSelected}
|
|
660
|
-
autoFocus={autoFocus && firstOption && question.options.length === 0}
|
|
661
|
-
onChange={(event) =>
|
|
662
|
-
onUpdate((current) => ({
|
|
663
|
-
...current,
|
|
664
|
-
otherSelected: event.target.checked,
|
|
665
|
-
...(question.kind === "single_select" && event.target.checked
|
|
666
|
-
? { values: [] }
|
|
667
|
-
: {}),
|
|
668
|
-
}))
|
|
669
|
-
}
|
|
670
|
-
className="mt-2 accent-og-accent"
|
|
671
|
-
/>
|
|
672
|
-
<span className="min-w-0 flex-1">
|
|
673
|
-
<label
|
|
674
|
-
id={otherLabelId}
|
|
675
|
-
htmlFor={otherChoiceId}
|
|
676
|
-
className="block text-og-sm font-medium"
|
|
677
|
-
>
|
|
678
|
-
{messages.other}
|
|
679
|
-
</label>
|
|
680
|
-
<label htmlFor={otherTextId} className="sr-only">
|
|
681
|
-
{messages.other} answer for {visibleLabel}
|
|
682
|
-
</label>
|
|
776
|
+
{!question.skillReview ? (
|
|
777
|
+
<div
|
|
778
|
+
className={cn(
|
|
779
|
+
"flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
|
|
780
|
+
draft.otherSelected
|
|
781
|
+
? "bg-og-status-waiting/12 text-og-fg"
|
|
782
|
+
: "text-og-fg hover:bg-og-surface-1/80",
|
|
783
|
+
)}
|
|
784
|
+
>
|
|
683
785
|
<input
|
|
684
|
-
id={
|
|
685
|
-
type="
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
onChange={(event) => {
|
|
692
|
-
const other = event.target.value;
|
|
786
|
+
id={otherChoiceId}
|
|
787
|
+
type={question.kind === "single_select" ? "radio" : "checkbox"}
|
|
788
|
+
name={question.kind === "single_select" ? fieldId : undefined}
|
|
789
|
+
aria-labelledby={otherLabelId}
|
|
790
|
+
checked={draft.otherSelected}
|
|
791
|
+
autoFocus={autoFocus && firstOption && question.options.length === 0}
|
|
792
|
+
onChange={(event) =>
|
|
693
793
|
onUpdate((current) => ({
|
|
694
|
-
...
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
794
|
+
...current,
|
|
795
|
+
otherSelected: event.target.checked,
|
|
796
|
+
...(question.kind === "single_select" && event.target.checked
|
|
797
|
+
? { values: [] }
|
|
798
|
+
: {}),
|
|
799
|
+
}))
|
|
800
|
+
}
|
|
801
|
+
className="mt-2 accent-og-accent"
|
|
699
802
|
/>
|
|
700
|
-
|
|
701
|
-
|
|
803
|
+
<span className="min-w-0 flex-1">
|
|
804
|
+
<label
|
|
805
|
+
id={otherLabelId}
|
|
806
|
+
htmlFor={otherChoiceId}
|
|
807
|
+
className="block text-og-sm font-medium"
|
|
808
|
+
>
|
|
809
|
+
{messages.other}
|
|
810
|
+
</label>
|
|
811
|
+
<label htmlFor={otherTextId} className="sr-only">
|
|
812
|
+
{messages.other} answer for {visibleLabel}
|
|
813
|
+
</label>
|
|
814
|
+
<input
|
|
815
|
+
id={otherTextId}
|
|
816
|
+
type="text"
|
|
817
|
+
value={draft.other}
|
|
818
|
+
disabled={busy}
|
|
819
|
+
placeholder="Type a value…"
|
|
820
|
+
onClick={() => onUpdate(selectOtherDraft)}
|
|
821
|
+
onFocus={() => onUpdate(selectOtherDraft)}
|
|
822
|
+
onChange={(event) => {
|
|
823
|
+
const other = event.target.value;
|
|
824
|
+
onUpdate((current) => ({
|
|
825
|
+
...selectOtherDraft(current),
|
|
826
|
+
other,
|
|
827
|
+
}));
|
|
828
|
+
}}
|
|
829
|
+
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"
|
|
830
|
+
/>
|
|
831
|
+
</span>
|
|
832
|
+
</div>
|
|
833
|
+
) : null}
|
|
702
834
|
</div>
|
|
703
835
|
)}
|
|
704
836
|
{error ? (
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./human-input-form";
|
|
10
10
|
|
|
11
11
|
export type HumanInputSurfaceProps = {
|
|
12
|
+
loadSkillReview?: HumanInputFormProps["loadSkillReview"];
|
|
12
13
|
requests: SessionHumanInputRequest[];
|
|
13
14
|
onSubmit: (requestId: string, response: SubmitHumanInputResponseRequest) => void | Promise<void>;
|
|
14
15
|
respondingRequestId?: string | null | undefined;
|
|
@@ -28,6 +29,7 @@ export type HumanInputSurfaceProps = {
|
|
|
28
29
|
export function HumanInputSurface({
|
|
29
30
|
requests,
|
|
30
31
|
onSubmit,
|
|
32
|
+
loadSkillReview,
|
|
31
33
|
respondingRequestId = null,
|
|
32
34
|
error,
|
|
33
35
|
messages,
|
|
@@ -68,6 +70,7 @@ export function HumanInputSurface({
|
|
|
68
70
|
|
|
69
71
|
const formProps: HumanInputFormProps = {
|
|
70
72
|
request: active,
|
|
73
|
+
loadSkillReview,
|
|
71
74
|
submitting: respondingRequestId !== null,
|
|
72
75
|
error: error ?? null,
|
|
73
76
|
progressLabel,
|
|
@@ -293,13 +293,18 @@ function invokeOlderLoad(
|
|
|
293
293
|
load: OlderHistoryLoader,
|
|
294
294
|
noProgress: () => void,
|
|
295
295
|
attempt: OlderLoadAttempt,
|
|
296
|
+
preserveTail = false,
|
|
296
297
|
): 1 | undefined {
|
|
297
298
|
try {
|
|
298
299
|
// Receipt creation is captured synchronously through legacy wrappers such
|
|
299
300
|
// as `() => void loadOlder()`, even when the wrapper discards the return.
|
|
300
|
-
const result = invokeOlderHistoryLoaderWithReceiptCapture(
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
const result = invokeOlderHistoryLoaderWithReceiptCapture(
|
|
302
|
+
load,
|
|
303
|
+
(receipt) => {
|
|
304
|
+
attempt[2] = receipt;
|
|
305
|
+
},
|
|
306
|
+
preserveTail,
|
|
307
|
+
) as OlderHistoryLoadReceipt | PromiseLike<unknown> | unknown;
|
|
303
308
|
const receipt =
|
|
304
309
|
attempt[2] ??
|
|
305
310
|
(typeof (result as { committed?: unknown } | undefined)?.committed === "boolean"
|
|
@@ -978,7 +983,7 @@ export function MessageTimeline({
|
|
|
978
983
|
// exact `false` is the first-party request-not-accepted receipt.
|
|
979
984
|
// All other fulfillment retains this exact owner until its prepend
|
|
980
985
|
// boundary commits; promise settlement alone cannot prove progress.
|
|
981
|
-
invokeOlderLoad(onLoadOlder, noProgress, attempt);
|
|
986
|
+
invokeOlderLoad(onLoadOlder, noProgress, attempt, !retry);
|
|
982
987
|
},
|
|
983
988
|
[hasOlder, loadingOlder, olderBoundaryKey, onLoadOlder],
|
|
984
989
|
);
|
|
@@ -1536,7 +1541,9 @@ export function MessageTimeline({
|
|
|
1536
1541
|
}
|
|
1537
1542
|
const observer = new IntersectionObserver(
|
|
1538
1543
|
(entries) => {
|
|
1539
|
-
|
|
1544
|
+
// An underfilled history window has both sentinels visible. Advancing
|
|
1545
|
+
// it automatically would undo an explicit older-page navigation.
|
|
1546
|
+
if (maxScrollOf(root) > 1 && entries.some((entry) => entry.isIntersecting)) {
|
|
1540
1547
|
onLoadNewer();
|
|
1541
1548
|
}
|
|
1542
1549
|
},
|
|
@@ -1959,7 +1966,9 @@ export function MessageTimeline({
|
|
|
1959
1966
|
className="pointer-events-auto rounded-full border border-og-border px-3 py-1.5 text-og-control"
|
|
1960
1967
|
>
|
|
1961
1968
|
{underfillRetryReady
|
|
1962
|
-
?
|
|
1969
|
+
? underfillSettledAttempt?.[2]?.tailPreserved
|
|
1970
|
+
? "Load earlier activity"
|
|
1971
|
+
: "Retry earlier activity"
|
|
1963
1972
|
: "Jump to start"}
|
|
1964
1973
|
</button>
|
|
1965
1974
|
) : null}
|
|
@@ -3702,6 +3711,32 @@ function formatVideoDuration(seconds: number): string {
|
|
|
3702
3711
|
|
|
3703
3712
|
function NoticeRow({ item }: { item: NoticeItem }) {
|
|
3704
3713
|
const enter = useEntranceAnimation();
|
|
3714
|
+
if (item.recordedOutcome) {
|
|
3715
|
+
return (
|
|
3716
|
+
<details
|
|
3717
|
+
className="group text-og-sm text-og-fg-muted"
|
|
3718
|
+
role="note"
|
|
3719
|
+
data-og-recorded-outcome="wait"
|
|
3720
|
+
>
|
|
3721
|
+
<summary className="flex cursor-pointer list-none items-center gap-2 py-1 [&::-webkit-details-marker]:hidden">
|
|
3722
|
+
<ChevronRightIcon
|
|
3723
|
+
aria-hidden
|
|
3724
|
+
className="size-3.5 transition-transform group-open:rotate-90"
|
|
3725
|
+
/>
|
|
3726
|
+
<span>
|
|
3727
|
+
Wait recorded ·{" "}
|
|
3728
|
+
<time dateTime={item.occurredAt}>
|
|
3729
|
+
{new Date(item.occurredAt).toLocaleString(undefined, {
|
|
3730
|
+
dateStyle: "medium",
|
|
3731
|
+
timeStyle: "short",
|
|
3732
|
+
})}
|
|
3733
|
+
</time>
|
|
3734
|
+
</span>
|
|
3735
|
+
</summary>
|
|
3736
|
+
<p className="mt-1 whitespace-pre-wrap break-words pl-5 text-og-fg-muted">{item.text}</p>
|
|
3737
|
+
</details>
|
|
3738
|
+
);
|
|
3739
|
+
}
|
|
3705
3740
|
const tone =
|
|
3706
3741
|
item.tone === "failed"
|
|
3707
3742
|
? "border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed"
|
|
@@ -80,7 +80,13 @@ export function SessionCommandsPanel({
|
|
|
80
80
|
</div>
|
|
81
81
|
</details>
|
|
82
82
|
<p className="mt-1 text-og-fg-subtle">
|
|
83
|
-
{command.
|
|
83
|
+
{command.observationStatus === "unavailable"
|
|
84
|
+
? command.state === "stopping"
|
|
85
|
+
? "Stop requested · status unavailable"
|
|
86
|
+
: "Command status unavailable"
|
|
87
|
+
: command.state === "stopping"
|
|
88
|
+
? "Stopping…"
|
|
89
|
+
: "Running"}
|
|
84
90
|
</p>
|
|
85
91
|
</div>
|
|
86
92
|
{!readOnly ? (
|