@opengeni/react 2.3.0-canary.0 → 2.5.0-canary.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.
Files changed (46) hide show
  1. package/README.md +9 -2
  2. package/dist/{chunk-LS4POUTY.js → chunk-6H6S5V4Z.js} +250 -120
  3. package/dist/chunk-6H6S5V4Z.js.map +1 -0
  4. package/dist/{chunk-SE4W4WQ3.js → chunk-ATQJEWCA.js} +154 -114
  5. package/dist/chunk-ATQJEWCA.js.map +1 -0
  6. package/dist/{chunk-LTCHJ4MS.js → chunk-KSDXER4X.js} +21 -7
  7. package/dist/chunk-KSDXER4X.js.map +1 -0
  8. package/dist/{chunk-RSXJN73N.js → chunk-MXJGO7LE.js} +34 -1
  9. package/dist/chunk-MXJGO7LE.js.map +1 -0
  10. package/dist/{chunk-JOAVA2TW.js → chunk-T7VAYG2I.js} +8 -7
  11. package/dist/{chunk-JOAVA2TW.js.map → chunk-T7VAYG2I.js.map} +1 -1
  12. package/dist/components/composer.d.ts +1 -1
  13. package/dist/components/fleet-tile.d.ts +1 -1
  14. package/dist/components/message-timeline.d.ts +7 -2
  15. package/dist/composer.js +2 -2
  16. package/dist/hooks/use-session-events.d.ts +2 -1
  17. package/dist/hooks/use-session-lineage.d.ts +4 -0
  18. package/dist/hooks/use-session.d.ts +6 -0
  19. package/dist/hooks/use-workspace-sessions.d.ts +6 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +41 -19
  22. package/dist/index.js.map +1 -1
  23. package/dist/older-history.d.ts +29 -0
  24. package/dist/session-ui.d.ts +2 -0
  25. package/dist/session-ui.js +5 -2
  26. package/dist/session.d.ts +2 -0
  27. package/dist/session.js +5 -3
  28. package/package.json +2 -2
  29. package/src/components/composer.tsx +19 -5
  30. package/src/components/fleet-tile.tsx +7 -5
  31. package/src/components/message-timeline.tsx +399 -160
  32. package/src/components/tip-follow.ts +18 -7
  33. package/src/hooks/use-composer.ts +20 -6
  34. package/src/hooks/use-session-events.ts +84 -76
  35. package/src/hooks/use-session-lineage.ts +26 -8
  36. package/src/hooks/use-session.ts +35 -8
  37. package/src/hooks/use-workspace-sessions.ts +38 -13
  38. package/src/index.ts +2 -0
  39. package/src/older-history.ts +69 -0
  40. package/src/session-ui.ts +2 -0
  41. package/src/session.ts +2 -0
  42. package/src/timeline/activity-rail.tsx +1 -0
  43. package/dist/chunk-LS4POUTY.js.map +0 -1
  44. package/dist/chunk-LTCHJ4MS.js.map +0 -1
  45. package/dist/chunk-RSXJN73N.js.map +0 -1
  46. package/dist/chunk-SE4W4WQ3.js.map +0 -1
