@opengeni/react 6.1.0 → 7.0.0-canary.35585322809001

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 (206) hide show
  1. package/README.md +83 -2
  2. package/dist/artifacts-document.js +1 -1
  3. package/dist/artifacts-presentation.js +1 -1
  4. package/dist/artifacts-spreadsheet.js +1 -1
  5. package/dist/artifacts.js +3 -3
  6. package/dist/{browser-viewer-NTD6UIPR.js → browser-viewer-LGH4IP47.js} +3 -3
  7. package/dist/capability-catalog-row.d.ts +20 -0
  8. package/dist/capability-logo-fallback.d.ts +3 -0
  9. package/dist/{chunk-NOSYBS2D.js → chunk-2VHARTBL.js} +2 -1
  10. package/dist/{chunk-VRBL3F5E.js → chunk-5GAL23FF.js} +10 -2
  11. package/dist/{chunk-VRBL3F5E.js.map → chunk-5GAL23FF.js.map} +1 -1
  12. package/dist/chunk-5UONOQ3Y.js +635 -0
  13. package/dist/chunk-5UONOQ3Y.js.map +1 -0
  14. package/dist/{chunk-NYESIADM.js → chunk-AKOMC3VO.js} +3 -3
  15. package/dist/chunk-AKOMC3VO.js.map +1 -0
  16. package/dist/chunk-BRM6FVZA.js +302 -0
  17. package/dist/chunk-BRM6FVZA.js.map +1 -0
  18. package/dist/{chunk-TDSEILUH.js → chunk-D5NOQPLR.js} +1289 -1530
  19. package/dist/chunk-D5NOQPLR.js.map +1 -0
  20. package/dist/chunk-D7GAPJ3V.js +1558 -0
  21. package/dist/chunk-D7GAPJ3V.js.map +1 -0
  22. package/dist/{chunk-5M6VTFJ5.js → chunk-GBPCZH3Y.js} +2 -2
  23. package/dist/{chunk-YBM6CQRU.js → chunk-GEN54DU5.js} +4 -4
  24. package/dist/{chunk-UMECRJRV.js → chunk-HJ5VJ4JB.js} +21 -12
  25. package/dist/chunk-HJ5VJ4JB.js.map +1 -0
  26. package/dist/{chunk-R4KRSFGA.js → chunk-IP4BUBKH.js} +3 -3
  27. package/dist/{chunk-KANFU34B.js → chunk-IYUPN32E.js} +6 -2
  28. package/dist/chunk-IYUPN32E.js.map +1 -0
  29. package/dist/{chunk-L2NBTKRX.js → chunk-JKLGJQO5.js} +193 -12
  30. package/dist/chunk-JKLGJQO5.js.map +1 -0
  31. package/dist/{chunk-NLTS7JHI.js → chunk-JPHDWKZE.js} +5 -5
  32. package/dist/{chunk-ICA6R6TW.js → chunk-OWHPKAOV.js} +28 -20
  33. package/dist/chunk-OWHPKAOV.js.map +1 -0
  34. package/dist/{chunk-24M4YBCL.js → chunk-PNAVEK2U.js} +4 -4
  35. package/dist/{chunk-45XEUVTK.js → chunk-UXE5SSNN.js} +293 -463
  36. package/dist/chunk-UXE5SSNN.js.map +1 -0
  37. package/dist/{chunk-PEI6RANI.js → chunk-VR4Z73EU.js} +203 -9
  38. package/dist/chunk-VR4Z73EU.js.map +1 -0
  39. package/dist/{chunk-HUIKIDM5.js → chunk-XMXRI5JK.js} +65 -18
  40. package/dist/chunk-XMXRI5JK.js.map +1 -0
  41. package/dist/client.d.ts +1 -1
  42. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  43. package/dist/components/chat-composer.d.ts +13 -3
  44. package/dist/components/markdown.d.ts +4 -3
  45. package/dist/components/message-timeline.d.ts +7 -2
  46. package/dist/components/preview-loading.d.ts +2 -0
  47. package/dist/components/session-capability-frame.d.ts +24 -0
  48. package/dist/components/session-chrome.d.ts +1 -2
  49. package/dist/components/session-commands.d.ts +6 -0
  50. package/dist/components/session-connection-request.d.ts +8 -0
  51. package/dist/components/session-mcp-capability-card.d.ts +22 -0
  52. package/dist/components/timeline-search.d.ts +34 -0
  53. package/dist/composer.js +7 -7
  54. package/dist/connect-account-identity.d.ts +8 -0
  55. package/dist/connect-accounts.d.ts +5 -0
  56. package/dist/connect-chooser.d.ts +6 -0
  57. package/dist/connect-panel.d.ts +9 -2
  58. package/dist/connect-setup.d.ts +5 -1
  59. package/dist/connect.d.ts +5 -21
  60. package/dist/connect.js +1268 -584
  61. package/dist/connect.js.map +1 -1
  62. package/dist/connection-catalog.d.ts +6 -1
  63. package/dist/connection-discovery.d.ts +12 -0
  64. package/dist/connection-installed.d.ts +1 -0
  65. package/dist/connection-logo.d.ts +5 -2
  66. package/dist/connection-service-logo.d.ts +8 -0
  67. package/dist/connection-service-presentation.d.ts +13 -0
  68. package/dist/connection-skeleton.d.ts +5 -0
  69. package/dist/discovery-cache.d.ts +5 -0
  70. package/dist/hooks/use-codex-accounts.d.ts +11 -5
  71. package/dist/hooks/use-connect.d.ts +22 -0
  72. package/dist/hooks/use-session-events.d.ts +5 -0
  73. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  74. package/dist/hooks/use-workspace-sessions.d.ts +2 -0
  75. package/dist/index.d.ts +8 -2
  76. package/dist/index.js +771 -793
  77. package/dist/index.js.map +1 -1
  78. package/dist/interaction.js +2 -2
  79. package/dist/machines.js +2 -2
  80. package/dist/mcp-connection-status.d.ts +14 -0
  81. package/dist/{model-policy-picker-menu-3R336DP2.js → model-policy-picker-menu-RVOQ4ZZG.js} +4 -4
  82. package/dist/model-policy.d.ts +6 -2
  83. package/dist/model-policy.js +1 -1
  84. package/dist/{platform-activity-row-DUE2W74J.js → platform-activity-row-HLOH7FW4.js} +9 -4
  85. package/dist/platform-activity-row-HLOH7FW4.js.map +1 -0
  86. package/dist/plugin-discovery.d.ts +6 -0
  87. package/dist/{queue-surface-implementation-LK3S4BIW.js → queue-surface-implementation-3RIFK2BS.js} +4 -4
  88. package/dist/realtime.js +22 -22
  89. package/dist/realtime.js.map +1 -1
  90. package/dist/session-auth-recommendation.d.ts +5 -0
  91. package/dist/session-capability-policy.d.ts +12 -0
  92. package/dist/session-ui.d.ts +2 -0
  93. package/dist/session-ui.js +14 -12
  94. package/dist/session.d.ts +1 -0
  95. package/dist/session.js +6 -4
  96. package/dist/skill-discovery.d.ts +11 -0
  97. package/dist/timeline/compaction-copy.d.ts +10 -0
  98. package/dist/timeline/projection.d.ts +3 -1
  99. package/dist/timeline/turn-summary.d.ts +2 -2
  100. package/dist/timeline/types.d.ts +22 -1
  101. package/dist/{timeline-annotation-markers-DRSTLEM6.js → timeline-annotation-markers-OY6OWR3V.js} +2 -2
  102. package/dist/{timeline-annotation-selection-IHLUGVND.js → timeline-annotation-selection-BOXA2TIN.js} +2 -2
  103. package/dist/{timeline-annotations-dialog-6Q53N5FG.js → timeline-annotations-dialog-RGY3MHL3.js} +3 -3
  104. package/package.json +3 -3
  105. package/src/assets/README.md +8 -0
  106. package/src/assets/gmail.ico +0 -0
  107. package/src/assets/outlook.ico +0 -0
  108. package/src/capability-catalog-row.tsx +94 -0
  109. package/src/capability-logo-fallback.ts +22 -0
  110. package/src/client.ts +0 -9
  111. package/src/components/artifacts/document-editor.tsx +63 -6
  112. package/src/components/artifacts/presentation-editor.tsx +214 -9
  113. package/src/components/artifacts/spreadsheet-canvas.ts +3 -8
  114. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  115. package/src/components/artifacts/spreadsheet-grid.tsx +10 -11
  116. package/src/components/chat-composer.tsx +26 -3
  117. package/src/components/composer.tsx +10 -4
  118. package/src/components/human-input-form.tsx +12 -2
  119. package/src/components/markdown.tsx +86 -4
  120. package/src/components/message-timeline.tsx +104 -36
  121. package/src/components/model-picker.tsx +11 -3
  122. package/src/components/model-policy-picker-menu.tsx +10 -3
  123. package/src/components/preview-loading.tsx +154 -0
  124. package/src/components/sandbox-workspace.tsx +20 -36
  125. package/src/components/session-capability-frame.tsx +163 -0
  126. package/src/components/session-chrome.tsx +46 -77
  127. package/src/components/session-commands.tsx +18 -0
  128. package/src/components/session-connection-request.tsx +97 -0
  129. package/src/components/session-conversation.tsx +5 -4
  130. package/src/components/session-mcp-capability-card.tsx +532 -0
  131. package/src/components/session-status.tsx +2 -2
  132. package/src/components/timeline-anchor.tsx +9 -8
  133. package/src/components/timeline-search.tsx +168 -0
  134. package/src/components/user-message-body.tsx +7 -0
  135. package/src/connect-account-identity.tsx +34 -0
  136. package/src/connect-accounts.tsx +114 -52
  137. package/src/connect-chooser.tsx +171 -39
  138. package/src/connect-panel.tsx +73 -9
  139. package/src/connect-setup.tsx +72 -25
  140. package/src/connect.ts +13 -22
  141. package/src/connection-assets.d.ts +4 -0
  142. package/src/connection-catalog.tsx +61 -39
  143. package/src/connection-discovery.tsx +235 -0
  144. package/src/connection-installed.tsx +2 -0
  145. package/src/connection-logo.tsx +18 -10
  146. package/src/connection-service-logo.tsx +55 -0
  147. package/src/connection-service-presentation.ts +46 -0
  148. package/src/connection-skeleton.tsx +16 -0
  149. package/src/conversation-timeline.ts +1 -0
  150. package/src/discovery-cache.ts +42 -0
  151. package/src/hooks/use-codex-accounts.ts +33 -14
  152. package/src/hooks/use-composer.ts +4 -5
  153. package/src/hooks/use-connect.ts +23 -0
  154. package/src/hooks/use-session-events.ts +114 -1
  155. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  156. package/src/hooks/use-workspace-sessions.ts +10 -0
  157. package/src/index.ts +22 -2
  158. package/src/mcp-connection-status.ts +35 -0
  159. package/src/model-policy.ts +21 -0
  160. package/src/plugin-details.tsx +8 -5
  161. package/src/plugin-discovery.tsx +92 -72
  162. package/src/realtime/realtime-control.tsx +6 -8
  163. package/src/session-auth-recommendation.ts +48 -0
  164. package/src/session-capability-policy.ts +83 -0
  165. package/src/session-ui.ts +2 -0
  166. package/src/session.ts +1 -0
  167. package/src/skill-discovery.tsx +101 -56
  168. package/src/timeline/compaction-copy.ts +40 -0
  169. package/src/timeline/platform-activity-row.tsx +8 -3
  170. package/src/timeline/projection.ts +74 -2
  171. package/src/timeline/shared.tsx +6 -1
  172. package/src/timeline/startup-timings.tsx +1 -1
  173. package/src/timeline/turn-summary.tsx +17 -3
  174. package/src/timeline/types.ts +22 -2
  175. package/styles/compiled.css +325 -27
  176. package/styles/connect.css +90 -15
  177. package/styles/index.css +46 -0
  178. package/styles/session-capability.css +42 -0
  179. package/dist/chunk-45XEUVTK.js.map +0 -1
  180. package/dist/chunk-HQV2I5HV.js +0 -124
  181. package/dist/chunk-HQV2I5HV.js.map +0 -1
  182. package/dist/chunk-HUIKIDM5.js.map +0 -1
  183. package/dist/chunk-ICA6R6TW.js.map +0 -1
  184. package/dist/chunk-IHQII5WO.js +0 -886
  185. package/dist/chunk-IHQII5WO.js.map +0 -1
  186. package/dist/chunk-KANFU34B.js.map +0 -1
  187. package/dist/chunk-L2NBTKRX.js.map +0 -1
  188. package/dist/chunk-NYESIADM.js.map +0 -1
  189. package/dist/chunk-PEI6RANI.js.map +0 -1
  190. package/dist/chunk-TDSEILUH.js.map +0 -1
  191. package/dist/chunk-UMECRJRV.js.map +0 -1
  192. package/dist/hooks/use-packs.d.ts +0 -32
  193. package/dist/platform-activity-row-DUE2W74J.js.map +0 -1
  194. package/src/hooks/use-packs.ts +0 -157
  195. /package/dist/{browser-viewer-NTD6UIPR.js.map → browser-viewer-LGH4IP47.js.map} +0 -0
  196. /package/dist/{chunk-NOSYBS2D.js.map → chunk-2VHARTBL.js.map} +0 -0
  197. /package/dist/{chunk-5M6VTFJ5.js.map → chunk-GBPCZH3Y.js.map} +0 -0
  198. /package/dist/{chunk-YBM6CQRU.js.map → chunk-GEN54DU5.js.map} +0 -0
  199. /package/dist/{chunk-R4KRSFGA.js.map → chunk-IP4BUBKH.js.map} +0 -0
  200. /package/dist/{chunk-NLTS7JHI.js.map → chunk-JPHDWKZE.js.map} +0 -0
  201. /package/dist/{chunk-24M4YBCL.js.map → chunk-PNAVEK2U.js.map} +0 -0
  202. /package/dist/{model-policy-picker-menu-3R336DP2.js.map → model-policy-picker-menu-RVOQ4ZZG.js.map} +0 -0
  203. /package/dist/{queue-surface-implementation-LK3S4BIW.js.map → queue-surface-implementation-3RIFK2BS.js.map} +0 -0
  204. /package/dist/{timeline-annotation-markers-DRSTLEM6.js.map → timeline-annotation-markers-OY6OWR3V.js.map} +0 -0
  205. /package/dist/{timeline-annotation-selection-IHLUGVND.js.map → timeline-annotation-selection-BOXA2TIN.js.map} +0 -0
  206. /package/dist/{timeline-annotations-dialog-6Q53N5FG.js.map → timeline-annotations-dialog-RGY3MHL3.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/embedded-session-client.ts","../src/hooks/use-file-attachments.ts","../src/hooks/use-goal.ts","../src/hooks/use-session-control.ts","../src/hooks/use-session-mcp-approval-policy.ts","../src/hooks/use-session-lineage.ts","../src/approvals.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 type { FileAsset, FileResourceRef } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n useEmbeddedFileAttachments,\n type EmbeddedFileAttachmentClientOverride,\n} from \"../session-context\";\n\nexport type UseFileAttachmentsOptions = EmbeddedFileAttachmentClientOverride & {\n /**\n * Only files matching this predicate are accepted by {@link\n * UseFileAttachmentsResult.addFromPaste} (the clipboard path). Defaults to\n * `image/*` — the console's historical paste filter. {@link\n * UseFileAttachmentsResult.addFiles} (the explicit picker / drop path)\n * bypasses it.\n */\n /** Retain original uploads in the chat owner’s personal scope when private. */\n scope?: \"workspace\" | \"personal\";\n pasteFilter?: ((file: File) => boolean) | undefined;\n};\n\nexport type FileAttachment = {\n id: string;\n name: string;\n contentType: string;\n sizeBytes: number;\n status: \"uploading\" | \"ready\" | \"failed\";\n /** The SDK `FileAsset` once the upload finishes. */\n file?: FileAsset | undefined;\n /** Object-URL for an inline preview; minted for `image/*` files only. */\n previewUrl?: string | undefined;\n /** Stable SDK failure code for UI behavior that must not parse error copy. */\n errorCode?: \"secure_context_required\" | undefined;\n error?: string | undefined;\n};\n\nexport type UseFileAttachmentsResult = {\n attachments: FileAttachment[];\n /**\n * `FileResourceRef[]` for every attachment that finished uploading — feed\n * straight into `useComposer`'s `sendExtras.resources`.\n */\n readyResources: FileResourceRef[];\n /** True while any attachment is still uploading (drives progress UI). */\n uploading: boolean;\n /**\n * True while any attachment still needs an explicit outcome: wait for an\n * upload, retry a failure, or remove it. This is the loss-prevention send\n * gate; failed cards must never be silently omitted from a message.\n */\n hasUnresolved: boolean;\n /** Explicit picker / drop path — uploads every file, no filter. */\n addFiles: (files: Iterable<File>) => void;\n /** Clipboard path — applies `pasteFilter` (default `image/*`) then uploads. */\n addFromPaste: (event: { clipboardData: DataTransfer | null }) => void;\n /** Restore already-ready server assets without recreating browser-local bytes. */\n restoreReadyFiles: (files: Iterable<FileAsset>) => void;\n /**\n * Resolve a ready image's short-lived server preview URL on demand. Optional\n * for upload-only embedded clients; local object-URL previews remain usable\n * without it.\n */\n loadPreview?: ((id: string, signal?: AbortSignal) => Promise<string | undefined>) | undefined;\n /**\n * Re-run the upload for a `failed` attachment, in place (same id, same\n * source file). No-op for an id that isn't a known failed upload.\n */\n retry: (id: string) => void;\n /**\n * Keep an attachment's object-URL alive for a consumer that outlives its\n * queue entry (for example, an open route-level lightbox). The returned\n * release is idempotent; pending revocation finishes after the last holder\n * releases. Returns `undefined` when the attachment has no local preview.\n */\n retainPreview: (id: string) => (() => void) | undefined;\n /** Remove one attachment; revokes its object-URL after retained users finish. */\n remove: (id: string) => void;\n /**\n * Remove only finalized files whose durable ids were accepted by a send.\n * Attachments added while that request was in flight remain queued for the\n * next message.\n */\n removeReadyFiles: (fileIds: Iterable<string>) => void;\n /** Remove all attachments and revoke every unretained object-URL. */\n clear: () => void;\n};\n\nconst isImage = (file: File): boolean => file.type.startsWith(\"image/\");\n\nlet fallbackAttachmentId = 0;\n\nfunction createAttachmentId(): string {\n const cryptoSource = globalThis.crypto;\n if (typeof cryptoSource?.randomUUID === \"function\") return cryptoSource.randomUUID();\n fallbackAttachmentId += 1;\n // This id is only a browser-local React key and retry lookup, never durable\n // authority. Keep attachment tracking usable when HTTP withholds randomUUID\n // or Web Crypto is unavailable so the SDK's typed failure reaches the card.\n return `attachment:${Date.now().toString(36)}:${fallbackAttachmentId.toString(36)}`;\n}\n\nfunction secureContextRequiredErrorCode(error: unknown): \"secure_context_required\" | undefined {\n return typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"secure_context_required\"\n ? error.code\n : undefined;\n}\n\n/**\n * Upload-and-track state for files attached to the next message. Owns the\n * full client-side upload layer: a per-file `uploading | ready | failed`\n * status machine driven by the SDK's `client.uploadFile`, object-URL image\n * previews with create/revoke lifecycle, the `image/*` clipboard paste filter,\n * and a `FileResourceRef[]` projection that drops straight into a message's\n * `resources`. Workspace-scoped, so it resolves both client and workspace from\n * the {@link OpenGeniProvider} (or a per-call `{ client, workspaceId }`).\n */\nexport function useFileAttachments(\n options: UseFileAttachmentsOptions = {},\n): UseFileAttachmentsResult {\n const { client, workspaceId } = useEmbeddedFileAttachments(options);\n const pasteFilter = options.pasteFilter ?? isImage;\n const [attachments, setAttachments] = useState<FileAttachment[]>([]);\n const attachmentsRef = useRef(attachments);\n attachmentsRef.current = attachments;\n // Keep the source File per attachment id so a failed upload can be retried\n // in place. Cleared on remove/clear so it never outlives its attachment.\n const sources = useRef<Map<string, File>>(new Map());\n // Object URLs must be owned synchronously: React may discard an attachment\n // state update when its component unmounts in the same batch that minted the\n // preview. The registry remains available to cleanup even before a render.\n const previewUrls = useRef<Map<string, string>>(new Map());\n const previewRetainers = useRef<Map<string, number>>(new Map());\n const pendingPreviewRevocations = useRef<Set<string>>(new Set());\n const revokePreview = useCallback((id: string) => {\n const previewUrl = previewUrls.current.get(id);\n if (!previewUrl) return;\n if ((previewRetainers.current.get(id) ?? 0) > 0) {\n pendingPreviewRevocations.current.add(id);\n return;\n }\n previewUrls.current.delete(id);\n pendingPreviewRevocations.current.delete(id);\n URL.revokeObjectURL(previewUrl);\n }, []);\n const revokeAllPreviews = useCallback(() => {\n for (const id of previewUrls.current.keys()) revokePreview(id);\n }, [revokePreview]);\n const retainPreview = useCallback(\n (id: string): (() => void) | undefined => {\n if (!previewUrls.current.has(id)) return undefined;\n previewRetainers.current.set(id, (previewRetainers.current.get(id) ?? 0) + 1);\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const remaining = (previewRetainers.current.get(id) ?? 1) - 1;\n if (remaining > 0) {\n previewRetainers.current.set(id, remaining);\n return;\n }\n previewRetainers.current.delete(id);\n if (pendingPreviewRevocations.current.has(id)) revokePreview(id);\n };\n },\n [revokePreview],\n );\n // Ready-file reconciliation uses functional state updaters, which React may\n // evaluate during a concurrent render that later suspends or is abandoned.\n // Diff only committed attachment sets here so URL revocation cannot run from\n // render-phase code while the previously committed DOM still uses a preview.\n const committedAttachmentIds = useRef<Set<string>>(new Set());\n useEffect(() => {\n const currentIds = new Set(attachments.map((attachment) => attachment.id));\n for (const id of committedAttachmentIds.current) {\n if (!currentIds.has(id)) revokePreview(id);\n }\n committedAttachmentIds.current = currentIds;\n }, [attachments, revokePreview]);\n // Upload promises are not cancellable at this layer. Fence their settlements\n // when the hook changes client/workspace or unmounts so an old tenant/session\n // cannot mutate the next attachment queue (or an already-unmounted component).\n const scopeGeneration = useRef(0);\n const previousScope = useRef({ client, workspaceId });\n\n useEffect(() => {\n const previous = previousScope.current;\n if (previous.client === client && previous.workspaceId === workspaceId) return;\n previousScope.current = { client, workspaceId };\n scopeGeneration.current += 1;\n sources.current.clear();\n revokeAllPreviews();\n setAttachments([]);\n }, [client, revokeAllPreviews, workspaceId]);\n\n useEffect(\n () => () => {\n scopeGeneration.current += 1;\n sources.current.clear();\n revokeAllPreviews();\n },\n [revokeAllPreviews],\n );\n\n // Run (or re-run) the upload for one already-tracked attachment id. Sets it\n // back to `uploading`, then resolves to `ready` (with the asset) or `failed`\n // (with the error message).\n const startUpload = useCallback(\n (id: string, file: File) => {\n const generation = scopeGeneration.current;\n void client\n .uploadFile(workspaceId, {\n filename: file.name || \"file\",\n contentType: file.type || \"application/octet-stream\",\n data: file,\n ...(options.scope ? { scope: options.scope } : {}),\n })\n .then((asset) => {\n if (scopeGeneration.current !== generation) return;\n // Retry bytes are useful only until durable finalization succeeds.\n // Drop the source File immediately; restored/ready attachments must\n // never retain browser-local byte authority.\n sources.current.delete(id);\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? {\n ...attachment,\n status: \"ready\",\n file: asset,\n name: asset.filename,\n contentType: asset.contentType,\n sizeBytes: asset.sizeBytes,\n errorCode: undefined,\n error: undefined,\n }\n : attachment,\n ),\n );\n })\n .catch((error: unknown) => {\n if (scopeGeneration.current !== generation) return;\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? {\n ...attachment,\n status: \"failed\",\n errorCode: secureContextRequiredErrorCode(error),\n error: error instanceof Error ? error.message : String(error),\n }\n : attachment,\n ),\n );\n });\n },\n [client, workspaceId, options.scope],\n );\n\n const addFiles = useCallback(\n (files: Iterable<File>) => {\n for (const file of files) {\n const id = createAttachmentId();\n sources.current.set(id, file);\n const previewUrl = isImage(file) ? URL.createObjectURL(file) : undefined;\n if (previewUrl) previewUrls.current.set(id, previewUrl);\n setAttachments((current) => [\n ...current,\n {\n id,\n name: file.name || \"image\",\n contentType: file.type || \"application/octet-stream\",\n sizeBytes: file.size,\n status: \"uploading\",\n ...(previewUrl ? { previewUrl } : {}),\n },\n ]);\n startUpload(id, file);\n }\n },\n [startUpload],\n );\n\n const retry = useCallback(\n (id: string) => {\n const file = sources.current.get(id);\n if (!file) {\n return;\n }\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? { ...attachment, status: \"uploading\", errorCode: undefined, error: undefined }\n : attachment,\n ),\n );\n startUpload(id, file);\n },\n [startUpload],\n );\n\n const addFromPaste = useCallback(\n (event: { clipboardData: DataTransfer | null }) => {\n const clipboardFiles = event.clipboardData?.files;\n if (!clipboardFiles) {\n return;\n }\n const files = [...clipboardFiles].filter(pasteFilter);\n if (files.length > 0) {\n addFiles(files);\n }\n },\n [addFiles, pasteFilter],\n );\n\n const restoreReadyFiles = useCallback(\n (files: Iterable<FileAsset>) => {\n const incoming = new Map<string, FileAsset>();\n for (const file of files) {\n if (file.status === \"ready\" && file.workspaceId === workspaceId) {\n incoming.set(file.id, file);\n }\n }\n setAttachments((current) => {\n const unresolved = current.filter((attachment) => attachment.status !== \"ready\");\n const existingReady = new Map(\n current.flatMap((attachment) =>\n attachment.status === \"ready\" && attachment.file\n ? ([[attachment.file.id, attachment]] as const)\n : [],\n ),\n );\n const restored = [...incoming.values()].map((file): FileAttachment => {\n const existing = existingReady.get(file.id);\n return existing\n ? {\n ...existing,\n name: file.filename,\n contentType: file.contentType,\n sizeBytes: file.sizeBytes,\n status: \"ready\",\n file,\n errorCode: undefined,\n error: undefined,\n }\n : {\n id: `restored:${file.id}`,\n name: file.filename,\n contentType: file.contentType,\n sizeBytes: file.sizeBytes,\n status: \"ready\",\n file,\n // No source File and no object URL: server metadata is the\n // only authority restored across page/device boundaries.\n };\n });\n // A server restoration is authoritative for finalized assets, but an\n // upload that has not finalized still belongs to the local actor. Keep\n // those unresolved entries while replacing the ready set exactly.\n return [...unresolved, ...restored];\n });\n },\n [workspaceId],\n );\n\n const loadPreview = useCallback(\n async (id: string, signal?: AbortSignal): Promise<string | undefined> => {\n const generation = scopeGeneration.current;\n const attachment = attachmentsRef.current.find((candidate) => candidate.id === id);\n const createDownloadUrl = client.createFileDownloadUrl;\n if (\n !attachment ||\n attachment.status !== \"ready\" ||\n !attachment.file ||\n !attachment.contentType.startsWith(\"image/\") ||\n typeof createDownloadUrl !== \"function\" ||\n signal?.aborted\n ) {\n return undefined;\n }\n const fileId = attachment.file.id;\n const signed = await createDownloadUrl.call(client, workspaceId, fileId, { signal });\n if (scopeGeneration.current !== generation || signal?.aborted) return undefined;\n const current = attachmentsRef.current.find((candidate) => candidate.id === id);\n if (current?.status !== \"ready\" || current.file?.id !== fileId) return undefined;\n return signed.url;\n },\n [client, workspaceId],\n );\n\n const remove = useCallback(\n (id: string) => {\n sources.current.delete(id);\n revokePreview(id);\n setAttachments((current) => current.filter((attachment) => attachment.id !== id));\n },\n [revokePreview],\n );\n\n const removeReadyFiles = useCallback((fileIds: Iterable<string>) => {\n const accepted = new Set(fileIds);\n if (accepted.size === 0) return;\n setAttachments((current) =>\n current.filter((attachment) => {\n return !(\n attachment.status === \"ready\" &&\n attachment.file !== undefined &&\n accepted.has(attachment.file.id)\n );\n }),\n );\n }, []);\n\n const clear = useCallback(() => {\n sources.current.clear();\n revokeAllPreviews();\n setAttachments([]);\n }, [revokeAllPreviews]);\n\n return {\n attachments,\n readyResources: attachments.flatMap((attachment): FileResourceRef[] =>\n attachment.status === \"ready\" && attachment.file\n ? [{ kind: \"file\", fileId: attachment.file.id }]\n : [],\n ),\n uploading: attachments.some((attachment) => attachment.status === \"uploading\"),\n hasUnresolved: attachments.some((attachment) => attachment.status !== \"ready\"),\n addFiles,\n addFromPaste,\n restoreReadyFiles,\n ...(typeof client.createFileDownloadUrl === \"function\" ? { loadPreview } : {}),\n retry,\n retainPreview,\n remove,\n removeReadyFiles,\n clear,\n };\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 {\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(cause instanceof Error ? cause : new Error(String(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 { SessionControlResponse, SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback, useLayoutEffect, useRef } from \"react\";\nimport { useEmbeddedSession, type EmbeddedSessionClientOverride } from \"../session-context\";\nimport { useMutationRunner } from \"./internal\";\n\nexport type UseSessionControlOptions = EmbeddedSessionClientOverride;\n\nexport type UseSessionControlResult = {\n pause: (reason?: string) => Promise<SessionControlResponse | null>;\n resume: (reason?: string) => Promise<SessionControlResponse | null>;\n controlling: boolean;\n /** Approve a pending `requires_action` approval. */\n approve: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** Reject a pending `requires_action` approval. */\n reject: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** True while an approval decision is in flight. */\n responding: boolean;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Session pause/resume and approval decisions. Pair with\n * `useSessionEvents` (for `session.requiresAction` payloads carrying the\n * `approvalId`) to render an approval bar.\n */\nexport function useSessionControl(\n sessionId: string | null | undefined,\n options: UseSessionControlOptions = {},\n): UseSessionControlResult {\n const { client, workspaceId } = useEmbeddedSession(options);\n const approvalTargetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n const pendingApproval = useRef<{\n targetKey: string;\n decisionKey: string;\n clientEventId: string;\n } | null>(null);\n useLayoutEffect(() => {\n if (pendingApproval.current?.targetKey !== approvalTargetKey) {\n pendingApproval.current = null;\n }\n }, [approvalTargetKey]);\n const {\n run: runControl,\n mutating: controlling,\n mutationError: controlError,\n clearMutationError: clearControlError,\n } = useMutationRunner(approvalTargetKey);\n const {\n run: runApproval,\n mutating: responding,\n mutationError: approvalError,\n clearMutationError: clearApprovalError,\n } = useMutationRunner(approvalTargetKey);\n\n const pause = useCallback(\n async (reason?: string): Promise<SessionControlResponse | null> => {\n if (!sessionId) {\n return null;\n }\n return await runControl(() =>\n client.pauseSession(workspaceId, sessionId, reason !== undefined ? { reason } : {}),\n );\n },\n [client, workspaceId, sessionId, runControl],\n );\n\n const resume = useCallback(\n async (reason?: string): Promise<SessionControlResponse | null> => {\n if (!sessionId) return null;\n return await runControl(() =>\n client.resumeSession(workspaceId, sessionId, reason !== undefined ? { reason } : {}),\n );\n },\n [client, workspaceId, sessionId, runControl],\n );\n\n const decide = useCallback(\n async (\n approvalId: string,\n decision: \"approve\" | \"reject\",\n message?: string,\n ): Promise<SessionEvent | null> => {\n if (!sessionId) {\n return null;\n }\n const decisionKey = JSON.stringify([approvalId, decision, message ?? null]);\n if (pendingApproval.current?.decisionKey !== decisionKey) {\n pendingApproval.current = {\n targetKey: approvalTargetKey,\n decisionKey,\n clientEventId: crypto.randomUUID(),\n };\n }\n const clientEventId = pendingApproval.current.clientEventId;\n const accepted = await runApproval(() =>\n client.sendApprovalDecision(workspaceId, sessionId, {\n approvalId,\n decision,\n ...(message !== undefined ? { message } : {}),\n clientEventId,\n }),\n );\n if (\n accepted !== null &&\n pendingApproval.current?.targetKey === approvalTargetKey &&\n pendingApproval.current.clientEventId === clientEventId\n ) {\n pendingApproval.current = null;\n }\n return accepted;\n },\n [approvalTargetKey, client, workspaceId, sessionId, runApproval],\n );\n\n const approve = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"approve\", message),\n [decide],\n );\n const reject = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"reject\", message),\n [decide],\n );\n\n const error = approvalError ?? controlError;\n const clearError = useCallback(() => {\n clearControlError();\n clearApprovalError();\n }, [clearControlError, clearApprovalError]);\n\n return {\n pause,\n resume,\n controlling,\n approve,\n reject,\n responding,\n error,\n clearError,\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","import type { SessionEvent } from \"@opengeni/sdk\";\n\n/* ----------------------------------------------------------------------------\n Pending-approvals projection\n\n `session.requiresAction` events live forever in the durable log, so a\n console that replays the log from sequence 0 must not render every\n historical approval as actionable. `projectPendingApprovals` folds the\n ordered event log into the approvals that are still undecided *now*:\n\n - `session.requiresAction` replaces the pending set with the payload's\n approvals (the producer always emits the full currently-pending set, so\n re-emission after a worker re-dispatch cannot duplicate cards);\n - `user.approvalDecision` subtracts the decided approval;\n - the owning turn finishing (`turn.completed`/`turn.failed`/\n `turn.cancelled`) clears the set — whatever was pending died with the\n turn. A `turn.cancelled` for a *different* turn (deleting a queued turn\n while the session waits on an approval) leaves the set alone.\n\n Pure function — same events in, same approvals out — so approve-then-reload\n projects to an empty set instead of a zombie Approve button.\n -------------------------------------------------------------------------- */\n\nexport type PendingApproval = {\n /** The id to send back via `user.approvalDecision` (`approvalId`). */\n id: string;\n /** Tool/function name awaiting the decision. */\n name: string;\n arguments?: unknown;\n /** The raw approval entry from the `session.requiresAction` payload. */\n raw?: unknown;\n};\n\n/** The approvals carried by one `session.requiresAction` payload. */\nexport function approvalsFromRequiresAction(payload: unknown): PendingApproval[] {\n const approvals =\n payload && typeof payload === \"object\"\n ? (payload as { approvals?: unknown }).approvals\n : undefined;\n if (!Array.isArray(approvals)) {\n return [];\n }\n return approvals.map((approval, index) => {\n const raw = (approval && typeof approval === \"object\" ? approval : {}) as Record<\n string,\n unknown\n >;\n const rawItem =\n raw.rawItem && typeof raw.rawItem === \"object\"\n ? (raw.rawItem as Record<string, unknown>)\n : {};\n return {\n // Mirror the runtime's canonical interruption identity before retaining\n // the legacy top-level callId fallback for already-normalized payloads.\n id: String(rawItem.callId ?? rawItem.id ?? raw.id ?? raw.callId ?? raw.name ?? index),\n name: String(raw.name ?? raw.toolName ?? rawItem.name ?? \"approval\"),\n arguments: raw.arguments ?? rawItem.arguments,\n raw: approval,\n };\n });\n}\n\n/** The approvals still awaiting a decision after replaying `events` in order. */\nexport function projectPendingApprovals(events: SessionEvent[]): PendingApproval[] {\n let pending: PendingApproval[] = [];\n let owningTurnId: string | null = null;\n for (const event of events) {\n switch (event.type) {\n case \"session.requiresAction\": {\n pending = approvalsFromRequiresAction(event.payload);\n owningTurnId = event.turnId ?? null;\n break;\n }\n case \"user.approvalDecision\": {\n const payload =\n event.payload && typeof event.payload === \"object\"\n ? (event.payload as { approvalId?: unknown })\n : {};\n if (typeof payload.approvalId === \"string\") {\n pending = pending.filter((approval) => approval.id !== payload.approvalId);\n }\n break;\n }\n case \"turn.completed\":\n case \"turn.failed\":\n case \"turn.cancelled\": {\n // Scope clearing to the turn that raised the approvals when both\n // sides carry a turn id; clear conservatively when either is unknown.\n if (owningTurnId === null || event.turnId == null || event.turnId === owningTurnId) {\n pending = [];\n owningTurnId = null;\n }\n break;\n }\n default:\n break;\n }\n }\n return pending;\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useRef","useRef","useCallback","useCallback","useEffect","useLayoutEffect","useRef","useState","useState","useRef","useLayoutEffect","useCallback","server","useEffect","useCallback","useEffect","useRef","useRef","useCallback","useEffect"]}
