@opengeni/react 3.0.0-canary.0 → 3.3.2-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/accounts.js +87 -11
  2. package/dist/accounts.js.map +1 -1
  3. package/dist/{browser-viewer-AEFHUYZK.js → browser-viewer-MKKFRRRV.js} +3 -3
  4. package/dist/{chunk-W6NFJXSA.js → chunk-2DZVYHVO.js} +20 -4
  5. package/dist/chunk-2DZVYHVO.js.map +1 -0
  6. package/dist/{chunk-YJFGAFBD.js → chunk-3AGBGTRT.js} +226 -95
  7. package/dist/chunk-3AGBGTRT.js.map +1 -0
  8. package/dist/{chunk-YFKJ7VZH.js → chunk-7EAFGICR.js} +45 -11
  9. package/dist/chunk-7EAFGICR.js.map +1 -0
  10. package/dist/{chunk-MZ2G2XBA.js → chunk-IOLVN74D.js} +31 -4
  11. package/dist/chunk-IOLVN74D.js.map +1 -0
  12. package/dist/{chunk-D3UIAJKY.js → chunk-JAQ5K7W6.js} +3 -2
  13. package/dist/{chunk-D3UIAJKY.js.map → chunk-JAQ5K7W6.js.map} +1 -1
  14. package/dist/{chunk-LAKLF4PA.js → chunk-VTOREEXF.js} +8 -7
  15. package/dist/chunk-VTOREEXF.js.map +1 -0
  16. package/dist/{chunk-RGALCTWO.js → chunk-XYRDDSXF.js} +4 -4
  17. package/dist/{chunk-HQVCKCLG.js → chunk-YG4QEQF5.js} +354 -255
  18. package/dist/chunk-YG4QEQF5.js.map +1 -0
  19. package/dist/{chunk-XXWH2JLC.js → chunk-YVCHAQZY.js} +2 -2
  20. package/dist/{chunk-OAM4WAAM.js → chunk-ZPBTI3TE.js} +2 -2
  21. package/dist/components/fleet-tile.d.ts +2 -2
  22. package/dist/components/model-policy-picker.d.ts +9 -0
  23. package/dist/components/tip-follow.d.ts +16 -0
  24. package/dist/composer.js +5 -5
  25. package/dist/hooks/use-session-events.d.ts +3 -3
  26. package/dist/index.js +76 -68
  27. package/dist/index.js.map +1 -1
  28. package/dist/interaction.js +2 -2
  29. package/dist/machines.js +2 -2
  30. package/dist/realtime.js +46 -7
  31. package/dist/realtime.js.map +1 -1
  32. package/dist/session-ui.js +4 -4
  33. package/dist/session.js +4 -4
  34. package/dist/timeline/entrance.d.ts +13 -1
  35. package/package.json +3 -2
  36. package/src/accounts.tsx +116 -14
  37. package/src/components/fleet-tile.tsx +4 -15
  38. package/src/components/message-timeline.tsx +237 -101
  39. package/src/components/model-policy-picker.tsx +24 -3
  40. package/src/components/tip-follow.ts +52 -0
  41. package/src/components/tooltip.tsx +38 -5
  42. package/src/hooks/use-available-models.ts +20 -14
  43. package/src/hooks/use-composer.ts +49 -3
  44. package/src/hooks/use-goal.ts +31 -7
  45. package/src/hooks/use-last-started-turn-policy.ts +11 -5
  46. package/src/hooks/use-session-events.ts +186 -61
  47. package/src/hooks/use-session-lineage.ts +20 -16
  48. package/src/hooks/use-session.ts +23 -19
  49. package/src/hooks/use-workspace-sessions.ts +31 -27
  50. package/src/lib/format.ts +8 -6
  51. package/src/realtime/realtime-control.tsx +55 -6
  52. package/src/timeline/entrance.tsx +28 -3
  53. package/src/timeline/projection.ts +4 -0
  54. package/dist/chunk-HQVCKCLG.js.map +0 -1
  55. package/dist/chunk-LAKLF4PA.js.map +0 -1
  56. package/dist/chunk-MZ2G2XBA.js.map +0 -1
  57. package/dist/chunk-W6NFJXSA.js.map +0 -1
  58. package/dist/chunk-YFKJ7VZH.js.map +0 -1
  59. package/dist/chunk-YJFGAFBD.js.map +0 -1
  60. /package/dist/{browser-viewer-AEFHUYZK.js.map → browser-viewer-MKKFRRRV.js.map} +0 -0
  61. /package/dist/{chunk-RGALCTWO.js.map → chunk-XYRDDSXF.js.map} +0 -0
  62. /package/dist/{chunk-XXWH2JLC.js.map → chunk-YVCHAQZY.js.map} +0 -0
  63. /package/dist/{chunk-OAM4WAAM.js.map → chunk-ZPBTI3TE.js.map} +0 -0