@@ -219,7 +219,7 @@ export declare function useChatComposerController({ delivery, draft, control, ef
219
219
  handlePaste: (event: ClipboardEvent<HTMLTextAreaElement>) => void;
220
220
  handleFileChange: (event: ChangeEvent<HTMLInputElement>) => void;
221
221
  focusInput: () => void | undefined;
222
- setValue: (value: string) => void;
222
+ setValue: (next: string) => void;
223
223
  value: string;
224
224
  };
225
225
  export type ChatComposerController = ReturnType<typeof useChatComposerController>;
@@ -1,7 +1,7 @@
1
1
  import type { Session } from "@opengeni/sdk";
2
2
  export type FleetTileProps = {
3
3
  session: Session;
4
- /** Overrides the derived title (metadata.title/name, else the initial message). */
4
+ /** Overrides the derived title (session title, metadata title/name, or safe fallback). */
5
5
  title?: string | undefined;
6
6
  /** Extra line under the title — e.g. "drift check" or the worker's task. */
7
7
  subtitle?: string | undefined;
@@ -1,5 +1,6 @@
1
1
  import type { DraftTimelineAnnotation, SessionEvent, SessionStatus } from "@opengeni/sdk";
2
2
  import { type ReactNode } from "react";
3
+ import { type OlderHistoryLoader } from "../older-history.js";
3
4
  import { type AgentMessageItem, type AuthNeededItem, type TimelineGroup, type TimelineItem, type RetainedArtifactLoader, type RetainedScreenshotLoader, type VideoArtifactPlaybackLoader, type ToolRegistry, type TurnSummaryOptions, type UserMessageItem } from "../timeline/index.js";
4
5
  export type MessageTimelineProps = {
5
6
  /** Raw session events (projected internally) … */
@@ -70,8 +71,12 @@ export type MessageTimelineProps = {
70
71
  hasOlder?: boolean | undefined;
71
72
  /** An older window is being fetched; shows the quiet top shimmer. */
72
73
  loadingOlder?: boolean | undefined;
73
- /** Called when the reader nears the top and older history should backfill. */
74
- onLoadOlder?: (() => void) | undefined;
74
+ /**
75
+ * Called when older history should backfill. Existing void, synchronous-value,
76
+ * and arbitrary-promise callbacks remain supported. Receipt-aware loaders
77
+ * preserve committed-page direction through wrappers and bounded windows.
78
+ */
79
+ onLoadOlder?: OlderHistoryLoader | undefined;
75
80
  /** Jump to the durable session start (bounded oldest window, no middle). */
76
81
  onJumpToStart?: (() => void | Promise<void>) | undefined;
77
82
  /** True while the oldest window is loading. */
package/dist/composer.js CHANGED
@@ -37,8 +37,8 @@ import {
37
37
  useChatComposer,
38
38
  useChatComposerController,
39
39
  useVoiceInput
40
- } from "./chunk-LTCHJ4MS.js";
41
- import "./chunk-JOAVA2TW.js";
40
+ } from "./chunk-KSDXER4X.js";
41
+ import "./chunk-T7VAYG2I.js";
42
42
  import {
43
43
  BillingClassMark,
44
44
  ModelPolicyPicker,
@@ -1,5 +1,6 @@
1
1
  import type { SessionEvent, SessionStatus, StreamConnectionState } from "@opengeni/sdk";
2
2
  import { type EmbeddedSessionClientOverride } from "../session-context.js";
3
+ import { type OlderHistoryLoadReceipt } from "../older-history.js";
3
4
  import type { TimelineItem } from "../timeline/types.js";
4
5
  export type SessionEventsConnectionState = StreamConnectionState | "idle" | "ended" | "error";
5
6
  export type UseSessionEventsOptions = EmbeddedSessionClientOverride & {
@@ -31,7 +32,7 @@ export type UseSessionEventsResult = {
31
32
  /** True while an older window is being fetched. */
32
33
  loadingOlder: boolean;
33
34
  /** Prepend an older density-bounded window; resolves true when more remain. */
34
- loadOlder: () => Promise<boolean>;
35
+ loadOlder: () => OlderHistoryLoadReceipt;
35
36
  /**
36
37
  * Durable events exist after the current window (history view jumped away
37
38
  * from the live tip, or a forward page is incomplete).
@@ -5,11 +5,15 @@ export type UseSessionLineageOptions = EmbeddedSessionLineageClientOverride & {
5
5
  /** Refresh interval (ms). Off by default. */
6
6
  pollIntervalMs?: number | undefined;
7
7
  enabled?: boolean | undefined;
8
+ /** Optional shared causal clock invoked when each network read starts. */
9
+ beginRead?: (() => number) | undefined;
8
10
  };
9
11
  export type UseSessionLineageResult = {
10
12
  lineage: SessionLineageResponse | null;
11
13
  loading: boolean;
12
14
  error: Error | null;
15
+ /** Causal generation captured when the accepted lineage read started. */
16
+ readGeneration: number;
13
17
  refresh: () => Promise<void>;
14
18
  };
15
19
  export declare function isLineageRefreshEvent(event: SessionEvent): boolean;
@@ -4,11 +4,17 @@ import { type SessionEventFeedOptions } from "./internal.js";
4
4
  export type UseSessionOptions = EmbeddedSessionReadClientOverride & SessionEventFeedOptions & {
5
5
  /** Re-fetch on an interval (ms). Off by default — pair with `useSessionEvents` for live status. */
6
6
  pollIntervalMs?: number | undefined;
7
+ /** Optional shared causal clock invoked when each network read starts. */
8
+ beginRead?: (() => number) | undefined;
7
9
  };
8
10
  export type UseSessionResult = {
9
11
  session: Session | null;
10
12
  loading: boolean;
11
13
  error: Error | null;
14
+ /** Monotonic revision of accepted authoritative detail reads. */
15
+ readRevision: number;
16
+ /** Causal generation captured when the accepted network read started. */
17
+ readGeneration: number;
12
18
  refresh: () => Promise<void>;
13
19
  /** Manually rename the session (PATCH, source='user'). Returns the updated session, or null on failure. */
14
20
  updateTitle: (title: string) => Promise<Session | null>;
@@ -11,6 +11,8 @@ export type UseWorkspaceSessionsOptions = ClientOverride & {
11
11
  /** Refresh interval (ms) for fleet/manager views. Off by default. */
12
12
  pollIntervalMs?: number | undefined;
13
13
  enabled?: boolean | undefined;
14
+ /** Optional shared causal clock invoked when each network read starts. */
15
+ beginRead?: (() => number) | undefined;
14
16
  };
15
17
  export type UseWorkspaceSessionsResult = {
16
18
  /**
@@ -25,6 +27,10 @@ export type UseWorkspaceSessionsResult = {
25
27
  nextCursor: string | null;
26
28
  loading: boolean;
27
29
  error: Error | null;
30
+ /** Monotonic revision of accepted authoritative list-page reads. */
31
+ readRevision: number;
32
+ /** Causal generation captured when the accepted network read started. */
33
+ readGeneration: number;
28
34
  refresh: () => Promise<void>;
29
35
  };
30
36
  /** List the workspace's sessions — the data behind fleet and manager views. */
package/dist/index.d.ts CHANGED
@@ -8,7 +8,9 @@ export { usePageLiveActivity } from "./hooks/internal.js";
8
8
  export { useSession, isTitleEvent } from "./hooks/use-session.js";
9
9
  export type { UseSessionOptions, UseSessionResult } from "./hooks/use-session.js";
10
10
  export { SESSION_EVENT_BROWSER_MAX_BYTES, SESSION_EVENT_BROWSER_MAX_COUNT, SESSION_EVENT_BROWSER_PENDING_MAX_BYTES, SESSION_EVENT_BROWSER_PENDING_MAX_COUNT, SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES, boundBrowserSessionEventWindow, useSessionEvents, } from "./hooks/use-session-events.js";
11
+ export { createOlderHistoryLoadReceipt } from "./older-history.js";
11
12
  export type { BrowserSessionEventWindow, SessionEventsConnectionState, UseSessionEventsOptions, UseSessionEventsResult, } from "./hooks/use-session-events.js";
13
+ export type { OlderHistoryLoader, OlderHistoryLoadReceipt } from "./older-history.js";
12
14
  export { useComposer, composeSendInput, shouldSteerOnKey, shouldSubmitOnKey, FILE_ONLY_MESSAGE_TEXT, } from "./hooks/use-composer.js";
13
15
  export type { ComposerControllerState, ComposerPolicy, ComposerSendExtras, ComposerState, UseComposerOptions, } from "./hooks/use-composer.js";
14
16
  export { VOICE_RECORDING_CLIENT_MAX_DURATION_SECONDS, VOICE_RECORDING_OWNER_HEARTBEAT_MILLISECONDS, VOICE_RECORDING_OWNER_STALE_MILLISECONDS, VOICE_RECORDING_TIMESLICE_MILLISECONDS, useVoiceInput, } from "./hooks/use-voice-input.js";
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  useSessionLineage,
25
25
  useSessionMcpApprovalPolicy,
26
26
  useTurnQueue
27
- } from "./chunk-SE4W4WQ3.js";
27
+ } from "./chunk-ATQJEWCA.js";
28
28
  import {
29
29
  CONNECTION_STATUS_META,
30
30
  ConnectionDot,
@@ -109,14 +109,14 @@ import {
109
109
  useSlashCommands,
110
110
  useTranscription,
111
111
  useVoiceInput
112
- } from "./chunk-LTCHJ4MS.js";
112
+ } from "./chunk-KSDXER4X.js";
113
113
  import {
114
114
  FILE_ONLY_MESSAGE_TEXT,
115
115
  composeSendInput,
116
116
  shouldSteerOnKey,
117
117
  shouldSubmitOnKey,
118
118
  useComposer
119
- } from "./chunk-JOAVA2TW.js";
119
+ } from "./chunk-T7VAYG2I.js";
120
120
  import {
121
121
  BillingClassMark,
122
122
  ModelPolicyPicker,
@@ -205,15 +205,16 @@ import {
205
205
  useThemeType,
206
206
  userMessageLikelyNeedsDisclosure,
207
207
  v4aToGitFileDiff
208
- } from "./chunk-LS4POUTY.js";
208
+ } from "./chunk-6H6S5V4Z.js";
209
209
  import {
210
210
  buildTimeline,
211
+ createOlderHistoryLoadReceipt,
211
212
  creditExhaustedFromEvents,
212
213
  extractSessionRef,
213
214
  groupTimeline,
214
215
  sessionStatusFromEvents,
215
216
  toolDisplayName
216
- } from "./chunk-RSXJN73N.js";
217
+ } from "./chunk-MXJGO7LE.js";
217
218
  import {
218
219
  TimelineAnnotationsChip
219
220
  } from "./chunk-WSK7G5LE.js";
@@ -374,6 +375,9 @@ function useWorkspaceSessions(options = {}) {
374
375
  const pinsOnly = options.pinsOnly;
375
376
  const archivedOnly = options.archivedOnly;
376
377
  const enabled = options.enabled ?? true;
378
+ const nextReadRevision = useRef(0);
379
+ const nextReadGeneration = useRef(0);
380
+ const beginRead = options.beginRead;
377
381
  const queryKey = [
378
382
  workspaceId,
379
383
  limit ?? "",
@@ -388,20 +392,34 @@ function useWorkspaceSessions(options = {}) {
388
392
  useEffect2(() => {
389
393
  previousQueryKey.current = queryKey;
390
394
  }, [queryKey]);
391
- const load = useCallback3(
392
- async () => ({
395
+ const load = useCallback3(async () => {
396
+ const readGeneration = beginRead?.() ?? ++nextReadGeneration.current;
397
+ const page2 = await client.listSessionPage(workspaceId, {
398
+ ...limit !== void 0 ? { limit } : {},
399
+ ...parentSessionId !== void 0 ? { parentSessionId } : {},
400
+ ...cursor !== void 0 ? { cursor } : {},
401
+ ...search !== void 0 ? { search } : {},
402
+ ...pinsOnly ? { pinsOnly: true } : {},
403
+ ...archivedOnly ? { archivedOnly: true } : {}
404
+ });
405
+ return {
393
406
  queryKey,
394
- page: await client.listSessionPage(workspaceId, {
395
- ...limit !== void 0 ? { limit } : {},
396
- ...parentSessionId !== void 0 ? { parentSessionId } : {},
397
- ...cursor !== void 0 ? { cursor } : {},
398
- ...search !== void 0 ? { search } : {},
399
- ...pinsOnly ? { pinsOnly: true } : {},
400
- ...archivedOnly ? { archivedOnly: true } : {}
401
- })
402
- }),
403
- [client, workspaceId, limit, parentSessionId, cursor, search, pinsOnly, archivedOnly, queryKey]
404
- );
407
+ page: page2,
408
+ revision: ++nextReadRevision.current,
409
+ readGeneration
410
+ };
411
+ }, [
412
+ beginRead,
413
+ client,
414
+ workspaceId,
415
+ limit,
416
+ parentSessionId,
417
+ cursor,
418
+ search,
419
+ pinsOnly,
420
+ archivedOnly,
421
+ queryKey
422
+ ]);
405
423
  const state = usePolledValue(load, {
406
424
  pollIntervalMs: options.pollIntervalMs,
407
425
  enabled
@@ -423,6 +441,8 @@ function useWorkspaceSessions(options = {}) {
423
441
  // announce a transient false zero-match result.
424
442
  loading: enabled && (state.loading || queryKeyTransition || state.data !== null && state.data.queryKey !== queryKey),
425
443
  error: state.error,
444
+ readRevision: page ? state.data?.revision ?? 0 : 0,
445
+ readGeneration: page ? state.data?.readGeneration ?? 0 : 0,
426
446
  refresh: state.refresh
427
447
  };
428
448
  }
@@ -4065,6 +4085,7 @@ function ChatComposer({
4065
4085
 
4066
4086
  // src/components/fleet-tile.tsx
4067
4087
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
4088
+ var AUTOMATIC_SESSION_TITLE_FALLBACK = "New conversation";
4068
4089
  function sessionDisplayTitle(session) {
4069
4090
  if (typeof session.title === "string" && session.title.trim().length > 0) {
4070
4091
  return session.title;
@@ -4075,7 +4096,7 @@ function sessionDisplayTitle(session) {
4075
4096
  return value;
4076
4097
  }
4077
4098
  }
4078
- return truncate(session.initialMessage, 100) || session.id.slice(0, 8);
4099
+ return AUTOMATIC_SESSION_TITLE_FALLBACK;
4079
4100
  }
4080
4101
  function FleetTile({ session, title, subtitle, onOpen, className }) {
4081
4102
  const running = session.status === "running" || session.status === "queued";
@@ -9527,6 +9548,7 @@ export {
9527
9548
  controlCaret,
9528
9549
  copyTextToClipboard,
9529
9550
  createDefaultToolRegistry,
9551
+ createOlderHistoryLoadReceipt,
9530
9552
  createToolRegistry,
9531
9553
  createVoiceRecordingManifest,
9532
9554
  creditExhaustedFromEvents,