@opengeni/react 1.3.0 → 1.4.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.
Files changed (69) hide show
  1. package/README.md +21 -1
  2. package/dist/artifacts.js +2 -2
  3. package/dist/artifacts.js.map +1 -1
  4. package/dist/{chunk-ERGYJIBB.js → chunk-AWZLIMKX.js} +2 -2
  5. package/dist/{chunk-ERGYJIBB.js.map → chunk-AWZLIMKX.js.map} +1 -1
  6. package/dist/{chunk-FZCP527Y.js → chunk-CJUO7J5Z.js} +2 -2
  7. package/dist/{chunk-742CZ3L3.js → chunk-H5X55XH7.js} +16 -200
  8. package/dist/chunk-H5X55XH7.js.map +1 -0
  9. package/dist/{chunk-PGSX7UCP.js → chunk-LJ2UTJJE.js} +1369 -785
  10. package/dist/chunk-LJ2UTJJE.js.map +1 -0
  11. package/dist/{chunk-CY7WK5FD.js → chunk-LN6TCXD3.js} +22 -1
  12. package/dist/chunk-LN6TCXD3.js.map +1 -0
  13. package/dist/{chunk-TMYGL6X5.js → chunk-MBMPHOMA.js} +71 -6
  14. package/dist/chunk-MBMPHOMA.js.map +1 -0
  15. package/dist/{chunk-RC6BZ44Q.js → chunk-OA6HFRQP.js} +2 -2
  16. package/dist/{chunk-WWEUO2PL.js → chunk-WZMYFJD3.js} +190 -11
  17. package/dist/chunk-WZMYFJD3.js.map +1 -0
  18. package/dist/components/composer-transcription-control.d.ts +3 -0
  19. package/dist/components/open-geni-chat.d.ts +6 -2
  20. package/dist/components/session-conversation.d.ts +25 -19
  21. package/dist/components/session-list.d.ts +4 -1
  22. package/dist/components/tool-action-review.d.ts +29 -2
  23. package/dist/components/tool-review-history.d.ts +8 -4
  24. package/dist/composer.js +1 -1
  25. package/dist/connect.js +1 -1
  26. package/dist/hooks/use-client-config-flags.d.ts +37 -0
  27. package/dist/index.d.ts +3 -3
  28. package/dist/index.js +21 -11
  29. package/dist/index.js.map +1 -1
  30. package/dist/{latest-question-YTOBHCWR.js → latest-question-GPYM2JNU.js} +3 -3
  31. package/dist/realtime/realtime-control.d.ts +2 -0
  32. package/dist/realtime.js +25 -4
  33. package/dist/realtime.js.map +1 -1
  34. package/dist/session-capability-policy.d.ts +20 -1
  35. package/dist/session-ui.js +6 -6
  36. package/dist/session.js +6 -6
  37. package/dist/timeline/index.d.ts +2 -0
  38. package/dist/timeline/retained-loaders.d.ts +27 -0
  39. package/package.json +3 -3
  40. package/src/components/approval-surface.tsx +190 -79
  41. package/src/components/artifacts/session-artifact-viewer.tsx +4 -2
  42. package/src/components/composer-transcription-control.tsx +14 -0
  43. package/src/components/composer.tsx +1 -0
  44. package/src/components/open-geni-chat.tsx +53 -13
  45. package/src/components/session-conversation.tsx +229 -63
  46. package/src/components/session-list.tsx +9 -2
  47. package/src/components/tool-action-review.tsx +502 -239
  48. package/src/components/tool-review-history.tsx +18 -43
  49. package/src/hooks/use-client-config-flags.ts +102 -0
  50. package/src/hooks/use-session-events.ts +19 -16
  51. package/src/hooks/use-transcription.ts +6 -0
  52. package/src/hooks/use-voice-input.ts +6 -0
  53. package/src/index.ts +9 -0
  54. package/src/realtime/realtime-control.tsx +28 -1
  55. package/src/session-capability-policy.ts +119 -6
  56. package/src/timeline/index.ts +10 -0
  57. package/src/timeline/retained-loaders.ts +86 -0
  58. package/src/timeline/tool-display-name.ts +5 -1
  59. package/src/timeline/tool-renderers.tsx +143 -10
  60. package/styles/compiled.css +65 -21
  61. package/styles/tokens.css +1 -1
  62. package/dist/chunk-742CZ3L3.js.map +0 -1
  63. package/dist/chunk-CY7WK5FD.js.map +0 -1
  64. package/dist/chunk-PGSX7UCP.js.map +0 -1
  65. package/dist/chunk-TMYGL6X5.js.map +0 -1
  66. package/dist/chunk-WWEUO2PL.js.map +0 -1
  67. /package/dist/{chunk-FZCP527Y.js.map → chunk-CJUO7J5Z.js.map} +0 -0
  68. /package/dist/{chunk-RC6BZ44Q.js.map → chunk-OA6HFRQP.js.map} +0 -0
  69. /package/dist/{latest-question-YTOBHCWR.js.map → latest-question-GPYM2JNU.js.map} +0 -0
@@ -1,4 +1,6 @@
1
- import { useHasToolReview, ToolReviewHistoryReceipt } from "../components/tool-review-history";
1
+ import { useHasToolReview, useRecordedToolReview } from "../components/tool-review-history";
2
+ import { ToolActionReviewCard } from "../components/tool-action-review";
3
+ import type { ToolReviewStatus } from "@opengeni/sdk";
2
4
  import { KnowledgeReceiptRow } from "./knowledge-receipt";
3
5
  import { defaultUrlTransform } from "react-markdown";
4
6
  import { isRetainedImageContentType, useRetainedImageObjectUrl } from "./retained-image";