@@ -105,7 +105,12 @@ const REALTIME_MODEL_CATALOG_CACHE_MAX_WORKSPACES = 64;
105
105
  type RealtimeControllerClient = EmbeddedRealtimeSessionClientLike & SessionRealtimeClientLike;
106
106
 
107
107
  type RealtimeModelCatalogCacheEntry =
108
- | { state: "loading"; promise: Promise<RealtimeModelOption[]> }
108
+ | {
109
+ state: "loading";
110
+ promise: Promise<RealtimeModelOption[]>;
111
+ controller: AbortController;
112
+ consumers: number;
113
+ }
109
114
  | { state: "ready"; models: RealtimeModelOption[]; expiresAt: number };
110
115
 
111
116
  // Scope advisory availability to the exact client object and workspace. The
@@ -166,19 +171,26 @@ function pruneRealtimeModelCatalogCache(
166
171
  function loadRealtimeModelCatalog(
167
172
  client: RealtimeControllerClient,
168
173
  workspaceId: string,
174
+ signal?: AbortSignal,
169
175
  ): Promise<RealtimeModelOption[]> | null {
170
176
  const load = client.getWorkspaceRealtimeModelCatalog;
171
177
  if (!load) return null;
178
+ if (signal?.aborted) {
179
+ return Promise.reject(signal.reason ?? new DOMException("Request aborted", "AbortError"));
180
+ }
172
181
  const now = Date.now();
173
182
  const cache = realtimeModelCatalogCacheFor(client);
174
183
  const entry = cache.get(workspaceId);
175
- if (entry?.state === "loading") return entry.promise;
184
+ if (entry?.state === "loading" && !entry.controller.signal.aborted) {
185
+ return consumeRealtimeModelCatalog(entry, signal);
186
+ }
176
187
  if (entry?.state === "ready" && entry.expiresAt > now) return Promise.resolve(entry.models);
177
188
  if (entry) cache.delete(workspaceId);
178
189
  pruneRealtimeModelCatalogCache(cache, now);
179
190
 
191
+ const controller = new AbortController();
180
192
  const promise = load
181
- .call(client, workspaceId)
193
+ .call(client, workspaceId, { signal: controller.signal })
182
194
  .then((response) => response.models.map(toRealtimeModelOption))
183
195
  .then((models) => {
184
196
  const current = cache.get(workspaceId);
@@ -197,8 +209,43 @@ function loadRealtimeModelCatalog(
197
209
  if (current?.state === "loading" && current.promise === promise) cache.delete(workspaceId);
198
210
  throw error;
199
211
  });
200
- cache.set(workspaceId, { state: "loading", promise });
201
- return promise;
212
+ const loading: RealtimeModelCatalogCacheEntry & { state: "loading" } = {
213
+ state: "loading",
214
+ promise,
215
+ controller,
216
+ consumers: 0,
217
+ };
218
+ cache.set(workspaceId, loading);
219
+ return consumeRealtimeModelCatalog(loading, signal);
220
+ }
221
+
222
+ function consumeRealtimeModelCatalog(
223
+ entry: RealtimeModelCatalogCacheEntry & { state: "loading" },
224
+ signal?: AbortSignal,
225
+ ): Promise<RealtimeModelOption[]> {
226
+ entry.consumers += 1;
227
+ return new Promise((resolve, reject) => {
228
+ let released = false;
229
+ const release = (abandoned: boolean) => {
230
+ if (released) return;
231
+ released = true;
232
+ entry.consumers = Math.max(0, entry.consumers - 1);
233
+ if (abandoned && entry.consumers === 0) {
234
+ entry.controller.abort(
235
+ signal?.reason ?? new DOMException("Request abandoned", "AbortError"),
236
+ );
237
+ }
238
+ };
239
+ const onAbort = () => {
240
+ release(true);
241
+ reject(signal?.reason ?? new DOMException("Request aborted", "AbortError"));
242
+ };
243
+ signal?.addEventListener("abort", onAbort, { once: true });
244
+ void entry.promise.then(resolve, reject).finally(() => {
245
+ signal?.removeEventListener("abort", onAbort);
246
+ release(false);
247
+ });
248
+ });
202
249
  }
203
250
 
204
251
  export type SessionRealtimeControllerFactory = (
@@ -550,6 +597,7 @@ export function useRealtimeModelSelection(options: {
550
597
 
551
598
  useEffect(() => {
552
599
  let disposed = false;
600
+ const requestAbort = new AbortController();
553
601
  const applyCatalog = (models: RealtimeModelOption[]) => {
554
602
  catalogScopeRef.current = { client, workspaceId, source: "cache" };
555
603
  setCatalog(models);
@@ -570,7 +618,7 @@ export function useRealtimeModelSelection(options: {
570
618
  }
571
619
  return;
572
620
  }
573
- const loading = loadRealtimeModelCatalog(client, workspaceId);
621
+ const loading = loadRealtimeModelCatalog(client, workspaceId, requestAbort.signal);
574
622
  if (!loading) return;
575
623
  void loading
576
624
  .then((models) => {
@@ -580,6 +628,7 @@ export function useRealtimeModelSelection(options: {
580
628
  .catch(() => undefined);
581
629
  return () => {
582
630
  disposed = true;
631
+ requestAbort.abort();
583
632
  };
584
633
  }, [client, workspaceId]);
585
634
 
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useRef } from "react";
1
+ import { createContext, useContext, useRef, type ReactNode } from "react";
2
2
 
3
3
  /* ----------------------------------------------------------------------------
4
4
  Entrance animation gating
@@ -15,8 +15,33 @@ import { createContext, useContext, useRef } from "react";
15
15
  -------------------------------------------------------------------------- */
16
16
 
17
17
  const EntranceAnimationContext = createContext(true);
18
+ const EntranceAnimationLiveContext = createContext(true);
18
19
 
19
- export const EntranceAnimationProvider = EntranceAnimationContext.Provider;
20
+ /**
21
+ * Freeze the mount-time gate for this subtree while publishing a separate live
22
+ * gate to activity rails that need later appends to animate after a bulk paint.
23
+ * MessageTimeline mounts one provider per durable group, so existing groups do
24
+ * not receive a context invalidation when a prepend toggles bulk mode and new
25
+ * groups still capture the value from the commit that created them.
26
+ */
27
+ export function EntranceAnimationProvider({
28
+ value,
29
+ liveValue = value,
30
+ children,
31
+ }: {
32
+ value: boolean;
33
+ liveValue?: boolean | undefined;
34
+ children: ReactNode;
35
+ }) {
36
+ const mountedValue = useRef(value).current;
37
+ return (
38
+ <EntranceAnimationContext.Provider value={mountedValue}>
39
+ <EntranceAnimationLiveContext.Provider value={liveValue}>
40
+ {children}
41
+ </EntranceAnimationLiveContext.Provider>
42
+ </EntranceAnimationContext.Provider>
43
+ );
44
+ }
20
45
 
21
46
  /**
22
47
  * Live entrance gate from the nearest provider. Prefer
@@ -25,7 +50,7 @@ export const EntranceAnimationProvider = EntranceAnimationContext.Provider;
25
50
  * later appends after a bulk window clears.
26
51
  */
27
52
  export function useEntranceAnimationLive(): boolean {
28
- return useContext(EntranceAnimationContext);
53
+ return useContext(EntranceAnimationLiveContext);
29
54
  }
30
55
 
31
56
  /**
@@ -2091,6 +2091,10 @@ function findOpenCall(
2091
2091
  if (byId) {
2092
2092
  return byId as ToolCallItem | WorkerItem;
2093
2093
  }
2094
+ // An explicit provider correlation id is authoritative. Falling back to
2095
+ // an unrelated running call corrupts its status/output when compact pages
2096
+ // or interleaved providers deliver an unmatched historical result.
2097
+ return undefined;
2094
2098
  }
2095
2099
  return reversed.find(
2096
2100
  (item): item is ToolCallItem | WorkerItem => isCall(item) && item.status === "running",