@@ -1,9 +1,3 @@
1
- import {
2
- CREDIT_EXHAUSTION_MESSAGE,
3
- isCreditExhaustion,
4
- presentFailure,
5
- tryParseJson
6
- } from "./chunk-PLYRL5ER.js";
7
1
  import {
8
2
  useDebouncedCallback,
9
3
  useMutationRunner,
@@ -11,6 +5,12 @@ import {
11
5
  usePolledValue,
12
6
  useSessionEventTrigger
13
7
  } from "./chunk-KZ73RL76.js";
8
+ import {
9
+ CREDIT_EXHAUSTION_MESSAGE,
10
+ isCreditExhaustion,
11
+ presentFailure,
12
+ tryParseJson
13
+ } from "./chunk-PLYRL5ER.js";
14
14
  import {
15
15
  useEmbeddedHumanInputSession,
16
16
  useEmbeddedSession,
@@ -408,10 +408,13 @@ function timelineAnnotationToolOutputText(output) {
408
408
  const text = (marker >= 0 ? raw.slice(marker + "\nOutput:\n".length) : raw.startsWith("Output:\n") ? raw.slice("Output:\n".length) : raw).replace(TIMELINE_ANNOTATION_ANSI_SEQUENCE, "");
409
409
  return text.length > 0 ? text : null;
410
410
  }
411
- function buildTimeline(events) {
411
+ function buildTimeline(events, options = {}) {
412
412
  const items = [];
413
413
  const prescan = prescanTurnAnchors(events);
414
414
  const ordered = orderTimelineEvents(events, prescan);
415
+ let completeHistoryPrefix = options.partialStart !== true;
416
+ const knownMessagePrefixTurns = /* @__PURE__ */ new Set();
417
+ const incompleteMessageKeys = /* @__PURE__ */ new Set();
415
418
  const pendingWaitOutcomeByTurn = /* @__PURE__ */ new Map();
416
419
  const latestAgentResponseByTurn = /* @__PURE__ */ new Map();
417
420
  const identifiedMessages = /* @__PURE__ */ new Map();
@@ -529,6 +532,11 @@ function buildTimeline(events) {
529
532
  for (const event of ordered) {
530
533
  const payload = asRecord2(event.payload);
531
534
  const turnId = event.turnId ?? null;
535
+ if (event.type === "session.created") {
536
+ completeHistoryPrefix = true;
537
+ } else if (event.type === "turn.started" || event.type === "user.message" && payload.delivery !== "steer" && payload.routing !== "accepted_for_steering") {
538
+ knownMessagePrefixTurns.add(turnId);
539
+ }
532
540
  startupEvent = event;
533
541
  startupTurnId = turnId;
534
542
  startupAttemptId = (typeof event.turnAttemptId === "string" ? event.turnAttemptId : null) ?? stringValue(payload.attemptId);
@@ -618,6 +626,10 @@ function buildTimeline(events) {
618
626
  }
619
627
  const messageId = stringValue(payload.messageId);
620
628
  const messageKey = messageId ? JSON.stringify([turnId, messageId]) : null;
629
+ if (!completeHistoryPrefix && !knownMessagePrefixTurns.has(turnId) || messageKey && incompleteMessageKeys.has(messageKey)) {
630
+ if (messageKey) incompleteMessageKeys.add(messageKey);
631
+ break;
632
+ }
621
633
  const identified = messageKey ? identifiedMessages.get(messageKey) : void 0;
622
634
  if (identified) {
623
635
  if (identified.annotationSource?.eventType !== "agent.message.completed") {
@@ -657,6 +669,7 @@ function buildTimeline(events) {
657
669
  break;
658
670
  }
659
671
  case "agent.message.completed": {
672
+ knownMessagePrefixTurns.add(turnId);
660
673
  const text = stringValue(payload.text);
661
674
  const messageId = stringValue(payload.messageId);
662
675
  const messageKey = messageId ? JSON.stringify([turnId, messageId]) : null;
@@ -984,6 +997,7 @@ ${message}` : message;
984
997
  estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
985
998
  estimatedTokensAfter: null,
986
999
  skipReason: null,
1000
+ providerRejection: null,
987
1001
  implementation: typeof payload.implementation === "string" ? payload.implementation : null,
988
1002
  occurredAt: event.occurredAt
989
1003
  });
@@ -999,6 +1013,7 @@ ${message}` : message;
999
1013
  estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
1000
1014
  estimatedTokensAfter: numberOrNull(payload.estimatedTokensAfter),
1001
1015
  skipReason: null,
1016
+ providerRejection: null,
1002
1017
  implementation: typeof payload.implementation === "string" ? payload.implementation : null,
1003
1018
  occurredAt: event.occurredAt
1004
1019
  });
@@ -1014,6 +1029,7 @@ ${message}` : message;
1014
1029
  estimatedTokensBefore: numberOrNull(payload.estimatedTokensBefore),
1015
1030
  estimatedTokensAfter: null,
1016
1031
  skipReason: typeof payload.reason === "string" ? payload.reason : null,
1032
+ providerRejection: compactionProviderRejection(payload),
1017
1033
  implementation: typeof payload.implementation === "string" ? payload.implementation : null,
1018
1034
  occurredAt: event.occurredAt
1019
1035
  });
@@ -1043,6 +1059,8 @@ ${message}` : message;
1043
1059
  id: event.id,
1044
1060
  turnId,
1045
1061
  serverId: typeof payload.serverId === "string" ? payload.serverId : null,
1062
+ canonicalServerId: typeof payload.canonicalServerId === "string" ? payload.canonicalServerId : null,
1063
+ connectionSubjectScope: payload.connectionSubjectScope === "subject" || payload.connectionSubjectScope === "workspace" ? payload.connectionSubjectScope : null,
1046
1064
  source: capability ? "capability" : event.type === "tool.auth_needed" ? "tool" : "credential",
1047
1065
  providerDomain: stringValue(payload.providerDomain),
1048
1066
  connectionId: typeof payload.connectionId === "string" ? payload.connectionId : null,
@@ -1251,7 +1269,14 @@ ${message}` : message;
1251
1269
  break;
1252
1270
  }
1253
1271
  }
1272
+ const sourceEventsById = new Map(events.map((event) => [event.id, event]));
1254
1273
  for (const item of items) {
1274
+ const source = sourceEventsById.get(item.id);
1275
+ const canonical = "annotationSource" in item ? item.annotationSource : void 0;
1276
+ item.sourceEvents = [
1277
+ ...source ? [{ eventId: source.id, sequence: source.sequence }] : [],
1278
+ ...canonical && canonical.eventId !== source?.id ? [{ eventId: canonical.eventId, sequence: canonical.sequence }] : []
1279
+ ];
1255
1280
  if (item.kind === "agent-message") {
1256
1281
  item.text = stripOpaqueCitationTokens(item.text);
1257
1282
  }
@@ -1807,6 +1832,20 @@ function assistantMessagePhase(value) {
1807
1832
  function numberOrNull(value) {
1808
1833
  return typeof value === "number" && Number.isFinite(value) ? value : null;
1809
1834
  }
1835
+ function compactionProviderRejection(payload) {
1836
+ const record = asRecord2(payload.providerRejection);
1837
+ if (typeof record.httpStatus !== "number" || !Number.isFinite(record.httpStatus)) {
1838
+ return null;
1839
+ }
1840
+ const text = (value) => typeof value === "string" && value.trim() ? value : null;
1841
+ return {
1842
+ httpStatus: record.httpStatus,
1843
+ type: text(record.type),
1844
+ code: text(record.code),
1845
+ param: text(record.param),
1846
+ requestId: text(record.requestId)
1847
+ };
1848
+ }
1810
1849
  function compactionTrigger(payload) {
1811
1850
  const trigger = payload.trigger;
1812
1851
  return trigger === "auto" || trigger === "operator" || trigger === "proactive" || trigger === "overflow" ? trigger : null;
@@ -2097,7 +2136,7 @@ function capabilityAuthorizationRequest(value) {
2097
2136
  const kind = record.kind;
2098
2137
  const source = record.source;
2099
2138
  const action = record.action;
2100
- if (typeof record.id !== "string" || typeof record.name !== "string" || !["pack", "mcp", "api", "skill", "plugin"].includes(String(kind)) || !["built_in", "library", "configured", "public_registry", "registry", "manual"].includes(
2139
+ if (typeof record.id !== "string" || typeof record.name !== "string" || !["mcp", "api", "skill", "plugin"].includes(String(kind)) || !["built_in", "library", "configured", "public_registry", "registry", "manual"].includes(
2101
2140
  String(source)
2102
2141
  ) || !["connect", "add_credentials", "enable"].includes(String(action)) || typeof record.rationale !== "string") {
2103
2142
  return null;
@@ -2268,6 +2307,8 @@ function useSessionEvents(sessionId, options = {}) {
2268
2307
  const replay = options.replay ?? "windowed";
2269
2308
  const fullReplay = replay === "full" || after !== 0;
2270
2309
  const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}\0${fullReplay ? "full" : "windowed"}`;
2310
+ const navigationIdentityRef = useRef({ client, streamKey, enabled });
2311
+ navigationIdentityRef.current = { client, streamKey, enabled };
2271
2312
  const [eventWindow, setEventWindow] = useState(EMPTY_EVENT_WINDOW);
2272
2313
  const [connectionState, setConnectionState] = useState("idle");
2273
2314
  const [error, setError] = useState(null);
@@ -2282,6 +2323,8 @@ function useSessionEvents(sessionId, options = {}) {
2282
2323
  const [loadingNewer, setLoadingNewer] = useState(false);
2283
2324
  const [loadingOldest, setLoadingOldest] = useState(false);
2284
2325
  const [loadingLatest, setLoadingLatest] = useState(false);
2326
+ const [loadingTarget, setLoadingTarget] = useState(false);
2327
+ const loadingTargetRef = useRef(false);
2285
2328
  const [streamEpoch, setStreamEpoch] = useState(0);
2286
2329
  const [viewMode, setViewMode] = useState("live");
2287
2330
  const lastSequenceRef = useRef(after);
@@ -2313,6 +2356,8 @@ function useSessionEvents(sessionId, options = {}) {
2313
2356
  loadingOlderRef.current = false;
2314
2357
  loadingNewerRef.current = false;
2315
2358
  loadingOldestRef.current = false;
2359
+ loadingTargetRef.current = false;
2360
+ setLoadingTarget(false);
2316
2361
  setLoadingOlder(false);
2317
2362
  setLoadingNewer(false);
2318
2363
  setLoadingOldest(false);
@@ -2579,7 +2624,7 @@ function useSessionEvents(sessionId, options = {}) {
2579
2624
  viewMode,
2580
2625
  reconcileSession
2581
2626
  ]);
2582
- const navigationBusy = () => loadingOlderRef.current || loadingNewerRef.current || loadingOldestRef.current || loadingLatestRef.current;
2627
+ const navigationBusy = () => loadingTargetRef.current || loadingOlderRef.current || loadingNewerRef.current || loadingOldestRef.current || loadingLatestRef.current;
2583
2628
  const loadOlder = useCallback(
2584
2629
  () => createOlderHistoryLoadReceipt(async (markCommitted, preserveTail, markTailPreserved) => {
2585
2630
  if (!sessionId || navigationBusy() || !hasOlderRef.current) {
@@ -2839,7 +2884,84 @@ function useSessionEvents(sessionId, options = {}) {
2839
2884
  }
2840
2885
  }
2841
2886
  }, [client, workspaceId, sessionId]);
2887
+ const jumpToSequence = useCallback(
2888
+ async (sequence, navigationOptions) => {
2889
+ const signal = navigationOptions?.signal;
2890
+ if (!sessionId || !Number.isSafeInteger(sequence) || sequence < 1) return false;
2891
+ if (signal?.aborted) return false;
2892
+ const generation = ++navigationGenerationRef.current;
2893
+ const current = () => generation === navigationGenerationRef.current && navigationIdentityRef.current.client === client && navigationIdentityRef.current.streamKey === streamKey && navigationIdentityRef.current.enabled === enabled;
2894
+ const previousMode = viewModeRef.current;
2895
+ streamAbortRef.current?.abort();
2896
+ generationRef.current += 1;
2897
+ viewModeRef.current = "history";
2898
+ setViewMode("history");
2899
+ loadingOlderRef.current = loadingNewerRef.current = loadingOldestRef.current = false;
2900
+ setLoadingOlder(false);
2901
+ setLoadingNewer(false);
2902
+ setLoadingOldest(false);
2903
+ loadingTargetRef.current = true;
2904
+ setLoadingTarget(true);
2905
+ let published = false;
2906
+ try {
2907
+ const [before, following] = await Promise.all([
2908
+ loadPreviousPage(client, workspaceId, sessionId, sequence + 1, { pageSize: 128 }),
2909
+ loadNextPage(client, workspaceId, sessionId, sequence, { pageSize: 128 })
2910
+ ]);
2911
+ if (signal?.aborted) return false;
2912
+ if (!current()) return false;
2913
+ if (!before.some((event) => event.sequence === sequence)) return false;
2914
+ const prefix = boundBrowserSessionEventWindow(before, {
2915
+ direction: "newest",
2916
+ maxBytes: SESSION_EVENT_BROWSER_MAX_BYTES / 2
2917
+ });
2918
+ const retained = boundBrowserSessionEventWindow([...prefix.events, ...following], {
2919
+ direction: "oldest"
2920
+ });
2921
+ if (!retained.events.some((event) => event.sequence === sequence)) return false;
2922
+ streamAbortRef.current?.abort();
2923
+ generationRef.current += 1;
2924
+ const status = observeSessionStatus(retained.events, sessionStatusRef);
2925
+ eventWindowRef.current = retained;
2926
+ oldestSequenceRef.current = retained.events[0].sequence;
2927
+ newestSequenceRef.current = maxResumeSequenceOrNull(retained.events);
2928
+ lastSequenceRef.current = Math.max(lastSequenceRef.current, newestSequenceRef.current ?? 0);
2929
+ hasOlderRef.current = !isLogStart(retained.events[0]);
2930
+ hasNewerRef.current = following.length > 0 || retained.truncated || (newestSequenceRef.current ?? 0) < lastSequenceRef.current;
2931
+ initialWindowLoadedRef.current = true;
2932
+ viewModeRef.current = "history";
2933
+ setEventWindow(retained);
2934
+ setHasOlder(hasOlderRef.current);
2935
+ setHasNewer(hasNewerRef.current);
2936
+ setInitialLoading(false);
2937
+ setViewMode("history");
2938
+ setNewerError(null);
2939
+ if (status !== void 0) setSessionStatusProjection(status);
2940
+ published = true;
2941
+ return true;
2942
+ } catch (reason) {
2943
+ if (!current() || signal?.aborted) return false;
2944
+ throw reason;
2945
+ } finally {
2946
+ if (current()) {
2947
+ loadingTargetRef.current = false;
2948
+ setLoadingTarget(false);
2949
+ if (!published && previousMode === "live") {
2950
+ viewModeRef.current = "live";
2951
+ setViewMode("live");
2952
+ setStreamEpoch((epoch) => epoch + 1);
2953
+ }
2954
+ }
2955
+ }
2956
+ },
2957
+ [client, workspaceId, sessionId, streamKey, enabled]
2958
+ );
2842
2959
  const jumpToLatest = useCallback(async () => {
2960
+ if (loadingTargetRef.current) {
2961
+ navigationGenerationRef.current += 1;
2962
+ loadingTargetRef.current = false;
2963
+ setLoadingTarget(false);
2964
+ }
2843
2965
  if (!sessionId || navigationBusy()) {
2844
2966
  return;
2845
2967
  }
@@ -2878,7 +3000,12 @@ function useSessionEvents(sessionId, options = {}) {
2878
3000
  }, [after, sessionId]);
2879
3001
  const identityMatches = stateStreamKey === streamKey;
2880
3002
  const visibleEvents = identityMatches ? eventWindow.events : EMPTY_EVENTS;
2881
- const timeline = useMemo(() => buildTimeline(visibleEvents), [visibleEvents]);
3003
+ const timeline = useMemo(
3004
+ () => buildTimeline(visibleEvents, {
3005
+ partialStart: hasOlder || eventWindow.truncated || after > 0
3006
+ }),
3007
+ [visibleEvents, hasOlder, eventWindow.truncated, after]
3008
+ );
2882
3009
  return {
2883
3010
  events: visibleEvents,
2884
3011
  timeline,
@@ -2899,6 +3026,8 @@ function useSessionEvents(sessionId, options = {}) {
2899
3026
  loadOldest,
2900
3027
  loadingLatest: !identityMatches ? false : loadingLatest,
2901
3028
  jumpToLatest,
3029
+ jumpToSequence,
3030
+ loadingTarget: identityMatches && loadingTarget,
2902
3031
  error: identityMatches ? newerError ?? error : null
2903
3032
  };
2904
3033
  }
@@ -3742,6 +3871,57 @@ function useHumanInputRequests(sessionId, options = {}) {
3742
3871
  };
3743
3872
  }
3744
3873
 
3874
+ // src/conversation-timeline.ts
3875
+ function conversationTimeline(items, queue, composer) {
3876
+ const queued = new Set(
3877
+ queue.queue.filter((turn) => turn.metadata.delivery !== "steer").map((turn) => turn.triggerEventId)
3878
+ );
3879
+ const pending = composer.optimisticMessages ?? [];
3880
+ const pendingQueue = new Set(
3881
+ pending.filter(
3882
+ (message) => message.destination === "queue" && !(message.turnId && message.appliedQueueVersion != null && queue.snapshot && queue.snapshot.version >= message.appliedQueueVersion && !queue.queue.some((turn) => turn.id === message.turnId))
3883
+ ).map((message) => `user-message:${message.clientEventId}`)
3884
+ );
3885
+ const visible = items.filter(
3886
+ (item) => item.kind !== "user-message" || !queued.has(item.id) && !pendingQueue.has(item.reconciliationKey ?? "")
3887
+ );
3888
+ const keys = new Set(
3889
+ visible.flatMap((item) => item.kind === "user-message" ? [item.reconciliationKey] : [])
3890
+ );
3891
+ const optimistic = pending.filter(
3892
+ (message) => (message.destination === "chat" || message.state === "failed") && !keys.has(`user-message:${message.clientEventId}`) && !queue.queue.some((turn) => turn.id === message.turnId)
3893
+ ).map((message) => ({
3894
+ kind: "user-message",
3895
+ id: `optimistic:${message.clientEventId}`,
3896
+ reconciliationKey: `user-message:${message.clientEventId}`,
3897
+ text: message.text,
3898
+ annotations: message.annotations.map((annotation, ordinal) => ({ ...annotation, ordinal })),
3899
+ resources: message.resources,
3900
+ tools: [],
3901
+ occurredAt: message.occurredAt,
3902
+ delivery: {
3903
+ state: message.state,
3904
+ ...message.error ? { error: message.error } : {},
3905
+ ...message.state === "failed" ? {
3906
+ onRetry: () => composer.retryOptimisticMessage?.(message.clientEventId),
3907
+ onRemove: () => composer.removeOptimisticMessage?.(message.clientEventId)
3908
+ } : {}
3909
+ }
3910
+ }));
3911
+ const ids = new Set(visible.map((item) => item.id));
3912
+ const steers = (queue.acceptedSteers ?? []).filter((steer) => !ids.has(steer.triggerEventId)).map((steer) => ({
3913
+ kind: "user-message",
3914
+ id: steer.triggerEventId,
3915
+ text: steer.text,
3916
+ annotations: steer.annotations,
3917
+ resources: steer.resources,
3918
+ tools: steer.tools,
3919
+ occurredAt: steer.occurredAt,
3920
+ delivery: { state: steer.state }
3921
+ }));
3922
+ return [...visible, ...optimistic, ...steers];
3923
+ }
3924
+
3745
3925
  export {
3746
3926
  isActionableHumanInputRequest,
3747
3927
  humanInputRequestFromEvent,
@@ -3766,6 +3946,7 @@ export {
3766
3946
  isTurnQueueEvent,
3767
3947
  useTurnQueue,
3768
3948
  isHumanInputEvent,
3769
- useHumanInputRequests
3949
+ useHumanInputRequests,
3950
+ conversationTimeline
3770
3951
  };
3771
- //# sourceMappingURL=chunk-L2NBTKRX.js.map
3952
+ //# sourceMappingURL=chunk-JKLGJQO5.js.map