@opengeni/react 0.29.0 → 0.33.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.
- package/dist/approvals.d.ts +14 -0
- package/dist/{chunk-M7X4JZOD.js → chunk-4QOQ2DSR.js} +8 -1
- package/dist/chunk-4QOQ2DSR.js.map +1 -0
- package/dist/{chunk-HQFPO7VX.js → chunk-7CJOAW3V.js} +24 -3
- package/dist/{chunk-HQFPO7VX.js.map → chunk-7CJOAW3V.js.map} +1 -1
- package/dist/{chunk-CSJBF3QJ.js → chunk-A2WITZTI.js} +377 -113
- package/dist/chunk-A2WITZTI.js.map +1 -0
- package/dist/{chunk-BC6RKIHS.js → chunk-GZ4KR67U.js} +11 -11
- package/dist/{chunk-AVLMIWYO.js → chunk-KZRUYCL4.js} +12 -6
- package/dist/chunk-KZRUYCL4.js.map +1 -0
- package/dist/{chunk-IPVOVOW6.js → chunk-MS3FBZ6A.js} +2539 -2174
- package/dist/chunk-MS3FBZ6A.js.map +1 -0
- package/dist/{chunk-OKXCECLG.js → chunk-TCCE5ZU5.js} +171 -22
- package/dist/chunk-TCCE5ZU5.js.map +1 -0
- package/dist/chunk-U255M5EZ.js +178 -0
- package/dist/chunk-U255M5EZ.js.map +1 -0
- package/dist/chunk-ZNNE2VES.js +6413 -0
- package/dist/chunk-ZNNE2VES.js.map +1 -0
- package/dist/client.d.ts +33 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/registry.d.ts +41 -0
- package/dist/commands/types.d.ts +85 -0
- package/dist/components/approval-surface.d.ts +28 -0
- package/dist/components/chat-composer.d.ts +51 -0
- package/dist/components/code-editor.d.ts +43 -0
- package/dist/components/command-palette.d.ts +25 -0
- package/dist/components/composer-transcription-control.d.ts +36 -0
- package/dist/components/composer.d.ts +277 -0
- package/dist/components/copy-button.d.ts +26 -0
- package/dist/components/desktop-viewer.d.ts +85 -0
- package/dist/components/diff-view.d.ts +38 -0
- package/dist/components/enrollment-consent.d.ts +33 -0
- package/dist/components/enrollment-device-flow.d.ts +27 -0
- package/dist/components/file-browser.d.ts +47 -0
- package/dist/components/fleet-tile.d.ts +18 -0
- package/dist/components/human-input-form.d.ts +47 -0
- package/dist/components/machine-card.d.ts +21 -0
- package/dist/components/machine-dock-bar.d.ts +31 -0
- package/dist/components/machine-health-pill.d.ts +9 -0
- package/dist/components/machine-metrics.d.ts +15 -0
- package/dist/components/machine-status-pill.d.ts +54 -0
- package/dist/components/machines/health.d.ts +25 -0
- package/dist/components/machines/machine-detail.d.ts +14 -0
- package/dist/components/machines/metric-history-chart.d.ts +24 -0
- package/dist/components/machines/metric-sparkline.d.ts +9 -0
- package/dist/components/machines/series.d.ts +24 -0
- package/dist/components/machines-dashboard.d.ts +30 -0
- package/dist/components/markdown.d.ts +31 -0
- package/dist/components/message-timeline.d.ts +98 -0
- package/dist/components/model-picker.d.ts +19 -0
- package/dist/components/pierre-diff.d.ts +34 -0
- package/dist/components/pierre-file.d.ts +27 -0
- package/dist/components/queue-draft-policy.d.ts +7 -0
- package/dist/components/queue-surface-implementation.d.ts +20 -0
- package/dist/components/queue-surface-state.d.ts +12 -0
- package/dist/components/queue-surface.d.ts +12 -0
- package/dist/components/sandbox-files.d.ts +49 -0
- package/dist/components/sandbox-terminal.d.ts +123 -0
- package/dist/components/sandbox-workspace.d.ts +128 -0
- package/dist/components/session-chrome.d.ts +70 -0
- package/dist/components/session-status.d.ts +25 -0
- package/dist/components/soften-streaming-markdown.d.ts +13 -0
- package/dist/components/stream-reveal.d.ts +37 -0
- package/dist/components/tip-follow.d.ts +139 -0
- package/dist/components/tooltip.d.ts +16 -0
- package/dist/components/workbench-changes.d.ts +34 -0
- package/dist/components/workspace-dock.d.ts +35 -0
- package/dist/composer.d.ts +11 -7
- package/dist/composer.js +9 -6
- package/dist/hooks/internal.d.ts +46 -0
- package/dist/hooks/use-available-models.d.ts +37 -0
- package/dist/hooks/use-billing-usage.d.ts +26 -0
- package/dist/hooks/use-codex-accounts.d.ts +69 -0
- package/dist/{use-composer-ClHy1rkL.d.ts → hooks/use-composer.d.ts} +16 -24
- package/dist/hooks/use-desktop-stream.d.ts +43 -0
- package/dist/hooks/use-environments.d.ts +35 -0
- package/dist/{use-file-attachments-BmT8WtqO.d.ts → hooks/use-file-attachments.d.ts} +6 -9
- package/dist/hooks/use-goal.d.ts +46 -0
- package/dist/hooks/use-human-input.d.ts +26 -0
- package/dist/hooks/use-last-started-turn-policy.d.ts +27 -0
- package/dist/hooks/use-machine-chip.d.ts +54 -0
- package/dist/hooks/use-machines.d.ts +81 -0
- package/dist/hooks/use-packs.d.ts +27 -0
- package/dist/hooks/use-relay-frame-stream.d.ts +53 -0
- package/dist/hooks/use-rigs.d.ts +87 -0
- package/dist/hooks/use-sandbox-files.d.ts +108 -0
- package/dist/hooks/use-sandbox-git.d.ts +58 -0
- package/dist/hooks/use-sandbox-terminal.d.ts +62 -0
- package/dist/hooks/use-scheduled-tasks.d.ts +15 -0
- package/dist/hooks/use-session-capabilities.d.ts +83 -0
- package/dist/hooks/use-session-control.d.ts +22 -0
- package/dist/hooks/use-session-events.d.ts +92 -0
- package/dist/hooks/use-session-lineage.d.ts +17 -0
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +23 -0
- package/dist/hooks/use-session.d.ts +23 -0
- package/dist/hooks/use-slash-commands.d.ts +66 -0
- package/dist/hooks/use-terminal-stream.d.ts +46 -0
- package/dist/hooks/use-transcription.d.ts +73 -0
- package/dist/hooks/use-turn-queue.d.ts +44 -0
- package/dist/hooks/use-voice-input.d.ts +25 -0
- package/dist/hooks/use-windowed-sections.d.ts +42 -0
- package/dist/hooks/use-workspace-capture.d.ts +49 -0
- package/dist/hooks/use-workspace-edit.d.ts +73 -0
- package/dist/hooks/use-workspace-sessions.d.ts +30 -0
- package/dist/hooks/use-workspaces.d.ts +22 -0
- package/dist/human-input.d.ts +18 -0
- package/dist/index.d.ts +144 -2119
- package/dist/index.js +421 -324
- package/dist/index.js.map +1 -1
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/format.d.ts +48 -0
- package/dist/lib/git-patch.d.ts +8 -0
- package/dist/lib/motion-inspect.d.ts +5 -0
- package/dist/lib/motion.d.ts +14 -0
- package/dist/lib/noto-sans-arabic-loader.d.ts +1 -0
- package/dist/lib/noto-sans-jp-loader.generated.d.ts +1 -0
- package/dist/lib/relay-wire.d.ts +30 -0
- package/dist/lib/use-portal-token-style.d.ts +9 -0
- package/dist/lib/use-theme-type.d.ts +5 -0
- package/dist/lib/use-unicode-fonts.d.ts +12 -0
- package/dist/lib/xterm-renderer.d.ts +19 -0
- package/dist/lib/xterm-theme.d.ts +75 -0
- package/dist/machines.d.ts +30 -413
- package/dist/machines.js +3 -3
- package/dist/model-policy.d.ts +32 -0
- package/dist/model-policy.js +33 -0
- package/dist/model-policy.js.map +1 -0
- package/dist/provider.d.ts +16 -0
- package/dist/{queue-surface-implementation-UQ535OKQ.js → queue-surface-implementation-THPAKGMD.js} +2 -2
- package/dist/{queue-surface-implementation-UQ535OKQ.js.map → queue-surface-implementation-THPAKGMD.js.map} +1 -1
- package/dist/session-context.d.ts +82 -0
- package/dist/session-ui.d.ts +10 -7
- package/dist/session-ui.js +9 -5
- package/dist/session.d.ts +28 -6
- package/dist/session.js +11 -11
- package/dist/timeline/activity-rail.d.ts +19 -0
- package/dist/timeline/disclosure-context.d.ts +14 -0
- package/dist/timeline/entrance.d.ts +14 -0
- package/dist/timeline/fleet-decision-projection.d.ts +9 -0
- package/dist/timeline/fleet-decision-row.d.ts +11 -0
- package/dist/timeline/fold-memory.d.ts +15 -0
- package/dist/timeline/index.d.ts +18 -0
- package/dist/timeline/parsers.d.ts +96 -0
- package/dist/timeline/projection.d.ts +38 -0
- package/dist/timeline/registry.d.ts +40 -0
- package/dist/timeline/screenshot-lightbox.d.ts +26 -0
- package/dist/timeline/seen-activity-ids.d.ts +2 -0
- package/dist/timeline/shared.d.ts +125 -0
- package/dist/timeline/tool-diff.d.ts +8 -0
- package/dist/timeline/tool-display-name.d.ts +10 -0
- package/dist/timeline/tool-renderers.d.ts +5 -0
- package/dist/timeline/turn-summary.d.ts +116 -0
- package/dist/{use-turn-queue-D_1a8W_l.d.ts → timeline/types.d.ts} +41 -69
- package/dist/types/machines.d.ts +11 -0
- package/package.json +8 -4
- package/src/client.ts +1 -0
- package/src/components/composer-transcription-control.tsx +278 -130
- package/src/components/composer.tsx +20 -15
- package/src/components/copy-button.tsx +127 -0
- package/src/components/markdown.tsx +231 -32
- package/src/components/message-timeline.tsx +1304 -378
- package/src/components/model-picker.tsx +83 -43
- package/src/components/queue-surface-implementation.tsx +1 -1
- package/src/components/session-chrome.tsx +942 -0
- package/src/components/soften-streaming-markdown.ts +205 -0
- package/src/components/stream-reveal.ts +195 -0
- package/src/components/tip-follow.ts +459 -0
- package/src/components/tooltip.tsx +103 -0
- package/src/composer.ts +6 -0
- package/src/hooks/internal.ts +30 -4
- package/src/hooks/use-available-models.ts +51 -4
- package/src/hooks/use-composer.ts +23 -3
- package/src/hooks/use-last-started-turn-policy.ts +95 -0
- package/src/hooks/use-session-events.ts +359 -5
- package/src/hooks/use-voice-input.ts +232 -0
- package/src/index.ts +47 -1
- package/src/lib/clipboard.ts +58 -0
- package/src/lib/format.ts +18 -0
- package/src/lib/motion-inspect.ts +5 -0
- package/src/lib/motion.ts +80 -0
- package/src/model-policy.ts +210 -0
- package/src/session-ui.ts +7 -0
- package/src/timeline/activity-rail.tsx +46 -7
- package/src/timeline/entrance.tsx +10 -0
- package/src/timeline/fold-memory.ts +52 -0
- package/src/timeline/index.ts +9 -1
- package/src/timeline/projection.ts +226 -41
- package/src/timeline/seen-activity-ids.ts +19 -0
- package/src/timeline/shared.tsx +1 -1
- package/src/timeline/tool-renderers.tsx +75 -6
- package/src/timeline/turn-summary.tsx +387 -97
- package/src/timeline/types.ts +21 -0
- package/styles/index.css +99 -7
- package/styles/tokens.css +44 -3
- package/dist/chunk-AVLMIWYO.js.map +0 -1
- package/dist/chunk-CSJBF3QJ.js.map +0 -1
- package/dist/chunk-IPVOVOW6.js.map +0 -1
- package/dist/chunk-M7X4JZOD.js.map +0 -1
- package/dist/chunk-OKXCECLG.js.map +0 -1
- package/dist/chunk-ZMNPFZWL.js +0 -3918
- package/dist/chunk-ZMNPFZWL.js.map +0 -1
- package/dist/composer-BMzimGTO.d.ts +0 -528
- package/dist/session-DaONt-dY.d.ts +0 -264
- package/dist/session-context-CAjlaeZb.d.ts +0 -84
- package/dist/session-ui-B5_roA95.d.ts +0 -259
- /package/dist/{chunk-BC6RKIHS.js.map → chunk-GZ4KR67U.js.map} +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { ClientModel, ReasoningEffort, WorkspaceModelCatalogModel } from "@opengeni/sdk";
|
|
2
|
+
|
|
3
|
+
export type PickerBillingClass = "opengeni_credits" | "codex_subscription" | "byok";
|
|
4
|
+
|
|
5
|
+
export type PickerModelRow = {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
billingClass: PickerBillingClass;
|
|
9
|
+
billingClassLabel: string;
|
|
10
|
+
selectable: boolean;
|
|
11
|
+
unavailableReason: string | null;
|
|
12
|
+
provider: string;
|
|
13
|
+
providerLabel: string;
|
|
14
|
+
catalog: WorkspaceModelCatalogModel;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type LatencyModeId = "standard" | "priority" | "fast";
|
|
18
|
+
|
|
19
|
+
const BILLING_CLASS_ORDER: PickerBillingClass[] = [
|
|
20
|
+
"opengeni_credits",
|
|
21
|
+
"codex_subscription",
|
|
22
|
+
"byok",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const BILLING_CLASS_LABELS: Record<PickerBillingClass, string> = {
|
|
26
|
+
opengeni_credits: "OpenGeni",
|
|
27
|
+
codex_subscription: "Codex",
|
|
28
|
+
byok: "Bring your own key",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const AVAILABILITY_REASON_LABELS: Record<string, string> = {
|
|
32
|
+
missing_credential: "Credentials required",
|
|
33
|
+
needs_reauth: "Reconnect required",
|
|
34
|
+
credential_not_ready: "Credential not ready",
|
|
35
|
+
not_entitled: "Not entitled",
|
|
36
|
+
provider_unhealthy: "Provider unavailable",
|
|
37
|
+
policy_blocked: "Blocked by workspace policy",
|
|
38
|
+
unsupported: "Unsupported",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function billingClassForModel(model: ClientModel): PickerBillingClass {
|
|
42
|
+
if (model.credentialSource?.kind === "connected_subscription") {
|
|
43
|
+
return "codex_subscription";
|
|
44
|
+
}
|
|
45
|
+
if (model.credentialSource?.kind === "workspace_connection") {
|
|
46
|
+
return "byok";
|
|
47
|
+
}
|
|
48
|
+
if (model.billing?.upstreamPayer === "connected_subscription") {
|
|
49
|
+
return "codex_subscription";
|
|
50
|
+
}
|
|
51
|
+
if (model.billing?.upstreamPayer === "workspace") {
|
|
52
|
+
return "byok";
|
|
53
|
+
}
|
|
54
|
+
return "opengeni_credits";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function billingClassLabel(billingClass: PickerBillingClass): string {
|
|
58
|
+
return BILLING_CLASS_LABELS[billingClass];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function availabilityReasonLabel(
|
|
62
|
+
reason: WorkspaceModelCatalogModel["availability"]["reason"],
|
|
63
|
+
): string | null {
|
|
64
|
+
if (!reason) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return AVAILABILITY_REASON_LABELS[reason] ?? "Unavailable";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function effortOptionsForModel(model: ClientModel): ReasoningEffort[] {
|
|
71
|
+
const efforts = model.capabilities?.reasoning.efforts;
|
|
72
|
+
if (!efforts || efforts.length === 0) {
|
|
73
|
+
return ["low"];
|
|
74
|
+
}
|
|
75
|
+
const order: ReasoningEffort[] = ["none", "minimal", "low", "medium", "high", "xhigh"];
|
|
76
|
+
return order.filter((effort) => efforts.includes(effort));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function defaultEffortForModel(model: ClientModel): ReasoningEffort {
|
|
80
|
+
const options = effortOptionsForModel(model);
|
|
81
|
+
const configured = model.capabilities?.reasoning.defaultEffort;
|
|
82
|
+
if (configured && options.includes(configured)) {
|
|
83
|
+
return configured;
|
|
84
|
+
}
|
|
85
|
+
return options[0] ?? "low";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function coerceReasoningEffortForModel(
|
|
89
|
+
model: ClientModel,
|
|
90
|
+
effort: ReasoningEffort,
|
|
91
|
+
): ReasoningEffort {
|
|
92
|
+
const options = effortOptionsForModel(model);
|
|
93
|
+
if (options.includes(effort)) {
|
|
94
|
+
return effort;
|
|
95
|
+
}
|
|
96
|
+
return defaultEffortForModel(model);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function runnableLatencyModesForModel(model: ClientModel): LatencyModeId[] {
|
|
100
|
+
const modes = model.capabilities?.latencyModes ?? [];
|
|
101
|
+
return modes.filter((mode) => mode.runnable).map((mode) => mode.id);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function labelLatencyMode(mode: LatencyModeId): string {
|
|
105
|
+
if (mode === "fast") {
|
|
106
|
+
return "Fast";
|
|
107
|
+
}
|
|
108
|
+
if (mode === "priority") {
|
|
109
|
+
return "Priority";
|
|
110
|
+
}
|
|
111
|
+
return "Standard";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function payerSummaryForModel(model: ClientModel): string {
|
|
115
|
+
const billing = model.billing;
|
|
116
|
+
if (!billing) {
|
|
117
|
+
return "Route unknown";
|
|
118
|
+
}
|
|
119
|
+
if (billing.metering === "opengeni_credits") {
|
|
120
|
+
return "OpenGeni credits · automatic managed route";
|
|
121
|
+
}
|
|
122
|
+
if (billing.upstreamPayer === "connected_subscription") {
|
|
123
|
+
return "Codex subscription · external billing";
|
|
124
|
+
}
|
|
125
|
+
if (billing.upstreamPayer === "workspace") {
|
|
126
|
+
return "Workspace credentials · external billing";
|
|
127
|
+
}
|
|
128
|
+
return "Deployment route · external billing";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function advancedSourceSummary(model: ClientModel): string | null {
|
|
132
|
+
const source = model.credentialSource;
|
|
133
|
+
if (!source) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
if (source.kind === "connected_subscription") {
|
|
137
|
+
return "Connected Codex subscription";
|
|
138
|
+
}
|
|
139
|
+
if (source.kind === "workspace_connection") {
|
|
140
|
+
return "Workspace API key connection";
|
|
141
|
+
}
|
|
142
|
+
if (source.kind === "deployment") {
|
|
143
|
+
return source.mechanism === "azure_ad_bearer"
|
|
144
|
+
? "Deployment Azure identity"
|
|
145
|
+
: "Deployment API key";
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerModelRow[] {
|
|
151
|
+
return models.map((catalog) => {
|
|
152
|
+
const billingClass = billingClassForModel(catalog);
|
|
153
|
+
return {
|
|
154
|
+
id: catalog.id,
|
|
155
|
+
label: catalog.label,
|
|
156
|
+
billingClass,
|
|
157
|
+
billingClassLabel: billingClassLabel(billingClass),
|
|
158
|
+
selectable: catalog.availability.selectable,
|
|
159
|
+
unavailableReason: catalog.availability.selectable
|
|
160
|
+
? null
|
|
161
|
+
: availabilityReasonLabel(catalog.availability.reason),
|
|
162
|
+
provider: catalog.provider,
|
|
163
|
+
providerLabel: catalog.providerLabel,
|
|
164
|
+
catalog,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function sortPickerRows(rows: PickerModelRow[]): PickerModelRow[] {
|
|
170
|
+
return [...rows].sort((left, right) => {
|
|
171
|
+
const classDelta =
|
|
172
|
+
BILLING_CLASS_ORDER.indexOf(left.billingClass) -
|
|
173
|
+
BILLING_CLASS_ORDER.indexOf(right.billingClass);
|
|
174
|
+
if (classDelta !== 0) {
|
|
175
|
+
return classDelta;
|
|
176
|
+
}
|
|
177
|
+
if (left.selectable !== right.selectable) {
|
|
178
|
+
return left.selectable ? -1 : 1;
|
|
179
|
+
}
|
|
180
|
+
return left.label.localeCompare(right.label);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function findPickerRow(rows: PickerModelRow[], modelId: string): PickerModelRow | null {
|
|
185
|
+
return rows.find((row) => row.id === modelId) ?? null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function groupPickerRowsByBillingClass(
|
|
189
|
+
rows: PickerModelRow[],
|
|
190
|
+
): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }> {
|
|
191
|
+
const sorted = sortPickerRows(rows);
|
|
192
|
+
const groups: Array<{
|
|
193
|
+
billingClass: PickerBillingClass;
|
|
194
|
+
label: string;
|
|
195
|
+
rows: PickerModelRow[];
|
|
196
|
+
}> = [];
|
|
197
|
+
for (const row of sorted) {
|
|
198
|
+
const existing = groups.find((group) => group.billingClass === row.billingClass);
|
|
199
|
+
if (existing) {
|
|
200
|
+
existing.rows.push(row);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
groups.push({
|
|
204
|
+
billingClass: row.billingClass,
|
|
205
|
+
label: row.billingClassLabel,
|
|
206
|
+
rows: [row],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return groups;
|
|
210
|
+
}
|
package/src/session-ui.ts
CHANGED
|
@@ -20,3 +20,10 @@ export type {
|
|
|
20
20
|
} from "./timeline/turn-summary";
|
|
21
21
|
export { QueueSurface } from "./components/queue-surface";
|
|
22
22
|
export type { QueueSurfaceProps } from "./components/queue-surface";
|
|
23
|
+
export { SessionChrome, sessionChromeGoalPillState } from "./components/session-chrome";
|
|
24
|
+
export type {
|
|
25
|
+
SessionChromeAgentsSignal,
|
|
26
|
+
SessionChromeProps,
|
|
27
|
+
SessionChromeSignalId,
|
|
28
|
+
SessionChromeSignalTone,
|
|
29
|
+
} from "./components/session-chrome";
|
|
@@ -5,13 +5,15 @@ import {
|
|
|
5
5
|
BrainIcon,
|
|
6
6
|
SquareTerminalIcon,
|
|
7
7
|
} from "lucide-react";
|
|
8
|
-
import { lazy, Suspense } from "react";
|
|
8
|
+
import { lazy, Suspense, useLayoutEffect, useRef } from "react";
|
|
9
9
|
import { jsx as rowJsx, jsxs as rowJsxs } from "react/jsx-runtime";
|
|
10
|
+
import { Markdown } from "../components/markdown";
|
|
10
11
|
import { cn } from "../lib/cn";
|
|
11
12
|
import { truncate } from "../lib/format";
|
|
12
13
|
import { defaultToolRegistry } from "./tool-renderers";
|
|
13
|
-
import { useEntranceAnimation } from "./entrance";
|
|
14
|
+
import { useEntranceAnimation, useEntranceAnimationLive } from "./entrance";
|
|
14
15
|
import type { ToolRegistry } from "./registry";
|
|
16
|
+
import { useSeenActivityIds } from "./seen-activity-ids";
|
|
15
17
|
import { BodyNote, PayloadBlock, ActivityDisclosure } from "./shared";
|
|
16
18
|
import { toolDisplayName } from "./tool-display-name";
|
|
17
19
|
import type { ActivityItem, MemoryItem, ReasoningItem, SandboxItem, WorkerItem } from "./types";
|
|
@@ -66,7 +68,34 @@ export function ActivityRail({
|
|
|
66
68
|
bare,
|
|
67
69
|
className,
|
|
68
70
|
}: ActivityRailProps) {
|
|
69
|
-
const
|
|
71
|
+
const enterMounted = useEntranceAnimation();
|
|
72
|
+
// Live gate: rails born during bulk capture enter=false forever; with a
|
|
73
|
+
// seen-id map we still want later live appends to fade (ids gate remounts).
|
|
74
|
+
const enterLive = useEntranceAnimationLive();
|
|
75
|
+
const seenIds = useSeenActivityIds();
|
|
76
|
+
const enter = seenIds ? enterLive : enterMounted;
|
|
77
|
+
const previousIdsRef = useRef<Set<string> | null>(null);
|
|
78
|
+
const enteringIds = new Set<string>();
|
|
79
|
+
if (enter) {
|
|
80
|
+
for (const item of items) {
|
|
81
|
+
if (seenIds) {
|
|
82
|
+
if (!seenIds.has(item.id)) {
|
|
83
|
+
enteringIds.add(item.id);
|
|
84
|
+
}
|
|
85
|
+
} else if (previousIdsRef.current !== null && !previousIdsRef.current.has(item.id)) {
|
|
86
|
+
// Standalone ActivityRail (tests / demo): append-only, no remount map.
|
|
87
|
+
enteringIds.add(item.id);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
useLayoutEffect(() => {
|
|
92
|
+
previousIdsRef.current = new Set(items.map((item) => item.id));
|
|
93
|
+
if (seenIds) {
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
seenIds.add(item.id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
70
99
|
return (
|
|
71
100
|
<div
|
|
72
101
|
className={cn(
|
|
@@ -75,7 +104,9 @@ export function ActivityRail({
|
|
|
75
104
|
// so a long rail reads as a few clusters, not a metronome of rows.
|
|
76
105
|
"flex flex-col gap-0.5",
|
|
77
106
|
!bare && "border-l-2 border-og-border pl-3 sm:pl-4",
|
|
78
|
-
|
|
107
|
+
// Whole-rail enter: standalone rails only (no seen-id map). Inside
|
|
108
|
+
// MessageTimeline, unknown ids take per-row enter — remounts stay quiet.
|
|
109
|
+
!bare && enter && !seenIds && previousIdsRef.current === null && "animate-og-enter",
|
|
79
110
|
className,
|
|
80
111
|
)}
|
|
81
112
|
>
|
|
@@ -83,7 +114,11 @@ export function ActivityRail({
|
|
|
83
114
|
const newFamily = index > 0 && familyOf(item) !== familyOf(items[index - 1]!);
|
|
84
115
|
const row = renderActivity(item, toolRegistry, onOpenSession, onMemoryClick);
|
|
85
116
|
return (
|
|
86
|
-
<div
|
|
117
|
+
<div
|
|
118
|
+
key={item.id}
|
|
119
|
+
data-og-timeline-row-anchor=""
|
|
120
|
+
className={cn(newFamily && "mt-3", enteringIds.has(item.id) && "animate-og-row-enter")}
|
|
121
|
+
>
|
|
87
122
|
{row}
|
|
88
123
|
</div>
|
|
89
124
|
);
|
|
@@ -135,7 +170,9 @@ function renderActivity(
|
|
|
135
170
|
|
|
136
171
|
function ReasoningRow({ item }: { item: ReasoningItem }) {
|
|
137
172
|
// Reasoning recedes: a dimmer, lighter-weight title so action rows lead and
|
|
138
|
-
// thought rows sit a half-step back in the hierarchy.
|
|
173
|
+
// thought rows sit a half-step back in the hierarchy. Body uses the same
|
|
174
|
+
// GFM markdown path as agent messages — Codex reasoning often carries
|
|
175
|
+
// headings/lists/bold that were previously shown as raw plaintext.
|
|
139
176
|
return (
|
|
140
177
|
<ActivityDisclosure
|
|
141
178
|
icon={<BrainIcon className="size-3.5" />}
|
|
@@ -150,7 +187,9 @@ function ReasoningRow({ item }: { item: ReasoningItem }) {
|
|
|
150
187
|
running={item.streaming}
|
|
151
188
|
preview={truncate(item.text, 110)}
|
|
152
189
|
>
|
|
153
|
-
<
|
|
190
|
+
<div className="text-og-base leading-6 text-og-fg-muted [&_strong]:text-og-fg-muted">
|
|
191
|
+
<Markdown streaming={item.streaming}>{item.text}</Markdown>
|
|
192
|
+
</div>
|
|
154
193
|
</ActivityDisclosure>
|
|
155
194
|
);
|
|
156
195
|
}
|
|
@@ -18,6 +18,16 @@ const EntranceAnimationContext = createContext(true);
|
|
|
18
18
|
|
|
19
19
|
export const EntranceAnimationProvider = EntranceAnimationContext.Provider;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Live entrance gate from the nearest provider. Prefer
|
|
23
|
+
* {@link useEntranceAnimation} for elements that must freeze the decision at
|
|
24
|
+
* mount; use this when a stable parent (e.g. ActivityRail) needs to animate
|
|
25
|
+
* later appends after a bulk window clears.
|
|
26
|
+
*/
|
|
27
|
+
export function useEntranceAnimationLive(): boolean {
|
|
28
|
+
return useContext(EntranceAnimationContext);
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
/**
|
|
22
32
|
* Whether this element should wear the entrance animation. Captured at mount
|
|
23
33
|
* from the nearest provider (true outside any provider) and stable for the
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
/* ----------------------------------------------------------------------------
|
|
4
|
+
Fold memory
|
|
5
|
+
|
|
6
|
+
Remembers, per durable timeline group id, that a fold reached a RESTING
|
|
7
|
+
state: "closed" when the settle choreography finished its collapse or the
|
|
8
|
+
reader closed the chip by hand, "open" when the reader explicitly expanded
|
|
9
|
+
it. The map lives OUTSIDE the component tree because the timeline
|
|
10
|
+
deliberately remounts chips with fresh keys (the activity→turn wrap, the
|
|
11
|
+
nested-chip key flip around settle chrome) — and a remount must never
|
|
12
|
+
forget that the reader already watched this cluster fold. Re-opening an
|
|
13
|
+
already-settled fold reads as the timeline undoing its own choreography.
|
|
14
|
+
|
|
15
|
+
With no provider the hook returns null and every fold keeps its
|
|
16
|
+
author-chosen default — standalone TurnSummary usage is unchanged.
|
|
17
|
+
-------------------------------------------------------------------------- */
|
|
18
|
+
|
|
19
|
+
export type FoldRestingState = "open" | "closed";
|
|
20
|
+
|
|
21
|
+
const FoldMemoryContext = createContext<Map<string, FoldRestingState> | null>(null);
|
|
22
|
+
|
|
23
|
+
/** Provide a per-timeline resting-state map (MessageTimeline owns one). */
|
|
24
|
+
export const FoldMemoryProvider = FoldMemoryContext.Provider;
|
|
25
|
+
|
|
26
|
+
/** The ancestor fold-memory map, or null when none is mounted (inert). */
|
|
27
|
+
export function useFoldMemory(): Map<string, FoldRestingState> | null {
|
|
28
|
+
return useContext(FoldMemoryContext);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Single-cluster activity→turn wrap: copy the activity resting state onto the
|
|
33
|
+
* new turn-* key. Those ids differ across the wrap; without this the turn
|
|
34
|
+
* remounts settleFold and re-opens a chip the reader already watched collapse.
|
|
35
|
+
*
|
|
36
|
+
* Multi-cluster wraps deliberately do NOT inherit — the outer turn chip is new
|
|
37
|
+
* and still takes one settle beat; nested clusters keep their own activity-*
|
|
38
|
+
* memory so they stay closed under that beat.
|
|
39
|
+
*/
|
|
40
|
+
export function inheritFoldRestingState(
|
|
41
|
+
memory: Map<string, FoldRestingState>,
|
|
42
|
+
targetKey: string,
|
|
43
|
+
sourceKeys: readonly string[],
|
|
44
|
+
): void {
|
|
45
|
+
if (memory.has(targetKey) || sourceKeys.length !== 1) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const state = memory.get(sourceKeys[0]!);
|
|
49
|
+
if (state !== undefined) {
|
|
50
|
+
memory.set(targetKey, state);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/timeline/index.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type {
|
|
|
30
30
|
ActivityItem,
|
|
31
31
|
AgentMessageItem,
|
|
32
32
|
AuthNeededItem,
|
|
33
|
+
ContextCompactionItem,
|
|
33
34
|
FleetDecisionItem,
|
|
34
35
|
FleetDecisionScoreItem,
|
|
35
36
|
GoalItem,
|
|
@@ -85,8 +86,15 @@ export { LightboxProvider, useLightbox, useLightboxOptional } from "./screenshot
|
|
|
85
86
|
// disclosure defaults (opt-in initial-open seed; for screenshot/test instrumentation)
|
|
86
87
|
export { DisclosureDefaultsProvider, useForcedDefaultOpen } from "./disclosure-context";
|
|
87
88
|
|
|
89
|
+
// fold memory (cross-remount resting state so wraps never reopen settled folds)
|
|
90
|
+
export { FoldMemoryProvider, inheritFoldRestingState, useFoldMemory } from "./fold-memory";
|
|
91
|
+
export type { FoldRestingState } from "./fold-memory";
|
|
92
|
+
|
|
93
|
+
// seen activity ids (live tool enter across rail remounts)
|
|
94
|
+
export { SeenActivityIdsProvider, useSeenActivityIds } from "./seen-activity-ids";
|
|
95
|
+
|
|
88
96
|
// turn-collapse summary chip
|
|
89
|
-
export { BUILT_IN_TURN_SUMMARY_FACET_IDS, TurnSummary } from "./turn-summary";
|
|
97
|
+
export { BUILT_IN_TURN_SUMMARY_FACET_IDS, TurnSummary, useTurnSettleOpen } from "./turn-summary";
|
|
90
98
|
export type {
|
|
91
99
|
BuiltInTurnSummaryFacetId,
|
|
92
100
|
TurnOutcome,
|