@@ -588,7 +590,10 @@ function ComputerCallRenderer({ item, loadRetainedScreenshot }: ToolRendererProp
588
590
  // every transport.
589
591
  const functionAction: ComputerAction | undefined =
590
592
  !raw.action && item.name.startsWith("computer_") && item.name !== "computer_call"
591
- ? { type: item.name.slice("computer_".length), ...asComputerArgs(item.arguments) }
593
+ ? {
594
+ type: item.name.slice("computer_".length),
595
+ ...asComputerArgs(item.arguments),
596
+ }
592
597
  : undefined;
593
598
  const action = raw.action ?? functionAction;
594
599
  const actions = raw.actions ?? (action ? [action] : []);
@@ -2335,10 +2340,74 @@ function RunOnRenderer({ item }: ToolRendererProps) {
2335
2340
  */
2336
2341
  function GenericRenderer({ item }: ToolRendererProps) {
2337
2342
  const reviewed = useHasToolReview(item.callId);
2338
- if (reviewed && item.callId) return <ToolReviewHistoryReceipt approvalId={item.callId} />;
2343
+ if (reviewed && item.callId) return <ReviewedGenericRenderer item={item} />;
2339
2344
  return <UnreviewedGenericRenderer item={item} />;
2340
2345
  }
2341
2346
 
2347
+ /** Settled review states earn one quiet gutter word; success and waiting stay chip-free. */
2348
+ const REVIEW_CHIP: Partial<Record<ToolReviewStatus, DisclosureChip>> = {
2349
+ rejected: { tone: "interrupted", text: "declined" },
2350
+ cancelled: { tone: "interrupted", text: "not run" },
2351
+ expired: { tone: "interrupted", text: "expired" },
2352
+ stale: { tone: "interrupted", text: "not run" },
2353
+ revoked: { tone: "interrupted", text: "not run" },
2354
+ blocked: { tone: "interrupted", text: "blocked" },
2355
+ unknown: { tone: "bad", text: "outcome unknown" },
2356
+ partial: { tone: "bad", text: "partly done" },
2357
+ failed: { tone: "bad", text: "failed" },
2358
+ };
2359
+
2360
+ /**
2361
+ * A call that went through approval keeps the ordinary row shape, titled with
2362
+ * what was approved. The expanded body is the saved review plus the result.
2363
+ */
2364
+ function ReviewedGenericRenderer({ item }: ToolRendererProps) {
2365
+ const { review, onViewDetails } = useRecordedToolReview(item.callId);
2366
+ if (!review) return <UnreviewedGenericRenderer item={item} />;
2367
+ const icon = <GenericToolIcon name={item.name} />;
2368
+ const waiting = review.status === "pending";
2369
+ const running =
2370
+ !waiting &&
2371
+ (review.status === "executing" || review.status === "approved") &&
2372
+ item.status === "running";
2373
+ const { text: outText, isError } = unwrapMcpOutput(item.output);
2374
+ const chip =
2375
+ REVIEW_CHIP[review.status] ??
2376
+ (isError && !running && !waiting ? ({ tone: "bad", text: "error" } as const) : undefined);
2377
+ return (
2378
+ <ActivityDisclosure
2379
+ icon={icon}
2380
+ iconTone={chip?.tone === "bad" ? "failed" : waiting ? "accent" : "muted"}
2381
+ title={review.title}
2382
+ running={running}
2383
+ chip={chip}
2384
+ preview={
2385
+ waiting ? (
2386
+ "Waiting for your approval"
2387
+ ) : running ? (
2388
+ <RunningPreview>Running…</RunningPreview>
2389
+ ) : (
2390
+ (review.accountLabel ?? undefined)
2391
+ )
2392
+ }
2393
+ >
2394
+ <div className="py-1" data-approval-id={item.callId} data-review-origin="history">
2395
+ <ToolActionReviewCard
2396
+ bare
2397
+ review={{ ...review, availableActions: [] }}
2398
+ onViewDetails={onViewDetails}
2399
+ />
2400
+ </div>
2401
+ {outText ? <PayloadBlock label="Result" value={outText} failed={isError} /> : null}
2402
+ </ActivityDisclosure>
2403
+ );
2404
+ }
2405
+
2406
+ /** The runtime's exact refusal for a tool whose effective permission is Block. */
2407
+ const BLOCKED_OUTPUT = /Connector action was not executed: blocked\b/;
2408
+ /** The runtime's refusal to guess whether an approved action ran. */
2409
+ const UNCERTAIN_OUTPUT = /Connector action outcome is uncertain\b/;
2410
+
2342
2411
  function UnreviewedGenericRenderer({ item }: ToolRendererProps) {
2343
2412
  const running = item.status === "running";
2344
2413
  const args = parseToolArgs(item.arguments);
@@ -2363,6 +2432,42 @@ function UnreviewedGenericRenderer({ item }: ToolRendererProps) {
2363
2432
  }
2364
2433
 
2365
2434
  const { text: outText, isError } = unwrapMcpOutput(item.output);
2435
+ // A permission Block is a decision, not a tool failure: say so plainly instead
2436
+ // of the generic "error occurred, please try again" wrapper.
2437
+ if (isError && BLOCKED_OUTPUT.test(outText)) {
2438
+ return (
2439
+ <ActivityDisclosure
2440
+ icon={icon}
2441
+ iconTone="muted"
2442
+ title={display}
2443
+ chip={{ tone: "interrupted", text: "blocked" }}
2444
+ preview="Blocked by your permission settings"
2445
+ >
2446
+ <p className="m-0 py-1 text-og-sm text-og-fg-muted">
2447
+ Your permission settings block this action, so it did not run. You can change this in the
2448
+ integration's tool permissions.
2449
+ </p>
2450
+ <PayloadBlock label="Arguments" value={args} />
2451
+ </ActivityDisclosure>
2452
+ );
2453
+ }
2454
+ // An interrupted approved action may have run. Never invite a blind retry.
2455
+ if (isError && UNCERTAIN_OUTPUT.test(outText)) {
2456
+ return (
2457
+ <ActivityDisclosure
2458
+ icon={icon}
2459
+ iconTone="failed"
2460
+ title={display}
2461
+ chip={{ tone: "bad", text: "outcome unknown" }}
2462
+ preview="It may have run"
2463
+ >
2464
+ <p className="m-0 py-1 text-og-sm text-og-fg-muted">
2465
+ This action may have run. Check the result in the connected app before trying again.
2466
+ </p>
2467
+ <PayloadBlock label="Arguments" value={args} />
2468
+ </ActivityDisclosure>
2469
+ );
2470
+ }
2366
2471
  // Cancelled is NOT an error — a user-cancelled tool should not surface the red
2367
2472
  // error chip even if the output payload carries an isError flag (the error may be
2368
2473
  // a consequence of the cancellation, not the tool's own failure).
@@ -2543,25 +2648,41 @@ const BASE_ENTRIES: ToolRegistryEntry[] = [
2543
2648
  { match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
2544
2649
  { match: "name", name: "apply_patch", render: ApplyPatchRenderer },
2545
2650
  { match: "name", name: "computer_call", render: ComputerCallRenderer },
2546
- { match: "name", name: "browser_screenshot", render: BrowserScreenshotRenderer },
2651
+ {
2652
+ match: "name",
2653
+ name: "browser_screenshot",
2654
+ render: BrowserScreenshotRenderer,
2655
+ },
2547
2656
  { match: "name", name: "browser_observe", render: BrowserScreenshotRenderer },
2548
2657
  { match: "name", name: "browser_act", render: BrowserScreenshotRenderer },
2549
2658
  // Function-mode computer tools (codex / chat-wire transports).
2550
2659
  { match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
2551
2660
  { match: "name", name: "computer_click", render: ComputerCallRenderer },
2552
- { match: "name", name: "computer_double_click", render: ComputerCallRenderer },
2661
+ {
2662
+ match: "name",
2663
+ name: "computer_double_click",
2664
+ render: ComputerCallRenderer,
2665
+ },
2553
2666
  { match: "name", name: "computer_move", render: ComputerCallRenderer },
2554
2667
  { match: "name", name: "computer_scroll", render: ComputerCallRenderer },
2555
2668
  { match: "name", name: "computer_type", render: ComputerCallRenderer },
2556
2669
  { match: "name", name: "computer_keypress", render: ComputerCallRenderer },
2557
2670
  { match: "name", name: "computer_drag", render: ComputerCallRenderer },
2558
2671
  { match: "name", name: "web_search_call", render: WebSearchRenderer },
2559
- { match: "name", name: "image_generation_call", render: GeneratedImageRenderer },
2672
+ {
2673
+ match: "name",
2674
+ name: "image_generation_call",
2675
+ render: GeneratedImageRenderer,
2676
+ },
2560
2677
  { match: "name", name: "generate_image", render: GeneratedImageRenderer },
2561
2678
  { match: "name", name: "generate_video", render: GeneratedVideoRenderer },
2562
2679
  { match: "name", name: "tool_search", render: ToolSearchRenderer },
2563
2680
  { match: "name", name: "view_image", render: ViewImageRenderer },
2564
- { match: "name", name: "sandbox_file_publish", render: SandboxFilePublishRenderer },
2681
+ {
2682
+ match: "name",
2683
+ name: "sandbox_file_publish",
2684
+ render: SandboxFilePublishRenderer,
2685
+ },
2565
2686
  {
2566
2687
  match: "name",
2567
2688
  name: "artifacts_create",
@@ -2586,13 +2707,25 @@ const BASE_ENTRIES: ToolRegistryEntry[] = [
2586
2707
  render: SiteArtifactRenderer,
2587
2708
  matchPrefixedLeaf: false,
2588
2709
  },
2589
- { match: "name", name: "environment_set_variable", render: SecretSetRenderer },
2590
- { match: "name", name: "variable_set_set_variable", render: SecretSetRenderer },
2710
+ {
2711
+ match: "name",
2712
+ name: "environment_set_variable",
2713
+ render: SecretSetRenderer,
2714
+ },
2715
+ {
2716
+ match: "name",
2717
+ name: "variable_set_set_variable",
2718
+ render: SecretSetRenderer,
2719
+ },
2591
2720
  { match: "name", name: "search_documents", render: DocsSearchRenderer },
2592
2721
  { match: "name", name: "knowledge_search", render: DocsSearchRenderer },
2593
2722
  { match: "name", name: "memory_propose", render: MemoryProposeRenderer },
2594
2723
  { match: "name", name: "set_session_title", render: SetSessionTitleRenderer },
2595
- { match: "name", name: "set_other_session_title", render: SetSessionTitleRenderer },
2724
+ {
2725
+ match: "name",
2726
+ name: "set_other_session_title",
2727
+ render: SetSessionTitleRenderer,
2728
+ },
2596
2729
  ];
2597
2730
 
2598
2731
  /** The built-in tool renderer registry: every first-party tool plus a fallback. */
@@ -698,7 +698,7 @@
698
698
  --_og-color-primary-hover: var(--og-color-primary-hover, var(--og-color-primary));
699
699
  --_og-color-diff-add-bg: var(--og-color-diff-add-bg, var(--og-color-status-idle));
700
700
  --_og-color-diff-del-bg: var(--og-color-diff-del-bg, var(--og-color-status-failed));
701
- --_og-shadow-glow: var(--og-shadow-glow, 0 0 24px var(--og-color-accent));
701
+ --_og-shadow-glow: var(--og-shadow-glow, 0 0 24px color-mix(in oklch, var(--og-color-accent) 10%, transparent));
702
702
  --_og-session-chrome-surface: var(--og-session-chrome-surface, var(--og-color-surface-2));
703
703
  --_og-session-chrome-surface-open: var(--og-session-chrome-surface-open, var(--og-color-surface-2));
704
704
  --_og-session-chrome-border: var(--og-session-chrome-border, var(--og-color-border));
@@ -1786,8 +1786,8 @@
1786
1786
  :where(.og-root).mt-5,:where(.og-root) .mt-5 {
1787
1787
  margin-top: calc(var(--spacing) * 5);
1788
1788
  }
1789
- :where(.og-root).mt-6,:where(.og-root) .mt-6 {
1790
- margin-top: calc(var(--spacing) * 6);
1789
+ :where(.og-root).mt-\[0\.55em\],:where(.og-root) .mt-\[0\.55em\] {
1790
+ margin-top: 0.55em;
1791
1791
  }
1792
1792
  :where(.og-root).mt-auto,:where(.og-root) .mt-auto {
1793
1793
  margin-top: auto;
@@ -1831,8 +1831,8 @@
1831
1831
  :where(.og-root).mb-3,:where(.og-root) .mb-3 {
1832
1832
  margin-bottom: calc(var(--spacing) * 3);
1833
1833
  }
1834
- :where(.og-root).mb-5,:where(.og-root) .mb-5 {
1835
- margin-bottom: calc(var(--spacing) * 5);
1834
+ :where(.og-root).mb-4,:where(.og-root) .mb-4 {
1835
+ margin-bottom: calc(var(--spacing) * 4);
1836
1836
  }
1837
1837
  :where(.og-root).ml-0\.5,:where(.og-root) .ml-0\.5 {
1838
1838
  margin-left: calc(var(--spacing) * 0.5);
@@ -1999,6 +1999,9 @@
1999
1999
  :where(.og-root).h-2\.5,:where(.og-root) .h-2\.5 {
2000
2000
  height: calc(var(--spacing) * 2.5);
2001
2001
  }
2002
+ :where(.og-root).h-3,:where(.og-root) .h-3 {
2003
+ height: calc(var(--spacing) * 3);
2004
+ }
2002
2005
  :where(.og-root).h-3\.5,:where(.og-root) .h-3\.5 {
2003
2006
  height: calc(var(--spacing) * 3.5);
2004
2007
  }
@@ -2176,9 +2179,15 @@
2176
2179
  :where(.og-root).w-1\.5,:where(.og-root) .w-1\.5 {
2177
2180
  width: calc(var(--spacing) * 1.5);
2178
2181
  }
2182
+ :where(.og-root).w-1\/2,:where(.og-root) .w-1\/2 {
2183
+ width: calc(1 / 2 * 100%);
2184
+ }
2179
2185
  :where(.og-root).w-3,:where(.og-root) .w-3 {
2180
2186
  width: calc(var(--spacing) * 3);
2181
2187
  }
2188
+ :where(.og-root).w-3\/4,:where(.og-root) .w-3\/4 {
2189
+ width: calc(3 / 4 * 100%);
2190
+ }
2182
2191
  :where(.og-root).w-5,:where(.og-root) .w-5 {
2183
2192
  width: calc(var(--spacing) * 5);
2184
2193
  }
@@ -2359,6 +2368,9 @@
2359
2368
  :where(.og-root).min-w-4,:where(.og-root) .min-w-4 {
2360
2369
  min-width: calc(var(--spacing) * 4);
2361
2370
  }
2371
+ :where(.og-root).min-w-8,:where(.og-root) .min-w-8 {
2372
+ min-width: calc(var(--spacing) * 8);
2373
+ }
2362
2374
  :where(.og-root).min-w-10,:where(.og-root) .min-w-10 {
2363
2375
  min-width: calc(var(--spacing) * 10);
2364
2376
  }
@@ -2410,6 +2422,9 @@
2410
2422
  :where(.og-root).grow,:where(.og-root) .grow {
2411
2423
  flex-grow: 1;
2412
2424
  }
2425
+ :where(.og-root).basis-48,:where(.og-root) .basis-48 {
2426
+ flex-basis: calc(var(--spacing) * 48);
2427
+ }
2413
2428
  :where(.og-root).border-collapse,:where(.og-root) .border-collapse {
2414
2429
  border-collapse: collapse;
2415
2430
  }
@@ -2557,9 +2572,6 @@
2557
2572
  :where(.og-root).grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1fr\)\],:where(.og-root) .grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1fr\)\] {
2558
2573
  grid-template-columns: minmax(0,1fr) minmax(0,1fr);
2559
2574
  }
2560
- :where(.og-root).grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,2fr\)\],:where(.og-root) .grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,2fr\)\] {
2561
- grid-template-columns: minmax(0,1fr) minmax(0,2fr);
2562
- }
2563
2575
  :where(.og-root).flex-col,:where(.og-root) .flex-col {
2564
2576
  flex-direction: column;
2565
2577
  }
@@ -2853,6 +2865,10 @@
2853
2865
  border-style: var(--tw-border-style);
2854
2866
  border-width: 2px;
2855
2867
  }
2868
+ :where(.og-root).border-y,:where(.og-root) .border-y {
2869
+ border-block-style: var(--tw-border-style);
2870
+ border-block-width: 1px;
2871
+ }
2856
2872
  :where(.og-root).border-t,:where(.og-root) .border-t {
2857
2873
  border-top-style: var(--tw-border-style);
2858
2874
  border-top-width: 1px;
@@ -3278,6 +3294,12 @@
3278
3294
  background-color: color-mix(in oklab, var(--og-color-fg) 5%, transparent);
3279
3295
  }
3280
3296
  }
