@opengeni/react 0.29.0 → 0.32.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-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-IPVOVOW6.js → chunk-WY2QN2CX.js} +2539 -2174
- package/dist/chunk-WY2QN2CX.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
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
AgentMessageItem,
|
|
11
11
|
ActivityItem,
|
|
12
12
|
AuthNeededItem,
|
|
13
|
+
ContextCompactionItem,
|
|
13
14
|
GoalItem,
|
|
14
15
|
MachineInputBatchItem,
|
|
15
16
|
MemoryItem,
|
|
@@ -165,12 +166,17 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
165
166
|
// Reconcile the most recent same-turn agent message — even when
|
|
166
167
|
// activity (tool calls, reasoning) landed after its deltas — so the
|
|
167
168
|
// completed text never duplicates the streamed one.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
let openIndex = -1;
|
|
170
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
171
|
+
const candidate = items[index];
|
|
172
|
+
if (candidate?.kind === "agent-message" && candidate.turnId === turnId) {
|
|
173
|
+
openIndex = index;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const candidate = openIndex >= 0 ? items[openIndex] : undefined;
|
|
178
|
+
const open: AgentMessageItem | undefined =
|
|
179
|
+
candidate?.kind === "agent-message" ? candidate : undefined;
|
|
174
180
|
if (
|
|
175
181
|
open &&
|
|
176
182
|
(open.streaming || !open.text || text === open.text || text.startsWith(open.text))
|
|
@@ -180,6 +186,15 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
180
186
|
open.text = text || open.text;
|
|
181
187
|
}
|
|
182
188
|
open.streaming = false;
|
|
189
|
+
// The SDK can emit a hosted-tool item only after its provider-native
|
|
190
|
+
// operation has completed, even though answer deltas were already
|
|
191
|
+
// streamed. The completed message event is the durable ordering
|
|
192
|
+
// authority, so move the reconciled row after any intervening tool
|
|
193
|
+
// activity instead of leaving completed web searches below the answer.
|
|
194
|
+
if (openIndex < items.length - 1) {
|
|
195
|
+
items.splice(openIndex, 1);
|
|
196
|
+
items.push(open);
|
|
197
|
+
}
|
|
183
198
|
break;
|
|
184
199
|
}
|
|
185
200
|
if (text) {
|
|
@@ -236,6 +251,26 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
236
251
|
});
|
|
237
252
|
break;
|
|
238
253
|
}
|
|
254
|
+
// Live Responses `web_search_call` events and the later SDK
|
|
255
|
+
// `RunToolCallItem` share the same item id. Merge so mid-stream cards
|
|
256
|
+
// do not duplicate when the step finally materializes.
|
|
257
|
+
if (callId) {
|
|
258
|
+
const existing = [...items]
|
|
259
|
+
.reverse()
|
|
260
|
+
.find(
|
|
261
|
+
(item): item is ToolCallItem => item.kind === "tool-call" && item.callId === callId,
|
|
262
|
+
);
|
|
263
|
+
if (existing) {
|
|
264
|
+
if (args != null) {
|
|
265
|
+
existing.arguments = args;
|
|
266
|
+
}
|
|
267
|
+
if (payload.raw !== undefined) {
|
|
268
|
+
existing.raw = mergeToolCallRaw(existing.raw, payload.raw);
|
|
269
|
+
}
|
|
270
|
+
existing.status = providerNativeToolStatus(existing.raw);
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
239
274
|
items.push({
|
|
240
275
|
kind: "tool-call",
|
|
241
276
|
id: event.id,
|
|
@@ -247,7 +282,7 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
247
282
|
// The provider-native item drives the per-tool renderers (apply_patch
|
|
248
283
|
// operation, computer_call action, web_search providerData, …).
|
|
249
284
|
raw: payload.raw,
|
|
250
|
-
status:
|
|
285
|
+
status: providerNativeToolStatus(payload.raw),
|
|
251
286
|
occurredAt: event.occurredAt,
|
|
252
287
|
});
|
|
253
288
|
break;
|
|
@@ -383,7 +418,12 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
383
418
|
if (previous?.status === status) {
|
|
384
419
|
break;
|
|
385
420
|
}
|
|
386
|
-
items.push({
|
|
421
|
+
items.push({
|
|
422
|
+
kind: "session-status",
|
|
423
|
+
id: event.id,
|
|
424
|
+
status,
|
|
425
|
+
occurredAt: event.occurredAt,
|
|
426
|
+
});
|
|
387
427
|
break;
|
|
388
428
|
}
|
|
389
429
|
|
|
@@ -399,24 +439,36 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
399
439
|
break;
|
|
400
440
|
}
|
|
401
441
|
|
|
442
|
+
case "session.context.compaction.requested":
|
|
443
|
+
case "session.context.compaction.started": {
|
|
444
|
+
closeStreamingTail();
|
|
445
|
+
settleOrPushContextCompaction(items, {
|
|
446
|
+
id: event.id,
|
|
447
|
+
turnId,
|
|
448
|
+
phase: "started",
|
|
449
|
+
trigger: compactionTrigger(payload),
|
|
450
|
+
estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
|
|
451
|
+
estimatedTokensAfter: null,
|
|
452
|
+
skipReason: null,
|
|
453
|
+
implementation:
|
|
454
|
+
typeof payload.implementation === "string" ? payload.implementation : null,
|
|
455
|
+
occurredAt: event.occurredAt,
|
|
456
|
+
});
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
|
|
402
460
|
case "session.context.compacted": {
|
|
403
461
|
closeStreamingTail();
|
|
404
|
-
|
|
405
|
-
typeof payload.estimatedTokensBefore === "number"
|
|
406
|
-
? Math.round(payload.estimatedTokensBefore).toLocaleString("en-US")
|
|
407
|
-
: null;
|
|
408
|
-
const after =
|
|
409
|
-
typeof payload.estimatedTokensAfter === "number"
|
|
410
|
-
? Math.round(payload.estimatedTokensAfter).toLocaleString("en-US")
|
|
411
|
-
: null;
|
|
412
|
-
items.push({
|
|
413
|
-
kind: "notice",
|
|
462
|
+
settleOrPushContextCompaction(items, {
|
|
414
463
|
id: event.id,
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
464
|
+
turnId,
|
|
465
|
+
phase: "compacted",
|
|
466
|
+
trigger: compactionTrigger(payload),
|
|
467
|
+
estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
|
|
468
|
+
estimatedTokensAfter: numberOrNull(payload.estimatedTokensAfter),
|
|
469
|
+
skipReason: null,
|
|
470
|
+
implementation:
|
|
471
|
+
typeof payload.implementation === "string" ? payload.implementation : null,
|
|
420
472
|
occurredAt: event.occurredAt,
|
|
421
473
|
});
|
|
422
474
|
break;
|
|
@@ -424,21 +476,16 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
424
476
|
|
|
425
477
|
case "session.context.compaction.skipped": {
|
|
426
478
|
closeStreamingTail();
|
|
427
|
-
|
|
428
|
-
items.push({
|
|
429
|
-
kind: "notice",
|
|
479
|
+
settleOrPushContextCompaction(items, {
|
|
430
480
|
id: event.id,
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
: reason === "summarization_failed"
|
|
440
|
-
? "Context compaction failed without replacing the active conversation history. Request it again to retry."
|
|
441
|
-
: "Context compaction was not needed.",
|
|
481
|
+
turnId,
|
|
482
|
+
phase: "skipped",
|
|
483
|
+
trigger: compactionTrigger(payload),
|
|
484
|
+
estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
|
|
485
|
+
estimatedTokensAfter: null,
|
|
486
|
+
skipReason: typeof payload.reason === "string" ? payload.reason : null,
|
|
487
|
+
implementation:
|
|
488
|
+
typeof payload.implementation === "string" ? payload.implementation : null,
|
|
442
489
|
occurredAt: event.occurredAt,
|
|
443
490
|
});
|
|
444
491
|
break;
|
|
@@ -485,8 +532,8 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
485
532
|
case "turn.completed": {
|
|
486
533
|
// A standalone manual compaction uses the turn ledger for fencing and
|
|
487
534
|
// recovery, but it is maintenance rather than a conversational turn.
|
|
488
|
-
// The dedicated
|
|
489
|
-
//
|
|
535
|
+
// The dedicated context-compaction landmark is the complete UI truth;
|
|
536
|
+
// adding a generic turn chip would falsely make it look like an
|
|
490
537
|
// extra agent response.
|
|
491
538
|
if (payload.maintenance === "context_compaction") {
|
|
492
539
|
finalizeOpen(turnId);
|
|
@@ -607,9 +654,74 @@ export function buildTimeline(events: SessionEvent[]): TimelineItem[] {
|
|
|
607
654
|
}
|
|
608
655
|
}
|
|
609
656
|
|
|
657
|
+
for (const item of items) {
|
|
658
|
+
if (item.kind === "agent-message") {
|
|
659
|
+
item.text = stripOpaqueCitationTokens(item.text);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
610
662
|
return items;
|
|
611
663
|
}
|
|
612
664
|
|
|
665
|
+
function providerNativeToolStatus(rawValue: unknown): ToolCallItem["status"] {
|
|
666
|
+
const raw = asRecord(rawValue);
|
|
667
|
+
if (raw.type !== "hosted_tool_call") {
|
|
668
|
+
return "running";
|
|
669
|
+
}
|
|
670
|
+
switch (raw.status) {
|
|
671
|
+
case "completed":
|
|
672
|
+
return "complete";
|
|
673
|
+
case "failed":
|
|
674
|
+
case "incomplete":
|
|
675
|
+
return "failed";
|
|
676
|
+
case "cancelled":
|
|
677
|
+
return "cancelled";
|
|
678
|
+
default:
|
|
679
|
+
return "running";
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Prefer newer status/fields, but keep earlier providerData.action when a
|
|
685
|
+
* progress-only Responses event arrives without the search query payload.
|
|
686
|
+
*/
|
|
687
|
+
function mergeToolCallRaw(existingValue: unknown, nextValue: unknown): unknown {
|
|
688
|
+
const existing = asRecord(existingValue);
|
|
689
|
+
const next = asRecord(nextValue);
|
|
690
|
+
if (Object.keys(next).length === 0) {
|
|
691
|
+
return existingValue;
|
|
692
|
+
}
|
|
693
|
+
const existingProvider = asRecord(existing.providerData);
|
|
694
|
+
const nextProvider = asRecord(next.providerData);
|
|
695
|
+
const providerData = {
|
|
696
|
+
...existingProvider,
|
|
697
|
+
...nextProvider,
|
|
698
|
+
};
|
|
699
|
+
if (
|
|
700
|
+
existingProvider.action != null &&
|
|
701
|
+
(nextProvider.action == null ||
|
|
702
|
+
(typeof nextProvider.action === "object" &&
|
|
703
|
+
nextProvider.action !== null &&
|
|
704
|
+
Object.keys(nextProvider.action as object).length === 0))
|
|
705
|
+
) {
|
|
706
|
+
providerData.action = existingProvider.action;
|
|
707
|
+
}
|
|
708
|
+
return {
|
|
709
|
+
...existing,
|
|
710
|
+
...next,
|
|
711
|
+
...(Object.keys(providerData).length > 0 ? { providerData } : {}),
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Codex subscription web search can return private citation handles without
|
|
717
|
+
* the URL annotation table that would make them resolvable. Keep the canonical
|
|
718
|
+
* model-history item untouched, but never expose those unusable handles in the
|
|
719
|
+
* human timeline. Ordinary markdown links and structured URL citations remain.
|
|
720
|
+
*/
|
|
721
|
+
export function stripOpaqueCitationTokens(text: string): string {
|
|
722
|
+
return text.replace(/\s*cite(?:[^]+)+/gu, "");
|
|
723
|
+
}
|
|
724
|
+
|
|
613
725
|
/** The turn-end payload shape, as `isCreditExhaustion` wants it. */
|
|
614
726
|
function isCreditExhaustionPayload(payload: Record<string, unknown>): boolean {
|
|
615
727
|
return isCreditExhaustion({
|
|
@@ -689,7 +801,11 @@ export function groupTimeline(items: TimelineItem[]): TimelineGroup[] {
|
|
|
689
801
|
if (open?.kind === "activity" && open.outcome === undefined) {
|
|
690
802
|
open.items.push(item);
|
|
691
803
|
} else {
|
|
692
|
-
groups.push({
|
|
804
|
+
groups.push({
|
|
805
|
+
kind: "activity",
|
|
806
|
+
id: `activity-${item.id}`,
|
|
807
|
+
items: [item],
|
|
808
|
+
});
|
|
693
809
|
}
|
|
694
810
|
continue;
|
|
695
811
|
}
|
|
@@ -776,7 +892,12 @@ function prescanTurnAnchors(events: SessionEvent[]): TurnAnchorPrescan {
|
|
|
776
892
|
}
|
|
777
893
|
}
|
|
778
894
|
|
|
779
|
-
return {
|
|
895
|
+
return {
|
|
896
|
+
queuedTurnByTrigger,
|
|
897
|
+
startSeqByTrigger,
|
|
898
|
+
cancelledBeforeStartTriggers,
|
|
899
|
+
startedTurnIds,
|
|
900
|
+
};
|
|
780
901
|
}
|
|
781
902
|
|
|
782
903
|
function orderTimelineEvents(events: SessionEvent[], prescan: TurnAnchorPrescan): SessionEvent[] {
|
|
@@ -963,6 +1084,13 @@ function foldSettledTurn(groups: TimelineGroup[], turnEnd: TurnEndItem): void {
|
|
|
963
1084
|
}
|
|
964
1085
|
|
|
965
1086
|
const firstOccurredAt = groupStartedAt(body[0]) ?? turnEnd.occurredAt;
|
|
1087
|
+
const prior = startIndex > 0 ? groups[startIndex - 1] : undefined;
|
|
1088
|
+
const contextCompactionCount =
|
|
1089
|
+
prior?.kind === "item" &&
|
|
1090
|
+
prior.item.kind === "context-compaction" &&
|
|
1091
|
+
prior.item.phase === "compacted"
|
|
1092
|
+
? 1
|
|
1093
|
+
: 0;
|
|
966
1094
|
const turnGroup: TimelineGroup = {
|
|
967
1095
|
kind: "turn",
|
|
968
1096
|
id: `turn-${turnEnd.turnId ?? turnEnd.id}`,
|
|
@@ -970,6 +1098,7 @@ function foldSettledTurn(groups: TimelineGroup[], turnEnd: TurnEndItem): void {
|
|
|
970
1098
|
startedAt: firstOccurredAt,
|
|
971
1099
|
endedAt: turnEnd.occurredAt,
|
|
972
1100
|
groups: body,
|
|
1101
|
+
...(contextCompactionCount > 0 ? { contextCompactionCount } : {}),
|
|
973
1102
|
};
|
|
974
1103
|
if (turnEnd.failureText) {
|
|
975
1104
|
turnGroup.failureText = turnEnd.failureText;
|
|
@@ -987,6 +1116,7 @@ function isTurnBoundary(group: TimelineGroup | undefined): boolean {
|
|
|
987
1116
|
group?.kind === "turn" ||
|
|
988
1117
|
(group?.kind === "item" &&
|
|
989
1118
|
(group.item.kind === "user-message" ||
|
|
1119
|
+
group.item.kind === "context-compaction" ||
|
|
990
1120
|
(group.item.kind === "notice" && group.item.tone === "input")))
|
|
991
1121
|
);
|
|
992
1122
|
}
|
|
@@ -1053,6 +1183,61 @@ function stringValue(value: unknown): string {
|
|
|
1053
1183
|
return typeof value === "string" ? value : "";
|
|
1054
1184
|
}
|
|
1055
1185
|
|
|
1186
|
+
function numberOrNull(value: unknown): number | null {
|
|
1187
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
function compactionTrigger(payload: Record<string, unknown>): ContextCompactionItem["trigger"] {
|
|
1191
|
+
const trigger = payload.trigger;
|
|
1192
|
+
return trigger === "auto" ||
|
|
1193
|
+
trigger === "operator" ||
|
|
1194
|
+
trigger === "proactive" ||
|
|
1195
|
+
trigger === "overflow"
|
|
1196
|
+
? trigger
|
|
1197
|
+
: null;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Keep one landmark per turn: a later started/compacted/skipped settles the
|
|
1202
|
+
* open started row instead of stacking notices.
|
|
1203
|
+
*/
|
|
1204
|
+
function settleOrPushContextCompaction(
|
|
1205
|
+
items: TimelineItem[],
|
|
1206
|
+
next: Omit<ContextCompactionItem, "kind">,
|
|
1207
|
+
): void {
|
|
1208
|
+
const openIndex = findOpenContextCompactionIndex(items, next.turnId);
|
|
1209
|
+
if (openIndex >= 0) {
|
|
1210
|
+
const open = items[openIndex];
|
|
1211
|
+
if (open?.kind === "context-compaction") {
|
|
1212
|
+
items[openIndex] = {
|
|
1213
|
+
...open,
|
|
1214
|
+
...next,
|
|
1215
|
+
// Prefer the settled event id so keys stay stable with the finish row.
|
|
1216
|
+
id: next.phase === "started" ? open.id : next.id,
|
|
1217
|
+
trigger: next.trigger ?? open.trigger,
|
|
1218
|
+
estimatedTokensBefore: next.estimatedTokensBefore ?? open.estimatedTokensBefore,
|
|
1219
|
+
implementation: next.implementation ?? open.implementation,
|
|
1220
|
+
};
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
items.push({ kind: "context-compaction", ...next });
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function findOpenContextCompactionIndex(items: TimelineItem[], turnId: string | null): number {
|
|
1228
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
1229
|
+
const item = items[index];
|
|
1230
|
+
if (item?.kind !== "context-compaction" || item.phase !== "started") {
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
if (turnId && item.turnId && item.turnId !== turnId) {
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
return index;
|
|
1237
|
+
}
|
|
1238
|
+
return -1;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1056
1241
|
function machineInputMembers(value: unknown): MachineInputBatchItem["members"] {
|
|
1057
1242
|
const kinds = new Set<MachineInputBatchItem["members"][number]["kind"]>([
|
|
1058
1243
|
"scheduled_occurrence",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
/* ----------------------------------------------------------------------------
|
|
4
|
+
Seen activity ids
|
|
5
|
+
|
|
6
|
+
ActivityRails remount across fold wraps / settle key flips. A per-rail
|
|
7
|
+
previousIds set resets on remount, so either every row re-fades (flash) or
|
|
8
|
+
the first live tool never animates (pop). This map lives on MessageTimeline
|
|
9
|
+
and records every activity id that has already painted — live appends of
|
|
10
|
+
unknown ids earn row-enter; remounts of known ids stay quiet.
|
|
11
|
+
-------------------------------------------------------------------------- */
|
|
12
|
+
|
|
13
|
+
const SeenActivityIdsContext = createContext<Set<string> | null>(null);
|
|
14
|
+
|
|
15
|
+
export const SeenActivityIdsProvider = SeenActivityIdsContext.Provider;
|
|
16
|
+
|
|
17
|
+
export function useSeenActivityIds(): Set<string> | null {
|
|
18
|
+
return useContext(SeenActivityIdsContext);
|
|
19
|
+
}
|
package/src/timeline/shared.tsx
CHANGED
|
@@ -164,7 +164,7 @@ export function ActivityDisclosure({
|
|
|
164
164
|
const inner = (
|
|
165
165
|
<>
|
|
166
166
|
{hasBody ? (
|
|
167
|
-
<ChevronRightIcon className="size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-
|
|
167
|
+
<ChevronRightIcon className="size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-[var(--og-duration-disclose)] ease-og-in-out group-data-[state=open]/disclosure:rotate-90" />
|
|
168
168
|
) : (
|
|
169
169
|
<span className="size-3.5 shrink-0" />
|
|
170
170
|
)}
|
|
@@ -698,15 +698,84 @@ function ComputerCallRenderer({ item }: ToolRendererProps) {
|
|
|
698
698
|
|
|
699
699
|
type WebSearchResult = { title: string; domain: string; snippet: string };
|
|
700
700
|
|
|
701
|
+
/** Pull a search string from tool-call arguments when providerData.action is sparse. */
|
|
702
|
+
function webSearchQueryFromArguments(args: unknown): string | null {
|
|
703
|
+
if (typeof args === "string") {
|
|
704
|
+
const trimmed = args.trim();
|
|
705
|
+
if (!trimmed) {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
try {
|
|
709
|
+
return webSearchQueryFromArguments(JSON.parse(trimmed));
|
|
710
|
+
} catch {
|
|
711
|
+
return trimmed;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (!args || typeof args !== "object") {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
const record = args as Record<string, unknown>;
|
|
718
|
+
if (typeof record.query === "string" && record.query.trim().length > 0) {
|
|
719
|
+
return record.query;
|
|
720
|
+
}
|
|
721
|
+
if (Array.isArray(record.queries)) {
|
|
722
|
+
const first = record.queries.find(
|
|
723
|
+
(value): value is string => typeof value === "string" && value.trim().length > 0,
|
|
724
|
+
);
|
|
725
|
+
if (first) {
|
|
726
|
+
return first;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
|
|
701
732
|
function WebSearchRenderer({ item }: ToolRendererProps) {
|
|
702
733
|
const raw = (item.raw ?? {}) as {
|
|
703
|
-
providerData?: {
|
|
734
|
+
providerData?: {
|
|
735
|
+
action?: {
|
|
736
|
+
type?: string;
|
|
737
|
+
query?: string;
|
|
738
|
+
queries?: string[];
|
|
739
|
+
url?: string;
|
|
740
|
+
pattern?: string;
|
|
741
|
+
};
|
|
742
|
+
};
|
|
704
743
|
};
|
|
705
744
|
const action = raw.providerData?.action ?? {};
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
|
|
745
|
+
const actionType = action.type ?? "search";
|
|
746
|
+
// Responses API deprecated singular `query` in favor of `queries[]`.
|
|
747
|
+
// Codex/current OpenAI often only populate the array.
|
|
748
|
+
const queries = (action.queries ?? []).filter(
|
|
749
|
+
(value): value is string => typeof value === "string" && value.trim().length > 0,
|
|
750
|
+
);
|
|
751
|
+
const searchQuery =
|
|
752
|
+
(typeof action.query === "string" && action.query.trim().length > 0 ? action.query : null) ??
|
|
753
|
+
queries[0] ??
|
|
754
|
+
webSearchQueryFromArguments(item.arguments);
|
|
709
755
|
const running = item.status === "running";
|
|
756
|
+
const query =
|
|
757
|
+
actionType === "open_page"
|
|
758
|
+
? (action.url ?? "(page unavailable)")
|
|
759
|
+
: actionType === "find_in_page"
|
|
760
|
+
? action.pattern && action.url
|
|
761
|
+
? `"${action.pattern}" in ${action.url}`
|
|
762
|
+
: (action.pattern ?? action.url ?? "(page unavailable)")
|
|
763
|
+
: // Codex often emits the live card before action.query/queries land;
|
|
764
|
+
// don't flash the scary unavailable copy while still searching.
|
|
765
|
+
(searchQuery ?? (running ? "…" : "(query unavailable)"));
|
|
766
|
+
const variants = queries.length > 1 ? ` +${queries.length - 1} variants` : "";
|
|
767
|
+
const runningTitle =
|
|
768
|
+
actionType === "open_page"
|
|
769
|
+
? "Opening web page"
|
|
770
|
+
: actionType === "find_in_page"
|
|
771
|
+
? "Searching within page"
|
|
772
|
+
: "Searching the web";
|
|
773
|
+
const completedTitle =
|
|
774
|
+
actionType === "open_page"
|
|
775
|
+
? "Opened web page"
|
|
776
|
+
: actionType === "find_in_page"
|
|
777
|
+
? "Searched within page"
|
|
778
|
+
: "Searched the web";
|
|
710
779
|
// web_search may surface a results array on the output when the host enriches it.
|
|
711
780
|
// Filter out null/undefined/non-object entries before casting: host-provided
|
|
712
781
|
// data is untrusted and a null element would throw on result.title access.
|
|
@@ -727,7 +796,7 @@ function WebSearchRenderer({ item }: ToolRendererProps) {
|
|
|
727
796
|
<ActivityDisclosure
|
|
728
797
|
icon={<SearchIcon className={ICON_SIZE} />}
|
|
729
798
|
iconTone="running"
|
|
730
|
-
title=
|
|
799
|
+
title={runningTitle}
|
|
731
800
|
running
|
|
732
801
|
preview={<RunningPreview>{`${query}${variants}`}</RunningPreview>}
|
|
733
802
|
>
|
|
@@ -740,7 +809,7 @@ function WebSearchRenderer({ item }: ToolRendererProps) {
|
|
|
740
809
|
<ActivityDisclosure
|
|
741
810
|
icon={<SearchIcon className={ICON_SIZE} />}
|
|
742
811
|
iconTone="muted"
|
|
743
|
-
title=
|
|
812
|
+
title={completedTitle}
|
|
744
813
|
preview={`${query}${variants}`}
|
|
745
814
|
failed={item.status === "failed"}
|
|
746
815
|
cancelled={item.status === "cancelled"}
|