@opengeni/react 0.48.0 → 0.57.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 +138 -2
- package/dist/artifacts-document.d.ts +3 -0
- package/dist/artifacts-document.js +17 -0
- package/dist/artifacts-document.js.map +1 -0
- package/dist/artifacts-presentation.d.ts +3 -0
- package/dist/artifacts-presentation.js +17 -0
- package/dist/artifacts-presentation.js.map +1 -0
- package/dist/artifacts-spreadsheet.d.ts +3 -0
- package/dist/artifacts-spreadsheet.js +17 -0
- package/dist/artifacts-spreadsheet.js.map +1 -0
- package/dist/artifacts.d.ts +2 -0
- package/dist/artifacts.js +199 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/{chunk-NJ7M2B6Z.js → chunk-5UQPNLIO.js} +16 -8
- package/dist/{chunk-NJ7M2B6Z.js.map → chunk-5UQPNLIO.js.map} +1 -1
- package/dist/{chunk-LHLYWG5R.js → chunk-6KLX2RH5.js} +461 -38
- package/dist/chunk-6KLX2RH5.js.map +1 -0
- package/dist/chunk-7WCLAEFV.js +2828 -0
- package/dist/chunk-7WCLAEFV.js.map +1 -0
- package/dist/{chunk-I4MPFDRP.js → chunk-B6WPZSTT.js} +104 -104
- package/dist/{chunk-I4MPFDRP.js.map → chunk-B6WPZSTT.js.map} +1 -1
- package/dist/{chunk-EKZH6IDG.js → chunk-C5ZPSSS5.js} +111 -1
- package/dist/chunk-C5ZPSSS5.js.map +1 -0
- package/dist/{chunk-OL6QVXGF.js → chunk-HA46CYQK.js} +152 -8
- package/dist/chunk-HA46CYQK.js.map +1 -0
- package/dist/chunk-HUIKIDM5.js +2148 -0
- package/dist/chunk-HUIKIDM5.js.map +1 -0
- package/dist/{chunk-FWXGSNXT.js → chunk-IGC6A2ZI.js} +585 -34
- package/dist/chunk-IGC6A2ZI.js.map +1 -0
- package/dist/chunk-JVYQRRC4.js +53 -0
- package/dist/chunk-JVYQRRC4.js.map +1 -0
- package/dist/chunk-KCGXPP5V.js +157 -0
- package/dist/chunk-KCGXPP5V.js.map +1 -0
- package/dist/chunk-LLOLUHVG.js +5937 -0
- package/dist/chunk-LLOLUHVG.js.map +1 -0
- package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
- package/dist/chunk-MKPIAGVL.js.map +1 -0
- package/dist/chunk-PEI6RANI.js +3234 -0
- package/dist/chunk-PEI6RANI.js.map +1 -0
- package/dist/chunk-R3AZOAB5.js +933 -0
- package/dist/chunk-R3AZOAB5.js.map +1 -0
- package/dist/{chunk-O4VXOBGF.js → chunk-WSK7G5LE.js} +70 -2
- package/dist/chunk-WSK7G5LE.js.map +1 -0
- package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
- package/dist/chunk-XBZWOM2K.js.map +1 -0
- package/dist/{chunk-XCNTXWBB.js → chunk-Y7OEDUJ5.js} +856 -338
- package/dist/chunk-Y7OEDUJ5.js.map +1 -0
- package/dist/client.d.ts +10 -2
- package/dist/clipboard.d.ts +1 -0
- package/dist/clipboard.js +7 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/registry.d.ts +1 -1
- package/dist/commands/types.d.ts +1 -1
- package/dist/components/approval-surface.d.ts +2 -2
- package/dist/components/artifacts/artifact-surface.d.ts +18 -0
- package/dist/components/artifacts/document-editor.d.ts +172 -0
- package/dist/components/artifacts/editable-artifact-ui.d.ts +13 -0
- package/dist/components/artifacts/editable-artifact-workbench.d.ts +49 -0
- package/dist/components/artifacts/editable-document.d.ts +24 -0
- package/dist/components/artifacts/editable-presentation.d.ts +24 -0
- package/dist/components/artifacts/editable-spreadsheet.d.ts +32 -0
- package/dist/components/artifacts/index.d.ts +9 -0
- package/dist/components/artifacts/presentation-editor.d.ts +297 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -0
- package/dist/components/artifacts/spreadsheet-canvas.d.ts +120 -0
- package/dist/components/artifacts/spreadsheet-grid.d.ts +113 -0
- package/dist/components/browser-input.d.ts +7 -0
- package/dist/components/browser-viewer.d.ts +30 -0
- package/dist/components/chat-composer.d.ts +8 -8
- package/dist/components/code-editor.d.ts +25 -3
- package/dist/components/command-palette.d.ts +2 -2
- package/dist/components/composer-transcription-control.d.ts +2 -2
- package/dist/components/composer.d.ts +17 -17
- package/dist/components/computer-viewer.d.ts +24 -0
- package/dist/components/copy-button.d.ts +2 -2
- package/dist/components/desktop-viewer.d.ts +50 -22
- package/dist/components/diff-view.d.ts +1 -1
- package/dist/components/enrollment-consent.d.ts +1 -1
- package/dist/components/enrollment-device-flow.d.ts +1 -1
- package/dist/components/file-browser.d.ts +2 -2
- package/dist/components/fleet-tile.d.ts +1 -1
- package/dist/components/generated-video-player.d.ts +10 -0
- package/dist/components/human-input-form.d.ts +1 -1
- package/dist/components/human-input-surface.d.ts +2 -2
- package/dist/components/interaction-intervention-banner.d.ts +11 -0
- package/dist/components/interactive-workbench-viewers.d.ts +2 -0
- package/dist/components/machine-card.d.ts +2 -2
- package/dist/components/machine-dock-bar.d.ts +3 -3
- package/dist/components/machine-health-pill.d.ts +2 -2
- package/dist/components/machine-input-display.d.ts +1 -1
- package/dist/components/machine-metrics.d.ts +2 -2
- package/dist/components/machine-status-pill.d.ts +4 -4
- package/dist/components/machines/health.d.ts +1 -1
- package/dist/components/machines/machine-detail.d.ts +3 -3
- package/dist/components/machines/metric-history-chart.d.ts +1 -1
- package/dist/components/machines/metric-sparkline.d.ts +2 -2
- package/dist/components/machines/series.d.ts +2 -2
- package/dist/components/machines-dashboard.d.ts +2 -2
- package/dist/components/markdown.d.ts +1 -1
- package/dist/components/message-timeline.d.ts +12 -5
- package/dist/components/model-picker.d.ts +2 -2
- package/dist/components/model-policy-picker.d.ts +7 -7
- package/dist/components/pierre-diff.d.ts +1 -1
- package/dist/components/pierre-file.d.ts +1 -1
- package/dist/components/queue-draft-policy.d.ts +1 -1
- package/dist/components/queue-surface-implementation.d.ts +3 -3
- package/dist/components/queue-surface-state.d.ts +4 -4
- package/dist/components/queue-surface.d.ts +5 -5
- package/dist/components/sandbox-files.d.ts +3 -3
- package/dist/components/sandbox-terminal.d.ts +24 -4
- package/dist/components/sandbox-workspace.d.ts +28 -9
- package/dist/components/session-chrome.d.ts +4 -4
- package/dist/components/session-status.d.ts +2 -2
- package/dist/components/timeline-annotation-selection.d.ts +9 -0
- package/dist/components/timeline-annotations-dialog.d.ts +16 -0
- package/dist/components/timeline-annotations.d.ts +13 -0
- package/dist/components/tooltip.d.ts +4 -4
- package/dist/components/user-message-body.d.ts +2 -2
- package/dist/components/workbench-changes.d.ts +2 -2
- package/dist/components/workspace-dock.d.ts +1 -1
- package/dist/composer.d.ts +11 -11
- package/dist/composer.js +7 -7
- package/dist/hooks/internal.d.ts +1 -1
- package/dist/hooks/use-attached-browsers.d.ts +21 -0
- package/dist/hooks/use-auth-runs.d.ts +32 -0
- package/dist/hooks/use-available-models.d.ts +2 -2
- package/dist/hooks/use-billing-usage.d.ts +1 -1
- package/dist/hooks/use-browser-downloads.d.ts +25 -0
- package/dist/hooks/use-browser-frame-stream.d.ts +28 -0
- package/dist/hooks/use-browser-identities.d.ts +30 -0
- package/dist/hooks/use-browser-session.d.ts +29 -0
- package/dist/hooks/use-browser-sessions.d.ts +32 -0
- package/dist/hooks/use-channels.d.ts +26 -0
- package/dist/hooks/use-codex-accounts.d.ts +2 -2
- package/dist/hooks/use-composer.d.ts +36 -9
- package/dist/hooks/use-computer-frame-stream.d.ts +24 -0
- package/dist/hooks/use-computer-session.d.ts +29 -0
- package/dist/hooks/use-computer-sessions.d.ts +28 -0
- package/dist/hooks/use-desktop-stream.d.ts +5 -1
- package/dist/hooks/use-environments.d.ts +1 -1
- package/dist/hooks/use-file-attachments.d.ts +1 -1
- package/dist/hooks/use-goal.d.ts +2 -2
- package/dist/hooks/use-human-input.d.ts +2 -2
- package/dist/hooks/use-interaction-interventions.d.ts +27 -0
- package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
- package/dist/hooks/use-last-started-turn-policy.d.ts +2 -2
- package/dist/hooks/use-machine-chip.d.ts +2 -2
- package/dist/hooks/use-machines.d.ts +4 -4
- package/dist/hooks/use-network-routes.d.ts +25 -0
- package/dist/hooks/use-packs.d.ts +7 -2
- package/dist/hooks/use-rigs.d.ts +1 -1
- package/dist/hooks/use-sandbox-files.d.ts +6 -4
- package/dist/hooks/use-sandbox-git.d.ts +6 -5
- package/dist/hooks/use-sandbox-terminal.d.ts +1 -1
- package/dist/hooks/use-scheduled-tasks.d.ts +1 -1
- package/dist/hooks/use-session-capabilities.d.ts +5 -4
- package/dist/hooks/use-session-control.d.ts +1 -1
- package/dist/hooks/use-session-events.d.ts +2 -2
- package/dist/hooks/use-session-lineage.d.ts +1 -1
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
- package/dist/hooks/use-session.d.ts +2 -2
- package/dist/hooks/use-site-auth-connections.d.ts +25 -0
- package/dist/hooks/use-slash-commands.d.ts +1 -1
- package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
- package/dist/hooks/use-terminal-stream.d.ts +11 -2
- package/dist/hooks/use-turn-queue.d.ts +2 -2
- package/dist/hooks/use-video-artifact-playback.d.ts +9 -0
- package/dist/hooks/use-voice-input.d.ts +1 -1
- package/dist/hooks/use-workspace-capture.d.ts +1 -1
- package/dist/hooks/use-workspace-edit.d.ts +1 -1
- package/dist/hooks/use-workspace-sessions.d.ts +1 -1
- package/dist/hooks/use-workspaces.d.ts +1 -1
- package/dist/index.d.ts +162 -155
- package/dist/index.js +1822 -1703
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +33 -0
- package/dist/interaction.js +550 -0
- package/dist/interaction.js.map +1 -0
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
- package/dist/interactive-workbench-viewers-TOHBXJEE.js.map +1 -0
- package/dist/lib/host-platform.d.ts +5 -0
- package/dist/lib/relay-wire.d.ts +24 -1
- package/dist/lib/sandbox-liveness.d.ts +9 -0
- package/dist/lib/terminal-capability.d.ts +5 -0
- package/dist/lib/xterm-theme.d.ts +1 -1
- package/dist/machines.d.ts +30 -30
- package/dist/machines.js +2 -2
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +6 -5
- package/dist/{queue-surface-implementation-U5JFG7HT.js → queue-surface-implementation-2KVJTYXH.js} +100 -48
- package/dist/queue-surface-implementation-2KVJTYXH.js.map +1 -0
- package/dist/realtime/dropdown-menu.d.ts +8 -8
- package/dist/realtime/realtime-control.d.ts +8 -8
- package/dist/realtime.d.ts +4 -4
- package/dist/realtime.js +38 -11
- package/dist/realtime.js.map +1 -1
- package/dist/session-context.d.ts +28 -2
- package/dist/session-ui.d.ts +14 -14
- package/dist/session-ui.js +5 -4
- package/dist/session.d.ts +28 -28
- package/dist/session.js +10 -10
- package/dist/timeline/activity-rail.d.ts +5 -3
- package/dist/timeline/disclosure-context.d.ts +1 -1
- package/dist/timeline/fleet-decision-projection.d.ts +1 -1
- package/dist/timeline/fleet-decision-row.d.ts +3 -3
- package/dist/timeline/index.d.ts +19 -19
- package/dist/timeline/parsers.d.ts +4 -1
- package/dist/timeline/projection.d.ts +3 -3
- package/dist/timeline/registry.d.ts +8 -2
- package/dist/timeline/screenshot-lightbox.d.ts +2 -2
- package/dist/timeline/shared.d.ts +21 -10
- package/dist/timeline/tool-diff.d.ts +2 -2
- package/dist/timeline/tool-renderers.d.ts +1 -1
- package/dist/timeline/turn-summary.d.ts +3 -3
- package/dist/timeline/types.d.ts +44 -3
- package/dist/timeline-annotation-selection-3L7LHGG2.js +187 -0
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +1 -0
- package/dist/timeline-annotations-dialog-U7EVLR75.js +196 -0
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +1 -0
- package/package.json +36 -7
- package/src/artifacts-document.ts +31 -0
- package/src/artifacts-presentation.ts +36 -0
- package/src/artifacts-spreadsheet.ts +21 -0
- package/src/artifacts.ts +89 -0
- package/src/client.ts +157 -1
- package/src/clipboard.ts +2 -0
- package/src/components/artifacts/artifact-surface.tsx +93 -0
- package/src/components/artifacts/document-editor.tsx +2255 -0
- package/src/components/artifacts/editable-artifact-ui.tsx +89 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +203 -0
- package/src/components/artifacts/editable-document.tsx +657 -0
- package/src/components/artifacts/editable-presentation.tsx +1020 -0
- package/src/components/artifacts/editable-spreadsheet.tsx +733 -0
- package/src/components/artifacts/index.ts +104 -0
- package/src/components/artifacts/presentation-editor.tsx +3148 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +799 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +2129 -0
- package/src/components/browser-input.ts +65 -0
- package/src/components/browser-viewer.tsx +2702 -0
- package/src/components/chat-composer.tsx +13 -0
- package/src/components/code-editor.tsx +89 -30
- package/src/components/composer-transcription-control.tsx +10 -6
- package/src/components/computer-viewer.tsx +1636 -0
- package/src/components/desktop-viewer.tsx +215 -74
- package/src/components/generated-video-player.tsx +89 -0
- package/src/components/interaction-intervention-banner.tsx +99 -0
- package/src/components/interactive-workbench-viewers.ts +2 -0
- package/src/components/machine-input-display.ts +3 -0
- package/src/components/machines/machine-detail.tsx +1 -1
- package/src/components/message-timeline.tsx +289 -32
- package/src/components/model-policy-picker.tsx +15 -0
- package/src/components/queue-surface-implementation.tsx +116 -60
- package/src/components/sandbox-files.tsx +2 -2
- package/src/components/sandbox-terminal.tsx +128 -46
- package/src/components/sandbox-workspace.tsx +256 -90
- package/src/components/session-chrome.tsx +53 -13
- package/src/components/timeline-annotation-selection.tsx +221 -0
- package/src/components/timeline-annotations-dialog.tsx +213 -0
- package/src/components/timeline-annotations.tsx +84 -0
- package/src/components/workbench-changes.tsx +188 -31
- package/src/components/workspace-dock.tsx +59 -5
- package/src/hooks/use-attached-browsers.ts +154 -0
- package/src/hooks/use-auth-runs.ts +278 -0
- package/src/hooks/use-browser-downloads.ts +218 -0
- package/src/hooks/use-browser-frame-stream.ts +425 -0
- package/src/hooks/use-browser-identities.ts +266 -0
- package/src/hooks/use-browser-session.ts +543 -0
- package/src/hooks/use-browser-sessions.ts +286 -0
- package/src/hooks/use-channels.ts +99 -0
- package/src/hooks/use-composer.ts +769 -24
- package/src/hooks/use-computer-frame-stream.ts +434 -0
- package/src/hooks/use-computer-session.ts +462 -0
- package/src/hooks/use-computer-sessions.ts +251 -0
- package/src/hooks/use-desktop-stream.ts +39 -7
- package/src/hooks/use-interaction-interventions.ts +242 -0
- package/src/hooks/use-interaction-invalidation.ts +66 -0
- package/src/hooks/use-machine-chip.ts +15 -3
- package/src/hooks/use-machines.ts +33 -3
- package/src/hooks/use-network-routes.ts +214 -0
- package/src/hooks/use-packs.ts +51 -0
- package/src/hooks/use-sandbox-files.ts +98 -55
- package/src/hooks/use-sandbox-git.ts +93 -38
- package/src/hooks/use-sandbox-terminal.ts +3 -2
- package/src/hooks/use-session-capabilities.ts +59 -46
- package/src/hooks/use-site-auth-connections.ts +226 -0
- package/src/hooks/use-supergrok-accounts.ts +81 -0
- package/src/hooks/use-terminal-stream.ts +359 -47
- package/src/hooks/use-video-artifact-playback.ts +28 -0
- package/src/hooks/use-workspace-edit.ts +2 -1
- package/src/index.ts +18 -0
- package/src/interaction.ts +101 -0
- package/src/lib/host-platform.ts +10 -0
- package/src/lib/relay-wire.ts +47 -4
- package/src/lib/sandbox-liveness.ts +11 -0
- package/src/lib/terminal-capability.ts +10 -0
- package/src/model-policy.ts +19 -4
- package/src/provider.tsx +133 -1
- package/src/realtime/realtime-control.tsx +34 -6
- package/src/session-context.ts +156 -1
- package/src/timeline/activity-rail.tsx +25 -3
- package/src/timeline/index.ts +3 -0
- package/src/timeline/parsers.ts +14 -1
- package/src/timeline/projection.ts +269 -14
- package/src/timeline/registry.ts +13 -1
- package/src/timeline/screenshot-lightbox.tsx +19 -9
- package/src/timeline/shared.tsx +56 -8
- package/src/timeline/tool-renderers.tsx +303 -50
- package/src/timeline/types.ts +57 -3
- package/styles/compiled.css +312 -21
- package/styles/index.css +15 -0
- package/styles/responsive.css +13 -1
- package/dist/chunk-23EJ676W.js.map +0 -1
- package/dist/chunk-EKZH6IDG.js.map +0 -1
- package/dist/chunk-FWXGSNXT.js.map +0 -1
- package/dist/chunk-LHLYWG5R.js.map +0 -1
- package/dist/chunk-O4VXOBGF.js.map +0 -1
- package/dist/chunk-OL6QVXGF.js.map +0 -1
- package/dist/chunk-WYA65Y3F.js.map +0 -1
- package/dist/chunk-XCNTXWBB.js.map +0 -1
- package/dist/fleet-decision-projection-SLNZMS42.js +0 -241
- package/dist/fleet-decision-projection-SLNZMS42.js.map +0 -1
- package/dist/queue-surface-implementation-U5JFG7HT.js.map +0 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
parseMediaGenerationResult,
|
|
3
|
+
type SessionEvent,
|
|
4
|
+
type SessionStatus,
|
|
5
|
+
type TimelineAnnotation,
|
|
6
|
+
} from "@opengeni/sdk";
|
|
7
|
+
import fleetDecisionItem from "./fleet-decision-projection";
|
|
3
8
|
import {
|
|
4
9
|
CREDIT_EXHAUSTION_MESSAGE,
|
|
5
10
|
humanizeFailureReason,
|
|
@@ -21,6 +26,7 @@ import type {
|
|
|
21
26
|
TimelineItem,
|
|
22
27
|
TurnEndItem,
|
|
23
28
|
ToolCallItem,
|
|
29
|
+
ToolCallTruncation,
|
|
24
30
|
WorkerItem,
|
|
25
31
|
} from "./types";
|
|
26
32
|
|
|
@@ -43,6 +49,8 @@ export { toolDisplayName, mcpToolLeaf, toolMatchesLeaf } from "./tool-display-na
|
|
|
43
49
|
/** Tool leaves on the first-party OpenGeni MCP server that operate on sessions. */
|
|
44
50
|
const WORKER_SPAWN_TOOL = "session_create";
|
|
45
51
|
const WORKER_MESSAGE_TOOL = "session_send_message";
|
|
52
|
+
const WORKER_FAILURE_CODE_MAX_LENGTH = 128;
|
|
53
|
+
const WORKER_FAILURE_MESSAGE_MAX_UTF8_BYTES = 1_024;
|
|
46
54
|
|
|
47
55
|
/**
|
|
48
56
|
* Tools whose durable side-effect events already own the timeline (MemoryRow).
|
|
@@ -61,6 +69,56 @@ const WORKER_MESSAGE_TOOL = "session_send_message";
|
|
|
61
69
|
* render as machine-input rows.
|
|
62
70
|
*/
|
|
63
71
|
const LANDMARK_ONLY_TOOL_LEAVES = new Set(["memory_save", "memory_correct"]);
|
|
72
|
+
const TIMELINE_ANNOTATION_ANSI_SEQUENCE = new RegExp("\\u001B\\[[0-?]*[ -/]*[@-~]", "g");
|
|
73
|
+
|
|
74
|
+
function safeTimelineAnnotationJson(value: unknown): string {
|
|
75
|
+
try {
|
|
76
|
+
return JSON.stringify(value) ?? "";
|
|
77
|
+
} catch {
|
|
78
|
+
return String(value ?? "");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function timelineAnnotationToolOutputValue(value: unknown, depth = 0): string {
|
|
83
|
+
if (depth > 8 || value === null || value === undefined) {
|
|
84
|
+
return value == null ? "" : safeTimelineAnnotationJson(value);
|
|
85
|
+
}
|
|
86
|
+
if (typeof value === "string") return value;
|
|
87
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
88
|
+
return safeTimelineAnnotationJson(value);
|
|
89
|
+
}
|
|
90
|
+
const record = value as Record<string, unknown>;
|
|
91
|
+
if (record.type === "text" && typeof record.text === "string") return record.text;
|
|
92
|
+
if (Array.isArray(record.content)) {
|
|
93
|
+
const text = record.content.find(
|
|
94
|
+
(part) =>
|
|
95
|
+
part !== null &&
|
|
96
|
+
typeof part === "object" &&
|
|
97
|
+
(part as { type?: unknown }).type === "text" &&
|
|
98
|
+
typeof (part as { text?: unknown }).text === "string",
|
|
99
|
+
) as { text: string } | undefined;
|
|
100
|
+
if (text) return text.text;
|
|
101
|
+
}
|
|
102
|
+
if ("structuredContent" in record) {
|
|
103
|
+
return timelineAnnotationToolOutputValue(record.structuredContent, depth + 1);
|
|
104
|
+
}
|
|
105
|
+
if ("result" in record) return timelineAnnotationToolOutputValue(record.result, depth + 1);
|
|
106
|
+
return safeTimelineAnnotationJson(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Browser mirror of the server's canonical annotation source projection. */
|
|
110
|
+
function timelineAnnotationToolOutputText(output: unknown): string | null {
|
|
111
|
+
const raw = timelineAnnotationToolOutputValue(output);
|
|
112
|
+
const marker = raw.indexOf("\nOutput:\n");
|
|
113
|
+
const text = (
|
|
114
|
+
marker >= 0
|
|
115
|
+
? raw.slice(marker + "\nOutput:\n".length)
|
|
116
|
+
: raw.startsWith("Output:\n")
|
|
117
|
+
? raw.slice("Output:\n".length)
|
|
118
|
+
: raw
|
|
119
|
+
).replace(TIMELINE_ANNOTATION_ANSI_SEQUENCE, "");
|
|
120
|
+
return text.length > 0 ? text : null;
|
|
121
|
+
}
|
|
64
122
|
|
|
65
123
|
export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
66
124
|
const items: TimelineItem[] = [];
|
|
@@ -134,6 +192,15 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
134
192
|
kind: "user-message",
|
|
135
193
|
id: event.id,
|
|
136
194
|
text: voiceMessage?.text ?? stringValue(payload.text),
|
|
195
|
+
annotations: timelineAnnotations(payload.annotations),
|
|
196
|
+
annotationSource: {
|
|
197
|
+
kind: "user_message",
|
|
198
|
+
eventId: event.id,
|
|
199
|
+
eventType: "user.message",
|
|
200
|
+
sequence: event.sequence,
|
|
201
|
+
turnId,
|
|
202
|
+
text: voiceMessage?.text ?? stringValue(payload.text),
|
|
203
|
+
},
|
|
137
204
|
...(voiceMessage ? { presentation: voiceMessage.presentation } : {}),
|
|
138
205
|
resources: resourceRefs(payload.resources),
|
|
139
206
|
tools: toolRefs(payload.tools),
|
|
@@ -212,6 +279,17 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
212
279
|
// Completion time is what the footer shows ("finished at"); keep the
|
|
213
280
|
// first-delta stamp only until this event arrives.
|
|
214
281
|
open.occurredAt = event.occurredAt;
|
|
282
|
+
open.annotationSource =
|
|
283
|
+
text && open.text === text
|
|
284
|
+
? {
|
|
285
|
+
kind: "assistant_message",
|
|
286
|
+
eventId: event.id,
|
|
287
|
+
eventType: "agent.message.completed",
|
|
288
|
+
sequence: event.sequence,
|
|
289
|
+
turnId,
|
|
290
|
+
text,
|
|
291
|
+
}
|
|
292
|
+
: undefined;
|
|
215
293
|
// The SDK can emit a hosted-tool item only after its provider-native
|
|
216
294
|
// operation has completed, even though answer deltas were already
|
|
217
295
|
// streamed. The completed message event is the durable ordering
|
|
@@ -231,6 +309,14 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
231
309
|
text,
|
|
232
310
|
streaming: false,
|
|
233
311
|
occurredAt: event.occurredAt,
|
|
312
|
+
annotationSource: {
|
|
313
|
+
kind: "assistant_message",
|
|
314
|
+
eventId: event.id,
|
|
315
|
+
eventType: "agent.message.completed",
|
|
316
|
+
sequence: event.sequence,
|
|
317
|
+
turnId,
|
|
318
|
+
text,
|
|
319
|
+
},
|
|
234
320
|
});
|
|
235
321
|
}
|
|
236
322
|
break;
|
|
@@ -275,6 +361,7 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
275
361
|
action: toolMatchesLeaf(name, WORKER_SPAWN_TOOL) ? "spawn" : "message",
|
|
276
362
|
prompt: workerPrompt(args),
|
|
277
363
|
workerSessionId: extractSessionRef(args),
|
|
364
|
+
failure: null,
|
|
278
365
|
status: "running",
|
|
279
366
|
occurredAt: event.occurredAt,
|
|
280
367
|
});
|
|
@@ -312,6 +399,7 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
312
399
|
name,
|
|
313
400
|
arguments: args,
|
|
314
401
|
output: undefined,
|
|
402
|
+
truncation: null,
|
|
315
403
|
// The provider-native item drives the per-tool renderers (apply_patch
|
|
316
404
|
// operation, computer_call action, web_search providerData, …).
|
|
317
405
|
raw: payload.raw,
|
|
@@ -332,12 +420,35 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
332
420
|
// isError result) settles to "failed" too, so WorkerRow surfaces it.
|
|
333
421
|
target.status = isErrorOutput(payload) ? "failed" : "complete";
|
|
334
422
|
target.workerSessionId = target.workerSessionId ?? extractSessionRef(payload.output);
|
|
423
|
+
target.failure = target.status === "failed" ? workerFailure(payload.output) : null;
|
|
335
424
|
break;
|
|
336
425
|
}
|
|
337
426
|
// An output carrying an explicit error flag (or an MCP isError result)
|
|
338
427
|
// settles the tool to "failed" so the renderer can surface it loudly.
|
|
428
|
+
const truncation = toolCallTruncation(payload);
|
|
339
429
|
target.status = isErrorOutput(payload) ? "failed" : "complete";
|
|
340
|
-
target.output = payload
|
|
430
|
+
target.output = Object.prototype.hasOwnProperty.call(payload, "output")
|
|
431
|
+
? payload.output
|
|
432
|
+
: truncation && typeof payload.preview === "string"
|
|
433
|
+
? payload.preview
|
|
434
|
+
: payload.output;
|
|
435
|
+
target.truncation = truncation;
|
|
436
|
+
const sourceText = timelineAnnotationToolOutputText(
|
|
437
|
+
Object.prototype.hasOwnProperty.call(payload, "output")
|
|
438
|
+
? payload.output
|
|
439
|
+
: payload.preview,
|
|
440
|
+
);
|
|
441
|
+
if (sourceText !== null) {
|
|
442
|
+
target.annotationSource = {
|
|
443
|
+
kind: "tool_output",
|
|
444
|
+
eventId: event.id,
|
|
445
|
+
eventType: "agent.toolCall.output",
|
|
446
|
+
sequence: event.sequence,
|
|
447
|
+
turnId,
|
|
448
|
+
text: sourceText,
|
|
449
|
+
label: target.name,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
341
452
|
break;
|
|
342
453
|
}
|
|
343
454
|
|
|
@@ -540,6 +651,7 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
540
651
|
|
|
541
652
|
case "tool.auth_needed":
|
|
542
653
|
case "credential.auth_needed": {
|
|
654
|
+
const capability = capabilityAuthorizationRequest(payload.capability);
|
|
543
655
|
if (
|
|
544
656
|
event.type === "tool.auth_needed" &&
|
|
545
657
|
!stringValue(payload.toolName) &&
|
|
@@ -562,7 +674,11 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
562
674
|
id: event.id,
|
|
563
675
|
turnId,
|
|
564
676
|
serverId: typeof payload.serverId === "string" ? payload.serverId : null,
|
|
565
|
-
source:
|
|
677
|
+
source: capability
|
|
678
|
+
? "capability"
|
|
679
|
+
: event.type === "tool.auth_needed"
|
|
680
|
+
? "tool"
|
|
681
|
+
: "credential",
|
|
566
682
|
providerDomain: stringValue(payload.providerDomain),
|
|
567
683
|
connectionId: typeof payload.connectionId === "string" ? payload.connectionId : null,
|
|
568
684
|
reason: authNeededReason(payload.reason),
|
|
@@ -571,6 +687,7 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
571
687
|
toolName: typeof payload.toolName === "string" ? payload.toolName : null,
|
|
572
688
|
authorizationUrl:
|
|
573
689
|
typeof payload.authorizationUrl === "string" ? payload.authorizationUrl : null,
|
|
690
|
+
capability,
|
|
574
691
|
occurredAt: event.occurredAt,
|
|
575
692
|
});
|
|
576
693
|
break;
|
|
@@ -1187,6 +1304,8 @@ function isTurnBoundary(group: TimelineGroup | undefined): boolean {
|
|
|
1187
1304
|
(group?.kind === "item" &&
|
|
1188
1305
|
(group.item.kind === "user-message" ||
|
|
1189
1306
|
group.item.kind === "context-compaction" ||
|
|
1307
|
+
(group.item.kind === "machine-input-batch" &&
|
|
1308
|
+
group.item.members.some((member) => member.kind === "media_generation_result")) ||
|
|
1190
1309
|
(group.item.kind === "notice" && group.item.tone === "input")))
|
|
1191
1310
|
);
|
|
1192
1311
|
}
|
|
@@ -1315,6 +1434,7 @@ function machineInputMembers(value: unknown): MachineInputBatchItem["members"] {
|
|
|
1315
1434
|
"agent_message",
|
|
1316
1435
|
"agent_steer_instruction",
|
|
1317
1436
|
"child_terminal_result",
|
|
1437
|
+
"media_generation_result",
|
|
1318
1438
|
]);
|
|
1319
1439
|
const classifications = new Set<MachineInputBatchItem["members"][number]["classification"]>([
|
|
1320
1440
|
"success",
|
|
@@ -1333,16 +1453,24 @@ function machineInputMembers(value: unknown): MachineInputBatchItem["members"] {
|
|
|
1333
1453
|
member.classification as MachineInputBatchItem["members"][number]["classification"],
|
|
1334
1454
|
) &&
|
|
1335
1455
|
typeof member.sourceId === "string"
|
|
1336
|
-
?
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
kind
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1456
|
+
? (() => {
|
|
1457
|
+
const kind = member.kind as MachineInputBatchItem["members"][number]["kind"];
|
|
1458
|
+
const result =
|
|
1459
|
+
kind === "media_generation_result"
|
|
1460
|
+
? parseMediaGenerationResult(member.result)
|
|
1461
|
+
: null;
|
|
1462
|
+
return [
|
|
1463
|
+
{
|
|
1464
|
+
id: member.id,
|
|
1465
|
+
kind,
|
|
1466
|
+
classification:
|
|
1467
|
+
member.classification as MachineInputBatchItem["members"][number]["classification"],
|
|
1468
|
+
sourceId: member.sourceId,
|
|
1469
|
+
summary: stringValue(member.summary),
|
|
1470
|
+
...(result ? { result } : {}),
|
|
1471
|
+
},
|
|
1472
|
+
];
|
|
1473
|
+
})()
|
|
1346
1474
|
: [];
|
|
1347
1475
|
})
|
|
1348
1476
|
: [];
|
|
@@ -1378,6 +1506,25 @@ function resourceRefs(value: unknown): import("@opengeni/sdk").ResourceRef[] {
|
|
|
1378
1506
|
});
|
|
1379
1507
|
}
|
|
1380
1508
|
|
|
1509
|
+
function timelineAnnotations(value: unknown): TimelineAnnotation[] {
|
|
1510
|
+
if (!Array.isArray(value)) return [];
|
|
1511
|
+
return value.filter((candidate): candidate is TimelineAnnotation => {
|
|
1512
|
+
const annotation = asRecord(candidate);
|
|
1513
|
+
const source = asRecord(annotation.source);
|
|
1514
|
+
return (
|
|
1515
|
+
typeof annotation.id === "string" &&
|
|
1516
|
+
typeof annotation.ordinal === "number" &&
|
|
1517
|
+
typeof annotation.quote === "string" &&
|
|
1518
|
+
typeof annotation.note === "string" &&
|
|
1519
|
+
typeof source.eventId === "string" &&
|
|
1520
|
+
typeof source.eventType === "string" &&
|
|
1521
|
+
typeof source.sequence === "number" &&
|
|
1522
|
+
typeof source.startOffset === "number" &&
|
|
1523
|
+
typeof source.endOffset === "number"
|
|
1524
|
+
);
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1381
1528
|
function toolRefs(value: unknown): import("@opengeni/sdk").ToolRef[] {
|
|
1382
1529
|
if (!Array.isArray(value)) {
|
|
1383
1530
|
return [];
|
|
@@ -1440,6 +1587,31 @@ function isErrorOutput(payload: Record<string, unknown>): boolean {
|
|
|
1440
1587
|
);
|
|
1441
1588
|
}
|
|
1442
1589
|
|
|
1590
|
+
function toolCallTruncation(payload: Record<string, unknown>): ToolCallTruncation | null {
|
|
1591
|
+
const truncation = asRecord(payload.truncation);
|
|
1592
|
+
const fullEvidence = asRecord(truncation.fullEvidence);
|
|
1593
|
+
const surface = stringValue(truncation.surface);
|
|
1594
|
+
const reason = stringValue(truncation.reason);
|
|
1595
|
+
if (
|
|
1596
|
+
truncation.truncated !== true ||
|
|
1597
|
+
!surface ||
|
|
1598
|
+
!reason ||
|
|
1599
|
+
typeof fullEvidence.available !== "boolean"
|
|
1600
|
+
) {
|
|
1601
|
+
return null;
|
|
1602
|
+
}
|
|
1603
|
+
return {
|
|
1604
|
+
truncated: true,
|
|
1605
|
+
surface,
|
|
1606
|
+
reason,
|
|
1607
|
+
omittedBytes: numberOrNull(truncation.omittedBytes),
|
|
1608
|
+
fullEvidence: {
|
|
1609
|
+
available: fullEvidence.available,
|
|
1610
|
+
reason: stringValue(fullEvidence.reason) || null,
|
|
1611
|
+
},
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1443
1615
|
function findOpenCall(
|
|
1444
1616
|
items: TimelineItem[],
|
|
1445
1617
|
callId: string | null,
|
|
@@ -1563,6 +1735,37 @@ function authNeededReason(value: unknown): AuthNeededItem["reason"] {
|
|
|
1563
1735
|
: null;
|
|
1564
1736
|
}
|
|
1565
1737
|
|
|
1738
|
+
function capabilityAuthorizationRequest(
|
|
1739
|
+
value: unknown,
|
|
1740
|
+
): NonNullable<AuthNeededItem["capability"]> | null {
|
|
1741
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1742
|
+
const record = value as Record<string, unknown>;
|
|
1743
|
+
const kind = record.kind;
|
|
1744
|
+
const source = record.source;
|
|
1745
|
+
const action = record.action;
|
|
1746
|
+
if (
|
|
1747
|
+
typeof record.id !== "string" ||
|
|
1748
|
+
typeof record.name !== "string" ||
|
|
1749
|
+
!["pack", "mcp", "api", "skill", "plugin"].includes(String(kind)) ||
|
|
1750
|
+
!["built_in", "library", "configured", "public_registry", "registry", "manual"].includes(
|
|
1751
|
+
String(source),
|
|
1752
|
+
) ||
|
|
1753
|
+
!["connect", "add_credentials", "enable"].includes(String(action)) ||
|
|
1754
|
+
typeof record.rationale !== "string"
|
|
1755
|
+
) {
|
|
1756
|
+
return null;
|
|
1757
|
+
}
|
|
1758
|
+
return {
|
|
1759
|
+
id: record.id,
|
|
1760
|
+
name: record.name,
|
|
1761
|
+
kind: kind as NonNullable<AuthNeededItem["capability"]>["kind"],
|
|
1762
|
+
source: source as NonNullable<AuthNeededItem["capability"]>["source"],
|
|
1763
|
+
action: action as NonNullable<AuthNeededItem["capability"]>["action"],
|
|
1764
|
+
rationale: record.rationale,
|
|
1765
|
+
requiredVariables: stringList(record.requiredVariables),
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1566
1769
|
function stringList(value: unknown): string[] {
|
|
1567
1770
|
return Array.isArray(value)
|
|
1568
1771
|
? value.filter((entry): entry is string => typeof entry === "string" && entry.trim().length > 0)
|
|
@@ -1598,6 +1801,58 @@ function workerPrompt(args: unknown): string | null {
|
|
|
1598
1801
|
return null;
|
|
1599
1802
|
}
|
|
1600
1803
|
|
|
1804
|
+
function boundedWorkerFailureMessage(value: string): string | null {
|
|
1805
|
+
const normalized = value.replace(/[\u0000-\u001f\u007f]+/g, " ").trim();
|
|
1806
|
+
if (!normalized) return null;
|
|
1807
|
+
const encoded = new TextEncoder().encode(normalized);
|
|
1808
|
+
if (encoded.byteLength <= WORKER_FAILURE_MESSAGE_MAX_UTF8_BYTES) return normalized;
|
|
1809
|
+
let end = WORKER_FAILURE_MESSAGE_MAX_UTF8_BYTES;
|
|
1810
|
+
while (end > 0 && (encoded[end]! & 0xc0) === 0x80) end -= 1;
|
|
1811
|
+
return new TextDecoder().decode(encoded.slice(0, end)).trim();
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
function boundedWorkerFailure(value: unknown): WorkerItem["failure"] {
|
|
1815
|
+
const record = asRecord(value);
|
|
1816
|
+
const code = typeof record.code === "string" ? record.code.trim() : "";
|
|
1817
|
+
const message =
|
|
1818
|
+
typeof record.message === "string" ? boundedWorkerFailureMessage(record.message) : null;
|
|
1819
|
+
if (!/^[A-Za-z0-9._:-]{1,128}$/.test(code) || !message) return null;
|
|
1820
|
+
return { code: code.slice(0, WORKER_FAILURE_CODE_MAX_LENGTH), message };
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
/**
|
|
1824
|
+
* Extract the API's structured orchestration failure from raw objects, JSON
|
|
1825
|
+
* text, or retained MCP CallToolResult wrappers. Legacy flat strings remain
|
|
1826
|
+
* unprojected rather than being mistaken for the trusted diagnostic contract.
|
|
1827
|
+
*/
|
|
1828
|
+
function workerFailure(value: unknown, depth = 0): WorkerItem["failure"] {
|
|
1829
|
+
if (depth > 6 || value === null || value === undefined) return null;
|
|
1830
|
+
if (typeof value === "string") {
|
|
1831
|
+
const parsed = tryParseJson(value);
|
|
1832
|
+
return parsed === value ? null : workerFailure(parsed, depth + 1);
|
|
1833
|
+
}
|
|
1834
|
+
if (Array.isArray(value)) {
|
|
1835
|
+
for (const entry of value) {
|
|
1836
|
+
const failure = workerFailure(entry, depth + 1);
|
|
1837
|
+
if (failure) return failure;
|
|
1838
|
+
}
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
if (typeof value !== "object") return null;
|
|
1842
|
+
const record = value as Record<string, unknown>;
|
|
1843
|
+
const direct = boundedWorkerFailure(record.error);
|
|
1844
|
+
if (direct) return direct;
|
|
1845
|
+
for (const key of ["structuredContent", "content", "result", "output"] as const) {
|
|
1846
|
+
if (!(key in record)) continue;
|
|
1847
|
+
const failure = workerFailure(record[key], depth + 1);
|
|
1848
|
+
if (failure) return failure;
|
|
1849
|
+
}
|
|
1850
|
+
if (record.type === "text" && typeof record.text === "string") {
|
|
1851
|
+
return workerFailure(record.text, depth + 1);
|
|
1852
|
+
}
|
|
1853
|
+
return null;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1601
1856
|
/**
|
|
1602
1857
|
* Find a session id in orchestration tool arguments or output. Handles raw
|
|
1603
1858
|
* objects, JSON strings, and MCP tool results (`{ content: [{ type: "text",
|
package/src/timeline/registry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RetainedArtifactReference } from "@opengeni/sdk";
|
|
1
|
+
import type { RetainedArtifactReference, VideoArtifactPlaybackSource } from "@opengeni/sdk";
|
|
2
2
|
import type { ComponentType } from "react";
|
|
3
3
|
import { mcpToolLeaf } from "./tool-display-name";
|
|
4
4
|
import type { ToolCallItem } from "./types";
|
|
@@ -24,6 +24,7 @@ import type { ToolCallItem } from "./types";
|
|
|
24
24
|
export type ToolRendererProps = {
|
|
25
25
|
item: ToolCallItem;
|
|
26
26
|
loadRetainedScreenshot?: RetainedScreenshotLoader | undefined;
|
|
27
|
+
loadRetainedArtifact?: RetainedArtifactLoader | undefined;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
export type RetainedScreenshotLoader = (
|
|
@@ -31,6 +32,17 @@ export type RetainedScreenshotLoader = (
|
|
|
31
32
|
signal: AbortSignal,
|
|
32
33
|
) => Promise<Uint8Array | null>;
|
|
33
34
|
|
|
35
|
+
export type RetainedArtifactLoader = (
|
|
36
|
+
artifact: RetainedArtifactReference,
|
|
37
|
+
signal: AbortSignal,
|
|
38
|
+
) => Promise<Uint8Array | { url: string } | null>;
|
|
39
|
+
|
|
40
|
+
/** Mint an expiring source for native browser playback without loading video bytes in JS. */
|
|
41
|
+
export type VideoArtifactPlaybackLoader = (
|
|
42
|
+
artifactId: string,
|
|
43
|
+
signal: AbortSignal,
|
|
44
|
+
) => Promise<VideoArtifactPlaybackSource>;
|
|
45
|
+
|
|
34
46
|
export type ToolRenderer = ComponentType<ToolRendererProps>;
|
|
35
47
|
|
|
36
48
|
/** A registry entry: which key it matches and the component that renders it. */
|
|
@@ -19,7 +19,7 @@ import { usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
|
19
19
|
-------------------------------------------------------------------------- */
|
|
20
20
|
|
|
21
21
|
type LightboxController = {
|
|
22
|
-
open: (src: string, caption?: string, source?: HTMLElement | null) => void;
|
|
22
|
+
open: (src: string, caption?: string, source?: HTMLElement | null, label?: string) => void;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const LightboxContext = createContext<LightboxController | null>(null);
|
|
@@ -59,14 +59,21 @@ export function LightboxProvider({ children }: { children: ReactNode }) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function LightboxRoot({ children }: { children: ReactNode }) {
|
|
62
|
-
const [state, setState] = useState<{
|
|
62
|
+
const [state, setState] = useState<{
|
|
63
|
+
src: string;
|
|
64
|
+
caption?: string;
|
|
65
|
+
label: string;
|
|
66
|
+
} | null>(null);
|
|
63
67
|
const [tokenSource, setTokenSource] = useState<HTMLElement | null>(null);
|
|
64
68
|
const portalStyle = usePortalTokenStyle(tokenSource);
|
|
65
69
|
|
|
66
|
-
const open = useCallback(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
const open = useCallback(
|
|
71
|
+
(src: string, caption?: string, source?: HTMLElement | null, label = "Screenshot") => {
|
|
72
|
+
setTokenSource(source ?? null);
|
|
73
|
+
setState(caption ? { src, caption, label } : { src, label });
|
|
74
|
+
},
|
|
75
|
+
[],
|
|
76
|
+
);
|
|
70
77
|
|
|
71
78
|
const close = useCallback(() => {
|
|
72
79
|
setState(null);
|
|
@@ -95,7 +102,7 @@ function LightboxRoot({ children }: { children: ReactNode }) {
|
|
|
95
102
|
<Dialog.Content
|
|
96
103
|
asChild
|
|
97
104
|
forceMount
|
|
98
|
-
aria-label=
|
|
105
|
+
aria-label={state.label}
|
|
99
106
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
100
107
|
>
|
|
101
108
|
<motion.div
|
|
@@ -117,7 +124,10 @@ function LightboxRoot({ children }: { children: ReactNode }) {
|
|
|
117
124
|
className="og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12"
|
|
118
125
|
style={portalStyle}
|
|
119
126
|
>
|
|
120
|
-
<Dialog.Title className="sr-only">
|
|
127
|
+
<Dialog.Title className="sr-only">{state.label}</Dialog.Title>
|
|
128
|
+
<Dialog.Description className="sr-only">
|
|
129
|
+
{state.caption ?? `Expanded ${state.label.toLowerCase()}`}
|
|
130
|
+
</Dialog.Description>
|
|
121
131
|
{/* The figure is one self-contained object: image, caption, and
|
|
122
132
|
its own close control. The close button anchors to a wrapper
|
|
123
133
|
sized to the IMAGE (w-fit), so it hugs the real top-right
|
|
@@ -128,7 +138,7 @@ function LightboxRoot({ children }: { children: ReactNode }) {
|
|
|
128
138
|
{/* A plain <img>: this SDK is framework-agnostic, with no host Image component. */}
|
|
129
139
|
<img
|
|
130
140
|
src={state.src}
|
|
131
|
-
alt={state.caption ??
|
|
141
|
+
alt={state.caption ?? state.label}
|
|
132
142
|
className="min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg"
|
|
133
143
|
/>
|
|
134
144
|
<Dialog.Close
|
package/src/timeline/shared.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { CameraIcon, CameraOffIcon, ChevronRightIcon } from "lucide-react";
|
|
2
|
-
import { useState, type ReactNode } from "react";
|
|
2
|
+
import { createContext, useContext, useState, type ReactNode } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
4
|
import { stringifyPayload } from "../lib/format";
|
|
5
5
|
import { useForcedDefaultOpen } from "./disclosure-context";
|
|
6
6
|
import { useLightboxOptional } from "./screenshot-lightbox";
|
|
7
|
+
import type { ToolCallTruncation } from "./types";
|
|
7
8
|
|
|
8
9
|
/* ----------------------------------------------------------------------------
|
|
9
10
|
Shared timeline primitives
|
|
@@ -37,6 +38,22 @@ export type DisclosureChip = {
|
|
|
37
38
|
text: string;
|
|
38
39
|
};
|
|
39
40
|
|
|
41
|
+
const ToolCallTruncationContext = createContext<ToolCallTruncation | null>(null);
|
|
42
|
+
|
|
43
|
+
export function ToolCallTruncationProvider({
|
|
44
|
+
value,
|
|
45
|
+
children,
|
|
46
|
+
}: {
|
|
47
|
+
value: ToolCallTruncation | null;
|
|
48
|
+
children: ReactNode;
|
|
49
|
+
}) {
|
|
50
|
+
return (
|
|
51
|
+
<ToolCallTruncationContext.Provider value={value}>
|
|
52
|
+
{children}
|
|
53
|
+
</ToolCallTruncationContext.Provider>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
40
57
|
export type ActivityDisclosureProps = {
|
|
41
58
|
icon: ReactNode;
|
|
42
59
|
/** Icon tint. Defaults to the muted foreground; renderers pass accent/failed. */
|
|
@@ -81,6 +98,8 @@ export type ActivityDisclosureProps = {
|
|
|
81
98
|
cancelled?: boolean | undefined;
|
|
82
99
|
/** When false the row is a static line (no expand affordance). */
|
|
83
100
|
expandable?: boolean | undefined;
|
|
101
|
+
/** Seed this individual disclosure open; user interaction still owns it afterwards. */
|
|
102
|
+
defaultOpen?: boolean | undefined;
|
|
84
103
|
children?: ReactNode | undefined;
|
|
85
104
|
};
|
|
86
105
|
|
|
@@ -109,6 +128,7 @@ export function ActivityDisclosure({
|
|
|
109
128
|
failed,
|
|
110
129
|
cancelled,
|
|
111
130
|
expandable = true,
|
|
131
|
+
defaultOpen,
|
|
112
132
|
children,
|
|
113
133
|
}: ActivityDisclosureProps) {
|
|
114
134
|
// `failed` takes precedence over `cancelled` when both are set (shouldn't happen, but be safe).
|
|
@@ -128,8 +148,9 @@ export function ActivityDisclosure({
|
|
|
128
148
|
// An ancestor may seed the initial open state (screenshot instrumentation);
|
|
129
149
|
// absent in normal app usage, where the row starts collapsed.
|
|
130
150
|
const forcedDefaultOpen = useForcedDefaultOpen();
|
|
131
|
-
const [open, setOpen] = useState(forcedDefaultOpen ?? false);
|
|
132
|
-
const
|
|
151
|
+
const [open, setOpen] = useState(defaultOpen ?? forcedDefaultOpen ?? false);
|
|
152
|
+
const truncation = useContext(ToolCallTruncationContext);
|
|
153
|
+
const hasBody = expandable && (children != null || truncation != null);
|
|
133
154
|
|
|
134
155
|
// The preview is detail-on-demand: it is suppressed once the row is open so a
|
|
135
156
|
// path/stat shown in the body never also sits in the collapsed row.
|
|
@@ -184,7 +205,7 @@ export function ActivityDisclosure({
|
|
|
184
205
|
)}
|
|
185
206
|
{/* The right gutter carries at most ONE signal: the media thumbnail, else a
|
|
186
207
|
terse settle chip (hidden once expanded — the body owns the detail). */}
|
|
187
|
-
{media ? (
|
|
208
|
+
{media && !open ? (
|
|
188
209
|
<span className="ml-auto flex shrink-0 items-center gap-2 pl-2">{media}</span>
|
|
189
210
|
) : chip && !open ? (
|
|
190
211
|
<span className="ml-auto shrink-0 pl-2">
|
|
@@ -235,12 +256,31 @@ export function ActivityDisclosure({
|
|
|
235
256
|
{open ? (
|
|
236
257
|
<div className="mb-2 ml-7 mt-1.5 flex flex-col gap-2 overflow-hidden animate-og-expand">
|
|
237
258
|
{children}
|
|
259
|
+
{truncation ? <ToolCallTruncationNotice truncation={truncation} /> : null}
|
|
238
260
|
</div>
|
|
239
261
|
) : null}
|
|
240
262
|
</div>
|
|
241
263
|
);
|
|
242
264
|
}
|
|
243
265
|
|
|
266
|
+
function ToolCallTruncationNotice({ truncation }: { truncation: ToolCallTruncation }) {
|
|
267
|
+
const fullEvidence = truncation.fullEvidence.available
|
|
268
|
+
? "retained"
|
|
269
|
+
: (truncation.fullEvidence.reason ?? "unavailable");
|
|
270
|
+
return (
|
|
271
|
+
<div data-og-tool-output-truncation="" className="text-og-sm leading-5 text-og-fg-subtle">
|
|
272
|
+
Output bounded at <code className="font-og-mono">{truncation.surface}</code>
|
|
273
|
+
{truncation.omittedBytes != null && truncation.omittedBytes > 0
|
|
274
|
+
? ` · ${truncation.omittedBytes.toLocaleString()} bytes omitted`
|
|
275
|
+
: null}
|
|
276
|
+
{" · reason "}
|
|
277
|
+
<code className="font-og-mono">{truncation.reason}</code>
|
|
278
|
+
{" · full evidence "}
|
|
279
|
+
<code className="font-og-mono">{fullEvidence}</code>
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
244
284
|
/**
|
|
245
285
|
* The right-gutter settle chip. Color is spent only on the exception: a failure
|
|
246
286
|
* is a red dot + red text (the one colored token in a healthy run); success and
|
|
@@ -467,10 +507,14 @@ export function Thumbnail({
|
|
|
467
507
|
src,
|
|
468
508
|
caption,
|
|
469
509
|
alt = "screenshot",
|
|
510
|
+
expandLabel = "Expand screenshot",
|
|
511
|
+
lightboxLabel = "Screenshot",
|
|
470
512
|
}: {
|
|
471
513
|
src: string;
|
|
472
514
|
caption?: string | undefined;
|
|
473
515
|
alt?: string;
|
|
516
|
+
expandLabel?: string | undefined;
|
|
517
|
+
lightboxLabel?: string | undefined;
|
|
474
518
|
}) {
|
|
475
519
|
const lightbox = useLightboxOptional();
|
|
476
520
|
const [failed, setFailed] = useState(false);
|
|
@@ -498,7 +542,7 @@ export function Thumbnail({
|
|
|
498
542
|
type="button"
|
|
499
543
|
onClick={(event) => {
|
|
500
544
|
event.stopPropagation();
|
|
501
|
-
lightbox.open(src, caption, event.currentTarget);
|
|
545
|
+
lightbox.open(src, caption, event.currentTarget, lightboxLabel);
|
|
502
546
|
}}
|
|
503
547
|
onKeyDown={(event) => {
|
|
504
548
|
if (event.key === "Enter" || event.key === " ") {
|
|
@@ -510,7 +554,7 @@ export function Thumbnail({
|
|
|
510
554
|
"group/thumb relative inline-flex overflow-hidden bg-og-bg outline-hidden",
|
|
511
555
|
"focus-visible:ring-2 focus-visible:ring-og-accent",
|
|
512
556
|
)}
|
|
513
|
-
aria-label=
|
|
557
|
+
aria-label={expandLabel}
|
|
514
558
|
>
|
|
515
559
|
{img}
|
|
516
560
|
</button>
|
|
@@ -527,10 +571,14 @@ export function ScreenshotFigure({
|
|
|
527
571
|
src,
|
|
528
572
|
caption,
|
|
529
573
|
alt = "screenshot",
|
|
574
|
+
expandLabel = "Expand screenshot",
|
|
575
|
+
lightboxLabel = "Screenshot",
|
|
530
576
|
}: {
|
|
531
577
|
src: string;
|
|
532
578
|
caption?: string | undefined;
|
|
533
579
|
alt?: string;
|
|
580
|
+
expandLabel?: string | undefined;
|
|
581
|
+
lightboxLabel?: string | undefined;
|
|
534
582
|
}) {
|
|
535
583
|
const lightbox = useLightboxOptional();
|
|
536
584
|
const [failed, setFailed] = useState(false);
|
|
@@ -554,9 +602,9 @@ export function ScreenshotFigure({
|
|
|
554
602
|
) : lightbox ? (
|
|
555
603
|
<button
|
|
556
604
|
type="button"
|
|
557
|
-
onClick={(event) => lightbox.open(src, caption, event.currentTarget)}
|
|
605
|
+
onClick={(event) => lightbox.open(src, caption, event.currentTarget, lightboxLabel)}
|
|
558
606
|
className={surface}
|
|
559
|
-
aria-label=
|
|
607
|
+
aria-label={expandLabel}
|
|
560
608
|
>
|
|
561
609
|
{img}
|
|
562
610
|
</button>
|