3297
+ :where(.og-root).bg-og-fg\/8,:where(.og-root) .bg-og-fg\/8 {
3298
+ background-color: var(--og-color-fg);
3299
+ @supports (color: color-mix(in lab, red, red)) {
3300
+ background-color: color-mix(in oklab, var(--og-color-fg) 8%, transparent);
3301
+ }
3302
+ }
3281
3303
  :where(.og-root).bg-og-primary,:where(.og-root) .bg-og-primary {
3282
3304
  background-color: var(--og-color-primary);
3283
3305
  }
@@ -3739,15 +3761,15 @@
3739
3761
  :where(.og-root).pt-3,:where(.og-root) .pt-3 {
3740
3762
  padding-top: calc(var(--spacing) * 3);
3741
3763
  }
3742
- :where(.og-root).pt-4,:where(.og-root) .pt-4 {
3743
- padding-top: calc(var(--spacing) * 4);
3744
- }
3745
3764
  :where(.og-root).pt-16,:where(.og-root) .pt-16 {
3746
3765
  padding-top: calc(var(--spacing) * 16);
3747
3766
  }
3748
3767
  :where(.og-root).pr-1,:where(.og-root) .pr-1 {
3749
3768
  padding-right: calc(var(--spacing) * 1);
3750
3769
  }
3770
+ :where(.og-root).pr-2,:where(.og-root) .pr-2 {
3771
+ padding-right: calc(var(--spacing) * 2);
3772
+ }
3751
3773
  :where(.og-root).pr-2\.5,:where(.og-root) .pr-2\.5 {
3752
3774
  padding-right: calc(var(--spacing) * 2.5);
3753
3775
  }
@@ -5053,16 +5075,6 @@
5053
5075
  }
5054
5076
  }
5055
5077
  }
5056
- :where(.og-root).hover\:bg-og-fg\/5,:where(.og-root) .hover\:bg-og-fg\/5 {
5057
- &:hover {
5058
- @media (hover: hover) {
5059
- background-color: var(--og-color-fg);
5060
- @supports (color: color-mix(in lab, red, red)) {
5061
- background-color: color-mix(in oklab, var(--og-color-fg) 5%, transparent);
5062
- }
5063
- }
5064
- }
5065
- }
5066
5078
  :where(.og-root).hover\:bg-og-hover,:where(.og-root) .hover\:bg-og-hover {
5067
5079
  &:hover {
5068
5080
  @media (hover: hover) {
@@ -6012,6 +6024,11 @@
6012
6024
  grid-template-columns: minmax(0,1.2fr) minmax(0,1fr) 11rem;
6013
6025
  }
6014
6026
  }
6027
+ :where(.og-root).sm\:grid-cols-\[minmax\(0\,9rem\)_minmax\(0\,1fr\)\],:where(.og-root) .sm\:grid-cols-\[minmax\(0\,9rem\)_minmax\(0\,1fr\)\] {
6028
+ @media (width >= 40rem) {
6029
+ grid-template-columns: minmax(0,9rem) minmax(0,1fr);
6030
+ }
6031
+ }
6015
6032
  :where(.og-root).sm\:flex-row,:where(.og-root) .sm\:flex-row {
6016
6033
  @media (width >= 40rem) {
6017
6034
  flex-direction: row;
@@ -6089,6 +6106,11 @@
6089
6106
  padding-block: calc(var(--spacing) * 2);
6090
6107
  }
6091
6108
  }
6109
+ :where(.og-root).sm\:pt-px,:where(.og-root) .sm\:pt-px {
6110
+ @media (width >= 40rem) {
6111
+ padding-top: 1px;
6112
+ }
6113
+ }
6092
6114
  :where(.og-root).sm\:pb-2\.5,:where(.og-root) .sm\:pb-2\.5 {
6093
6115
  @media (width >= 40rem) {
6094
6116
  padding-bottom: calc(var(--spacing) * 2.5);
@@ -6099,6 +6121,23 @@
6099
6121
  padding-left: calc(var(--spacing) * 4);
6100
6122
  }
6101
6123
  }
6124
+ :where(.og-root).sm\:pl-\[3\.75rem\],:where(.og-root) .sm\:pl-\[3\.75rem\] {
6125
+ @media (width >= 40rem) {
6126
+ padding-left: 3.75rem;
6127
+ }
6128
+ }
6129
+ :where(.og-root).sm\:text-og-sm,:where(.og-root) .sm\:text-og-sm {
6130
+ @media (width >= 40rem) {
6131
+ font-size: var(--og-font-size-sm);
6132
+ line-height: var(--tw-leading, var(--og-line-height-sm));
6133
+ }
6134
+ }
6135
+ :where(.og-root).sm\:text-og-sm,:where(.og-root) .sm\:text-og-sm {
6136
+ @media (width >= 40rem) {
6137
+ --og-component-font-size: var(--og-font-size-sm);
6138
+ --og-component-line-height: var(--og-line-height-sm);
6139
+ }
6140
+ }
6102
6141
  :where(.og-root).md\:px-4,:where(.og-root) .md\:px-4 {
6103
6142
  @media (width >= 48rem) {
6104
6143
  padding-inline: calc(var(--spacing) * 4);
@@ -6545,6 +6584,11 @@
6545
6584
  min-height: calc(var(--spacing) * 11);
6546
6585
  }
6547
6586
  }
6587
+ :where(.og-root).\[\@media\(pointer\:coarse\)\]\:min-w-11,:where(.og-root) .\[\@media\(pointer\:coarse\)\]\:min-w-11 {
6588
+ @media (pointer:coarse) {
6589
+ min-width: calc(var(--spacing) * 11);
6590
+ }
6591
+ }
6548
6592
  :where(.og-root).\[tr\:last-child\>\&\]\:border-b-0,:where(.og-root) .\[tr\:last-child\>\&\]\:border-b-0 {
6549
6593
  tr:last-child>& {
6550
6594
  border-bottom-style: var(--tw-border-style);
package/styles/tokens.css CHANGED
@@ -165,7 +165,7 @@
165
165
  draws a crisp edge via `focus-within:border-og-accent/50`; the old
166
166
  `0 0 0 1px` ring sat flush against that border and read as a doubled
167
167
  hairline, so the glow is purely a faint diffuse grey halo. */
168
- --og-shadow-glow: 0 0 24px var(--og-color-accent);
168
+ --og-shadow-glow: 0 0 24px color-mix(in oklch, var(--og-color-accent) 10%, transparent);
169
169
 
170
170
  /* Session chrome — override on `.og-session-chrome` (or an ancestor) to rebrand.
171
171
  Defaults stay quiet: soft surface, short motion, no gold shout. */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/embedded-session-client.ts","../src/hooks/use-goal.ts","../src/hooks/use-session-mcp-approval-policy.ts","../src/hooks/use-session-lineage.ts"],"sourcesContent":["import type { ComposerDraft } from \"@opengeni/sdk\";\nimport type { EmbeddedSessionClientLike } from \"./client\";\n\nexport type ComposerDraftMapContext = {\n operation: \"read\" | \"save\" | \"submit\";\n workspaceId: string;\n sessionId: string;\n};\n\nexport type CreateEmbeddedSessionClientOptions = {\n /**\n * Explicit host-owned method replacements. Methods inherited from `base`\n * retain `base` as their receiver; overrides retain this object as theirs.\n */\n overrides?: Partial<EmbeddedSessionClientLike> | undefined;\n /** Presentation/policy projection for every draft entering the React layer. */\n mapComposerDraft?:\n | ((draft: ComposerDraft, context: ComposerDraftMapContext) => ComposerDraft)\n | undefined;\n};\n\nconst requiredMethods = [\n \"getSession\",\n \"listEvents\",\n \"streamEvents\",\n \"getComposerDraft\",\n \"saveComposerDraft\",\n \"submitComposerDraft\",\n \"sendMessage\",\n \"steerMessage\",\n \"getQueue\",\n \"moveQueueItem\",\n \"editQueueItem\",\n \"steerQueueItem\",\n \"deleteQueueItem\",\n \"pauseSession\",\n \"resumeSession\",\n \"sendApprovalDecision\",\n] as const satisfies readonly (keyof EmbeddedSessionClientLike)[];\n\n/**\n * Build the exact client required by `@opengeni/react/session` from a full SDK\n * client or host proxy. The constructor binds every delegated method once,\n * supports a host-owned atomic composer-submit override, and fails at creation\n * time instead of waiting for a missing method to be exercised by a hook.\n */\nexport function createEmbeddedSessionClient(\n base: EmbeddedSessionClientLike,\n options: CreateEmbeddedSessionClientOptions = {},\n): EmbeddedSessionClientLike {\n const overrides = options.overrides ?? {};\n const client = {} as EmbeddedSessionClientLike;\n for (const key of requiredMethods) {\n const override = overrides[key];\n const method = override ?? base[key];\n if (typeof method !== \"function\") {\n throw new TypeError(`Embedded session client method is required: ${key}`);\n }\n client[key] = method.bind(override === undefined ? base : overrides) as never;\n }\n\n const inferenceOverride = overrides.setWorkspaceInferenceState;\n const inferenceBase = base.setWorkspaceInferenceState;\n const inferenceMethod = inferenceOverride ?? inferenceBase;\n if (typeof inferenceMethod === \"function\") {\n client.setWorkspaceInferenceState = inferenceMethod.bind(\n inferenceOverride === undefined ? base : overrides,\n );\n }\n\n const mapDraft = options.mapComposerDraft;\n if (!mapDraft) return client;\n\n const getComposerDraft = client.getComposerDraft;\n client.getComposerDraft = async (workspaceId, sessionId) =>\n mapDraft(await getComposerDraft(workspaceId, sessionId), {\n operation: \"read\",\n workspaceId,\n sessionId,\n });\n\n const saveComposerDraft = client.saveComposerDraft;\n client.saveComposerDraft = async (workspaceId, sessionId, request) =>\n mapDraft(await saveComposerDraft(workspaceId, sessionId, request), {\n operation: \"save\",\n workspaceId,\n sessionId,\n });\n\n const submitComposerDraft = client.submitComposerDraft;\n client.submitComposerDraft = async (workspaceId, sessionId, request) => {\n const response = await submitComposerDraft(workspaceId, sessionId, request);\n return {\n ...response,\n draft: mapDraft(response.draft, {\n operation: \"submit\",\n workspaceId,\n sessionId,\n }),\n };\n };\n\n return client;\n}\n","import { OpenGeniApiError, type SessionEvent, type SessionGoal } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useEmbeddedGoal, type EmbeddedGoalClientOverride } from \"../session-context\";\nimport { normalizeError } from \"../lib/error-message\";\nimport {\n useDebouncedCallback,\n useMutationRunner,\n usePageLiveActivity,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\n/** Event types that change the session goal (set/updated/completed/paused/...). */\nexport function isGoalEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type.startsWith(\"goal.\");\n}\n\n/**\n * Events that can change the server-authoritative continuation projection.\n * The projection is derived from durable turn, session, control, and system\n * update state, so those events refresh the goal without model polling.\n */\nexport function isGoalRefreshEvent(event: Pick<SessionEvent, \"type\">): boolean {\n const type = event.type;\n return (\n isGoalEvent(event) ||\n type.startsWith(\"turn.\") ||\n type.startsWith(\"session.\") ||\n type.startsWith(\"system.update.\") ||\n type.startsWith(\"workspace.inference.\") ||\n type.startsWith(\"user.\")\n );\n}\n\nexport type UseGoalOptions = EmbeddedGoalClientOverride &\n SessionEventFeedOptions & {\n /** Optional safety-net polling (ms). Off by default — event refreshes drive updates. */\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseGoalResult = {\n /** The session goal, or null when the session has none. */\n goal: SessionGoal | null;\n /** Convenience flags over `goal.status`. */\n isActive: boolean;\n isPaused: boolean;\n isCompleted: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Pause the goal loop (PATCH status=paused). */\n pause: (rationale?: string) => Promise<SessionGoal | null>;\n /** Resume a paused goal: resets counters and re-arms continuations. */\n resume: () => Promise<SessionGoal | null>;\n /** Clear the session goal; goal-less sessions remain a successful no-op. */\n clearGoal: () => Promise<void>;\n /** Alias for `clearGoal`. */\n deleteGoal: () => Promise<void>;\n /** True while a pause/resume/clear is in flight. */\n updating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The session's goal: state, the autonomy counters (`autoContinuations`,\n * `noProgressStreak`), and pause/resume control. A goal-less session yields\n * `goal: null` (the 404 is absorbed). Live-updates on goal, turn, session,\n * control, and system-update events — pass `options.events` from\n * `useSessionEvents` to reuse its stream.\n */\nexport function useGoal(\n sessionId: string | null | undefined,\n options: UseGoalOptions = {},\n): UseGoalResult {\n const { client, workspaceId } = useEmbeddedGoal(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const sharedEvents = options.events;\n const sharedFeed = sharedEvents !== undefined;\n const pageLive = usePageLiveActivity();\n const [goal, setGoal] = useState<SessionGoal | null>(null);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n const generation = useRef(0);\n const targetKeyRef = useRef<string | null>(null);\n const loadAbort = useRef<AbortController | null>(null);\n\n const retireLoads = useCallback(() => {\n generation.current += 1;\n loadAbort.current?.abort();\n loadAbort.current = null;\n }, []);\n\n const load = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n const ticket = ++generation.current;\n loadAbort.current?.abort();\n const controller = new AbortController();\n loadAbort.current = controller;\n try {\n const fetched = await client.getGoal(workspaceId, sessionId, {\n signal: controller.signal,\n });\n if (ticket === generation.current) {\n setGoal(fetched);\n setError(null);\n setLoading(false);\n }\n } catch (cause) {\n if (ticket !== generation.current) {\n return;\n }\n if (cause instanceof OpenGeniApiError && cause.status === 404) {\n // No goal is a normal state, not an error.\n setGoal(null);\n setError(null);\n } else {\n setError(normalizeError(cause));\n }\n setLoading(false);\n } finally {\n if (loadAbort.current === controller) loadAbort.current = null;\n }\n }, [client, workspaceId, sessionId]);\n\n useEffect(() => {\n const targetKey = `${workspaceId} ${sessionId ?? \"\"}`;\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n setGoal(null);\n setError(null);\n }\n if (!enabled || !pageLive) {\n retireLoads();\n setLoading(false);\n return;\n }\n if (sharedFeed) {\n // A shared log supplies invalidations, not the authoritative goal snapshot.\n setLoading(true);\n void load();\n return () => {\n retireLoads();\n };\n }\n setLoading(true);\n const pollIntervalMs = options.pollIntervalMs;\n if (pollIntervalMs === undefined || pollIntervalMs <= 0) {\n void load();\n return () => {\n retireLoads();\n };\n }\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const schedule = () => {\n if (cancelled) return;\n timer = setTimeout(() => {\n timer = null;\n void load().finally(schedule);\n }, pollIntervalMs);\n };\n void load().finally(schedule);\n return () => {\n cancelled = true;\n if (timer !== null) clearTimeout(timer);\n retireLoads();\n };\n }, [\n load,\n enabled,\n pageLive,\n workspaceId,\n sessionId,\n options.pollIntervalMs,\n retireLoads,\n sharedFeed,\n ]);\n\n const scheduleRefresh = useDebouncedCallback(() => void load());\n useSessionEventTrigger(client, workspaceId, sessionId, isGoalRefreshEvent, scheduleRefresh, {\n enabled,\n ...(sharedEvents !== undefined ? { events: sharedEvents } : {}),\n });\n\n const pause = useCallback(\n async (rationale?: string): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await run(() =>\n client.updateGoal(workspaceId, sessionId, {\n status: \"paused\",\n ...(rationale !== undefined ? { rationale } : {}),\n }),\n );\n if (result) {\n setGoal(result);\n }\n return result;\n },\n [client, workspaceId, sessionId, run],\n );\n\n const resume = useCallback(async (): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await run(() => client.updateGoal(workspaceId, sessionId, { status: \"active\" }));\n if (result) {\n setGoal(result);\n }\n return result;\n }, [client, workspaceId, sessionId, run]);\n\n const clearGoal = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n // deleteGoal resolves void, so distinguish success (a truthy sentinel) from\n // mutation.run's null-on-failure. Only a SUCCESSFUL delete hides the goal:\n // a failed one leaves the pill up so its mutationError renders. And invalidate\n // any in-flight load first so a slower getGoal started before the delete can't\n // commit and repopulate the just-cleared goal.\n const ok = await run(async () => {\n await client.deleteGoal(workspaceId, sessionId);\n return true as const;\n });\n if (ok) {\n retireLoads();\n setGoal(null);\n setError(null);\n }\n }, [client, workspaceId, sessionId, run, retireLoads]);\n\n return {\n goal,\n isActive: goal?.status === \"active\",\n isPaused: goal?.status === \"paused\",\n isCompleted: goal?.status === \"completed\",\n loading,\n error,\n refresh: load,\n pause,\n resume,\n clearGoal,\n deleteGoal: clearGoal,\n updating: mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type {\n SessionEvent,\n SessionMcpApprovalPolicy,\n SessionMcpApprovalPolicyTarget,\n UpdateSessionMcpApprovalPolicyResponse,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport {\n useEmbeddedSessionMcpApprovalPolicy,\n type EmbeddedSessionMcpApprovalPolicyClientOverride,\n} from \"../session-context\";\nimport {\n useDebouncedCallback,\n useMutationRunner,\n usePolledValue,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\nexport function isSessionMcpApprovalPolicyEvent(\n event: Pick<SessionEvent, \"type\" | \"payload\">,\n serverId?: string,\n): boolean {\n if (event.type !== \"session.mcp.approval_policy.updated\") {\n return false;\n }\n if (serverId === undefined) {\n return true;\n }\n const payload = event.payload as { serverId?: unknown } | null;\n return payload?.serverId === serverId;\n}\n\nexport type UseSessionMcpApprovalPolicyOptions = EmbeddedSessionMcpApprovalPolicyClientOverride &\n SessionEventFeedOptions & {\n /** Optional safety-net polling (ms). Off by default; policy events drive refreshes. */\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseSessionMcpApprovalPolicyResult = {\n server: SessionMcpApprovalPolicyTarget | null;\n policy: SessionMcpApprovalPolicy | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n update: (\n policy: SessionMcpApprovalPolicy,\n ) => Promise<UpdateSessionMcpApprovalPolicyResponse | null>;\n updating: boolean;\n clearError: () => void;\n};\n\n/**\n * Read and update one existing session MCP server's approval policy. Updates\n * become effective for the next claimed attempt; current work is unchanged.\n */\nexport function useSessionMcpApprovalPolicy(\n sessionId: string | null | undefined,\n serverId: string | null | undefined,\n options: UseSessionMcpApprovalPolicyOptions = {},\n): UseSessionMcpApprovalPolicyResult {\n const { client, workspaceId } = useEmbeddedSessionMcpApprovalPolicy(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId && serverId);\n const [override, setOverride] = useState<SessionMcpApprovalPolicyTarget | null>(null);\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${serverId ?? \"\"}`;\n const authoritativeGeneration = useRef(0);\n const mutationIdentity = useMemo(() => ({ client, targetKey }), [client, targetKey]);\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner(mutationIdentity);\n\n useLayoutEffect(() => {\n authoritativeGeneration.current += 1;\n setOverride(null);\n }, [client, targetKey]);\n\n type PolicyRead = {\n targetKey: string;\n generation: number;\n server: SessionMcpApprovalPolicyTarget | null;\n };\n const load = useCallback(async (): Promise<PolicyRead> => {\n const generation = authoritativeGeneration.current;\n if (!sessionId || !serverId) {\n return { targetKey, generation, server: null };\n }\n const session = await client.getSession(workspaceId, sessionId);\n return {\n targetKey,\n generation,\n server:\n session.mcpServers.find((server) => server.id === serverId) ??\n (session.mcpApprovalPolicies && Object.hasOwn(session.mcpApprovalPolicies, serverId)\n ? {\n id: serverId,\n source: \"workspace\",\n requireApproval: session.mcpApprovalPolicies[serverId]!,\n }\n : null),\n };\n }, [client, serverId, sessionId, targetKey, workspaceId]);\n const {\n data,\n loading,\n error: loadError,\n refresh,\n } = usePolledValue(load, {\n enabled,\n pollIntervalMs: options.pollIntervalMs,\n });\n useEffect(() => {\n if (data?.targetKey === targetKey && data.generation === authoritativeGeneration.current) {\n setOverride(null);\n }\n }, [data, targetKey]);\n\n const scheduleRefresh = useDebouncedCallback(() => void refresh());\n const matchesPolicyEvent = useCallback(\n (event: Pick<SessionEvent, \"type\" | \"payload\">) =>\n isSessionMcpApprovalPolicyEvent(event, serverId ?? undefined),\n [serverId],\n );\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n matchesPolicyEvent,\n scheduleRefresh,\n {\n enabled,\n ...(options.events !== undefined ? { events: options.events } : {}),\n },\n async () => await refresh(),\n );\n\n const update = useCallback(\n async (\n policy: SessionMcpApprovalPolicy,\n ): Promise<UpdateSessionMcpApprovalPolicyResponse | null> => {\n if (!sessionId || !serverId) {\n return null;\n }\n const response = await run(() =>\n client.updateSessionMcpApprovalPolicy(workspaceId, sessionId, serverId, {\n requireApproval: policy,\n }),\n );\n if (response) {\n authoritativeGeneration.current += 1;\n setOverride(response.server);\n void refresh();\n }\n return response;\n },\n [client, refresh, run, serverId, sessionId, workspaceId],\n );\n\n const server = override ?? data?.server ?? null;\n return {\n server,\n policy: server?.requireApproval ?? null,\n loading,\n error: mutationError ?? loadError,\n refresh: async () => {\n await refresh();\n },\n update,\n updating: mutating,\n clearError: clearMutationError,\n };\n}\n","import type { SessionEvent, SessionLineageResponse } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport {\n useEmbeddedSessionLineage,\n type EmbeddedSessionLineageClientOverride,\n} from \"../session-context\";\nimport { useDebouncedCallback, usePolledValue, useSessionEventTrigger } from \"./internal\";\n\nexport type UseSessionLineageOptions = EmbeddedSessionLineageClientOverride & {\n events?: SessionEvent[] | undefined;\n /** Refresh interval (ms). Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n /** Optional shared causal clock invoked when each network read starts. */\n beginRead?: (() => number) | undefined;\n};\n\nexport type UseSessionLineageResult = {\n lineage: SessionLineageResponse | null;\n loading: boolean;\n error: Error | null;\n /** Causal generation captured when the accepted lineage read started. */\n readGeneration: number;\n refresh: () => Promise<void>;\n};\n\nexport function isLineageRefreshEvent(event: SessionEvent): boolean {\n if (event.type === \"session.status.changed\" || event.type === \"session.created\") {\n return true;\n }\n // A child's creation never appears on the PARENT's stream as session.created —\n // the parent sees its own spawn as an agent.toolCall.* for session_create.\n // Created events are handled separately so they can refresh immediately and\n // once after the child row has had time to commit.\n if (event.type === \"agent.toolCall.output\") {\n const payload = event.payload as { name?: unknown; toolName?: unknown } | null | undefined;\n const name =\n typeof payload?.name === \"string\"\n ? payload.name\n : typeof payload?.toolName === \"string\"\n ? payload.toolName\n : \"\";\n return name === \"session_create\" || name.endsWith(\"__session_create\");\n }\n return false;\n}\n\nfunction isSessionCreateToolCallCreated(event: SessionEvent): boolean {\n if (event.type !== \"agent.toolCall.created\") {\n return false;\n }\n const payload = event.payload as { name?: unknown; toolName?: unknown } | null | undefined;\n const name =\n typeof payload?.name === \"string\"\n ? payload.name\n : typeof payload?.toolName === \"string\"\n ? payload.toolName\n : \"\";\n return name === \"session_create\" || name.endsWith(\"__session_create\");\n}\n\n/** Read the ancestors + descendant tree for one session. Data-only; no UI state. */\nexport function useSessionLineage(\n sessionId: string | null | undefined,\n options: UseSessionLineageOptions = {},\n): UseSessionLineageResult {\n const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } =\n useEmbeddedSessionLineage(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const nextReadGeneration = useRef(0);\n const beginRead = options.beginRead;\n const load = useCallback(\n async (signal?: AbortSignal) => {\n if (!sessionId) {\n return {\n lineage: { ancestors: [], children: [], truncated: false },\n readGeneration: 0,\n };\n }\n let readGeneration = 0;\n const lineage = await client.getSessionLineage(workspaceId, sessionId, {\n signal,\n onRequestStart: (sharedReadGeneration) => {\n readGeneration = sharedReadGeneration ?? beginRead?.() ?? ++nextReadGeneration.current;\n },\n });\n return {\n lineage,\n readGeneration,\n };\n },\n [beginRead, client, workspaceId, sessionId],\n );\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled });\n const refresh = state.refresh;\n useEffect(() => {\n if (enabled && workspaceControlEvent) void refresh();\n }, [enabled, refresh, workspaceControlEvent]);\n useEffect(() => {\n if (!sessionId || !enabled) return;\n return registerSessionReconciler(sessionId, \"lineage\", refresh);\n }, [enabled, refresh, registerSessionReconciler, sessionId]);\n const refreshSoon = useDebouncedCallback(() => void refresh(), 150);\n const delayedChildRefreshRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n // Clear a pending delayed refresh on session/workspace SWITCH (not just\n // unmount): otherwise a timer scheduled for the previous session can fire\n // ~2.5s later and commit that session's lineage onto the new one.\n useEffect(() => {\n return () => {\n if (delayedChildRefreshRef.current !== null) {\n clearTimeout(delayedChildRefreshRef.current);\n delayedChildRefreshRef.current = null;\n }\n };\n }, [sessionId, workspaceId]);\n const refreshAfterChildCreate = useCallback(() => {\n void refresh();\n if (delayedChildRefreshRef.current !== null) {\n clearTimeout(delayedChildRefreshRef.current);\n }\n delayedChildRefreshRef.current = setTimeout(() => {\n delayedChildRefreshRef.current = null;\n void refresh();\n }, 2500);\n }, [refresh]);\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isLineageRefreshEvent,\n refreshSoon,\n // SHARED-FEED ONLY: without a caller-provided events log the trigger would\n // open its OWN streamEvents tail — a second live SSE connection next to the\n // session route's useSessionEvents. A caller with no feed opts into polling\n // (pollIntervalMs), never a duplicate stream.\n { events: options.events, enabled: enabled && options.events !== undefined },\n );\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isSessionCreateToolCallCreated,\n refreshAfterChildCreate,\n { events: options.events, enabled: enabled && options.events !== undefined },\n );\n return {\n lineage: state.data?.lineage ?? null,\n loading: state.loading,\n error: state.error,\n readGeneration: state.data?.readGeneration ?? 0,\n refresh,\n };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useState","useRef","useCallback","server","useEffect","useCallback","useEffect","useRef","useRef","useCallback","useEffect"]}