@opengeni/react 3.3.2 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +769 -22
- package/dist/accounts.js +2 -0
- package/dist/accounts.js.map +1 -1
- package/dist/approvals.d.ts +2 -1
- package/dist/artifacts-document.js +5 -3
- package/dist/artifacts-presentation.js +5 -3
- package/dist/artifacts-spreadsheet.d.ts +1 -1
- package/dist/artifacts-spreadsheet.js +5 -3
- package/dist/artifacts.d.ts +5 -1
- package/dist/artifacts.js +536 -42
- package/dist/artifacts.js.map +1 -1
- package/dist/browser-viewer-ZWR6MWJ7.js +19 -0
- package/dist/capability-catalog-row.d.ts +20 -0
- package/dist/capability-logo-fallback.d.ts +3 -0
- package/dist/chat-interactive-block-4EUKJXUO.js +14 -0
- package/dist/chunk-2DDJ6YH6.js +41 -0
- package/dist/chunk-2DDJ6YH6.js.map +1 -0
- package/dist/chunk-2HVLQ26H.js +183 -0
- package/dist/chunk-2HVLQ26H.js.map +1 -0
- package/dist/{chunk-XYRDDSXF.js → chunk-2I6R3GCZ.js} +4285 -3980
- package/dist/chunk-2I6R3GCZ.js.map +1 -0
- package/dist/{chunk-JAQ5K7W6.js → chunk-2SFFYIH3.js} +1178 -166
- package/dist/chunk-2SFFYIH3.js.map +1 -0
- package/dist/chunk-3PVDYTTB.js +24 -0
- package/dist/chunk-3PVDYTTB.js.map +1 -0
- package/dist/chunk-3RJKUVCA.js +14068 -0
- package/dist/chunk-3RJKUVCA.js.map +1 -0
- package/dist/chunk-3UZCWK46.js +298 -0
- package/dist/chunk-3UZCWK46.js.map +1 -0
- package/dist/chunk-47CKUXTW.js +293 -0
- package/dist/chunk-47CKUXTW.js.map +1 -0
- package/dist/chunk-4QYP6QUI.js +109 -0
- package/dist/chunk-4QYP6QUI.js.map +1 -0
- package/dist/chunk-5EY26VZ7.js +1053 -0
- package/dist/chunk-5EY26VZ7.js.map +1 -0
- package/dist/chunk-5I4VRWBB.js +56 -0
- package/dist/chunk-5I4VRWBB.js.map +1 -0
- package/dist/chunk-5WOR7UCL.js +191 -0
- package/dist/chunk-5WOR7UCL.js.map +1 -0
- package/dist/chunk-5YJLGOM5.js +51 -0
- package/dist/chunk-5YJLGOM5.js.map +1 -0
- package/dist/chunk-6JFN3OWG.js +386 -0
- package/dist/chunk-6JFN3OWG.js.map +1 -0
- package/dist/chunk-7QJT5O4S.js +35 -0
- package/dist/chunk-7QJT5O4S.js.map +1 -0
- package/dist/chunk-A55KV72M.js +402 -0
- package/dist/chunk-A55KV72M.js.map +1 -0
- package/dist/chunk-ADWCLI4G.js +2028 -0
- package/dist/chunk-ADWCLI4G.js.map +1 -0
- package/dist/chunk-B27E3V37.js +29 -0
- package/dist/chunk-B27E3V37.js.map +1 -0
- package/dist/chunk-B7TC2A33.js +83 -0
- package/dist/chunk-B7TC2A33.js.map +1 -0
- package/dist/chunk-BLL56F7R.js +385 -0
- package/dist/chunk-BLL56F7R.js.map +1 -0
- package/dist/chunk-BOFEQC6K.js +162 -0
- package/dist/chunk-BOFEQC6K.js.map +1 -0
- package/dist/chunk-CM7LVUKC.js +35 -0
- package/dist/chunk-CM7LVUKC.js.map +1 -0
- package/dist/chunk-CORUP6JB.js +122 -0
- package/dist/chunk-CORUP6JB.js.map +1 -0
- package/dist/chunk-CSX5FFKZ.js +35 -0
- package/dist/chunk-CSX5FFKZ.js.map +1 -0
- package/dist/chunk-EGVHJKGJ.js +3125 -0
- package/dist/chunk-EGVHJKGJ.js.map +1 -0
- package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
- package/dist/chunk-G76LSA76.js.map +1 -0
- package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
- package/dist/chunk-GQMRL52F.js.map +1 -0
- package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
- package/dist/chunk-GUUXOISA.js.map +1 -0
- package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
- package/dist/chunk-I7X2P4FU.js.map +1 -0
- package/dist/chunk-IGFZFLI2.js +1390 -0
- package/dist/chunk-IGFZFLI2.js.map +1 -0
- package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
- package/dist/chunk-IMSUVYQB.js.map +1 -0
- package/dist/chunk-IOYHDEP3.js +38 -0
- package/dist/chunk-IOYHDEP3.js.map +1 -0
- package/dist/chunk-IZV5FTJC.js +55 -0
- package/dist/chunk-IZV5FTJC.js.map +1 -0
- package/dist/chunk-KF33GTWN.js +343 -0
- package/dist/chunk-KF33GTWN.js.map +1 -0
- package/dist/chunk-KSGQ5ODA.js +457 -0
- package/dist/chunk-KSGQ5ODA.js.map +1 -0
- package/dist/{chunk-ZPBTI3TE.js → chunk-KZC6QRNR.js} +1513 -697
- package/dist/chunk-KZC6QRNR.js.map +1 -0
- package/dist/chunk-LJUMYUBO.js +218 -0
- package/dist/chunk-LJUMYUBO.js.map +1 -0
- package/dist/chunk-LSW2OJVV.js +380 -0
- package/dist/chunk-LSW2OJVV.js.map +1 -0
- package/dist/chunk-M357MHH3.js +2 -0
- package/dist/chunk-M357MHH3.js.map +1 -0
- package/dist/chunk-MK2TQO4Y.js +24 -0
- package/dist/chunk-MK2TQO4Y.js.map +1 -0
- package/dist/chunk-N7S72EXK.js +25 -0
- package/dist/chunk-N7S72EXK.js.map +1 -0
- package/dist/{chunk-YVCHAQZY.js → chunk-NKMYZFHA.js} +616 -621
- package/dist/chunk-NKMYZFHA.js.map +1 -0
- package/dist/chunk-NX4ADH73.js +14 -0
- package/dist/chunk-NX4ADH73.js.map +1 -0
- package/dist/chunk-O7F6UJO4.js +71 -0
- package/dist/chunk-O7F6UJO4.js.map +1 -0
- package/dist/chunk-OYQQJL3J.js +16 -0
- package/dist/chunk-OYQQJL3J.js.map +1 -0
- package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
- package/dist/chunk-P4BNUO57.js.map +1 -0
- package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
- package/dist/chunk-PEHTX3V7.js.map +1 -0
- package/dist/chunk-PMV53IMM.js +26 -0
- package/dist/chunk-PMV53IMM.js.map +1 -0
- package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
- package/dist/chunk-PYEOPA4M.js.map +1 -0
- package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
- package/dist/chunk-QHUE7E4N.js.map +1 -0
- package/dist/chunk-QV3DJVRZ.js +11 -0
- package/dist/chunk-QV3DJVRZ.js.map +1 -0
- package/dist/chunk-R5SBNG7S.js +810 -0
- package/dist/chunk-R5SBNG7S.js.map +1 -0
- package/dist/chunk-RI42H5IU.js +326 -0
- package/dist/chunk-RI42H5IU.js.map +1 -0
- package/dist/chunk-S2QH6EZ5.js +211 -0
- package/dist/chunk-S2QH6EZ5.js.map +1 -0
- package/dist/chunk-SHLZMAJN.js +304 -0
- package/dist/chunk-SHLZMAJN.js.map +1 -0
- package/dist/chunk-TGXK4BAZ.js +293 -0
- package/dist/chunk-TGXK4BAZ.js.map +1 -0
- package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
- package/dist/chunk-TNEZNMSN.js.map +1 -0
- package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
- package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
- package/dist/chunk-UNJPZGNK.js +63 -0
- package/dist/chunk-UNJPZGNK.js.map +1 -0
- package/dist/{chunk-IOLVN74D.js → chunk-V5ZUJT2T.js} +175 -42
- package/dist/chunk-V5ZUJT2T.js.map +1 -0
- package/dist/chunk-WBJY57A3.js +402 -0
- package/dist/chunk-WBJY57A3.js.map +1 -0
- package/dist/chunk-WIUKB3LD.js +1911 -0
- package/dist/chunk-WIUKB3LD.js.map +1 -0
- package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
- package/dist/chunk-WNN7NO2N.js.map +1 -0
- package/dist/{chunk-3AGBGTRT.js → chunk-X5UVUIMF.js} +1712 -1174
- package/dist/chunk-X5UVUIMF.js.map +1 -0
- package/dist/chunk-XDA5QJE7.js +402 -0
- package/dist/chunk-XDA5QJE7.js.map +1 -0
- package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
- package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
- package/dist/chunk-XHF7OYAN.js +1150 -0
- package/dist/chunk-XHF7OYAN.js.map +1 -0
- package/dist/chunk-YSRBFJMQ.js +43 -0
- package/dist/chunk-YSRBFJMQ.js.map +1 -0
- package/dist/chunk-ZOZAPAUO.js +174 -0
- package/dist/chunk-ZOZAPAUO.js.map +1 -0
- package/dist/chunk-ZQV5W7YC.js +809 -0
- package/dist/chunk-ZQV5W7YC.js.map +1 -0
- package/dist/chunk-ZUWF4NF7.js +13 -0
- package/dist/chunk-ZUWF4NF7.js.map +1 -0
- package/dist/client.d.ts +16 -7
- package/dist/clipboard.js +3 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/anthropic-mark.d.ts +3 -0
- package/dist/components/approval-surface.d.ts +19 -6
- package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
- package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
- package/dist/components/artifacts/artifact-surface.d.ts +4 -2
- package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
- package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
- package/dist/components/artifacts/document-editor.d.ts +4 -2
- package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
- package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
- package/dist/components/artifacts/editable-document.d.ts +1 -1
- package/dist/components/artifacts/editable-presentation.d.ts +2 -2
- package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
- package/dist/components/artifacts/index.d.ts +9 -2
- package/dist/components/artifacts/inline-html-document.d.ts +2 -0
- package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
- package/dist/components/artifacts/presentation-editor.d.ts +6 -2
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
- package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
- package/dist/components/artifacts/site-view.d.ts +26 -0
- package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
- package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
- package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
- package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
- package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
- package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
- package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
- package/dist/components/browser-select-control.d.ts +16 -0
- package/dist/components/browser-viewer.d.ts +11 -2
- package/dist/components/chat-composer.d.ts +21 -3
- package/dist/components/child-session-link.d.ts +9 -0
- package/dist/components/claude-mark.d.ts +3 -0
- package/dist/components/code-editor.d.ts +1 -4
- package/dist/components/composer-transcription-control.d.ts +7 -0
- package/dist/components/composer.d.ts +34 -67
- package/dist/components/computer-viewer.d.ts +1 -1
- package/dist/components/copy-button.d.ts +3 -1
- package/dist/components/desktop-viewer.d.ts +1 -1
- package/dist/components/grok-mark.d.ts +26 -0
- package/dist/components/human-input-form.d.ts +28 -32
- package/dist/components/human-input-surface.d.ts +7 -2
- package/dist/components/linkified-text.d.ts +18 -0
- package/dist/components/machine-input-display.d.ts +22 -1
- package/dist/components/machines/agent-status-icon.d.ts +6 -0
- package/dist/components/machines/machine-detail.d.ts +7 -1
- package/dist/components/machines/machine-status.d.ts +48 -0
- package/dist/components/markdown-table-layout.d.ts +18 -0
- package/dist/components/markdown.d.ts +37 -4
- package/dist/components/message-timeline.d.ts +86 -7
- package/dist/components/model-mark.d.ts +29 -0
- package/dist/components/model-policy-picker-menu.d.ts +9 -0
- package/dist/components/model-policy-picker.d.ts +35 -28
- package/dist/components/new-conversation.d.ts +32 -0
- package/dist/components/open-geni-chat.d.ts +73 -0
- package/dist/components/open-geni-links.d.ts +68 -0
- package/dist/components/openrouter-mark.d.ts +6 -0
- package/dist/components/opper-mark.d.ts +7 -0
- package/dist/components/preview-loading.d.ts +2 -0
- package/dist/components/provider-recovery-notice.d.ts +16 -0
- package/dist/components/queue-item-content.d.ts +9 -0
- package/dist/components/rehype-secret-refs.d.ts +23 -0
- package/dist/components/remark-soft-line-breaks.d.ts +38 -0
- package/dist/components/sandbox-files.d.ts +3 -1
- package/dist/components/sandbox-workspace.d.ts +18 -0
- package/dist/components/secret-question-field.d.ts +31 -0
- package/dist/components/secret-ref-chip.d.ts +35 -0
- package/dist/components/session-capability-frame.d.ts +37 -0
- package/dist/components/session-chrome.d.ts +57 -8
- package/dist/components/session-commands-panel.d.ts +6 -0
- package/dist/components/session-commands.d.ts +6 -0
- package/dist/components/session-connection-request.d.ts +8 -0
- package/dist/components/session-conversation.d.ts +157 -0
- package/dist/components/session-list.d.ts +39 -0
- package/dist/components/session-mcp-capability-card.d.ts +41 -0
- package/dist/components/session-proxy-scope.d.ts +35 -0
- package/dist/components/session-status.d.ts +4 -1
- package/dist/components/session-usage-limit-notice.d.ts +39 -0
- package/dist/components/timeline-anchor.d.ts +24 -0
- package/dist/components/timeline-annotation-chrome.d.ts +25 -0
- package/dist/components/timeline-annotation-layout.d.ts +42 -0
- package/dist/components/timeline-annotation-markers.d.ts +8 -0
- package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
- package/dist/components/timeline-annotation-shared.d.ts +31 -0
- package/dist/components/timeline-annotations-dialog.d.ts +3 -2
- package/dist/components/timeline-annotations.d.ts +13 -3
- package/dist/components/timeline-reading-progress.d.ts +11 -0
- package/dist/components/timeline-search.d.ts +34 -0
- package/dist/components/timeline-settlement.d.ts +16 -0
- package/dist/components/tool-action-review.d.ts +47 -0
- package/dist/components/tool-review-history.d.ts +25 -0
- package/dist/components/usage-limit-notice.d.ts +49 -0
- package/dist/components/usage-member-list.d.ts +91 -0
- package/dist/components/usage-meter.d.ts +73 -0
- package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
- package/dist/components/user-message-body.d.ts +10 -1
- package/dist/composer-messages.d.ts +74 -0
- package/dist/composer-messages.js +9 -0
- package/dist/composer-messages.js.map +1 -0
- package/dist/composer-voice-events.d.ts +8 -0
- package/dist/composer.d.ts +5 -4
- package/dist/composer.js +26 -13
- package/dist/computer-viewer-GMLDXPON.js +20 -0
- package/dist/computer-viewer-GMLDXPON.js.map +1 -0
- package/dist/connect-account-identity.d.ts +8 -0
- package/dist/connect-accounts.d.ts +15 -0
- package/dist/connect-chooser.d.ts +18 -0
- package/dist/connect-panel.d.ts +18 -0
- package/dist/connect-setup.d.ts +18 -0
- package/dist/connect.d.ts +21 -0
- package/dist/connect.js +2149 -0
- package/dist/connect.js.map +1 -0
- package/dist/connection-catalog.d.ts +38 -0
- package/dist/connection-discovery.d.ts +12 -0
- package/dist/connection-installed.d.ts +17 -0
- package/dist/connection-logo.d.ts +9 -0
- package/dist/connection-service-logo.d.ts +8 -0
- package/dist/connection-service-presentation.d.ts +13 -0
- package/dist/connection-skeleton.d.ts +5 -0
- package/dist/connection-type-picker.d.ts +6 -0
- package/dist/conversation-timeline.d.ts +5 -0
- package/dist/desktop.d.ts +7 -0
- package/dist/desktop.js +27 -0
- package/dist/desktop.js.map +1 -0
- package/dist/device-authorization.d.ts +23 -0
- package/dist/diffs.d.ts +8 -0
- package/dist/diffs.js +15 -0
- package/dist/diffs.js.map +1 -0
- package/dist/discovery-cache.d.ts +5 -0
- package/dist/editor.d.ts +7 -0
- package/dist/editor.js +22 -0
- package/dist/editor.js.map +1 -0
- package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
- package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
- package/dist/embedded-voice-RPHPYVBT.js +18 -0
- package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
- package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
- package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
- package/dist/hooks/latest-question.d.ts +25 -0
- package/dist/hooks/shared-machines-list.d.ts +4 -0
- package/dist/hooks/shared-query.d.ts +113 -0
- package/dist/hooks/use-attached-browsers.d.ts +1 -1
- package/dist/hooks/use-auth-runs.d.ts +1 -4
- package/dist/hooks/use-available-models.d.ts +1 -1
- package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
- package/dist/hooks/use-browser-session.d.ts +12 -1
- package/dist/hooks/use-client-config-flags.d.ts +49 -0
- package/dist/hooks/use-codex-accounts.d.ts +59 -10
- package/dist/hooks/use-composer.d.ts +24 -2
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-input-posture.d.ts +13 -0
- package/dist/hooks/use-computer-session.d.ts +4 -0
- package/dist/hooks/use-connect.d.ts +23 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-file-attachments.d.ts +12 -0
- package/dist/hooks/use-goal.d.ts +2 -1
- package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
- package/dist/hooks/use-new-conversation.d.ts +56 -0
- package/dist/hooks/use-new-session-draft.d.ts +74 -0
- package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
- package/dist/hooks/use-sandbox-files.d.ts +4 -1
- package/dist/hooks/use-session-conversation.d.ts +49 -0
- package/dist/hooks/use-session-events.d.ts +26 -5
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
- package/dist/hooks/use-session-model-account.d.ts +48 -0
- package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
- package/dist/hooks/use-terminal-stream.d.ts +11 -5
- package/dist/hooks/use-usage.d.ts +40 -0
- package/dist/hooks/use-vaults.d.ts +53 -0
- package/dist/hooks/use-voice-input.d.ts +8 -1
- package/dist/hooks/use-workspace-edit.d.ts +4 -0
- package/dist/hooks/use-workspace-sessions.d.ts +24 -5
- package/dist/human-input-model.d.ts +122 -0
- package/dist/identity-link-accounts.d.ts +11 -0
- package/dist/identity-link-consent.d.ts +18 -0
- package/dist/index.d.ts +82 -20
- package/dist/index.js +2340 -6603
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +1 -1
- package/dist/interaction.js +14 -24
- package/dist/interaction.js.map +1 -1
- package/dist/latest-question-R77KWSUP.js +118 -0
- package/dist/latest-question-R77KWSUP.js.map +1 -0
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/error-message.d.ts +7 -0
- package/dist/lib/format.d.ts +58 -4
- package/dist/lib/host-theme.d.ts +77 -0
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/lib/menu-styles.d.ts +22 -0
- package/dist/lib/notify-observer.d.ts +2 -0
- package/dist/lib/pierre-diffs-loader.d.ts +20 -0
- package/dist/lib/provider-recovery.d.ts +55 -0
- package/dist/lib/scrollbars.d.ts +11 -0
- package/dist/lib/terminal-input-readiness.d.ts +11 -0
- package/dist/lib/transient-retry.d.ts +25 -0
- package/dist/lib/workbench-peers.d.ts +36 -0
- package/dist/lib/xterm-theme.d.ts +7 -5
- package/dist/machines.js +9 -5
- package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
- package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
- package/dist/mcp-connection-status.d.ts +14 -0
- package/dist/model-mark-paths.d.ts +34 -0
- package/dist/model-mark-paths.js +16 -0
- package/dist/model-mark-paths.js.map +1 -0
- package/dist/model-picker-model.d.ts +111 -0
- package/dist/model-picker-model.js +25 -0
- package/dist/model-picker-model.js.map +1 -0
- package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
- package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
- package/dist/model-policy.d.ts +30 -3
- package/dist/model-policy.js +14 -1
- package/dist/native-previews.d.ts +28 -0
- package/dist/native-previews.js +82 -0
- package/dist/native-previews.js.map +1 -0
- package/dist/new-session-draft.d.ts +7 -0
- package/dist/new-session-draft.js +639 -0
- package/dist/new-session-draft.js.map +1 -0
- package/dist/notification-text.d.ts +27 -0
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
- package/dist/older-history.d.ts +3 -2
- package/dist/organization-model.d.ts +32 -0
- package/dist/organization-model.js +65 -0
- package/dist/organization-model.js.map +1 -0
- package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
- package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
- package/dist/plugin-details.d.ts +14 -0
- package/dist/plugin-discovery.d.ts +25 -0
- package/dist/preview-loading-paint.d.ts +20 -0
- package/dist/provider.d.ts +25 -2
- package/dist/queue-presentation-model.d.ts +72 -0
- package/dist/queue-presentation-model.js +38 -0
- package/dist/queue-presentation-model.js.map +1 -0
- package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
- package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
- package/dist/realtime/embedded-new-voice.d.ts +1 -0
- package/dist/realtime/embedded-voice.d.ts +1 -0
- package/dist/realtime/realtime-control.d.ts +4 -65
- package/dist/realtime/session-realtime.d.ts +78 -0
- package/dist/realtime.js +25 -1333
- package/dist/realtime.js.map +1 -1
- package/dist/sandbox-files-O27IPOZW.js +21 -0
- package/dist/sandbox-files-O27IPOZW.js.map +1 -0
- package/dist/sandbox-label-model.d.ts +30 -0
- package/dist/sandbox-label-model.js +20 -0
- package/dist/sandbox-label-model.js.map +1 -0
- package/dist/scrollbars.d.ts +1 -0
- package/dist/scrollbars.js +10 -0
- package/dist/scrollbars.js.map +1 -0
- package/dist/secret-reference-label.d.ts +14 -0
- package/dist/secrets-ui.d.ts +57 -0
- package/dist/session-agents-model.d.ts +10 -0
- package/dist/session-agents-model.js +25 -0
- package/dist/session-agents-model.js.map +1 -0
- package/dist/session-attention-model.d.ts +8 -0
- package/dist/session-attention-model.js +47 -0
- package/dist/session-attention-model.js.map +1 -0
- package/dist/session-auth-recommendation.d.ts +5 -0
- package/dist/session-capability-policy.d.ts +31 -0
- package/dist/session-feedback-model.d.ts +20 -0
- package/dist/session-feedback-model.js +56 -0
- package/dist/session-feedback-model.js.map +1 -0
- package/dist/session-list-model.d.ts +138 -0
- package/dist/session-list-model.js +274 -0
- package/dist/session-list-model.js.map +1 -0
- package/dist/session-realtime-7DJOIHQW.js +21 -0
- package/dist/session-realtime-7DJOIHQW.js.map +1 -0
- package/dist/session-realtime.d.ts +7 -0
- package/dist/session-realtime.js +19 -0
- package/dist/session-realtime.js.map +1 -0
- package/dist/session-status-model.d.ts +36 -0
- package/dist/session-ui.d.ts +39 -1
- package/dist/session-ui.js +126 -12
- package/dist/session-ui.js.map +1 -1
- package/dist/session.d.ts +8 -2
- package/dist/session.js +35 -20
- package/dist/site-snapshot.d.ts +14 -0
- package/dist/sites-ui.d.ts +24 -0
- package/dist/sites.d.ts +3 -0
- package/dist/sites.js +14 -0
- package/dist/sites.js.map +1 -0
- package/dist/skill-discovery.d.ts +47 -0
- package/dist/terminal.d.ts +8 -0
- package/dist/terminal.js +32 -0
- package/dist/terminal.js.map +1 -0
- package/dist/testing/session-scenarios.d.ts +10 -0
- package/dist/testing/session-scenarios.js +367 -0
- package/dist/testing/session-scenarios.js.map +1 -0
- package/dist/timeline/activity-rail.d.ts +11 -2
- package/dist/timeline/agent-identity.d.ts +30 -0
- package/dist/timeline/agent-row.d.ts +31 -0
- package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
- package/dist/timeline/compaction-copy.d.ts +46 -0
- package/dist/timeline/focus-sequence.d.ts +9 -0
- package/dist/timeline/genie-copy.d.ts +3 -0
- package/dist/timeline/genie-loading.d.ts +47 -0
- package/dist/timeline/index.d.ts +10 -5
- package/dist/timeline/knowledge-receipt.d.ts +17 -0
- package/dist/timeline/message-sender.d.ts +19 -0
- package/dist/timeline/notice-presentation.d.ts +13 -0
- package/dist/timeline/parsers.d.ts +11 -0
- package/dist/timeline/patch-apply-command.d.ts +18 -0
- package/dist/timeline/platform-activity-presentation.d.ts +21 -0
- package/dist/timeline/platform-activity-row.d.ts +1 -2
- package/dist/timeline/presented-image.d.ts +11 -0
- package/dist/timeline/projection.d.ts +31 -2
- package/dist/timeline/provider-logo.d.ts +15 -0
- package/dist/timeline/question-nav-model.d.ts +23 -0
- package/dist/timeline/registry.d.ts +12 -1
- package/dist/timeline/retained-image.d.ts +18 -0
- package/dist/timeline/retained-loaders.d.ts +27 -0
- package/dist/timeline/rolling-activity.d.ts +11 -0
- package/dist/timeline/screenshot-lightbox.d.ts +23 -1
- package/dist/timeline/session-usage-limit-row.d.ts +11 -0
- package/dist/timeline/shared.d.ts +4 -1
- package/dist/timeline/startup-dispatch-details.d.ts +5 -0
- package/dist/timeline/startup-preference.d.ts +3 -0
- package/dist/timeline/startup-timings.d.ts +4 -0
- package/dist/timeline/tool-display-name.d.ts +5 -2
- package/dist/timeline/tool-presentation.d.ts +172 -0
- package/dist/timeline/turn-summary-model.d.ts +95 -0
- package/dist/timeline/turn-summary.d.ts +20 -54
- package/dist/timeline/types.d.ts +179 -7
- package/dist/timeline/work-presentation.d.ts +60 -0
- package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
- package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
- package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
- package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
- package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
- package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
- package/dist/timeline-model.d.ts +29 -0
- package/dist/timeline-model.js +254 -0
- package/dist/timeline-model.js.map +1 -0
- package/dist/usage/allowance-copy.d.ts +25 -0
- package/dist/usage/session-usage-limit.d.ts +88 -0
- package/dist/usage/summary.d.ts +35 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +1187 -0
- package/dist/usage.js.map +1 -0
- package/dist/voice-recording-owner.d.ts +7 -0
- package/package.json +106 -7
- package/src/approvals.ts +8 -1
- package/src/artifacts-spreadsheet.ts +1 -0
- package/src/artifacts.ts +44 -0
- package/src/assets/README.md +8 -0
- package/src/assets/gmail.ico +0 -0
- package/src/assets/outlook.ico +0 -0
- package/src/capability-catalog-row.tsx +94 -0
- package/src/capability-logo-fallback.ts +22 -0
- package/src/client.ts +20 -31
- package/src/commands/registry.ts +18 -15
- package/src/commands/types.ts +2 -0
- package/src/components/anthropic-mark.tsx +10 -0
- package/src/components/approval-surface.tsx +401 -138
- package/src/components/artifacts/artifact-chrome.tsx +413 -0
- package/src/components/artifacts/artifact-sandbox.tsx +193 -0
- package/src/components/artifacts/artifact-surface.tsx +40 -20
- package/src/components/artifacts/chat-interactive-block.tsx +260 -0
- package/src/components/artifacts/deferred-chat-media.tsx +67 -0
- package/src/components/artifacts/document-editor.tsx +141 -16
- package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
- package/src/components/artifacts/editable-artifact-view.tsx +197 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
- package/src/components/artifacts/editable-document.tsx +37 -36
- package/src/components/artifacts/editable-presentation.tsx +36 -18
- package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
- package/src/components/artifacts/index.ts +45 -0
- package/src/components/artifacts/inline-html-document.ts +24 -0
- package/src/components/artifacts/latest-task-runner.ts +49 -0
- package/src/components/artifacts/presentation-editor.tsx +323 -67
- package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
- package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
- package/src/components/artifacts/site-view.tsx +121 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
- package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
- package/src/components/artifacts/spreadsheet-download.tsx +109 -0
- package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
- package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
- package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
- package/src/components/artifacts/visualization-assets/base.css +1015 -0
- package/src/components/artifacts/visualization-assets/helpers.html +349 -0
- package/src/components/artifacts/visualization-assets.gen.ts +3 -0
- package/src/components/browser-select-control.tsx +312 -0
- package/src/components/browser-viewer.tsx +778 -318
- package/src/components/chat-composer.tsx +47 -5
- package/src/components/child-session-link.tsx +36 -0
- package/src/components/claude-mark.tsx +11 -0
- package/src/components/code-editor.tsx +13 -16
- package/src/components/composer-transcription-control.tsx +128 -30
- package/src/components/composer.tsx +404 -195
- package/src/components/computer-viewer.tsx +880 -253
- package/src/components/copy-button.tsx +13 -5
- package/src/components/desktop-viewer.tsx +1 -1
- package/src/components/enrollment-consent.tsx +1 -1
- package/src/components/enrollment-device-flow.tsx +1 -1
- package/src/components/file-browser.tsx +10 -14
- package/src/components/fleet-tile.tsx +5 -3
- package/src/components/generated-video-player.tsx +4 -2
- package/src/components/grok-mark.tsx +34 -0
- package/src/components/human-input-form.tsx +590 -283
- package/src/components/human-input-surface.tsx +11 -0
- package/src/components/interaction-intervention-banner.tsx +2 -2
- package/src/components/linkified-text.tsx +79 -0
- package/src/components/machine-card.tsx +35 -78
- package/src/components/machine-dock-bar.tsx +1 -1
- package/src/components/machine-input-display.ts +197 -3
- package/src/components/machines/agent-status-icon.tsx +31 -0
- package/src/components/machines/machine-detail.tsx +200 -31
- package/src/components/machines/machine-operation-policy.tsx +1 -1
- package/src/components/machines/machine-status.ts +241 -0
- package/src/components/machines-dashboard.tsx +2 -17
- package/src/components/markdown-table-layout.ts +143 -0
- package/src/components/markdown.tsx +466 -129
- package/src/components/message-timeline.tsx +2370 -667
- package/src/components/model-mark.tsx +102 -0
- package/src/components/model-picker.tsx +15 -4
- package/src/components/model-policy-picker-menu.tsx +371 -0
- package/src/components/model-policy-picker.tsx +252 -429
- package/src/components/new-conversation.tsx +221 -0
- package/src/components/open-geni-chat.tsx +309 -0
- package/src/components/open-geni-links.tsx +179 -0
- package/src/components/openrouter-mark.tsx +13 -0
- package/src/components/opper-mark.tsx +18 -0
- package/src/components/pierre-diff.tsx +41 -16
- package/src/components/pierre-file.tsx +35 -10
- package/src/components/preview-loading.tsx +109 -0
- package/src/components/provider-recovery-notice.tsx +49 -0
- package/src/components/queue-item-content.ts +14 -0
- package/src/components/queue-surface-implementation.tsx +51 -356
- package/src/components/queue-surface-state.tsx +3 -1
- package/src/components/rehype-secret-refs.ts +98 -0
- package/src/components/remark-soft-line-breaks.ts +166 -0
- package/src/components/sandbox-files.tsx +91 -15
- package/src/components/sandbox-terminal.tsx +84 -13
- package/src/components/sandbox-workspace.tsx +147 -51
- package/src/components/secret-question-field.tsx +324 -0
- package/src/components/secret-ref-chip.tsx +185 -0
- package/src/components/session-capability-frame.tsx +197 -0
- package/src/components/session-chrome.tsx +842 -251
- package/src/components/session-commands-panel.tsx +126 -0
- package/src/components/session-commands.tsx +18 -0
- package/src/components/session-connection-request.tsx +97 -0
- package/src/components/session-conversation.tsx +876 -0
- package/src/components/session-list.tsx +257 -0
- package/src/components/session-mcp-capability-card.tsx +680 -0
- package/src/components/session-proxy-scope.tsx +153 -0
- package/src/components/session-status.tsx +26 -17
- package/src/components/session-usage-limit-notice.tsx +174 -0
- package/src/components/timeline-anchor.tsx +119 -0
- package/src/components/timeline-annotation-chrome.tsx +196 -0
- package/src/components/timeline-annotation-layout.ts +268 -0
- package/src/components/timeline-annotation-markers.tsx +185 -0
- package/src/components/timeline-annotation-reveal-context.ts +9 -0
- package/src/components/timeline-annotation-selection.tsx +106 -54
- package/src/components/timeline-annotation-shared.ts +245 -0
- package/src/components/timeline-annotations-dialog.tsx +185 -128
- package/src/components/timeline-annotations.tsx +189 -45
- package/src/components/timeline-reading-progress.ts +80 -0
- package/src/components/timeline-search.tsx +168 -0
- package/src/components/timeline-settlement.ts +60 -0
- package/src/components/tool-action-review.tsx +650 -0
- package/src/components/tool-review-history.tsx +88 -0
- package/src/components/usage-limit-notice.tsx +179 -0
- package/src/components/usage-member-list.tsx +792 -0
- package/src/components/usage-meter.tsx +382 -0
- package/src/components/use-viewer-menu-dismiss.ts +33 -0
- package/src/components/user-message-body.tsx +27 -2
- package/src/components/workspace-dock.tsx +18 -1
- package/src/composer-messages.ts +150 -0
- package/src/composer-voice-events.ts +12 -0
- package/src/composer.ts +6 -1
- package/src/connect-account-identity.tsx +34 -0
- package/src/connect-accounts.tsx +233 -0
- package/src/connect-chooser.tsx +336 -0
- package/src/connect-panel.tsx +99 -0
- package/src/connect-setup.tsx +355 -0
- package/src/connect.ts +60 -0
- package/src/connection-assets.d.ts +4 -0
- package/src/connection-catalog.tsx +162 -0
- package/src/connection-discovery.tsx +238 -0
- package/src/connection-installed.tsx +51 -0
- package/src/connection-logo.tsx +37 -0
- package/src/connection-service-logo.tsx +55 -0
- package/src/connection-service-presentation.ts +46 -0
- package/src/connection-skeleton.tsx +16 -0
- package/src/connection-type-picker.tsx +36 -0
- package/src/conversation-timeline.ts +92 -0
- package/src/desktop.ts +24 -0
- package/src/device-authorization.tsx +98 -0
- package/src/diffs.ts +16 -0
- package/src/discovery-cache.ts +42 -0
- package/src/editor.ts +13 -0
- package/src/hooks/internal.ts +3 -2
- package/src/hooks/latest-question.ts +164 -0
- package/src/hooks/shared-machines-list.ts +34 -1
- package/src/hooks/shared-query.ts +721 -0
- package/src/hooks/use-attached-browsers.ts +1 -1
- package/src/hooks/use-auth-runs.ts +0 -27
- package/src/hooks/use-available-models.ts +2 -2
- package/src/hooks/use-browser-frame-stream.ts +19 -2
- package/src/hooks/use-browser-session.ts +680 -205
- package/src/hooks/use-browser-sessions.ts +32 -1
- package/src/hooks/use-client-config-flags.ts +118 -0
- package/src/hooks/use-codex-accounts.ts +247 -47
- package/src/hooks/use-composer.ts +227 -44
- package/src/hooks/use-computer-frame-stream.ts +25 -7
- package/src/hooks/use-computer-input-posture.ts +94 -0
- package/src/hooks/use-computer-session.ts +409 -95
- package/src/hooks/use-connect.ts +23 -0
- package/src/hooks/use-desktop-stream.ts +19 -28
- package/src/hooks/use-file-attachments.ts +80 -4
- package/src/hooks/use-goal.ts +79 -9
- package/src/hooks/use-last-started-turn-policy.ts +37 -11
- package/src/hooks/use-machines.ts +4 -0
- package/src/hooks/use-new-conversation.ts +374 -0
- package/src/hooks/use-new-session-draft.ts +813 -0
- package/src/hooks/use-realtime-voice-models.ts +46 -0
- package/src/hooks/use-sandbox-files.ts +68 -20
- package/src/hooks/use-session-background-commands.ts +22 -11
- package/src/hooks/use-session-capabilities.ts +3 -2
- package/src/hooks/use-session-conversation.ts +150 -0
- package/src/hooks/use-session-events.ts +531 -335
- package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
- package/src/hooks/use-session-model-account.ts +174 -0
- package/src/hooks/use-session.ts +30 -2
- package/src/hooks/use-slash-commands.ts +6 -11
- package/src/hooks/use-supergrok-accounts.ts +22 -8
- package/src/hooks/use-terminal-stream.ts +153 -27
- package/src/hooks/use-transcription.ts +6 -0
- package/src/hooks/use-turn-queue.ts +2 -1
- package/src/hooks/use-usage.ts +100 -0
- package/src/hooks/use-vaults.ts +153 -0
- package/src/hooks/use-video-artifact-playback.ts +1 -1
- package/src/hooks/use-voice-input.ts +127 -19
- package/src/hooks/use-workspace-capture.ts +3 -2
- package/src/hooks/use-workspace-edit.ts +23 -5
- package/src/hooks/use-workspace-sessions.ts +74 -7
- package/src/human-input-model.ts +359 -0
- package/src/identity-link-accounts.tsx +148 -0
- package/src/identity-link-consent.tsx +192 -0
- package/src/index.ts +262 -16
- package/src/interaction.ts +1 -0
- package/src/lib/clipboard.ts +29 -0
- package/src/lib/error-message.ts +37 -0
- package/src/lib/format.ts +205 -10
- package/src/lib/host-theme.ts +529 -0
- package/src/lib/interaction-errors.ts +15 -0
- package/src/lib/menu-styles.ts +44 -0
- package/src/lib/notify-observer.ts +15 -0
- package/src/lib/pierre-diffs-loader.ts +53 -0
- package/src/lib/provider-recovery.ts +243 -0
- package/src/lib/scrollbars.ts +30 -0
- package/src/lib/terminal-input-readiness.ts +51 -0
- package/src/lib/transient-retry.ts +99 -0
- package/src/lib/workbench-peers.ts +62 -0
- package/src/lib/xterm-theme.ts +23 -21
- package/src/mcp-connection-status.ts +35 -0
- package/src/model-mark-paths.ts +53 -0
- package/src/model-picker-model.ts +330 -0
- package/src/model-policy.ts +299 -74
- package/src/native-previews.ts +100 -0
- package/src/new-session-draft.ts +22 -0
- package/src/notification-text.ts +81 -0
- package/src/older-history.ts +22 -4
- package/src/organization-model.ts +118 -0
- package/src/plugin-details.tsx +185 -0
- package/src/plugin-discovery.tsx +196 -0
- package/src/preview-loading-paint.ts +68 -0
- package/src/provider.tsx +74 -15
- package/src/queue-presentation-model.ts +464 -0
- package/src/realtime/dropdown-menu.tsx +19 -12
- package/src/realtime/embedded-new-voice.tsx +1 -0
- package/src/realtime/embedded-voice.tsx +3 -0
- package/src/realtime/realtime-control.tsx +138 -550
- package/src/realtime/session-realtime.ts +566 -0
- package/src/sandbox-label-model.ts +53 -0
- package/src/scrollbars.ts +3 -0
- package/src/secret-reference-label.ts +43 -0
- package/src/secrets-ui.tsx +59 -0
- package/src/session-agents-model.ts +33 -0
- package/src/session-attention-model.ts +62 -0
- package/src/session-auth-recommendation.ts +48 -0
- package/src/session-capability-policy.ts +196 -0
- package/src/session-context.ts +3 -4
- package/src/session-feedback-model.ts +95 -0
- package/src/session-list-model.ts +434 -0
- package/src/session-realtime.ts +18 -0
- package/src/session-status-model.ts +99 -0
- package/src/session-ui.ts +98 -1
- package/src/session.ts +17 -1
- package/src/site-snapshot.ts +74 -0
- package/src/sites-ui.tsx +348 -0
- package/src/sites.ts +3 -0
- package/src/skill-discovery.tsx +208 -0
- package/src/terminal.ts +26 -0
- package/src/testing/session-scenarios.ts +404 -0
- package/src/timeline/activity-rail.tsx +242 -101
- package/src/timeline/agent-identity.tsx +84 -0
- package/src/timeline/agent-row.tsx +231 -0
- package/src/timeline/allowance-exhausted-row.tsx +86 -0
- package/src/timeline/compaction-copy.ts +115 -0
- package/src/timeline/fleet-decision-projection.ts +2 -1
- package/src/timeline/fleet-decision-row.tsx +1 -0
- package/src/timeline/focus-sequence.ts +44 -0
- package/src/timeline/genie-copy.ts +19 -0
- package/src/timeline/genie-loading.tsx +143 -0
- package/src/timeline/index.ts +30 -2
- package/src/timeline/knowledge-receipt.tsx +100 -0
- package/src/timeline/message-sender.tsx +71 -0
- package/src/timeline/notice-presentation.ts +48 -0
- package/src/timeline/parsers.ts +42 -2
- package/src/timeline/patch-apply-command.tsx +135 -0
- package/src/timeline/platform-activity-presentation.ts +166 -0
- package/src/timeline/platform-activity-row.tsx +15 -90
- package/src/timeline/presented-image.ts +63 -0
- package/src/timeline/projection.ts +1742 -76
- package/src/timeline/provider-logo.tsx +53 -0
- package/src/timeline/question-nav-model.ts +28 -0
- package/src/timeline/registry.ts +26 -4
- package/src/timeline/retained-image.ts +97 -0
- package/src/timeline/retained-loaders.ts +91 -0
- package/src/timeline/rolling-activity.tsx +80 -0
- package/src/timeline/screenshot-lightbox.tsx +228 -5
- package/src/timeline/session-usage-limit-row.tsx +42 -0
- package/src/timeline/shared.tsx +42 -15
- package/src/timeline/startup-dispatch-details.tsx +36 -0
- package/src/timeline/startup-preference.ts +33 -0
- package/src/timeline/startup-timings.tsx +145 -0
- package/src/timeline/tool-display-name.ts +19 -7
- package/src/timeline/tool-presentation.ts +1316 -0
- package/src/timeline/tool-renderers.tsx +835 -1138
- package/src/timeline/turn-summary-model.ts +343 -0
- package/src/timeline/turn-summary.tsx +272 -365
- package/src/timeline/types.ts +189 -6
- package/src/timeline/work-presentation.ts +189 -0
- package/src/timeline-model.ts +143 -0
- package/src/usage/allowance-copy.ts +64 -0
- package/src/usage/session-usage-limit.ts +266 -0
- package/src/usage/summary.ts +93 -0
- package/src/usage.ts +70 -0
- package/src/voice-recording-owner.ts +22 -0
- package/styles/compiled.css +2319 -748
- package/styles/connect.css +290 -0
- package/styles/connect.d.ts +1 -0
- package/styles/effective-tokens.css +1 -0
- package/styles/index.css +309 -9
- package/styles/responsive.css +99 -7
- package/styles/session-capability.css +44 -0
- package/styles/tokens.css +134 -66
- package/dist/browser-viewer-MKKFRRRV.js +0 -14
- package/dist/chunk-2DZVYHVO.js +0 -470
- package/dist/chunk-2DZVYHVO.js.map +0 -1
- package/dist/chunk-3AGBGTRT.js.map +0 -1
- package/dist/chunk-4MDLEHXL.js.map +0 -1
- package/dist/chunk-5YK2ZDIG.js.map +0 -1
- package/dist/chunk-7EAFGICR.js +0 -302
- package/dist/chunk-7EAFGICR.js.map +0 -1
- package/dist/chunk-ELIYWBZR.js.map +0 -1
- package/dist/chunk-H5YGYNXS.js.map +0 -1
- package/dist/chunk-HUIKIDM5.js.map +0 -1
- package/dist/chunk-ICA6R6TW.js.map +0 -1
- package/dist/chunk-IOLVN74D.js.map +0 -1
- package/dist/chunk-JAQ5K7W6.js.map +0 -1
- package/dist/chunk-JVYQRRC4.js.map +0 -1
- package/dist/chunk-KCGXPP5V.js.map +0 -1
- package/dist/chunk-KZ73RL76.js.map +0 -1
- package/dist/chunk-NEXLLTP4.js.map +0 -1
- package/dist/chunk-PEI6RANI.js.map +0 -1
- package/dist/chunk-VTOREEXF.js +0 -142
- package/dist/chunk-VTOREEXF.js.map +0 -1
- package/dist/chunk-WSK7G5LE.js +0 -170
- package/dist/chunk-WSK7G5LE.js.map +0 -1
- package/dist/chunk-X4A66EWZ.js +0 -223
- package/dist/chunk-X4A66EWZ.js.map +0 -1
- package/dist/chunk-XYRDDSXF.js.map +0 -1
- package/dist/chunk-YG4QEQF5.js +0 -9557
- package/dist/chunk-YG4QEQF5.js.map +0 -1
- package/dist/chunk-YVCHAQZY.js.map +0 -1
- package/dist/chunk-ZPBTI3TE.js.map +0 -1
- package/dist/computer-viewer-FWEZISW4.js +0 -16
- package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
- package/dist/hooks/use-environments.d.ts +0 -41
- package/dist/hooks/use-packs.d.ts +0 -32
- package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
- package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
- package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
- package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
- package/src/hooks/use-environments.ts +0 -182
- package/src/hooks/use-packs.ts +0 -157
- /package/dist/{browser-viewer-MKKFRRRV.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
- /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-4EUKJXUO.js.map} +0 -0
|
@@ -1,108 +1,642 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
buildTimeline,
|
|
3
|
-
createOlderHistoryLoadReceipt,
|
|
4
4
|
groupTimeline,
|
|
5
|
-
isActionableHumanInputRequest,
|
|
6
5
|
sessionStatusFromEvents
|
|
7
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2SFFYIH3.js";
|
|
7
|
+
import {
|
|
8
|
+
isActionableHumanInputRequest
|
|
9
|
+
} from "./chunk-IZV5FTJC.js";
|
|
10
|
+
import {
|
|
11
|
+
FILE_ONLY_MESSAGE_TEXT,
|
|
12
|
+
notifyObserver,
|
|
13
|
+
useComposer
|
|
14
|
+
} from "./chunk-V5ZUJT2T.js";
|
|
15
|
+
import {
|
|
16
|
+
coerceReasoningEffortForModel,
|
|
17
|
+
defaultEffortForModel,
|
|
18
|
+
projectPickerRows,
|
|
19
|
+
runnableLatencyModesForModel,
|
|
20
|
+
sortPickerRows
|
|
21
|
+
} from "./chunk-KF33GTWN.js";
|
|
8
22
|
import {
|
|
9
23
|
useDebouncedCallback,
|
|
10
24
|
useMutationRunner,
|
|
11
25
|
usePageLiveActivity,
|
|
12
26
|
usePolledValue,
|
|
13
27
|
useSessionEventTrigger
|
|
14
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-QHUE7E4N.js";
|
|
29
|
+
import {
|
|
30
|
+
normalizeError,
|
|
31
|
+
useErrorMessage
|
|
32
|
+
} from "./chunk-CM7LVUKC.js";
|
|
15
33
|
import {
|
|
16
34
|
useEmbeddedFileAttachments,
|
|
17
35
|
useEmbeddedGoal,
|
|
18
36
|
useEmbeddedHumanInputSession,
|
|
19
37
|
useEmbeddedSession,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from "./chunk-
|
|
38
|
+
useEmbeddedSessionRead,
|
|
39
|
+
useOpenGeni,
|
|
40
|
+
useOpenGeniClient
|
|
41
|
+
} from "./chunk-G76LSA76.js";
|
|
24
42
|
|
|
25
|
-
// src/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
// src/approvals.ts
|
|
44
|
+
import {
|
|
45
|
+
parseToolDisplayMetadata
|
|
46
|
+
} from "@opengeni/sdk";
|
|
47
|
+
function approvalsFromRequiresAction(payload) {
|
|
48
|
+
const approvals = payload && typeof payload === "object" ? payload.approvals : void 0;
|
|
49
|
+
if (!Array.isArray(approvals)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
return approvals.map((approval, index) => {
|
|
53
|
+
const raw = approval && typeof approval === "object" ? approval : {};
|
|
54
|
+
const rawItem = raw.rawItem && typeof raw.rawItem === "object" ? raw.rawItem : {};
|
|
55
|
+
const display = parseToolDisplayMetadata(raw.display);
|
|
56
|
+
return {
|
|
57
|
+
// Mirror the runtime's canonical interruption identity before retaining
|
|
58
|
+
// the legacy top-level callId fallback for already-normalized payloads.
|
|
59
|
+
id: String(rawItem.callId ?? rawItem.id ?? raw.id ?? raw.callId ?? raw.name ?? index),
|
|
60
|
+
name: String(raw.name ?? raw.toolName ?? rawItem.name ?? "approval"),
|
|
61
|
+
...display ? { display } : {},
|
|
62
|
+
arguments: raw.arguments ?? rawItem.arguments,
|
|
63
|
+
raw: approval
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function projectPendingApprovals(events) {
|
|
68
|
+
let pending = [];
|
|
69
|
+
let owningTurnId = null;
|
|
70
|
+
for (const event of events) {
|
|
71
|
+
switch (event.type) {
|
|
72
|
+
case "session.requiresAction": {
|
|
73
|
+
pending = approvalsFromRequiresAction(event.payload);
|
|
74
|
+
owningTurnId = event.turnId ?? null;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case "user.approvalDecision": {
|
|
78
|
+
const payload = event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
79
|
+
if (typeof payload.approvalId === "string") {
|
|
80
|
+
pending = pending.filter((approval) => approval.id !== payload.approvalId);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "turn.completed":
|
|
85
|
+
case "turn.failed":
|
|
86
|
+
case "turn.cancelled": {
|
|
87
|
+
if (owningTurnId === null || event.turnId == null || event.turnId === owningTurnId) {
|
|
88
|
+
pending = [];
|
|
89
|
+
owningTurnId = null;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
default:
|
|
94
|
+
break;
|
|
52
95
|
}
|
|
53
|
-
client[key] = method.bind(override === void 0 ? base : overrides);
|
|
54
96
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
97
|
+
return pending;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/older-history.ts
|
|
101
|
+
var activeReceiptCapture;
|
|
102
|
+
var preserveTailForAutomaticLoad = false;
|
|
103
|
+
function invokeOlderHistoryLoaderWithReceiptCapture(load, capture, preserveTail = false) {
|
|
104
|
+
const previousCapture = activeReceiptCapture;
|
|
105
|
+
const previousPreserveTail = preserveTailForAutomaticLoad;
|
|
106
|
+
activeReceiptCapture = capture;
|
|
107
|
+
preserveTailForAutomaticLoad = preserveTail;
|
|
108
|
+
try {
|
|
109
|
+
return load();
|
|
110
|
+
} finally {
|
|
111
|
+
activeReceiptCapture = previousCapture;
|
|
112
|
+
preserveTailForAutomaticLoad = previousPreserveTail;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function createOlderHistoryLoadReceipt(load) {
|
|
116
|
+
let resolveResult;
|
|
117
|
+
let rejectResult;
|
|
118
|
+
const result = new Promise((resolve, reject) => {
|
|
119
|
+
resolveResult = resolve;
|
|
120
|
+
rejectResult = reject;
|
|
121
|
+
});
|
|
122
|
+
result.committed = false;
|
|
123
|
+
result.tailPreserved = false;
|
|
124
|
+
activeReceiptCapture?.(result);
|
|
125
|
+
try {
|
|
126
|
+
const loaded = load(
|
|
127
|
+
() => {
|
|
128
|
+
result.committed = true;
|
|
129
|
+
},
|
|
130
|
+
preserveTailForAutomaticLoad,
|
|
131
|
+
() => {
|
|
132
|
+
result.tailPreserved = true;
|
|
133
|
+
}
|
|
61
134
|
);
|
|
135
|
+
Promise.resolve(loaded).then(resolveResult, rejectResult);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
rejectResult(error);
|
|
62
138
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/conversation-timeline.ts
|
|
143
|
+
function conversationTimeline(items, queue, composer) {
|
|
144
|
+
const queued = new Set(
|
|
145
|
+
queue.queue.filter((turn) => turn.metadata.delivery !== "steer").map((turn) => turn.triggerEventId)
|
|
146
|
+
);
|
|
147
|
+
const pending = composer.optimisticMessages ?? [];
|
|
148
|
+
const pendingQueue = new Set(
|
|
149
|
+
pending.filter(
|
|
150
|
+
(message) => message.destination === "queue" && !(message.turnId && message.appliedQueueVersion != null && queue.snapshot && queue.snapshot.version >= message.appliedQueueVersion && !queue.queue.some((turn) => turn.id === message.turnId))
|
|
151
|
+
).map((message) => `user-message:${message.clientEventId}`)
|
|
152
|
+
);
|
|
153
|
+
const visible = items.filter(
|
|
154
|
+
(item) => item.kind !== "user-message" || !queued.has(item.id) && !pendingQueue.has(item.reconciliationKey ?? "")
|
|
155
|
+
);
|
|
156
|
+
const keys = new Set(
|
|
157
|
+
visible.flatMap((item) => item.kind === "user-message" ? [item.reconciliationKey] : [])
|
|
158
|
+
);
|
|
159
|
+
const optimistic = pending.filter(
|
|
160
|
+
(message) => (message.destination === "chat" || message.state === "failed") && !keys.has(`user-message:${message.clientEventId}`) && !queue.queue.some((turn) => turn.id === message.turnId)
|
|
161
|
+
).map((message) => ({
|
|
162
|
+
kind: "user-message",
|
|
163
|
+
id: `optimistic:${message.clientEventId}`,
|
|
164
|
+
reconciliationKey: `user-message:${message.clientEventId}`,
|
|
165
|
+
text: message.text,
|
|
166
|
+
annotations: message.annotations.map((annotation, ordinal) => ({ ...annotation, ordinal })),
|
|
167
|
+
resources: message.resources,
|
|
168
|
+
tools: [],
|
|
169
|
+
occurredAt: message.occurredAt,
|
|
170
|
+
delivery: {
|
|
171
|
+
state: message.state,
|
|
172
|
+
...message.error ? { error: message.error } : {},
|
|
173
|
+
...message.state === "failed" ? {
|
|
174
|
+
...message.retryable !== false && composer.retryOptimisticMessage ? { onRetry: () => composer.retryOptimisticMessage?.(message.clientEventId) } : {},
|
|
175
|
+
...message.retryable === false && composer.restoreOptimisticMessage ? { onEdit: () => composer.restoreOptimisticMessage?.(message.clientEventId) } : {},
|
|
176
|
+
onRemove: () => composer.removeOptimisticMessage?.(message.clientEventId)
|
|
177
|
+
} : {}
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
const ids = new Set(visible.map((item) => item.id));
|
|
181
|
+
const steers = (queue.acceptedSteers ?? []).filter((steer) => !ids.has(steer.triggerEventId)).map((steer) => ({
|
|
182
|
+
kind: "user-message",
|
|
183
|
+
id: steer.triggerEventId,
|
|
184
|
+
text: steer.text,
|
|
185
|
+
annotations: steer.annotations,
|
|
186
|
+
resources: steer.resources,
|
|
187
|
+
tools: steer.tools,
|
|
188
|
+
occurredAt: steer.occurredAt,
|
|
189
|
+
delivery: { state: steer.state }
|
|
190
|
+
}));
|
|
191
|
+
return [...visible, ...optimistic, ...steers];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/hooks/use-available-models.ts
|
|
195
|
+
import { useCallback } from "react";
|
|
196
|
+
function useAvailableModels(options = {}) {
|
|
197
|
+
const client = useOpenGeniClient(options);
|
|
198
|
+
const load = useCallback(
|
|
199
|
+
async (signal) => await client.getClientConfig({ signal }),
|
|
200
|
+
[client]
|
|
201
|
+
);
|
|
202
|
+
const state = usePolledValue(load, {
|
|
203
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
204
|
+
enabled: options.enabled
|
|
70
205
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
206
|
+
return {
|
|
207
|
+
models: state.data?.models ?? [],
|
|
208
|
+
defaultModel: state.data?.defaultModel ?? null,
|
|
209
|
+
loading: state.loading,
|
|
210
|
+
error: state.error,
|
|
211
|
+
refresh: state.refresh
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function useWorkspaceModelCatalog(options) {
|
|
215
|
+
const client = useOpenGeniClient(options);
|
|
216
|
+
const load = useCallback(
|
|
217
|
+
async (signal) => {
|
|
218
|
+
if (!options.workspaceId) {
|
|
219
|
+
return { models: [], defaultModel: null };
|
|
220
|
+
}
|
|
221
|
+
const [catalog, config] = await Promise.all([
|
|
222
|
+
client.getWorkspaceModelCatalog(options.workspaceId, { signal }),
|
|
223
|
+
client.getClientConfig({ signal, workspaceId: options.workspaceId })
|
|
224
|
+
]);
|
|
225
|
+
return {
|
|
226
|
+
models: catalog.models,
|
|
227
|
+
defaultModel: config.defaultModel
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
[client, options.workspaceId]
|
|
231
|
+
);
|
|
232
|
+
const state = usePolledValue(load, {
|
|
233
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
234
|
+
enabled: options.enabled !== false && Boolean(options.workspaceId)
|
|
76
235
|
});
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
236
|
+
const rows = sortPickerRows(projectPickerRows(state.data?.models ?? []));
|
|
237
|
+
return {
|
|
238
|
+
models: state.data?.models ?? [],
|
|
239
|
+
rows,
|
|
240
|
+
defaultModel: state.data?.defaultModel ?? null,
|
|
241
|
+
loading: state.loading,
|
|
242
|
+
error: state.error,
|
|
243
|
+
refresh: state.refresh
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/hooks/use-file-attachments.ts
|
|
248
|
+
import { useCallback as useCallback2, useEffect, useRef, useState } from "react";
|
|
249
|
+
var isImage = (file) => file.type.startsWith("image/");
|
|
250
|
+
var fallbackAttachmentId = 0;
|
|
251
|
+
function createAttachmentId() {
|
|
252
|
+
const cryptoSource = globalThis.crypto;
|
|
253
|
+
if (typeof cryptoSource?.randomUUID === "function") return cryptoSource.randomUUID();
|
|
254
|
+
fallbackAttachmentId += 1;
|
|
255
|
+
return `attachment:${Date.now().toString(36)}:${fallbackAttachmentId.toString(36)}`;
|
|
256
|
+
}
|
|
257
|
+
function secureContextRequiredErrorCode(error) {
|
|
258
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "secure_context_required" ? error.code : void 0;
|
|
259
|
+
}
|
|
260
|
+
function useFileAttachments(options = {}) {
|
|
261
|
+
const { client, workspaceId } = useEmbeddedFileAttachments(options);
|
|
262
|
+
const formatError = useErrorMessage();
|
|
263
|
+
const pasteFilter = options.pasteFilter ?? isImage;
|
|
264
|
+
const [attachments, setAttachments] = useState([]);
|
|
265
|
+
const attachmentsRef = useRef(attachments);
|
|
266
|
+
attachmentsRef.current = attachments;
|
|
267
|
+
const sources = useRef(/* @__PURE__ */ new Map());
|
|
268
|
+
const previewUrls = useRef(/* @__PURE__ */ new Map());
|
|
269
|
+
const previewRetainers = useRef(/* @__PURE__ */ new Map());
|
|
270
|
+
const pendingPreviewRevocations = useRef(/* @__PURE__ */ new Set());
|
|
271
|
+
const revokePreview = useCallback2((id) => {
|
|
272
|
+
const previewUrl = previewUrls.current.get(id);
|
|
273
|
+
if (!previewUrl) return;
|
|
274
|
+
if ((previewRetainers.current.get(id) ?? 0) > 0) {
|
|
275
|
+
pendingPreviewRevocations.current.add(id);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
previewUrls.current.delete(id);
|
|
279
|
+
pendingPreviewRevocations.current.delete(id);
|
|
280
|
+
URL.revokeObjectURL(previewUrl);
|
|
281
|
+
}, []);
|
|
282
|
+
const revokeAllPreviews = useCallback2(() => {
|
|
283
|
+
for (const id of previewUrls.current.keys()) revokePreview(id);
|
|
284
|
+
}, [revokePreview]);
|
|
285
|
+
const retainPreview = useCallback2(
|
|
286
|
+
(id) => {
|
|
287
|
+
if (!previewUrls.current.has(id)) return void 0;
|
|
288
|
+
previewRetainers.current.set(id, (previewRetainers.current.get(id) ?? 0) + 1);
|
|
289
|
+
let released = false;
|
|
290
|
+
return () => {
|
|
291
|
+
if (released) return;
|
|
292
|
+
released = true;
|
|
293
|
+
const remaining = (previewRetainers.current.get(id) ?? 1) - 1;
|
|
294
|
+
if (remaining > 0) {
|
|
295
|
+
previewRetainers.current.set(id, remaining);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
previewRetainers.current.delete(id);
|
|
299
|
+
if (pendingPreviewRevocations.current.has(id)) revokePreview(id);
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
[revokePreview]
|
|
303
|
+
);
|
|
304
|
+
const committedAttachmentIds = useRef(/* @__PURE__ */ new Set());
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
const currentIds = new Set(attachments.map((attachment) => attachment.id));
|
|
307
|
+
for (const id of committedAttachmentIds.current) {
|
|
308
|
+
if (!currentIds.has(id)) revokePreview(id);
|
|
309
|
+
}
|
|
310
|
+
committedAttachmentIds.current = currentIds;
|
|
311
|
+
}, [attachments, revokePreview]);
|
|
312
|
+
const scopeGeneration = useRef(0);
|
|
313
|
+
const previousScope = useRef({ client, workspaceId });
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
const previous = previousScope.current;
|
|
316
|
+
if (previous.client === client && previous.workspaceId === workspaceId) return;
|
|
317
|
+
previousScope.current = { client, workspaceId };
|
|
318
|
+
scopeGeneration.current += 1;
|
|
319
|
+
sources.current.clear();
|
|
320
|
+
revokeAllPreviews();
|
|
321
|
+
setAttachments([]);
|
|
322
|
+
}, [client, revokeAllPreviews, workspaceId]);
|
|
323
|
+
useEffect(
|
|
324
|
+
() => () => {
|
|
325
|
+
scopeGeneration.current += 1;
|
|
326
|
+
sources.current.clear();
|
|
327
|
+
revokeAllPreviews();
|
|
328
|
+
},
|
|
329
|
+
[revokeAllPreviews]
|
|
330
|
+
);
|
|
331
|
+
const startUpload = useCallback2(
|
|
332
|
+
(id, file) => {
|
|
333
|
+
const generation = scopeGeneration.current;
|
|
334
|
+
void client.uploadFile(workspaceId, {
|
|
335
|
+
filename: file.name || "file",
|
|
336
|
+
contentType: file.type || "application/octet-stream",
|
|
337
|
+
data: file,
|
|
338
|
+
...options.scope ? { scope: options.scope } : {}
|
|
339
|
+
}).then((asset) => {
|
|
340
|
+
if (scopeGeneration.current !== generation) return;
|
|
341
|
+
sources.current.delete(id);
|
|
342
|
+
setAttachments(
|
|
343
|
+
(current) => current.map(
|
|
344
|
+
(attachment) => attachment.id === id ? {
|
|
345
|
+
...attachment,
|
|
346
|
+
status: "ready",
|
|
347
|
+
file: asset,
|
|
348
|
+
name: asset.filename,
|
|
349
|
+
contentType: asset.contentType,
|
|
350
|
+
sizeBytes: asset.sizeBytes,
|
|
351
|
+
errorCode: void 0,
|
|
352
|
+
error: void 0,
|
|
353
|
+
errorCause: void 0
|
|
354
|
+
} : attachment
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
}).catch((error) => {
|
|
358
|
+
if (scopeGeneration.current !== generation) return;
|
|
359
|
+
setAttachments(
|
|
360
|
+
(current) => current.map(
|
|
361
|
+
(attachment) => attachment.id === id ? {
|
|
362
|
+
...attachment,
|
|
363
|
+
status: "failed",
|
|
364
|
+
errorCode: secureContextRequiredErrorCode(error),
|
|
365
|
+
error: formatError(error),
|
|
366
|
+
errorCause: error
|
|
367
|
+
} : attachment
|
|
368
|
+
)
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
[client, workspaceId, options.scope, formatError]
|
|
373
|
+
);
|
|
374
|
+
const addFiles = useCallback2(
|
|
375
|
+
(files) => {
|
|
376
|
+
for (const file of files) {
|
|
377
|
+
const id = createAttachmentId();
|
|
378
|
+
sources.current.set(id, file);
|
|
379
|
+
const previewUrl = isImage(file) ? URL.createObjectURL(file) : void 0;
|
|
380
|
+
if (previewUrl) previewUrls.current.set(id, previewUrl);
|
|
381
|
+
setAttachments((current) => [
|
|
382
|
+
...current,
|
|
383
|
+
{
|
|
384
|
+
id,
|
|
385
|
+
name: file.name || "image",
|
|
386
|
+
contentType: file.type || "application/octet-stream",
|
|
387
|
+
sizeBytes: file.size,
|
|
388
|
+
status: "uploading",
|
|
389
|
+
...previewUrl ? { previewUrl } : {}
|
|
390
|
+
}
|
|
391
|
+
]);
|
|
392
|
+
startUpload(id, file);
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
[startUpload]
|
|
396
|
+
);
|
|
397
|
+
const retry = useCallback2(
|
|
398
|
+
(id) => {
|
|
399
|
+
const file = sources.current.get(id);
|
|
400
|
+
if (!file) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
setAttachments(
|
|
404
|
+
(current) => current.map(
|
|
405
|
+
(attachment) => attachment.id === id ? {
|
|
406
|
+
...attachment,
|
|
407
|
+
status: "uploading",
|
|
408
|
+
errorCode: void 0,
|
|
409
|
+
error: void 0,
|
|
410
|
+
errorCause: void 0
|
|
411
|
+
} : attachment
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
startUpload(id, file);
|
|
415
|
+
},
|
|
416
|
+
[startUpload]
|
|
417
|
+
);
|
|
418
|
+
const addFromPaste = useCallback2(
|
|
419
|
+
(event) => {
|
|
420
|
+
const clipboardFiles = event.clipboardData?.files;
|
|
421
|
+
if (!clipboardFiles) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const files = [...clipboardFiles].filter(pasteFilter);
|
|
425
|
+
if (files.length > 0) {
|
|
426
|
+
addFiles(files);
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
[addFiles, pasteFilter]
|
|
430
|
+
);
|
|
431
|
+
const restoreReadyFiles = useCallback2(
|
|
432
|
+
(files) => {
|
|
433
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
434
|
+
for (const file of files) {
|
|
435
|
+
if (file.status === "ready" && file.workspaceId === workspaceId) {
|
|
436
|
+
incoming.set(file.id, file);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
setAttachments((current) => {
|
|
440
|
+
const unresolved = current.filter((attachment) => attachment.status !== "ready");
|
|
441
|
+
const existingReady = new Map(
|
|
442
|
+
current.flatMap(
|
|
443
|
+
(attachment) => attachment.status === "ready" && attachment.file ? [[attachment.file.id, attachment]] : []
|
|
444
|
+
)
|
|
445
|
+
);
|
|
446
|
+
const restored = [...incoming.values()].map((file) => {
|
|
447
|
+
const existing = existingReady.get(file.id);
|
|
448
|
+
return existing ? {
|
|
449
|
+
...existing,
|
|
450
|
+
name: file.filename,
|
|
451
|
+
contentType: file.contentType,
|
|
452
|
+
sizeBytes: file.sizeBytes,
|
|
453
|
+
status: "ready",
|
|
454
|
+
file,
|
|
455
|
+
errorCode: void 0,
|
|
456
|
+
error: void 0,
|
|
457
|
+
errorCause: void 0
|
|
458
|
+
} : {
|
|
459
|
+
id: `restored:${file.id}`,
|
|
460
|
+
name: file.filename,
|
|
461
|
+
contentType: file.contentType,
|
|
462
|
+
sizeBytes: file.sizeBytes,
|
|
463
|
+
status: "ready",
|
|
464
|
+
file
|
|
465
|
+
// No source File and no object URL: server metadata is the
|
|
466
|
+
// only authority restored across page/device boundaries.
|
|
467
|
+
};
|
|
468
|
+
});
|
|
469
|
+
return [...unresolved, ...restored];
|
|
470
|
+
});
|
|
471
|
+
},
|
|
472
|
+
[workspaceId]
|
|
473
|
+
);
|
|
474
|
+
const loadPreview = useCallback2(
|
|
475
|
+
async (id, signal) => {
|
|
476
|
+
const generation = scopeGeneration.current;
|
|
477
|
+
const attachment = attachmentsRef.current.find((candidate) => candidate.id === id);
|
|
478
|
+
const createDownloadUrl = client.createFileDownloadUrl;
|
|
479
|
+
if (!attachment || attachment.status !== "ready" || !attachment.file || !attachment.contentType.startsWith("image/") || typeof createDownloadUrl !== "function" || signal?.aborted) {
|
|
480
|
+
return void 0;
|
|
481
|
+
}
|
|
482
|
+
const fileId = attachment.file.id;
|
|
483
|
+
const signed = await createDownloadUrl.call(client, workspaceId, fileId, { signal });
|
|
484
|
+
if (scopeGeneration.current !== generation || signal?.aborted) return void 0;
|
|
485
|
+
const current = attachmentsRef.current.find((candidate) => candidate.id === id);
|
|
486
|
+
if (current?.status !== "ready" || current.file?.id !== fileId) return void 0;
|
|
487
|
+
return signed.url;
|
|
488
|
+
},
|
|
489
|
+
[client, workspaceId]
|
|
490
|
+
);
|
|
491
|
+
const remove = useCallback2(
|
|
492
|
+
(id) => {
|
|
493
|
+
sources.current.delete(id);
|
|
494
|
+
revokePreview(id);
|
|
495
|
+
setAttachments((current) => current.filter((attachment) => attachment.id !== id));
|
|
496
|
+
},
|
|
497
|
+
[revokePreview]
|
|
498
|
+
);
|
|
499
|
+
const removeReadyFiles = useCallback2((fileIds) => {
|
|
500
|
+
const accepted = new Set(fileIds);
|
|
501
|
+
if (accepted.size === 0) return;
|
|
502
|
+
setAttachments(
|
|
503
|
+
(current) => current.filter((attachment) => {
|
|
504
|
+
return !(attachment.status === "ready" && attachment.file !== void 0 && accepted.has(attachment.file.id));
|
|
86
505
|
})
|
|
87
|
-
|
|
506
|
+
);
|
|
507
|
+
}, []);
|
|
508
|
+
const clear = useCallback2(() => {
|
|
509
|
+
sources.current.clear();
|
|
510
|
+
revokeAllPreviews();
|
|
511
|
+
setAttachments([]);
|
|
512
|
+
}, [revokeAllPreviews]);
|
|
513
|
+
return {
|
|
514
|
+
attachments,
|
|
515
|
+
readyResources: attachments.flatMap(
|
|
516
|
+
(attachment) => attachment.status === "ready" && attachment.file ? [{ kind: "file", fileId: attachment.file.id }] : []
|
|
517
|
+
),
|
|
518
|
+
uploading: attachments.some((attachment) => attachment.status === "uploading"),
|
|
519
|
+
hasUnresolved: attachments.some((attachment) => attachment.status !== "ready"),
|
|
520
|
+
addFiles,
|
|
521
|
+
addFromPaste,
|
|
522
|
+
restoreReadyFiles,
|
|
523
|
+
...typeof client.createFileDownloadUrl === "function" ? { loadPreview } : {},
|
|
524
|
+
retry,
|
|
525
|
+
retainPreview,
|
|
526
|
+
remove,
|
|
527
|
+
removeReadyFiles,
|
|
528
|
+
clear
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// src/hooks/use-human-input.ts
|
|
533
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
534
|
+
function isHumanInputEvent(event) {
|
|
535
|
+
return event.type === "session.humanInput.requested" || event.type === "user.humanInputResponse" || event.type === "turn.completed" || event.type === "turn.failed" || event.type === "turn.cancelled";
|
|
536
|
+
}
|
|
537
|
+
function useHumanInputRequests(sessionId, options = {}) {
|
|
538
|
+
const { client, workspaceId, registerSessionReconciler } = useEmbeddedHumanInputSession(options);
|
|
539
|
+
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
540
|
+
const load = useCallback3(
|
|
541
|
+
async () => sessionId ? await client.listHumanInputRequests(workspaceId, sessionId, { status: "pending" }) : [],
|
|
542
|
+
[client, sessionId, workspaceId]
|
|
543
|
+
);
|
|
544
|
+
const state = usePolledValue(load, {
|
|
545
|
+
enabled,
|
|
546
|
+
pollIntervalMs: options.pollIntervalMs
|
|
547
|
+
});
|
|
548
|
+
const loadedRequests = state.data;
|
|
549
|
+
const refreshRequests = state.refresh;
|
|
550
|
+
const mutation = useMutationRunner(`${workspaceId}\0${sessionId ?? ""}`);
|
|
551
|
+
const [respondingRequestId, setRespondingRequestId] = useState2(null);
|
|
552
|
+
const [deadlineVersion, setDeadlineVersion] = useState2(0);
|
|
553
|
+
const respondingRequestRef = useRef2(null);
|
|
554
|
+
useEffect2(() => {
|
|
555
|
+
respondingRequestRef.current = null;
|
|
556
|
+
setRespondingRequestId(null);
|
|
557
|
+
}, [sessionId, workspaceId]);
|
|
558
|
+
useEffect2(() => {
|
|
559
|
+
if (!sessionId || !enabled) return;
|
|
560
|
+
return registerSessionReconciler(sessionId, "human-input", state.refresh);
|
|
561
|
+
}, [enabled, registerSessionReconciler, sessionId, state.refresh]);
|
|
562
|
+
const scheduleRefresh = useDebouncedCallback(() => void state.refresh());
|
|
563
|
+
useSessionEventTrigger(client, workspaceId, sessionId, isHumanInputEvent, scheduleRefresh, {
|
|
564
|
+
enabled,
|
|
565
|
+
...options.events !== void 0 ? { events: options.events } : {}
|
|
566
|
+
});
|
|
567
|
+
useEffect2(() => {
|
|
568
|
+
const now2 = Date.now();
|
|
569
|
+
const nextDeadline = (loadedRequests ?? []).reduce((next, request) => {
|
|
570
|
+
if (request.status !== "pending" || !request.expiresAt) return next;
|
|
571
|
+
const deadline = Date.parse(request.expiresAt);
|
|
572
|
+
if (!Number.isFinite(deadline) || deadline <= now2) return next;
|
|
573
|
+
return next === null ? deadline : Math.min(next, deadline);
|
|
574
|
+
}, null);
|
|
575
|
+
if (nextDeadline === null) return;
|
|
576
|
+
const timer = globalThis.setTimeout(
|
|
577
|
+
() => {
|
|
578
|
+
setDeadlineVersion((current) => current + 1);
|
|
579
|
+
void refreshRequests();
|
|
580
|
+
},
|
|
581
|
+
Math.min(2147483647, Math.max(0, nextDeadline - now2 + 1))
|
|
582
|
+
);
|
|
583
|
+
return () => globalThis.clearTimeout(timer);
|
|
584
|
+
}, [loadedRequests, refreshRequests]);
|
|
585
|
+
const respond = useCallback3(
|
|
586
|
+
async (requestId, response) => {
|
|
587
|
+
if (!sessionId || respondingRequestRef.current !== null) return null;
|
|
588
|
+
respondingRequestRef.current = requestId;
|
|
589
|
+
setRespondingRequestId(requestId);
|
|
590
|
+
try {
|
|
591
|
+
const event = await mutation.run(
|
|
592
|
+
() => client.submitHumanInputResponse(workspaceId, sessionId, requestId, response, {
|
|
593
|
+
clientEventId: globalThis.crypto.randomUUID()
|
|
594
|
+
})
|
|
595
|
+
);
|
|
596
|
+
if (event) await state.refresh();
|
|
597
|
+
return event;
|
|
598
|
+
} finally {
|
|
599
|
+
if (respondingRequestRef.current === requestId) {
|
|
600
|
+
respondingRequestRef.current = null;
|
|
601
|
+
setRespondingRequestId(null);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
[client, mutation, sessionId, state, workspaceId]
|
|
606
|
+
);
|
|
607
|
+
const now = Date.now();
|
|
608
|
+
void deadlineVersion;
|
|
609
|
+
return {
|
|
610
|
+
requests: [...state.data ?? []].filter((request) => isActionableHumanInputRequest(request, now)).sort(
|
|
611
|
+
(left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id)
|
|
612
|
+
),
|
|
613
|
+
loading: state.loading,
|
|
614
|
+
error: state.error,
|
|
615
|
+
refresh: state.refresh,
|
|
616
|
+
respond,
|
|
617
|
+
respondingRequestId,
|
|
618
|
+
mutationError: mutation.mutationError,
|
|
619
|
+
clearMutationError: mutation.clearMutationError
|
|
88
620
|
};
|
|
89
|
-
return client;
|
|
90
621
|
}
|
|
91
622
|
|
|
92
623
|
// src/hooks/use-session.ts
|
|
93
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
624
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState3 } from "react";
|
|
94
625
|
function isTitleEvent(event) {
|
|
95
626
|
return event.type === "session.title_set";
|
|
96
627
|
}
|
|
628
|
+
function isSessionDetailEvent(event) {
|
|
629
|
+
return isTitleEvent(event) || event.type.startsWith("session.command.") || event.type.startsWith("session.wait.") || event.type === "session.status.changed" || event.type === "system.update.pending";
|
|
630
|
+
}
|
|
97
631
|
function useSession(sessionId, options = {}) {
|
|
98
632
|
const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } = useEmbeddedSessionRead(options);
|
|
99
633
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
100
|
-
const [override, setOverride] =
|
|
101
|
-
const nextReadRevision =
|
|
102
|
-
const nextReadGeneration =
|
|
634
|
+
const [override, setOverride] = useState3(null);
|
|
635
|
+
const nextReadRevision = useRef3(0);
|
|
636
|
+
const nextReadGeneration = useRef3(0);
|
|
103
637
|
const beginRead = options.beginRead;
|
|
104
638
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
105
|
-
const load =
|
|
639
|
+
const load = useCallback4(
|
|
106
640
|
async (signal) => {
|
|
107
641
|
if (!sessionId) {
|
|
108
642
|
return null;
|
|
@@ -128,10 +662,10 @@ function useSession(sessionId, options = {}) {
|
|
|
128
662
|
pollIntervalMs: options.pollIntervalMs,
|
|
129
663
|
enabled
|
|
130
664
|
});
|
|
131
|
-
|
|
665
|
+
useEffect3(() => {
|
|
132
666
|
if (enabled && workspaceControlEvent) void refresh();
|
|
133
667
|
}, [enabled, refresh, workspaceControlEvent]);
|
|
134
|
-
|
|
668
|
+
useEffect3(() => {
|
|
135
669
|
if (!sessionId || !enabled) return;
|
|
136
670
|
return registerSessionReconciler(sessionId, "session", refresh);
|
|
137
671
|
}, [enabled, refresh, registerSessionReconciler, sessionId]);
|
|
@@ -142,8 +676,17 @@ function useSession(sessionId, options = {}) {
|
|
|
142
676
|
() => base && override && override.id === base.id ? { ...base, title: override.title, titleSource: override.titleSource } : base,
|
|
143
677
|
[base, override]
|
|
144
678
|
);
|
|
145
|
-
const
|
|
679
|
+
const sharedEvents = options.events;
|
|
680
|
+
const onTitleEvent = useCallback4(
|
|
146
681
|
(event) => {
|
|
682
|
+
if (sharedEvents?.some(
|
|
683
|
+
(item) => item.sessionId === sessionId && !isTitleEvent(item) && isSessionDetailEvent(item) && item.sequence > (base?.lastSequence ?? -1)
|
|
684
|
+
)) {
|
|
685
|
+
void refresh();
|
|
686
|
+
} else if (!isTitleEvent(event)) {
|
|
687
|
+
if (!base || event.sequence > base.lastSequence) void refresh();
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
147
690
|
if (!base || event.sequence <= base.lastSequence) {
|
|
148
691
|
return;
|
|
149
692
|
}
|
|
@@ -158,13 +701,13 @@ function useSession(sessionId, options = {}) {
|
|
|
158
701
|
return { ...next, title, titleSource: source };
|
|
159
702
|
});
|
|
160
703
|
},
|
|
161
|
-
[base]
|
|
704
|
+
[base, refresh, sharedEvents, sessionId]
|
|
162
705
|
);
|
|
163
|
-
useSessionEventTrigger(client, workspaceId, sessionId,
|
|
706
|
+
useSessionEventTrigger(client, workspaceId, sessionId, isSessionDetailEvent, onTitleEvent, {
|
|
164
707
|
enabled,
|
|
165
708
|
...options.events !== void 0 ? { events: options.events } : {}
|
|
166
709
|
});
|
|
167
|
-
const updateTitle =
|
|
710
|
+
const updateTitle = useCallback4(
|
|
168
711
|
async (title) => {
|
|
169
712
|
if (!sessionId) {
|
|
170
713
|
return null;
|
|
@@ -191,12 +734,109 @@ function useSession(sessionId, options = {}) {
|
|
|
191
734
|
};
|
|
192
735
|
}
|
|
193
736
|
|
|
737
|
+
// src/hooks/use-session-control.ts
|
|
738
|
+
import { useCallback as useCallback5, useLayoutEffect, useRef as useRef4 } from "react";
|
|
739
|
+
function useSessionControl(sessionId, options = {}) {
|
|
740
|
+
const { client, workspaceId } = useEmbeddedSession(options);
|
|
741
|
+
const approvalTargetKey = `${workspaceId}\0${sessionId ?? ""}`;
|
|
742
|
+
const pendingApproval = useRef4(null);
|
|
743
|
+
useLayoutEffect(() => {
|
|
744
|
+
if (pendingApproval.current?.targetKey !== approvalTargetKey) {
|
|
745
|
+
pendingApproval.current = null;
|
|
746
|
+
}
|
|
747
|
+
}, [approvalTargetKey]);
|
|
748
|
+
const {
|
|
749
|
+
run: runControl,
|
|
750
|
+
mutating: controlling,
|
|
751
|
+
mutationError: controlError,
|
|
752
|
+
clearMutationError: clearControlError
|
|
753
|
+
} = useMutationRunner(approvalTargetKey);
|
|
754
|
+
const {
|
|
755
|
+
run: runApproval,
|
|
756
|
+
mutating: responding,
|
|
757
|
+
mutationError: approvalError,
|
|
758
|
+
clearMutationError: clearApprovalError
|
|
759
|
+
} = useMutationRunner(approvalTargetKey);
|
|
760
|
+
const pause = useCallback5(
|
|
761
|
+
async (reason) => {
|
|
762
|
+
if (!sessionId) {
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
return await runControl(
|
|
766
|
+
() => client.pauseSession(workspaceId, sessionId, reason !== void 0 ? { reason } : {})
|
|
767
|
+
);
|
|
768
|
+
},
|
|
769
|
+
[client, workspaceId, sessionId, runControl]
|
|
770
|
+
);
|
|
771
|
+
const resume = useCallback5(
|
|
772
|
+
async (reason) => {
|
|
773
|
+
if (!sessionId) return null;
|
|
774
|
+
return await runControl(
|
|
775
|
+
() => client.resumeSession(workspaceId, sessionId, reason !== void 0 ? { reason } : {})
|
|
776
|
+
);
|
|
777
|
+
},
|
|
778
|
+
[client, workspaceId, sessionId, runControl]
|
|
779
|
+
);
|
|
780
|
+
const decide = useCallback5(
|
|
781
|
+
async (approvalId, decision, message) => {
|
|
782
|
+
if (!sessionId) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
const decisionKey = JSON.stringify([approvalId, decision, message ?? null]);
|
|
786
|
+
if (pendingApproval.current?.decisionKey !== decisionKey) {
|
|
787
|
+
pendingApproval.current = {
|
|
788
|
+
targetKey: approvalTargetKey,
|
|
789
|
+
decisionKey,
|
|
790
|
+
clientEventId: crypto.randomUUID()
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
const clientEventId = pendingApproval.current.clientEventId;
|
|
794
|
+
const accepted = await runApproval(
|
|
795
|
+
() => client.sendApprovalDecision(workspaceId, sessionId, {
|
|
796
|
+
approvalId,
|
|
797
|
+
decision,
|
|
798
|
+
...message !== void 0 ? { message } : {},
|
|
799
|
+
clientEventId
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
if (accepted !== null && pendingApproval.current?.targetKey === approvalTargetKey && pendingApproval.current.clientEventId === clientEventId) {
|
|
803
|
+
pendingApproval.current = null;
|
|
804
|
+
}
|
|
805
|
+
return accepted;
|
|
806
|
+
},
|
|
807
|
+
[approvalTargetKey, client, workspaceId, sessionId, runApproval]
|
|
808
|
+
);
|
|
809
|
+
const approve = useCallback5(
|
|
810
|
+
async (approvalId, message) => await decide(approvalId, "approve", message),
|
|
811
|
+
[decide]
|
|
812
|
+
);
|
|
813
|
+
const reject = useCallback5(
|
|
814
|
+
async (approvalId, message) => await decide(approvalId, "reject", message),
|
|
815
|
+
[decide]
|
|
816
|
+
);
|
|
817
|
+
const error = approvalError ?? controlError;
|
|
818
|
+
const clearError = useCallback5(() => {
|
|
819
|
+
clearControlError();
|
|
820
|
+
clearApprovalError();
|
|
821
|
+
}, [clearControlError, clearApprovalError]);
|
|
822
|
+
return {
|
|
823
|
+
pause,
|
|
824
|
+
resume,
|
|
825
|
+
controlling,
|
|
826
|
+
approve,
|
|
827
|
+
reject,
|
|
828
|
+
responding,
|
|
829
|
+
error,
|
|
830
|
+
clearError
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
|
|
194
834
|
// src/hooks/use-session-events.ts
|
|
195
|
-
import {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
var
|
|
835
|
+
import {
|
|
836
|
+
sessionEventStreamCoveredThrough
|
|
837
|
+
} from "@opengeni/sdk";
|
|
838
|
+
import { startTransition, useCallback as useCallback6, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
|
|
839
|
+
var SESSION_HISTORY_PAGE_SIZE = 1e3;
|
|
200
840
|
var INITIAL_FETCH_CAP = 1;
|
|
201
841
|
var OLDER_GROUP_TARGET = 32;
|
|
202
842
|
var OLDER_FETCH_CAP = 2;
|
|
@@ -204,35 +844,16 @@ var NEWER_GROUP_TARGET = 32;
|
|
|
204
844
|
var NEWER_FETCH_CAP = 2;
|
|
205
845
|
var OLDEST_GROUP_TARGET = 32;
|
|
206
846
|
var OLDEST_FETCH_CAP = 2;
|
|
207
|
-
var BOUNDARY_PAGE_CAP =
|
|
847
|
+
var BOUNDARY_PAGE_CAP = 1;
|
|
848
|
+
var FOREGROUND_DIRECT_REPLAY_MAX_SEQUENCES = 16;
|
|
849
|
+
var FOREGROUND_COMPACT_PROBE_MAX_SEQUENCES = SESSION_HISTORY_PAGE_SIZE;
|
|
850
|
+
var FOREGROUND_COMPACT_CATCHUP_MAX_EVENTS = 128;
|
|
851
|
+
var FOREGROUND_COMPACT_CATCHUP_MAX_GROUPS = 16;
|
|
852
|
+
var FOREGROUND_COMPACT_CATCHUP_MAX_BYTES = 512 * 1024;
|
|
208
853
|
var EMPTY_EVENTS = [];
|
|
209
854
|
var encoder = new TextEncoder();
|
|
210
|
-
var
|
|
211
|
-
var
|
|
212
|
-
var BROWSER_EVENT_ID_MAX_BYTES = 256;
|
|
213
|
-
var BROWSER_EVENT_CLIENT_ID_MAX_BYTES = 4 * 1024;
|
|
214
|
-
var BROWSER_EVENT_DUPLICATE_REASON_MAX_BYTES = 4 * 1024;
|
|
215
|
-
var BROWSER_EVENT_PAYLOAD_PREVIEW_MAX_BYTES = 48 * 1024;
|
|
216
|
-
var BROWSER_EVENT_PAYLOAD_IDENTITY_FIELDS = [
|
|
217
|
-
"id",
|
|
218
|
-
"callId",
|
|
219
|
-
"call_id",
|
|
220
|
-
"name",
|
|
221
|
-
"toolName",
|
|
222
|
-
"status",
|
|
223
|
-
"code",
|
|
224
|
-
"isError",
|
|
225
|
-
"stream",
|
|
226
|
-
"commandId",
|
|
227
|
-
"sequence",
|
|
228
|
-
"coalescedUntil",
|
|
229
|
-
"coalescedCount",
|
|
230
|
-
"firstSequence",
|
|
231
|
-
"lastSequence"
|
|
232
|
-
];
|
|
233
|
-
var SESSION_EVENT_BROWSER_MAX_BYTES = 8 * 1024 * 1024;
|
|
234
|
-
var SESSION_EVENT_BROWSER_MAX_COUNT = 1e4;
|
|
235
|
-
var SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES = 96 * 1024;
|
|
855
|
+
var SESSION_EVENT_BROWSER_MAX_BYTES = 16 * 1024 * 1024;
|
|
856
|
+
var SESSION_EVENT_BROWSER_MAX_COUNT = 2e4;
|
|
236
857
|
var SESSION_EVENT_BROWSER_PENDING_MAX_BYTES = 1024 * 1024;
|
|
237
858
|
var SESSION_EVENT_BROWSER_PENDING_MAX_COUNT = 256;
|
|
238
859
|
var EMPTY_EVENT_WINDOW = {
|
|
@@ -249,43 +870,75 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
249
870
|
const replay = options.replay ?? "windowed";
|
|
250
871
|
const fullReplay = replay === "full" || after !== 0;
|
|
251
872
|
const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}\0${fullReplay ? "full" : "windowed"}`;
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
const
|
|
873
|
+
const navigationIdentityRef = useRef5({ client, streamKey, enabled });
|
|
874
|
+
if (navigationIdentityRef.current.client !== client || navigationIdentityRef.current.streamKey !== streamKey || navigationIdentityRef.current.enabled !== enabled) {
|
|
875
|
+
navigationIdentityRef.current = { client, streamKey, enabled };
|
|
876
|
+
}
|
|
877
|
+
const navigationIdentity = navigationIdentityRef.current;
|
|
878
|
+
const ownsNavigation = useCallback6(
|
|
879
|
+
() => navigationIdentityRef.current === navigationIdentity,
|
|
880
|
+
[navigationIdentity]
|
|
881
|
+
);
|
|
882
|
+
const [eventWindow, setEventWindow] = useState4(EMPTY_EVENT_WINDOW);
|
|
883
|
+
const [questionEvidence, setQuestionEvidence] = useState4(null);
|
|
884
|
+
const [connectionState, setConnectionState] = useState4("idle");
|
|
885
|
+
const [error, setError] = useState4(null);
|
|
886
|
+
const [newerError, setNewerError] = useState4(null);
|
|
887
|
+
const [hasOlder, setHasOlder] = useState4(false);
|
|
888
|
+
const [hasNewer, setHasNewer] = useState4(false);
|
|
889
|
+
const [sessionStatusProjection, setSessionStatusProjection] = useState4(
|
|
258
890
|
null
|
|
259
891
|
);
|
|
260
|
-
const [initialLoading, setInitialLoading] =
|
|
261
|
-
const [
|
|
262
|
-
const [
|
|
263
|
-
const [
|
|
264
|
-
const [
|
|
265
|
-
const [
|
|
266
|
-
const [
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
892
|
+
const [initialLoading, setInitialLoading] = useState4(true);
|
|
893
|
+
const [initialHistoryReady, setInitialHistoryReady] = useState4(false);
|
|
894
|
+
const [loadingOlder, setLoadingOlder] = useState4(false);
|
|
895
|
+
const [loadingNewer, setLoadingNewer] = useState4(false);
|
|
896
|
+
const [loadingOldest, setLoadingOldest] = useState4(false);
|
|
897
|
+
const [loadingLatest, setLoadingLatest] = useState4(false);
|
|
898
|
+
const [loadingTarget, setLoadingTarget] = useState4(false);
|
|
899
|
+
const loadingTargetRef = useRef5(false);
|
|
900
|
+
const [streamEpoch, setStreamEpoch] = useState4(0);
|
|
901
|
+
const [viewMode, setViewMode] = useState4("live");
|
|
902
|
+
const lastSequenceRef = useRef5(after);
|
|
903
|
+
const streamResumeSequenceRef = useRef5(after);
|
|
904
|
+
const oldestSequenceRef = useRef5(null);
|
|
905
|
+
const newestSequenceRef = useRef5(null);
|
|
906
|
+
const hasOlderRef = useRef5(false);
|
|
907
|
+
const hasNewerRef = useRef5(false);
|
|
908
|
+
const loadingOlderRef = useRef5(false);
|
|
909
|
+
const loadingNewerRef = useRef5(false);
|
|
910
|
+
const loadingOldestRef = useRef5(false);
|
|
911
|
+
const loadingLatestRef = useRef5(false);
|
|
912
|
+
const viewModeRef = useRef5("live");
|
|
913
|
+
const initialWindowLoadedRef = useRef5(false);
|
|
914
|
+
const reconcileAfterPageResumeRef = useRef5(false);
|
|
915
|
+
const streamAbortRef = useRef5(null);
|
|
916
|
+
const streamKeyRef = useRef5(null);
|
|
917
|
+
const generationRef = useRef5(0);
|
|
918
|
+
const navigationGenerationRef = useRef5(0);
|
|
919
|
+
const eventWindowRef = useRef5(EMPTY_EVENT_WINDOW);
|
|
920
|
+
const sessionStatusRef = useRef5({
|
|
284
921
|
sequence: after,
|
|
285
922
|
status: null
|
|
286
923
|
});
|
|
287
|
-
const [stateStreamKey, setStateStreamKey] =
|
|
288
|
-
|
|
924
|
+
const [stateStreamKey, setStateStreamKey] = useState4(streamKey);
|
|
925
|
+
useEffect4(() => {
|
|
926
|
+
navigationGenerationRef.current += 1;
|
|
927
|
+
setNewerError(null);
|
|
928
|
+
loadingOlderRef.current = false;
|
|
929
|
+
loadingNewerRef.current = false;
|
|
930
|
+
loadingOldestRef.current = false;
|
|
931
|
+
loadingTargetRef.current = false;
|
|
932
|
+
setQuestionEvidence(null);
|
|
933
|
+
setLoadingTarget(false);
|
|
934
|
+
setLoadingOlder(false);
|
|
935
|
+
setLoadingNewer(false);
|
|
936
|
+
setLoadingOldest(false);
|
|
937
|
+
return () => {
|
|
938
|
+
navigationGenerationRef.current += 1;
|
|
939
|
+
};
|
|
940
|
+
}, [client, workspaceId, sessionId, after, enabled, fullReplay]);
|
|
941
|
+
useEffect4(() => {
|
|
289
942
|
if (streamKeyRef.current !== streamKey) {
|
|
290
943
|
streamKeyRef.current = streamKey;
|
|
291
944
|
setStateStreamKey(streamKey);
|
|
@@ -301,6 +954,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
301
954
|
setLoadingOldest(false);
|
|
302
955
|
setLoadingLatest(false);
|
|
303
956
|
setInitialLoading(true);
|
|
957
|
+
setInitialHistoryReady(false);
|
|
304
958
|
lastSequenceRef.current = after;
|
|
305
959
|
streamResumeSequenceRef.current = after;
|
|
306
960
|
oldestSequenceRef.current = null;
|
|
@@ -314,24 +968,27 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
314
968
|
viewModeRef.current = "live";
|
|
315
969
|
setViewMode("live");
|
|
316
970
|
initialWindowLoadedRef.current = false;
|
|
971
|
+
reconcileAfterPageResumeRef.current = false;
|
|
317
972
|
}
|
|
318
973
|
const generation = generationRef.current + 1;
|
|
319
974
|
generationRef.current = generation;
|
|
320
|
-
if (loadingOlderRef.current) {
|
|
321
|
-
loadingOlderRef.current = false;
|
|
322
|
-
setLoadingOlder(false);
|
|
323
|
-
}
|
|
324
975
|
if (!sessionId || !streamEnabled) {
|
|
976
|
+
if (sessionId && enabled && !pageLive && !fullReplay && viewModeRef.current === "live" && initialWindowLoadedRef.current) {
|
|
977
|
+
reconcileAfterPageResumeRef.current = true;
|
|
978
|
+
}
|
|
325
979
|
setConnectionState("idle");
|
|
326
980
|
return;
|
|
327
981
|
}
|
|
328
982
|
if (viewMode === "history") {
|
|
983
|
+
reconcileAfterPageResumeRef.current = false;
|
|
329
984
|
setConnectionState("idle");
|
|
330
985
|
setInitialLoading(false);
|
|
331
986
|
return;
|
|
332
987
|
}
|
|
988
|
+
const reconcileForegroundResume = reconcileAfterPageResumeRef.current && !fullReplay;
|
|
989
|
+
reconcileAfterPageResumeRef.current = false;
|
|
333
990
|
const controller = new AbortController();
|
|
334
|
-
const isCurrent = () => generationRef.current === generation && !controller.signal.aborted;
|
|
991
|
+
const isCurrent = () => generationRef.current === generation && !controller.signal.aborted && navigationIdentityRef.current.client === client && navigationIdentityRef.current.streamKey === streamKey && navigationIdentityRef.current.enabled === enabled;
|
|
335
992
|
streamAbortRef.current = controller;
|
|
336
993
|
let pending = [];
|
|
337
994
|
let pendingBytes = 2;
|
|
@@ -366,7 +1023,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
366
1023
|
setSessionStatusProjection(status);
|
|
367
1024
|
}
|
|
368
1025
|
const current = eventWindowRef.current;
|
|
369
|
-
const next =
|
|
1026
|
+
const next = appendBrowserSessionEventWindow(current, batch);
|
|
370
1027
|
const retained = {
|
|
371
1028
|
...next,
|
|
372
1029
|
truncated: current.truncated || next.truncated
|
|
@@ -386,13 +1043,57 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
386
1043
|
};
|
|
387
1044
|
void (async () => {
|
|
388
1045
|
try {
|
|
1046
|
+
if (reconcileForegroundResume) {
|
|
1047
|
+
setConnectionState("connecting");
|
|
1048
|
+
const cursor = streamResumeSequenceRef.current;
|
|
1049
|
+
let plan = { kind: "resume" };
|
|
1050
|
+
try {
|
|
1051
|
+
plan = await planForegroundCatchup(client, workspaceId, sessionId, cursor, {
|
|
1052
|
+
signal: controller.signal
|
|
1053
|
+
});
|
|
1054
|
+
} catch {
|
|
1055
|
+
if (controller.signal.aborted) return;
|
|
1056
|
+
plan = { kind: "resume" };
|
|
1057
|
+
}
|
|
1058
|
+
if (!isCurrent()) return;
|
|
1059
|
+
if (plan.kind === "append") {
|
|
1060
|
+
const current = eventWindowRef.current;
|
|
1061
|
+
assertAppendOrder(current.events, plan.events);
|
|
1062
|
+
const status = observeSessionStatus(plan.events, sessionStatusRef);
|
|
1063
|
+
const next = appendBrowserSessionEventWindow(current, plan.events);
|
|
1064
|
+
const retained = {
|
|
1065
|
+
...next,
|
|
1066
|
+
truncated: current.truncated || next.truncated
|
|
1067
|
+
};
|
|
1068
|
+
eventWindowRef.current = retained;
|
|
1069
|
+
oldestSequenceRef.current = retained.events[0]?.sequence ?? null;
|
|
1070
|
+
newestSequenceRef.current = maxResumeSequenceOrNull(retained.events);
|
|
1071
|
+
lastSequenceRef.current = Math.max(lastSequenceRef.current, plan.resumeSequence);
|
|
1072
|
+
streamResumeSequenceRef.current = Math.max(
|
|
1073
|
+
streamResumeSequenceRef.current,
|
|
1074
|
+
plan.resumeSequence
|
|
1075
|
+
);
|
|
1076
|
+
if (status !== void 0) {
|
|
1077
|
+
setSessionStatusProjection(status);
|
|
1078
|
+
}
|
|
1079
|
+
setEventWindow(retained);
|
|
1080
|
+
if (retained.truncated) {
|
|
1081
|
+
hasOlderRef.current = true;
|
|
1082
|
+
setHasOlder(true);
|
|
1083
|
+
}
|
|
1084
|
+
} else if (plan.kind === "reload") {
|
|
1085
|
+
initialWindowLoadedRef.current = false;
|
|
1086
|
+
setError(null);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
389
1089
|
if (!fullReplay && !initialWindowLoadedRef.current) {
|
|
390
1090
|
setConnectionState("connecting");
|
|
391
1091
|
const window = await loadEventWindow(client, workspaceId, sessionId, {
|
|
392
1092
|
before: Number.MAX_SAFE_INTEGER,
|
|
393
|
-
pageSize:
|
|
1093
|
+
pageSize: SESSION_HISTORY_PAGE_SIZE,
|
|
394
1094
|
targetGroups: Number.POSITIVE_INFINITY,
|
|
395
1095
|
maxFetches: INITIAL_FETCH_CAP,
|
|
1096
|
+
boundaryPageCap: BOUNDARY_PAGE_CAP,
|
|
396
1097
|
signal: controller.signal
|
|
397
1098
|
});
|
|
398
1099
|
if (!isCurrent()) {
|
|
@@ -400,6 +1101,13 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
400
1101
|
}
|
|
401
1102
|
const status = observeSessionStatus(window.events, sessionStatusRef);
|
|
402
1103
|
const retained = boundBrowserSessionEventWindow(window.events);
|
|
1104
|
+
navigationGenerationRef.current += 1;
|
|
1105
|
+
loadingOlderRef.current = false;
|
|
1106
|
+
loadingNewerRef.current = false;
|
|
1107
|
+
loadingOldestRef.current = false;
|
|
1108
|
+
setLoadingOlder(false);
|
|
1109
|
+
setLoadingNewer(false);
|
|
1110
|
+
setLoadingOldest(false);
|
|
403
1111
|
eventWindowRef.current = retained;
|
|
404
1112
|
oldestSequenceRef.current = retained.events[0]?.sequence ?? window.oldestSequence;
|
|
405
1113
|
newestSequenceRef.current = maxResumeSequenceOrNull(retained.events) ?? window.newestSequence;
|
|
@@ -408,6 +1116,8 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
408
1116
|
lastSequenceRef.current = window.newestSequence;
|
|
409
1117
|
streamResumeSequenceRef.current = window.newestSequence;
|
|
410
1118
|
initialWindowLoadedRef.current = true;
|
|
1119
|
+
setInitialHistoryReady(true);
|
|
1120
|
+
setError(null);
|
|
411
1121
|
if (status !== void 0) {
|
|
412
1122
|
setSessionStatusProjection(status);
|
|
413
1123
|
}
|
|
@@ -425,7 +1135,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
425
1135
|
onOpen: () => {
|
|
426
1136
|
void Promise.resolve().then(() => reconcileSession(sessionId)).catch((cause) => {
|
|
427
1137
|
if (isCurrent()) {
|
|
428
|
-
setError(
|
|
1138
|
+
setError(normalizeError(cause));
|
|
429
1139
|
}
|
|
430
1140
|
});
|
|
431
1141
|
},
|
|
@@ -437,7 +1147,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
437
1147
|
});
|
|
438
1148
|
for await (const event of stream) {
|
|
439
1149
|
if (!isCurrent()) break;
|
|
440
|
-
const boundedEvent =
|
|
1150
|
+
const boundedEvent = event;
|
|
441
1151
|
const boundedEventBytes = browserJsonBytes(boundedEvent);
|
|
442
1152
|
const separatorBytes = pending.length === 0 ? 0 : 1;
|
|
443
1153
|
if (pending.length > 0 && (pending.length >= SESSION_EVENT_BROWSER_PENDING_MAX_COUNT || pendingBytes + separatorBytes + boundedEventBytes > SESSION_EVENT_BROWSER_PENDING_MAX_BYTES)) {
|
|
@@ -458,7 +1168,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
458
1168
|
} catch (cause) {
|
|
459
1169
|
if (isCurrent()) {
|
|
460
1170
|
flush();
|
|
461
|
-
setError(
|
|
1171
|
+
setError(normalizeError(cause));
|
|
462
1172
|
setConnectionState("error");
|
|
463
1173
|
setInitialLoading(false);
|
|
464
1174
|
}
|
|
@@ -481,6 +1191,8 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
481
1191
|
workspaceId,
|
|
482
1192
|
sessionId,
|
|
483
1193
|
after,
|
|
1194
|
+
enabled,
|
|
1195
|
+
pageLive,
|
|
484
1196
|
streamEnabled,
|
|
485
1197
|
fullReplay,
|
|
486
1198
|
streamKey,
|
|
@@ -488,10 +1200,10 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
488
1200
|
viewMode,
|
|
489
1201
|
reconcileSession
|
|
490
1202
|
]);
|
|
491
|
-
const navigationBusy = () => loadingOlderRef.current || loadingNewerRef.current || loadingOldestRef.current || loadingLatestRef.current;
|
|
492
|
-
const loadOlder =
|
|
493
|
-
() => createOlderHistoryLoadReceipt(async (markCommitted) => {
|
|
494
|
-
if (!sessionId || navigationBusy() || !hasOlderRef.current) {
|
|
1203
|
+
const navigationBusy = () => loadingTargetRef.current || loadingOlderRef.current || loadingNewerRef.current || loadingOldestRef.current || loadingLatestRef.current;
|
|
1204
|
+
const loadOlder = useCallback6(
|
|
1205
|
+
() => createOlderHistoryLoadReceipt(async (markCommitted, preserveTail, markTailPreserved) => {
|
|
1206
|
+
if (!ownsNavigation() || !sessionId || navigationBusy() || !hasOlderRef.current) {
|
|
495
1207
|
return false;
|
|
496
1208
|
}
|
|
497
1209
|
const before = oldestSequenceRef.current;
|
|
@@ -501,18 +1213,20 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
501
1213
|
setHasOlder(false);
|
|
502
1214
|
return false;
|
|
503
1215
|
}
|
|
504
|
-
const generation =
|
|
1216
|
+
const generation = navigationGenerationRef.current;
|
|
1217
|
+
const isCurrent = () => ownsNavigation() && navigationGenerationRef.current === generation;
|
|
505
1218
|
loadingOlderRef.current = true;
|
|
506
1219
|
setLoadingOlder(true);
|
|
507
1220
|
let published = false;
|
|
508
1221
|
try {
|
|
509
1222
|
const window = await loadEventWindow(client, workspaceId, sessionId, {
|
|
510
1223
|
before,
|
|
511
|
-
pageSize:
|
|
1224
|
+
pageSize: SESSION_HISTORY_PAGE_SIZE,
|
|
512
1225
|
targetGroups: OLDER_GROUP_TARGET,
|
|
513
|
-
maxFetches: OLDER_FETCH_CAP
|
|
1226
|
+
maxFetches: OLDER_FETCH_CAP,
|
|
1227
|
+
isCurrent
|
|
514
1228
|
});
|
|
515
|
-
if (
|
|
1229
|
+
if (!isCurrent()) {
|
|
516
1230
|
return false;
|
|
517
1231
|
}
|
|
518
1232
|
if (window.events.length === 0) {
|
|
@@ -523,11 +1237,14 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
523
1237
|
}
|
|
524
1238
|
const current = eventWindowRef.current;
|
|
525
1239
|
assertPrependOrder(current.events, window.events);
|
|
526
|
-
streamAbortRef.current?.abort();
|
|
527
|
-
const status = observeSessionStatus(window.events, sessionStatusRef);
|
|
528
1240
|
const next = boundBrowserSessionEventWindow([...window.events, ...current.events], {
|
|
529
1241
|
direction: "oldest"
|
|
530
1242
|
});
|
|
1243
|
+
if (preserveTail && maxResumeSequence(next.events) < maxResumeSequence(current.events)) {
|
|
1244
|
+
markTailPreserved();
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
const status = observeSessionStatus(window.events, sessionStatusRef);
|
|
531
1248
|
const retained = {
|
|
532
1249
|
...next,
|
|
533
1250
|
truncated: current.truncated || next.truncated
|
|
@@ -538,17 +1255,21 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
538
1255
|
}
|
|
539
1256
|
const retainedNewest = maxResumeSequenceOrNull(retained.events);
|
|
540
1257
|
const previousNewest = maxResumeSequenceOrNull(current.events);
|
|
1258
|
+
const evictedLiveTail = previousNewest !== null && retainedNewest !== null && retainedNewest < previousNewest;
|
|
1259
|
+
if (evictedLiveTail && viewModeRef.current === "live") {
|
|
1260
|
+
streamAbortRef.current?.abort();
|
|
1261
|
+
}
|
|
541
1262
|
eventWindowRef.current = retained;
|
|
542
1263
|
markCommitted();
|
|
543
1264
|
oldestSequenceRef.current = retainedOldest;
|
|
544
1265
|
newestSequenceRef.current = retainedNewest;
|
|
545
|
-
|
|
1266
|
+
if (evictedLiveTail) {
|
|
1267
|
+
streamResumeSequenceRef.current = maxResumeSequence(retained.events);
|
|
1268
|
+
}
|
|
546
1269
|
const olderStillAvailable = window.hasOlder;
|
|
547
1270
|
hasOlderRef.current = olderStillAvailable;
|
|
548
|
-
const evictedLiveTail = previousNewest !== null && retainedNewest !== null && retainedNewest < previousNewest;
|
|
549
1271
|
let newer = null;
|
|
550
1272
|
let enterHistory = false;
|
|
551
|
-
let reconnectLive = false;
|
|
552
1273
|
if (viewModeRef.current === "history" || evictedLiveTail) {
|
|
553
1274
|
const highWater = lastSequenceRef.current;
|
|
554
1275
|
newer = retainedNewest !== null && (retainedNewest < highWater || retained.truncated);
|
|
@@ -557,8 +1278,6 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
557
1278
|
viewModeRef.current = "history";
|
|
558
1279
|
enterHistory = true;
|
|
559
1280
|
}
|
|
560
|
-
} else {
|
|
561
|
-
reconnectLive = true;
|
|
562
1281
|
}
|
|
563
1282
|
loadingOlderRef.current = false;
|
|
564
1283
|
startTransition(() => {
|
|
@@ -572,38 +1291,42 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
572
1291
|
}
|
|
573
1292
|
if (enterHistory) {
|
|
574
1293
|
setViewMode("history");
|
|
575
|
-
} else if (reconnectLive) {
|
|
576
|
-
setStreamEpoch((epoch) => epoch + 1);
|
|
577
1294
|
}
|
|
578
1295
|
setLoadingOlder(false);
|
|
579
1296
|
});
|
|
580
1297
|
published = true;
|
|
581
1298
|
return olderStillAvailable;
|
|
1299
|
+
} catch (reason) {
|
|
1300
|
+
if (!isCurrent()) return false;
|
|
1301
|
+
throw reason;
|
|
582
1302
|
} finally {
|
|
583
|
-
if (!published) {
|
|
1303
|
+
if (!published && isCurrent()) {
|
|
584
1304
|
loadingOlderRef.current = false;
|
|
585
1305
|
setLoadingOlder(false);
|
|
586
1306
|
}
|
|
587
1307
|
}
|
|
588
1308
|
}),
|
|
589
|
-
[client, workspaceId, sessionId]
|
|
1309
|
+
[client, workspaceId, sessionId, ownsNavigation]
|
|
590
1310
|
);
|
|
591
|
-
const loadOldest =
|
|
592
|
-
if (!sessionId || navigationBusy() || !hasOlderRef.current) {
|
|
1311
|
+
const loadOldest = useCallback6(async () => {
|
|
1312
|
+
if (!ownsNavigation() || !sessionId || navigationBusy() || !hasOlderRef.current) {
|
|
593
1313
|
return false;
|
|
594
1314
|
}
|
|
595
|
-
const generation =
|
|
1315
|
+
const generation = ++navigationGenerationRef.current;
|
|
1316
|
+
const isCurrent = () => ownsNavigation() && navigationGenerationRef.current === generation;
|
|
1317
|
+
setQuestionEvidence(null);
|
|
596
1318
|
loadingOldestRef.current = true;
|
|
597
1319
|
setLoadingOldest(true);
|
|
598
1320
|
let published = false;
|
|
599
1321
|
try {
|
|
600
1322
|
const window = await loadForwardEventWindow(client, workspaceId, sessionId, {
|
|
601
1323
|
after: 0,
|
|
602
|
-
pageSize:
|
|
1324
|
+
pageSize: SESSION_HISTORY_PAGE_SIZE,
|
|
603
1325
|
targetGroups: OLDEST_GROUP_TARGET,
|
|
604
|
-
maxFetches: OLDEST_FETCH_CAP
|
|
1326
|
+
maxFetches: OLDEST_FETCH_CAP,
|
|
1327
|
+
isCurrent
|
|
605
1328
|
});
|
|
606
|
-
if (
|
|
1329
|
+
if (!isCurrent()) {
|
|
607
1330
|
return false;
|
|
608
1331
|
}
|
|
609
1332
|
if (window.events.length === 0) {
|
|
@@ -625,8 +1348,11 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
625
1348
|
const newer = window.hasNewer || retained.truncated || retainedNewest !== null && retainedNewest < highWater;
|
|
626
1349
|
hasNewerRef.current = newer;
|
|
627
1350
|
initialWindowLoadedRef.current = true;
|
|
1351
|
+
setInitialHistoryReady(true);
|
|
1352
|
+
setError(null);
|
|
628
1353
|
viewModeRef.current = "history";
|
|
629
1354
|
loadingOldestRef.current = false;
|
|
1355
|
+
setNewerError(null);
|
|
630
1356
|
startTransition(() => {
|
|
631
1357
|
if (status !== void 0) {
|
|
632
1358
|
setSessionStatusProjection(status);
|
|
@@ -639,15 +1365,18 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
639
1365
|
});
|
|
640
1366
|
published = true;
|
|
641
1367
|
return newer;
|
|
1368
|
+
} catch (reason) {
|
|
1369
|
+
if (!isCurrent()) return false;
|
|
1370
|
+
throw reason;
|
|
642
1371
|
} finally {
|
|
643
|
-
if (!published) {
|
|
1372
|
+
if (!published && isCurrent()) {
|
|
644
1373
|
loadingOldestRef.current = false;
|
|
645
1374
|
setLoadingOldest(false);
|
|
646
1375
|
}
|
|
647
1376
|
}
|
|
648
|
-
}, [client, workspaceId, sessionId]);
|
|
649
|
-
const loadNewer =
|
|
650
|
-
if (!sessionId || navigationBusy() || !hasNewerRef.current) {
|
|
1377
|
+
}, [client, workspaceId, sessionId, ownsNavigation]);
|
|
1378
|
+
const loadNewer = useCallback6(async () => {
|
|
1379
|
+
if (!ownsNavigation() || !sessionId || navigationBusy() || !hasNewerRef.current) {
|
|
651
1380
|
return false;
|
|
652
1381
|
}
|
|
653
1382
|
const afterSequence = newestSequenceRef.current;
|
|
@@ -656,21 +1385,24 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
656
1385
|
setHasNewer(false);
|
|
657
1386
|
return false;
|
|
658
1387
|
}
|
|
659
|
-
const generation =
|
|
1388
|
+
const generation = navigationGenerationRef.current;
|
|
1389
|
+
const isCurrent = () => ownsNavigation() && navigationGenerationRef.current === generation;
|
|
660
1390
|
loadingNewerRef.current = true;
|
|
661
1391
|
setLoadingNewer(true);
|
|
662
1392
|
let published = false;
|
|
663
1393
|
try {
|
|
664
1394
|
const window = await loadForwardEventWindow(client, workspaceId, sessionId, {
|
|
665
1395
|
after: afterSequence,
|
|
666
|
-
pageSize:
|
|
1396
|
+
pageSize: SESSION_HISTORY_PAGE_SIZE,
|
|
667
1397
|
targetGroups: NEWER_GROUP_TARGET,
|
|
668
|
-
maxFetches: NEWER_FETCH_CAP
|
|
1398
|
+
maxFetches: NEWER_FETCH_CAP,
|
|
1399
|
+
isCurrent
|
|
669
1400
|
});
|
|
670
|
-
if (
|
|
1401
|
+
if (!isCurrent()) {
|
|
671
1402
|
return false;
|
|
672
1403
|
}
|
|
673
1404
|
if (window.events.length === 0) {
|
|
1405
|
+
setNewerError(null);
|
|
674
1406
|
hasNewerRef.current = false;
|
|
675
1407
|
setHasNewer(false);
|
|
676
1408
|
streamResumeSequenceRef.current = afterSequence;
|
|
@@ -683,9 +1415,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
683
1415
|
assertAppendOrder(current.events, window.events);
|
|
684
1416
|
const status = observeSessionStatus(window.events, sessionStatusRef);
|
|
685
1417
|
const previousOldest = current.events[0]?.sequence ?? null;
|
|
686
|
-
const next =
|
|
687
|
-
direction: "newest"
|
|
688
|
-
});
|
|
1418
|
+
const next = appendBrowserSessionEventWindow(current, window.events);
|
|
689
1419
|
const retained = {
|
|
690
1420
|
...next,
|
|
691
1421
|
truncated: current.truncated || next.truncated || window.hasNewer
|
|
@@ -713,6 +1443,7 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
713
1443
|
resumeLive = true;
|
|
714
1444
|
}
|
|
715
1445
|
loadingNewerRef.current = false;
|
|
1446
|
+
setNewerError(null);
|
|
716
1447
|
startTransition(() => {
|
|
717
1448
|
if (status !== void 0) {
|
|
718
1449
|
setSessionStatusProjection(status);
|
|
@@ -728,19 +1459,147 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
728
1459
|
});
|
|
729
1460
|
published = true;
|
|
730
1461
|
return newer;
|
|
1462
|
+
} catch (reason) {
|
|
1463
|
+
if (!isCurrent()) {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
setNewerError(normalizeError(reason));
|
|
1467
|
+
throw reason;
|
|
731
1468
|
} finally {
|
|
732
|
-
if (!published) {
|
|
1469
|
+
if (!published && isCurrent()) {
|
|
733
1470
|
loadingNewerRef.current = false;
|
|
734
1471
|
setLoadingNewer(false);
|
|
735
1472
|
}
|
|
736
1473
|
}
|
|
737
|
-
}, [client, workspaceId, sessionId]);
|
|
738
|
-
const
|
|
1474
|
+
}, [client, workspaceId, sessionId, ownsNavigation]);
|
|
1475
|
+
const jumpToSequence = useCallback6(
|
|
1476
|
+
async (sequence, navigationOptions) => {
|
|
1477
|
+
const signal = navigationOptions?.signal;
|
|
1478
|
+
if (!ownsNavigation() || !sessionId || !Number.isSafeInteger(sequence) || sequence < 1)
|
|
1479
|
+
return false;
|
|
1480
|
+
if (signal?.aborted) return false;
|
|
1481
|
+
const generation = ++navigationGenerationRef.current;
|
|
1482
|
+
setQuestionEvidence(null);
|
|
1483
|
+
const current = () => generation === navigationGenerationRef.current && ownsNavigation();
|
|
1484
|
+
const previousMode = viewModeRef.current;
|
|
1485
|
+
streamAbortRef.current?.abort();
|
|
1486
|
+
generationRef.current += 1;
|
|
1487
|
+
viewModeRef.current = "history";
|
|
1488
|
+
setViewMode("history");
|
|
1489
|
+
loadingOlderRef.current = loadingNewerRef.current = loadingOldestRef.current = false;
|
|
1490
|
+
setLoadingOlder(false);
|
|
1491
|
+
setLoadingNewer(false);
|
|
1492
|
+
setLoadingOldest(false);
|
|
1493
|
+
loadingTargetRef.current = true;
|
|
1494
|
+
setLoadingTarget(true);
|
|
1495
|
+
let published = false;
|
|
1496
|
+
try {
|
|
1497
|
+
const [before, following] = await Promise.all([
|
|
1498
|
+
loadPreviousPage(client, workspaceId, sessionId, sequence + 1, { pageSize: 128 }),
|
|
1499
|
+
loadNextPage(client, workspaceId, sessionId, sequence, { pageSize: 128 })
|
|
1500
|
+
]);
|
|
1501
|
+
if (signal?.aborted) return false;
|
|
1502
|
+
if (!current()) return false;
|
|
1503
|
+
if (!before.some((event) => event.sequence === sequence)) return false;
|
|
1504
|
+
const prefix = boundBrowserSessionEventWindow(before, {
|
|
1505
|
+
direction: "newest",
|
|
1506
|
+
maxBytes: SESSION_EVENT_BROWSER_MAX_BYTES / 2
|
|
1507
|
+
});
|
|
1508
|
+
const retained = boundBrowserSessionEventWindow([...prefix.events, ...following], {
|
|
1509
|
+
direction: "oldest"
|
|
1510
|
+
});
|
|
1511
|
+
if (!retained.events.some((event) => event.sequence === sequence)) return false;
|
|
1512
|
+
streamAbortRef.current?.abort();
|
|
1513
|
+
generationRef.current += 1;
|
|
1514
|
+
const status = observeSessionStatus(retained.events, sessionStatusRef);
|
|
1515
|
+
eventWindowRef.current = retained;
|
|
1516
|
+
oldestSequenceRef.current = retained.events[0].sequence;
|
|
1517
|
+
newestSequenceRef.current = maxResumeSequenceOrNull(retained.events);
|
|
1518
|
+
lastSequenceRef.current = Math.max(lastSequenceRef.current, newestSequenceRef.current ?? 0);
|
|
1519
|
+
hasOlderRef.current = !isLogStart(retained.events[0]);
|
|
1520
|
+
hasNewerRef.current = following.length > 0 || retained.truncated || (newestSequenceRef.current ?? 0) < lastSequenceRef.current;
|
|
1521
|
+
initialWindowLoadedRef.current = true;
|
|
1522
|
+
setInitialHistoryReady(true);
|
|
1523
|
+
setError(null);
|
|
1524
|
+
viewModeRef.current = "history";
|
|
1525
|
+
setEventWindow(retained);
|
|
1526
|
+
setHasOlder(hasOlderRef.current);
|
|
1527
|
+
setHasNewer(hasNewerRef.current);
|
|
1528
|
+
setInitialLoading(false);
|
|
1529
|
+
setViewMode("history");
|
|
1530
|
+
setNewerError(null);
|
|
1531
|
+
if (status !== void 0) setSessionStatusProjection(status);
|
|
1532
|
+
published = true;
|
|
1533
|
+
return true;
|
|
1534
|
+
} catch (reason) {
|
|
1535
|
+
if (!current() || signal?.aborted) return false;
|
|
1536
|
+
throw reason;
|
|
1537
|
+
} finally {
|
|
1538
|
+
if (current()) {
|
|
1539
|
+
loadingTargetRef.current = false;
|
|
1540
|
+
setLoadingTarget(false);
|
|
1541
|
+
if (!published && previousMode === "live") {
|
|
1542
|
+
viewModeRef.current = "live";
|
|
1543
|
+
setViewMode("live");
|
|
1544
|
+
setStreamEpoch((epoch) => epoch + 1);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
[client, workspaceId, sessionId, ownsNavigation]
|
|
1550
|
+
);
|
|
1551
|
+
const jumpToLatestQuestion = useCallback6(
|
|
1552
|
+
async (questionOptions) => {
|
|
1553
|
+
if (!sessionId || !ownsNavigation()) return null;
|
|
1554
|
+
let generation = navigationGenerationRef.current;
|
|
1555
|
+
const current = () => ownsNavigation() && generation === navigationGenerationRef.current;
|
|
1556
|
+
try {
|
|
1557
|
+
const { resolveLatestQuestion } = await import("./latest-question-R77KWSUP.js");
|
|
1558
|
+
if (!current()) return null;
|
|
1559
|
+
const destination = await resolveLatestQuestion({
|
|
1560
|
+
client,
|
|
1561
|
+
workspaceId,
|
|
1562
|
+
sessionId,
|
|
1563
|
+
isCurrent: current,
|
|
1564
|
+
resumeSequence: maxResumeSequence,
|
|
1565
|
+
options: questionOptions
|
|
1566
|
+
});
|
|
1567
|
+
if (!destination || !current()) return null;
|
|
1568
|
+
if (!eventWindowRef.current.events.some((event) => event.sequence === destination.anchor)) {
|
|
1569
|
+
const navigation = jumpToSequence(destination.anchor);
|
|
1570
|
+
generation = navigationGenerationRef.current;
|
|
1571
|
+
if (!await navigation || !current()) return null;
|
|
1572
|
+
}
|
|
1573
|
+
setQuestionEvidence({
|
|
1574
|
+
client,
|
|
1575
|
+
streamKey,
|
|
1576
|
+
anchor: destination.anchor,
|
|
1577
|
+
events: destination.events
|
|
1578
|
+
});
|
|
1579
|
+
return destination.questionSequence;
|
|
1580
|
+
} catch (reason) {
|
|
1581
|
+
if (!current()) return null;
|
|
1582
|
+
throw reason;
|
|
1583
|
+
}
|
|
1584
|
+
},
|
|
1585
|
+
[client, workspaceId, sessionId, streamKey, ownsNavigation, jumpToSequence]
|
|
1586
|
+
);
|
|
1587
|
+
const jumpToLatest = useCallback6(async () => {
|
|
1588
|
+
if (!ownsNavigation()) return;
|
|
1589
|
+
if (loadingTargetRef.current) {
|
|
1590
|
+
navigationGenerationRef.current += 1;
|
|
1591
|
+
loadingTargetRef.current = false;
|
|
1592
|
+
setLoadingTarget(false);
|
|
1593
|
+
}
|
|
739
1594
|
if (!sessionId || navigationBusy()) {
|
|
740
1595
|
return;
|
|
741
1596
|
}
|
|
1597
|
+
navigationGenerationRef.current += 1;
|
|
1598
|
+
setQuestionEvidence(null);
|
|
742
1599
|
loadingLatestRef.current = true;
|
|
743
1600
|
setLoadingLatest(true);
|
|
1601
|
+
setNewerError(null);
|
|
1602
|
+
setError(null);
|
|
744
1603
|
let published = false;
|
|
745
1604
|
try {
|
|
746
1605
|
streamAbortRef.current?.abort();
|
|
@@ -770,19 +1629,30 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
770
1629
|
setLoadingLatest(false);
|
|
771
1630
|
}
|
|
772
1631
|
}
|
|
773
|
-
}, [after, sessionId]);
|
|
1632
|
+
}, [after, sessionId, ownsNavigation]);
|
|
774
1633
|
const identityMatches = stateStreamKey === streamKey;
|
|
775
1634
|
const visibleEvents = identityMatches ? eventWindow.events : EMPTY_EVENTS;
|
|
776
|
-
const timeline = useMemo2(() =>
|
|
1635
|
+
const timeline = useMemo2(() => {
|
|
1636
|
+
const witness = questionEvidence?.client === client && questionEvidence.streamKey === streamKey && visibleEvents.some((event) => event.sequence === questionEvidence.anchor) ? questionEvidence.events : EMPTY_EVENTS;
|
|
1637
|
+
const timelineOptions = { partialStart: hasOlder || eventWindow.truncated || after > 0 };
|
|
1638
|
+
if (witness.length === 0) return buildTimeline(visibleEvents, timelineOptions);
|
|
1639
|
+
const ids = new Set(visibleEvents.map((event) => event.id));
|
|
1640
|
+
return buildTimeline(
|
|
1641
|
+
[...visibleEvents, ...witness.filter((event) => !ids.has(event.id))],
|
|
1642
|
+
timelineOptions
|
|
1643
|
+
);
|
|
1644
|
+
}, [visibleEvents, hasOlder, eventWindow.truncated, after, questionEvidence, client, streamKey]);
|
|
777
1645
|
return {
|
|
778
1646
|
events: visibleEvents,
|
|
779
1647
|
timeline,
|
|
780
1648
|
sessionStatus: identityMatches ? sessionStatusProjection : null,
|
|
1649
|
+
sessionStatusSequence: identityMatches ? sessionStatusRef.current.sequence : 0,
|
|
781
1650
|
connectionState: identityMatches ? connectionState : "idle",
|
|
782
1651
|
lastSequence: identityMatches ? lastSequenceRef.current : after,
|
|
783
1652
|
windowBytes: identityMatches ? eventWindow.bytes : 2,
|
|
784
1653
|
windowTruncated: identityMatches ? eventWindow.truncated : false,
|
|
785
1654
|
initialLoading: fullReplay ? false : identityMatches ? initialLoading : true,
|
|
1655
|
+
initialHistoryReady: identityMatches && initialHistoryReady,
|
|
786
1656
|
hasOlder: !identityMatches ? false : hasOlder,
|
|
787
1657
|
loadingOlder: !identityMatches ? false : loadingOlder,
|
|
788
1658
|
loadOlder,
|
|
@@ -793,13 +1663,16 @@ function useSessionEvents(sessionId, options = {}) {
|
|
|
793
1663
|
loadOldest,
|
|
794
1664
|
loadingLatest: !identityMatches ? false : loadingLatest,
|
|
795
1665
|
jumpToLatest,
|
|
796
|
-
|
|
1666
|
+
jumpToLatestQuestion,
|
|
1667
|
+
jumpToSequence,
|
|
1668
|
+
loadingTarget: identityMatches && loadingTarget,
|
|
1669
|
+
error: identityMatches ? newerError ?? error : null
|
|
797
1670
|
};
|
|
798
1671
|
}
|
|
799
1672
|
function boundBrowserSessionEventWindow(events, options = {}) {
|
|
800
1673
|
const maxBytes = Math.max(1024, options.maxBytes ?? SESSION_EVENT_BROWSER_MAX_BYTES);
|
|
801
1674
|
const maxCount = Math.max(1, Math.floor(options.maxCount ?? SESSION_EVENT_BROWSER_MAX_COUNT));
|
|
802
|
-
const safe = events
|
|
1675
|
+
const safe = events;
|
|
803
1676
|
const selected = [];
|
|
804
1677
|
let bytes = 2;
|
|
805
1678
|
const direction = options.direction ?? "newest";
|
|
@@ -810,7 +1683,7 @@ function boundBrowserSessionEventWindow(events, options = {}) {
|
|
|
810
1683
|
const event = safe[index];
|
|
811
1684
|
const eventBytes = browserJsonBytes(event);
|
|
812
1685
|
const separator = selected.length === 0 ? 0 : 1;
|
|
813
|
-
if (bytes + separator + eventBytes > maxBytes) break;
|
|
1686
|
+
if (selected.length > 0 && bytes + separator + eventBytes > maxBytes) break;
|
|
814
1687
|
selected.push(event);
|
|
815
1688
|
bytes += separator + eventBytes;
|
|
816
1689
|
}
|
|
@@ -821,182 +1694,27 @@ function boundBrowserSessionEventWindow(events, options = {}) {
|
|
|
821
1694
|
truncated: selected.length < safe.length
|
|
822
1695
|
};
|
|
823
1696
|
}
|
|
824
|
-
function
|
|
825
|
-
const
|
|
826
|
-
const
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
);
|
|
832
|
-
const duplicateReason = boundBrowserOptionalText(
|
|
833
|
-
event.duplicateReason,
|
|
834
|
-
BROWSER_EVENT_DUPLICATE_REASON_MAX_BYTES
|
|
835
|
-
);
|
|
836
|
-
if (serialized.serializable && originalBytes !== null && originalBytes <= SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES && typeIsSafe && clientEventId === event.clientEventId && duplicateReason === event.duplicateReason) {
|
|
837
|
-
return event;
|
|
838
|
-
}
|
|
839
|
-
const envelopeProjection = [
|
|
840
|
-
!typeIsSafe ? browserEnvelopeFieldProjection("type", event.type, "session.event.envelope_omitted") : null,
|
|
841
|
-
clientEventId !== event.clientEventId ? browserEnvelopeFieldProjection("clientEventId", event.clientEventId, clientEventId) : null,
|
|
842
|
-
duplicateReason !== event.duplicateReason ? browserEnvelopeFieldProjection("duplicateReason", event.duplicateReason, duplicateReason) : null
|
|
843
|
-
].filter((field) => field !== null);
|
|
844
|
-
const payloadSerialization = browserSerialize(event.payload);
|
|
845
|
-
const payloadBytes = payloadSerialization.serializable ? encoder.encode(payloadSerialization.value).byteLength : null;
|
|
846
|
-
const preview = truncateBrowserUtf8Middle(
|
|
847
|
-
payloadSerialization.value,
|
|
848
|
-
BROWSER_EVENT_PAYLOAD_PREVIEW_MAX_BYTES
|
|
849
|
-
);
|
|
850
|
-
const truncation = {
|
|
851
|
-
truncated: true,
|
|
852
|
-
surface: "browser_legacy_guard",
|
|
853
|
-
reason: serialized.serializable ? "event_envelope_bytes_exceeded" : "event_not_serializable",
|
|
854
|
-
originalBytes,
|
|
855
|
-
deliveredBytes: 0,
|
|
856
|
-
omittedBytes: originalBytes,
|
|
857
|
-
estimatedOriginalTokens: originalBytes === null ? null : Math.ceil(originalBytes / 4),
|
|
858
|
-
estimatedDeliveredTokens: 0,
|
|
859
|
-
fullEvidence: { available: false, reason: "not_retained" },
|
|
860
|
-
details: [
|
|
861
|
-
{
|
|
862
|
-
path: "$.payload",
|
|
863
|
-
kind: "payload_preview",
|
|
864
|
-
originalBytes: payloadBytes,
|
|
865
|
-
deliveredBytes: browserUtf8Bytes(preview)
|
|
866
|
-
}
|
|
867
|
-
]
|
|
868
|
-
};
|
|
869
|
-
const payload = {
|
|
870
|
-
...browserPayloadIdentity(event.payload),
|
|
871
|
-
preview,
|
|
872
|
-
...envelopeProjection.length > 0 ? {
|
|
873
|
-
originalType: boundBrowserText(event.type, BROWSER_EVENT_TYPE_MAX_BYTES),
|
|
874
|
-
envelopeProjection: {
|
|
875
|
-
truncated: true,
|
|
876
|
-
surface: "browser_legacy_guard",
|
|
877
|
-
fields: envelopeProjection
|
|
878
|
-
}
|
|
879
|
-
} : {},
|
|
880
|
-
truncation
|
|
881
|
-
};
|
|
882
|
-
const bounded = {
|
|
883
|
-
id: boundBrowserText(event.id, BROWSER_EVENT_ID_MAX_BYTES),
|
|
884
|
-
workspaceId: boundBrowserText(event.workspaceId, BROWSER_EVENT_ID_MAX_BYTES),
|
|
885
|
-
sessionId: boundBrowserText(event.sessionId, BROWSER_EVENT_ID_MAX_BYTES),
|
|
886
|
-
sequence: event.sequence,
|
|
887
|
-
type: typeIsSafe ? event.type : "session.event.envelope_omitted",
|
|
888
|
-
payload,
|
|
889
|
-
occurredAt: boundBrowserText(event.occurredAt, BROWSER_EVENT_ID_MAX_BYTES),
|
|
890
|
-
clientEventId,
|
|
891
|
-
turnId: boundBrowserOptionalText(event.turnId, BROWSER_EVENT_ID_MAX_BYTES),
|
|
892
|
-
turnGeneration: event.turnGeneration,
|
|
893
|
-
turnAttemptId: boundBrowserOptionalText(event.turnAttemptId, BROWSER_EVENT_ID_MAX_BYTES),
|
|
894
|
-
turnAssociation: event.turnAssociation,
|
|
895
|
-
duplicateOfEventId: boundBrowserOptionalText(
|
|
896
|
-
event.duplicateOfEventId,
|
|
897
|
-
BROWSER_EVENT_ID_MAX_BYTES
|
|
898
|
-
),
|
|
899
|
-
duplicateReason
|
|
900
|
-
};
|
|
901
|
-
settleBrowserEventTruncation(bounded, truncation);
|
|
902
|
-
if (browserJsonBytes(bounded) > SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES) {
|
|
903
|
-
payload.preview = truncateBrowserUtf8Middle(String(payload.preview), 4 * 1024);
|
|
904
|
-
truncation.details = truncation.details.slice(0, 1);
|
|
905
|
-
settleBrowserEventTruncation(bounded, truncation);
|
|
906
|
-
}
|
|
907
|
-
if (browserJsonBytes(bounded) > SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES) {
|
|
908
|
-
bounded.clientEventId = null;
|
|
909
|
-
bounded.duplicateReason = null;
|
|
910
|
-
payload.preview = "[legacy event omitted at the browser byte boundary]";
|
|
911
|
-
settleBrowserEventTruncation(bounded, truncation);
|
|
912
|
-
}
|
|
913
|
-
return bounded;
|
|
914
|
-
}
|
|
915
|
-
function browserJsonBytes(value) {
|
|
916
|
-
return encoder.encode(browserSerialize(value).value).byteLength;
|
|
917
|
-
}
|
|
918
|
-
function browserSerialize(value) {
|
|
919
|
-
try {
|
|
920
|
-
const serialized = JSON.stringify(value);
|
|
921
|
-
return { value: serialized === void 0 ? "null" : serialized, serializable: true };
|
|
922
|
-
} catch {
|
|
923
|
-
return {
|
|
924
|
-
value: '"[unserializable event payload omitted at browser boundary]"',
|
|
925
|
-
serializable: false
|
|
926
|
-
};
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
function browserPayloadIdentity(payload) {
|
|
930
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return {};
|
|
931
|
-
const record = payload;
|
|
932
|
-
const identity = {};
|
|
933
|
-
for (const field of BROWSER_EVENT_PAYLOAD_IDENTITY_FIELDS) {
|
|
934
|
-
const value = record[field];
|
|
935
|
-
if (typeof value === "string") {
|
|
936
|
-
identity[field] = boundBrowserText(value, BROWSER_EVENT_ID_MAX_BYTES);
|
|
937
|
-
} else if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
938
|
-
identity[field] = value;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
return identity;
|
|
942
|
-
}
|
|
943
|
-
function browserEnvelopeFieldProjection(field, original, delivered) {
|
|
944
|
-
return {
|
|
945
|
-
field,
|
|
946
|
-
originalBytes: typeof original === "string" ? browserUtf8Bytes(original) : 0,
|
|
947
|
-
deliveredBytes: typeof delivered === "string" ? browserUtf8Bytes(delivered) : 0
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
function boundBrowserOptionalText(value, maxBytes) {
|
|
951
|
-
return typeof value === "string" ? boundBrowserText(value, maxBytes) : value;
|
|
952
|
-
}
|
|
953
|
-
function boundBrowserText(value, maxBytes) {
|
|
954
|
-
const bytes = encoder.encode(value);
|
|
955
|
-
if (bytes.byteLength <= maxBytes) return value;
|
|
956
|
-
const marker = "\u2026[truncated]";
|
|
957
|
-
const prefixBudget = Math.max(0, maxBytes - browserUtf8Bytes(marker));
|
|
958
|
-
let prefixEnd = Math.min(prefixBudget, bytes.byteLength);
|
|
959
|
-
while (prefixEnd > 0 && prefixEnd < bytes.byteLength && isBrowserUtf8Continuation(bytes[prefixEnd])) {
|
|
960
|
-
prefixEnd -= 1;
|
|
961
|
-
}
|
|
962
|
-
return `${decoder.decode(bytes.subarray(0, prefixEnd))}${marker}`;
|
|
963
|
-
}
|
|
964
|
-
function truncateBrowserUtf8Middle(value, maxBytes) {
|
|
965
|
-
const bytes = encoder.encode(value);
|
|
966
|
-
if (bytes.byteLength <= maxBytes) return value;
|
|
967
|
-
const marker = `\u2026[${bytes.byteLength - maxBytes} bytes omitted]\u2026`;
|
|
968
|
-
const contentBudget = Math.max(0, maxBytes - browserUtf8Bytes(marker));
|
|
969
|
-
const leftBudget = Math.floor(contentBudget / 2);
|
|
970
|
-
const rightBudget = contentBudget - leftBudget;
|
|
971
|
-
let leftEnd = Math.min(leftBudget, bytes.byteLength);
|
|
972
|
-
while (leftEnd > 0 && leftEnd < bytes.byteLength && isBrowserUtf8Continuation(bytes[leftEnd])) {
|
|
973
|
-
leftEnd -= 1;
|
|
974
|
-
}
|
|
975
|
-
let rightStart = Math.max(0, bytes.byteLength - rightBudget);
|
|
976
|
-
while (rightStart < bytes.byteLength && isBrowserUtf8Continuation(bytes[rightStart])) {
|
|
977
|
-
rightStart += 1;
|
|
978
|
-
}
|
|
979
|
-
return `${decoder.decode(bytes.subarray(0, leftEnd))}${marker}${decoder.decode(bytes.subarray(rightStart))}`;
|
|
980
|
-
}
|
|
981
|
-
function settleBrowserEventTruncation(event, truncation) {
|
|
982
|
-
for (let attempt = 0; attempt < 16; attempt += 1) {
|
|
983
|
-
const deliveredBytes = browserJsonBytes(event);
|
|
984
|
-
const omittedBytes = truncation.originalBytes === null ? null : Math.max(0, truncation.originalBytes - deliveredBytes);
|
|
985
|
-
const estimatedDeliveredTokens = Math.ceil(deliveredBytes / 4);
|
|
986
|
-
if (truncation.deliveredBytes === deliveredBytes && truncation.omittedBytes === omittedBytes && truncation.estimatedDeliveredTokens === estimatedDeliveredTokens) {
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
truncation.deliveredBytes = deliveredBytes;
|
|
990
|
-
truncation.omittedBytes = omittedBytes;
|
|
991
|
-
truncation.estimatedDeliveredTokens = estimatedDeliveredTokens;
|
|
1697
|
+
function appendBrowserSessionEventWindow(current, batch, options = {}) {
|
|
1698
|
+
const maxBytes = Math.max(1024, options.maxBytes ?? SESSION_EVENT_BROWSER_MAX_BYTES);
|
|
1699
|
+
const maxCount = Math.max(1, Math.floor(options.maxCount ?? SESSION_EVENT_BROWSER_MAX_COUNT));
|
|
1700
|
+
const events = [...current.events, ...batch];
|
|
1701
|
+
let bytes = current.bytes;
|
|
1702
|
+
for (let index = 0; index < batch.length; index += 1) {
|
|
1703
|
+
bytes += browserJsonBytes(batch[index]) + (current.events.length + index > 0 ? 1 : 0);
|
|
992
1704
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1705
|
+
let start = 0;
|
|
1706
|
+
while (events.length - start > 1 && (bytes > maxBytes || events.length - start > maxCount)) {
|
|
1707
|
+
bytes -= browserJsonBytes(events[start]) + 1;
|
|
1708
|
+
start += 1;
|
|
1709
|
+
}
|
|
1710
|
+
return {
|
|
1711
|
+
events: start === 0 ? events : events.slice(start),
|
|
1712
|
+
bytes,
|
|
1713
|
+
truncated: current.truncated || start > 0
|
|
1714
|
+
};
|
|
997
1715
|
}
|
|
998
|
-
function
|
|
999
|
-
return (value
|
|
1716
|
+
function browserJsonBytes(value) {
|
|
1717
|
+
return encoder.encode(JSON.stringify(value)).byteLength;
|
|
1000
1718
|
}
|
|
1001
1719
|
function observeSessionStatus(events, ref) {
|
|
1002
1720
|
let latest = null;
|
|
@@ -1010,6 +1728,39 @@ function observeSessionStatus(events, ref) {
|
|
|
1010
1728
|
ref.current = latest;
|
|
1011
1729
|
return latest.status;
|
|
1012
1730
|
}
|
|
1731
|
+
async function planForegroundCatchup(client, workspaceId, sessionId, cursor, options = {}) {
|
|
1732
|
+
if (options.signal?.aborted) throw abortError();
|
|
1733
|
+
const session = await client.getSession(workspaceId, sessionId, {
|
|
1734
|
+
fresh: true,
|
|
1735
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1736
|
+
});
|
|
1737
|
+
if (options.signal?.aborted) throw abortError();
|
|
1738
|
+
const durableHead = Math.max(cursor, session.lastSequence);
|
|
1739
|
+
const rawGap = durableHead - cursor;
|
|
1740
|
+
if (rawGap <= FOREGROUND_DIRECT_REPLAY_MAX_SEQUENCES) {
|
|
1741
|
+
return { kind: "resume" };
|
|
1742
|
+
}
|
|
1743
|
+
if (rawGap > FOREGROUND_COMPACT_PROBE_MAX_SEQUENCES) {
|
|
1744
|
+
return { kind: "reload" };
|
|
1745
|
+
}
|
|
1746
|
+
const page = await loadNextPage(client, workspaceId, sessionId, cursor, {
|
|
1747
|
+
pageSize: rawGap,
|
|
1748
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1749
|
+
});
|
|
1750
|
+
const events = page.filter((event) => eventResumeSequence(event) > cursor);
|
|
1751
|
+
if (events.length === 0) {
|
|
1752
|
+
return { kind: "reload" };
|
|
1753
|
+
}
|
|
1754
|
+
assertAscending(events);
|
|
1755
|
+
const resumeSequence = maxResumeSequence(events);
|
|
1756
|
+
if (resumeSequence < durableHead) {
|
|
1757
|
+
return { kind: "reload" };
|
|
1758
|
+
}
|
|
1759
|
+
if (events.length > FOREGROUND_COMPACT_CATCHUP_MAX_EVENTS || groupCount(events) > FOREGROUND_COMPACT_CATCHUP_MAX_GROUPS || browserJsonBytes(events) > FOREGROUND_COMPACT_CATCHUP_MAX_BYTES) {
|
|
1760
|
+
return { kind: "reload" };
|
|
1761
|
+
}
|
|
1762
|
+
return { kind: "append", events, resumeSequence };
|
|
1763
|
+
}
|
|
1013
1764
|
async function loadEventWindow(client, workspaceId, sessionId, options) {
|
|
1014
1765
|
let cursor = options.before;
|
|
1015
1766
|
let buffer = [];
|
|
@@ -1023,6 +1774,7 @@ async function loadEventWindow(client, workspaceId, sessionId, options) {
|
|
|
1023
1774
|
pageSize: options.pageSize,
|
|
1024
1775
|
...options.signal ? { signal: options.signal } : {}
|
|
1025
1776
|
});
|
|
1777
|
+
if (options.isCurrent?.() === false) throw abortError();
|
|
1026
1778
|
fetches += 1;
|
|
1027
1779
|
if (page.length === 0) {
|
|
1028
1780
|
reachedStart = true;
|
|
@@ -1037,11 +1789,12 @@ async function loadEventWindow(client, workspaceId, sessionId, options) {
|
|
|
1037
1789
|
}
|
|
1038
1790
|
}
|
|
1039
1791
|
let snapPages = 0;
|
|
1040
|
-
while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages <
|
|
1792
|
+
while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages < (options.boundaryPageCap ?? 0)) {
|
|
1041
1793
|
const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
|
|
1042
1794
|
pageSize: options.pageSize,
|
|
1043
1795
|
...options.signal ? { signal: options.signal } : {}
|
|
1044
1796
|
});
|
|
1797
|
+
if (options.isCurrent?.() === false) throw abortError();
|
|
1045
1798
|
fetches += 1;
|
|
1046
1799
|
snapPages += 1;
|
|
1047
1800
|
if (page.length === 0) {
|
|
@@ -1097,6 +1850,7 @@ async function loadForwardEventWindow(client, workspaceId, sessionId, options) {
|
|
|
1097
1850
|
pageSize: options.pageSize,
|
|
1098
1851
|
...options.signal ? { signal: options.signal } : {}
|
|
1099
1852
|
});
|
|
1853
|
+
if (options.isCurrent?.() === false) throw abortError();
|
|
1100
1854
|
fetches += 1;
|
|
1101
1855
|
if (page.length === 0) {
|
|
1102
1856
|
reachedEnd = true;
|
|
@@ -1202,12 +1956,9 @@ function maxResumeSequenceOrNull(events) {
|
|
|
1202
1956
|
return events.length > 0 ? maxResumeSequence(events) : null;
|
|
1203
1957
|
}
|
|
1204
1958
|
function eventResumeSequence(event) {
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
return
|
|
1208
|
-
}
|
|
1209
|
-
function asRecord(value) {
|
|
1210
|
-
return value && typeof value === "object" ? value : {};
|
|
1959
|
+
const streamedCoverage = sessionEventStreamCoveredThrough(event);
|
|
1960
|
+
if (streamedCoverage !== null) return streamedCoverage;
|
|
1961
|
+
return typeof event.coveredThrough === "number" && Number.isSafeInteger(event.coveredThrough) && event.coveredThrough >= event.sequence ? event.coveredThrough : event.sequence;
|
|
1211
1962
|
}
|
|
1212
1963
|
function assertAscending(events) {
|
|
1213
1964
|
for (let index = 1; index < events.length; index += 1) {
|
|
@@ -1216,275 +1967,34 @@ function assertAscending(events) {
|
|
|
1216
1967
|
}
|
|
1217
1968
|
}
|
|
1218
1969
|
}
|
|
1219
|
-
function assertPrependOrder(existing, older) {
|
|
1220
|
-
if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
|
-
if (older[older.length - 1].sequence >= existing[0].sequence) {
|
|
1224
|
-
throw new Error("@opengeni/react: loadOlder returned overlapping session events");
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
function assertAppendOrder(existing, newer) {
|
|
1228
|
-
if (!shouldAssertDevelopment() || existing.length === 0 || newer.length === 0) {
|
|
1229
|
-
return;
|
|
1230
|
-
}
|
|
1231
|
-
if (newer[0].sequence <= existing[existing.length - 1].sequence) {
|
|
1232
|
-
throw new Error("@opengeni/react: loadNewer returned overlapping session events");
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
function shouldAssertDevelopment() {
|
|
1236
|
-
const processEnv = globalThis.process?.env;
|
|
1237
|
-
return processEnv !== void 0 && processEnv.NODE_ENV !== "production";
|
|
1238
|
-
}
|
|
1239
|
-
function abortError() {
|
|
1240
|
-
const error = new Error("The operation was aborted.");
|
|
1241
|
-
error.name = "AbortError";
|
|
1242
|
-
return error;
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
// src/hooks/use-file-attachments.ts
|
|
1246
|
-
import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
1247
|
-
var isImage = (file) => file.type.startsWith("image/");
|
|
1248
|
-
function useFileAttachments(options = {}) {
|
|
1249
|
-
const { client, workspaceId } = useEmbeddedFileAttachments(options);
|
|
1250
|
-
const pasteFilter = options.pasteFilter ?? isImage;
|
|
1251
|
-
const [attachments, setAttachments] = useState3([]);
|
|
1252
|
-
const sources = useRef3(/* @__PURE__ */ new Map());
|
|
1253
|
-
const previewUrls = useRef3(/* @__PURE__ */ new Map());
|
|
1254
|
-
const previewRetainers = useRef3(/* @__PURE__ */ new Map());
|
|
1255
|
-
const pendingPreviewRevocations = useRef3(/* @__PURE__ */ new Set());
|
|
1256
|
-
const revokePreview = useCallback3((id) => {
|
|
1257
|
-
const previewUrl = previewUrls.current.get(id);
|
|
1258
|
-
if (!previewUrl) return;
|
|
1259
|
-
if ((previewRetainers.current.get(id) ?? 0) > 0) {
|
|
1260
|
-
pendingPreviewRevocations.current.add(id);
|
|
1261
|
-
return;
|
|
1262
|
-
}
|
|
1263
|
-
previewUrls.current.delete(id);
|
|
1264
|
-
pendingPreviewRevocations.current.delete(id);
|
|
1265
|
-
URL.revokeObjectURL(previewUrl);
|
|
1266
|
-
}, []);
|
|
1267
|
-
const revokeAllPreviews = useCallback3(() => {
|
|
1268
|
-
for (const id of previewUrls.current.keys()) revokePreview(id);
|
|
1269
|
-
}, [revokePreview]);
|
|
1270
|
-
const retainPreview = useCallback3(
|
|
1271
|
-
(id) => {
|
|
1272
|
-
if (!previewUrls.current.has(id)) return void 0;
|
|
1273
|
-
previewRetainers.current.set(id, (previewRetainers.current.get(id) ?? 0) + 1);
|
|
1274
|
-
let released = false;
|
|
1275
|
-
return () => {
|
|
1276
|
-
if (released) return;
|
|
1277
|
-
released = true;
|
|
1278
|
-
const remaining = (previewRetainers.current.get(id) ?? 1) - 1;
|
|
1279
|
-
if (remaining > 0) {
|
|
1280
|
-
previewRetainers.current.set(id, remaining);
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
previewRetainers.current.delete(id);
|
|
1284
|
-
if (pendingPreviewRevocations.current.has(id)) revokePreview(id);
|
|
1285
|
-
};
|
|
1286
|
-
},
|
|
1287
|
-
[revokePreview]
|
|
1288
|
-
);
|
|
1289
|
-
const committedAttachmentIds = useRef3(/* @__PURE__ */ new Set());
|
|
1290
|
-
useEffect3(() => {
|
|
1291
|
-
const currentIds = new Set(attachments.map((attachment) => attachment.id));
|
|
1292
|
-
for (const id of committedAttachmentIds.current) {
|
|
1293
|
-
if (!currentIds.has(id)) revokePreview(id);
|
|
1294
|
-
}
|
|
1295
|
-
committedAttachmentIds.current = currentIds;
|
|
1296
|
-
}, [attachments, revokePreview]);
|
|
1297
|
-
const scopeGeneration = useRef3(0);
|
|
1298
|
-
const previousScope = useRef3({ client, workspaceId });
|
|
1299
|
-
useEffect3(() => {
|
|
1300
|
-
const previous = previousScope.current;
|
|
1301
|
-
if (previous.client === client && previous.workspaceId === workspaceId) return;
|
|
1302
|
-
previousScope.current = { client, workspaceId };
|
|
1303
|
-
scopeGeneration.current += 1;
|
|
1304
|
-
sources.current.clear();
|
|
1305
|
-
revokeAllPreviews();
|
|
1306
|
-
setAttachments([]);
|
|
1307
|
-
}, [client, revokeAllPreviews, workspaceId]);
|
|
1308
|
-
useEffect3(
|
|
1309
|
-
() => () => {
|
|
1310
|
-
scopeGeneration.current += 1;
|
|
1311
|
-
sources.current.clear();
|
|
1312
|
-
revokeAllPreviews();
|
|
1313
|
-
},
|
|
1314
|
-
[revokeAllPreviews]
|
|
1315
|
-
);
|
|
1316
|
-
const startUpload = useCallback3(
|
|
1317
|
-
(id, file) => {
|
|
1318
|
-
const generation = scopeGeneration.current;
|
|
1319
|
-
void client.uploadFile(workspaceId, {
|
|
1320
|
-
filename: file.name || "file",
|
|
1321
|
-
contentType: file.type || "application/octet-stream",
|
|
1322
|
-
data: file
|
|
1323
|
-
}).then((asset) => {
|
|
1324
|
-
if (scopeGeneration.current !== generation) return;
|
|
1325
|
-
sources.current.delete(id);
|
|
1326
|
-
setAttachments(
|
|
1327
|
-
(current) => current.map(
|
|
1328
|
-
(attachment) => attachment.id === id ? {
|
|
1329
|
-
...attachment,
|
|
1330
|
-
status: "ready",
|
|
1331
|
-
file: asset,
|
|
1332
|
-
name: asset.filename,
|
|
1333
|
-
contentType: asset.contentType,
|
|
1334
|
-
sizeBytes: asset.sizeBytes,
|
|
1335
|
-
error: void 0
|
|
1336
|
-
} : attachment
|
|
1337
|
-
)
|
|
1338
|
-
);
|
|
1339
|
-
}).catch((error) => {
|
|
1340
|
-
if (scopeGeneration.current !== generation) return;
|
|
1341
|
-
setAttachments(
|
|
1342
|
-
(current) => current.map(
|
|
1343
|
-
(attachment) => attachment.id === id ? {
|
|
1344
|
-
...attachment,
|
|
1345
|
-
status: "failed",
|
|
1346
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1347
|
-
} : attachment
|
|
1348
|
-
)
|
|
1349
|
-
);
|
|
1350
|
-
});
|
|
1351
|
-
},
|
|
1352
|
-
[client, workspaceId]
|
|
1353
|
-
);
|
|
1354
|
-
const addFiles = useCallback3(
|
|
1355
|
-
(files) => {
|
|
1356
|
-
for (const file of files) {
|
|
1357
|
-
const id = crypto.randomUUID();
|
|
1358
|
-
sources.current.set(id, file);
|
|
1359
|
-
const previewUrl = isImage(file) ? URL.createObjectURL(file) : void 0;
|
|
1360
|
-
if (previewUrl) previewUrls.current.set(id, previewUrl);
|
|
1361
|
-
setAttachments((current) => [
|
|
1362
|
-
...current,
|
|
1363
|
-
{
|
|
1364
|
-
id,
|
|
1365
|
-
name: file.name || "image",
|
|
1366
|
-
contentType: file.type || "application/octet-stream",
|
|
1367
|
-
sizeBytes: file.size,
|
|
1368
|
-
status: "uploading",
|
|
1369
|
-
...previewUrl ? { previewUrl } : {}
|
|
1370
|
-
}
|
|
1371
|
-
]);
|
|
1372
|
-
startUpload(id, file);
|
|
1373
|
-
}
|
|
1374
|
-
},
|
|
1375
|
-
[startUpload]
|
|
1376
|
-
);
|
|
1377
|
-
const retry = useCallback3(
|
|
1378
|
-
(id) => {
|
|
1379
|
-
const file = sources.current.get(id);
|
|
1380
|
-
if (!file) {
|
|
1381
|
-
return;
|
|
1382
|
-
}
|
|
1383
|
-
setAttachments(
|
|
1384
|
-
(current) => current.map(
|
|
1385
|
-
(attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment
|
|
1386
|
-
)
|
|
1387
|
-
);
|
|
1388
|
-
startUpload(id, file);
|
|
1389
|
-
},
|
|
1390
|
-
[startUpload]
|
|
1391
|
-
);
|
|
1392
|
-
const addFromPaste = useCallback3(
|
|
1393
|
-
(event) => {
|
|
1394
|
-
const clipboardFiles = event.clipboardData?.files;
|
|
1395
|
-
if (!clipboardFiles) {
|
|
1396
|
-
return;
|
|
1397
|
-
}
|
|
1398
|
-
const files = [...clipboardFiles].filter(pasteFilter);
|
|
1399
|
-
if (files.length > 0) {
|
|
1400
|
-
addFiles(files);
|
|
1401
|
-
}
|
|
1402
|
-
},
|
|
1403
|
-
[addFiles, pasteFilter]
|
|
1404
|
-
);
|
|
1405
|
-
const restoreReadyFiles = useCallback3(
|
|
1406
|
-
(files) => {
|
|
1407
|
-
const incoming = /* @__PURE__ */ new Map();
|
|
1408
|
-
for (const file of files) {
|
|
1409
|
-
if (file.status === "ready" && file.workspaceId === workspaceId) {
|
|
1410
|
-
incoming.set(file.id, file);
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
setAttachments((current) => {
|
|
1414
|
-
const unresolved = current.filter((attachment) => attachment.status !== "ready");
|
|
1415
|
-
const existingReady = new Map(
|
|
1416
|
-
current.flatMap(
|
|
1417
|
-
(attachment) => attachment.status === "ready" && attachment.file ? [[attachment.file.id, attachment]] : []
|
|
1418
|
-
)
|
|
1419
|
-
);
|
|
1420
|
-
const restored = [...incoming.values()].map((file) => {
|
|
1421
|
-
const existing = existingReady.get(file.id);
|
|
1422
|
-
return existing ? {
|
|
1423
|
-
...existing,
|
|
1424
|
-
name: file.filename,
|
|
1425
|
-
contentType: file.contentType,
|
|
1426
|
-
sizeBytes: file.sizeBytes,
|
|
1427
|
-
status: "ready",
|
|
1428
|
-
file,
|
|
1429
|
-
error: void 0
|
|
1430
|
-
} : {
|
|
1431
|
-
id: `restored:${file.id}`,
|
|
1432
|
-
name: file.filename,
|
|
1433
|
-
contentType: file.contentType,
|
|
1434
|
-
sizeBytes: file.sizeBytes,
|
|
1435
|
-
status: "ready",
|
|
1436
|
-
file
|
|
1437
|
-
// No source File and no object URL: server metadata is the
|
|
1438
|
-
// only authority restored across page/device boundaries.
|
|
1439
|
-
};
|
|
1440
|
-
});
|
|
1441
|
-
return [...unresolved, ...restored];
|
|
1442
|
-
});
|
|
1443
|
-
},
|
|
1444
|
-
[workspaceId]
|
|
1445
|
-
);
|
|
1446
|
-
const remove = useCallback3(
|
|
1447
|
-
(id) => {
|
|
1448
|
-
sources.current.delete(id);
|
|
1449
|
-
revokePreview(id);
|
|
1450
|
-
setAttachments((current) => current.filter((attachment) => attachment.id !== id));
|
|
1451
|
-
},
|
|
1452
|
-
[revokePreview]
|
|
1453
|
-
);
|
|
1454
|
-
const removeReadyFiles = useCallback3((fileIds) => {
|
|
1455
|
-
const accepted = new Set(fileIds);
|
|
1456
|
-
if (accepted.size === 0) return;
|
|
1457
|
-
setAttachments(
|
|
1458
|
-
(current) => current.filter((attachment) => {
|
|
1459
|
-
return !(attachment.status === "ready" && attachment.file !== void 0 && accepted.has(attachment.file.id));
|
|
1460
|
-
})
|
|
1461
|
-
);
|
|
1462
|
-
}, []);
|
|
1463
|
-
const clear = useCallback3(() => {
|
|
1464
|
-
sources.current.clear();
|
|
1465
|
-
revokeAllPreviews();
|
|
1466
|
-
setAttachments([]);
|
|
1467
|
-
}, [revokeAllPreviews]);
|
|
1468
|
-
return {
|
|
1469
|
-
attachments,
|
|
1470
|
-
readyResources: attachments.flatMap(
|
|
1471
|
-
(attachment) => attachment.status === "ready" && attachment.file ? [{ kind: "file", fileId: attachment.file.id }] : []
|
|
1472
|
-
),
|
|
1473
|
-
uploading: attachments.some((attachment) => attachment.status === "uploading"),
|
|
1474
|
-
hasUnresolved: attachments.some((attachment) => attachment.status !== "ready"),
|
|
1475
|
-
addFiles,
|
|
1476
|
-
addFromPaste,
|
|
1477
|
-
restoreReadyFiles,
|
|
1478
|
-
retry,
|
|
1479
|
-
retainPreview,
|
|
1480
|
-
remove,
|
|
1481
|
-
removeReadyFiles,
|
|
1482
|
-
clear
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1970
|
+
function assertPrependOrder(existing, older) {
|
|
1971
|
+
if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
if (older[older.length - 1].sequence >= existing[0].sequence) {
|
|
1975
|
+
throw new Error("@opengeni/react: loadOlder returned overlapping session events");
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
function assertAppendOrder(existing, newer) {
|
|
1979
|
+
if (!shouldAssertDevelopment() || existing.length === 0 || newer.length === 0) {
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
if (newer[0].sequence <= existing[existing.length - 1].sequence) {
|
|
1983
|
+
throw new Error("@opengeni/react: loadNewer returned overlapping session events");
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
function shouldAssertDevelopment() {
|
|
1987
|
+
const processEnv = globalThis.process?.env;
|
|
1988
|
+
return processEnv !== void 0 && processEnv.NODE_ENV !== "production";
|
|
1989
|
+
}
|
|
1990
|
+
function abortError() {
|
|
1991
|
+
const error = new Error("The operation was aborted.");
|
|
1992
|
+
error.name = "AbortError";
|
|
1993
|
+
return error;
|
|
1994
|
+
}
|
|
1485
1995
|
|
|
1486
1996
|
// src/hooks/use-turn-queue.ts
|
|
1487
|
-
import { useCallback as
|
|
1997
|
+
import { useCallback as useCallback7, useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useRef as useRef6, useState as useState5 } from "react";
|
|
1488
1998
|
function isTurnQueueEvent(event) {
|
|
1489
1999
|
return event.type.startsWith("turn.") || event.type.startsWith("session.queue.") || event.type.startsWith("session.control.") || event.type.startsWith("system.update.") || event.type.startsWith("workspace.inference.");
|
|
1490
2000
|
}
|
|
@@ -1499,18 +2009,18 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1499
2009
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
1500
2010
|
const targetKey = `${workspaceId}\0${sessionId ?? ""}`;
|
|
1501
2011
|
const pageLive = usePageLiveActivity();
|
|
1502
|
-
const [snapshot, setSnapshot] =
|
|
1503
|
-
const [stateTargetKey, setStateTargetKey] =
|
|
1504
|
-
const [loading, setLoading] =
|
|
1505
|
-
const [error, setError] =
|
|
1506
|
-
const [mutationError, setMutationError] =
|
|
1507
|
-
const [pendingByTurn, setPendingByTurn] =
|
|
1508
|
-
const [acceptedSteers, setAcceptedSteers] =
|
|
1509
|
-
const pendingRef =
|
|
1510
|
-
const readGeneration =
|
|
1511
|
-
const targetKeyRef =
|
|
1512
|
-
const snapshotRef =
|
|
1513
|
-
|
|
2012
|
+
const [snapshot, setSnapshot] = useState5(null);
|
|
2013
|
+
const [stateTargetKey, setStateTargetKey] = useState5(targetKey);
|
|
2014
|
+
const [loading, setLoading] = useState5(enabled);
|
|
2015
|
+
const [error, setError] = useState5(null);
|
|
2016
|
+
const [mutationError, setMutationError] = useState5(null);
|
|
2017
|
+
const [pendingByTurn, setPendingByTurn] = useState5({});
|
|
2018
|
+
const [acceptedSteers, setAcceptedSteers] = useState5([]);
|
|
2019
|
+
const pendingRef = useRef6({});
|
|
2020
|
+
const readGeneration = useRef6(0);
|
|
2021
|
+
const targetKeyRef = useRef6(targetKey);
|
|
2022
|
+
const snapshotRef = useRef6(null);
|
|
2023
|
+
useLayoutEffect2(() => {
|
|
1514
2024
|
if (targetKeyRef.current === targetKey) return;
|
|
1515
2025
|
targetKeyRef.current = targetKey;
|
|
1516
2026
|
readGeneration.current += 1;
|
|
@@ -1524,7 +2034,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1524
2034
|
setPendingByTurn({});
|
|
1525
2035
|
setAcceptedSteers([]);
|
|
1526
2036
|
}, [enabled, targetKey]);
|
|
1527
|
-
|
|
2037
|
+
useEffect5(() => {
|
|
1528
2038
|
if (acceptedSteers.length === 0 || options.events === void 0) return;
|
|
1529
2039
|
const durablyStartedTurnIds = new Set(
|
|
1530
2040
|
options.events.flatMap(
|
|
@@ -1536,7 +2046,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1536
2046
|
(current) => current.filter((steer) => !durablyStartedTurnIds.has(steer.turnId))
|
|
1537
2047
|
);
|
|
1538
2048
|
}, [acceptedSteers.length, options.events]);
|
|
1539
|
-
const acceptSnapshot =
|
|
2049
|
+
const acceptSnapshot = useCallback7(
|
|
1540
2050
|
(ownedTargetKey, next) => {
|
|
1541
2051
|
if (targetKeyRef.current !== ownedTargetKey) return false;
|
|
1542
2052
|
const current = snapshotRef.current;
|
|
@@ -1550,7 +2060,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1550
2060
|
},
|
|
1551
2061
|
[]
|
|
1552
2062
|
);
|
|
1553
|
-
const load =
|
|
2063
|
+
const load = useCallback7(
|
|
1554
2064
|
async (rejectOnFailure = false) => {
|
|
1555
2065
|
if (!sessionId) return;
|
|
1556
2066
|
const ownedTargetKey = `${workspaceId}\0${sessionId}`;
|
|
@@ -1581,7 +2091,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1581
2091
|
},
|
|
1582
2092
|
[client, workspaceId, sessionId, acceptSnapshot]
|
|
1583
2093
|
);
|
|
1584
|
-
|
|
2094
|
+
useEffect5(() => {
|
|
1585
2095
|
if (!enabled || !pageLive) {
|
|
1586
2096
|
setLoading(false);
|
|
1587
2097
|
return;
|
|
@@ -1610,10 +2120,10 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1610
2120
|
readGeneration.current += 1;
|
|
1611
2121
|
};
|
|
1612
2122
|
}, [load, enabled, pageLive, options.pollIntervalMs]);
|
|
1613
|
-
|
|
2123
|
+
useEffect5(() => {
|
|
1614
2124
|
if (enabled && workspaceControlEvent) void load();
|
|
1615
2125
|
}, [enabled, load, workspaceControlEvent]);
|
|
1616
|
-
|
|
2126
|
+
useEffect5(() => {
|
|
1617
2127
|
if (!sessionId || !enabled) return;
|
|
1618
2128
|
return registerSessionReconciler(sessionId, "queue", load);
|
|
1619
2129
|
}, [enabled, load, registerSessionReconciler, sessionId]);
|
|
@@ -1630,7 +2140,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1630
2140
|
},
|
|
1631
2141
|
async () => await load(true)
|
|
1632
2142
|
);
|
|
1633
|
-
const mutate =
|
|
2143
|
+
const mutate = useCallback7(
|
|
1634
2144
|
async (turnId, kind, command) => {
|
|
1635
2145
|
const ownedTargetKey = targetKey;
|
|
1636
2146
|
if (!sessionId || targetKeyRef.current !== ownedTargetKey || pendingRef.current[turnId]) {
|
|
@@ -1672,7 +2182,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1672
2182
|
},
|
|
1673
2183
|
[acceptSnapshot, load, sessionId, targetKey]
|
|
1674
2184
|
);
|
|
1675
|
-
const moveTurn =
|
|
2185
|
+
const moveTurn = useCallback7(
|
|
1676
2186
|
async (turnId, beforeTurnId) => {
|
|
1677
2187
|
const result = await mutate(
|
|
1678
2188
|
turnId,
|
|
@@ -1687,7 +2197,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1687
2197
|
},
|
|
1688
2198
|
[client, mutate, sessionId, workspaceId]
|
|
1689
2199
|
);
|
|
1690
|
-
const editTurn =
|
|
2200
|
+
const editTurn = useCallback7(
|
|
1691
2201
|
async (turnId, edit) => {
|
|
1692
2202
|
const result = await mutate(
|
|
1693
2203
|
turnId,
|
|
@@ -1703,7 +2213,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1703
2213
|
},
|
|
1704
2214
|
[client, mutate, sessionId, workspaceId]
|
|
1705
2215
|
);
|
|
1706
|
-
const steerTurn =
|
|
2216
|
+
const steerTurn = useCallback7(
|
|
1707
2217
|
async (turnId) => {
|
|
1708
2218
|
const ownedTargetKey = targetKey;
|
|
1709
2219
|
const turn = snapshotRef.current?.items.find((candidate) => candidate.id === turnId);
|
|
@@ -1755,7 +2265,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1755
2265
|
},
|
|
1756
2266
|
[client, load, mutate, sessionId, targetKey, workspaceId]
|
|
1757
2267
|
);
|
|
1758
|
-
const removeTurn =
|
|
2268
|
+
const removeTurn = useCallback7(
|
|
1759
2269
|
async (turnId) => {
|
|
1760
2270
|
const result = await mutate(
|
|
1761
2271
|
turnId,
|
|
@@ -1777,7 +2287,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1777
2287
|
() => Object.keys(visiblePendingByTurn).length > 0,
|
|
1778
2288
|
[visiblePendingByTurn]
|
|
1779
2289
|
);
|
|
1780
|
-
const mutationFor =
|
|
2290
|
+
const mutationFor = useCallback7(
|
|
1781
2291
|
(turnId) => visiblePendingByTurn[turnId] ?? null,
|
|
1782
2292
|
[visiblePendingByTurn]
|
|
1783
2293
|
);
|
|
@@ -1800,7 +2310,7 @@ function useTurnQueue(sessionId, options = {}) {
|
|
|
1800
2310
|
mutationFor,
|
|
1801
2311
|
mutating,
|
|
1802
2312
|
mutationError: identityMatches ? mutationError : null,
|
|
1803
|
-
clearMutationError:
|
|
2313
|
+
clearMutationError: useCallback7(() => {
|
|
1804
2314
|
if (targetKeyRef.current === targetKey) setMutationError(null);
|
|
1805
2315
|
}, [targetKey]),
|
|
1806
2316
|
acceptedSteers: identityMatches ? acceptedSteers : []
|
|
@@ -1810,15 +2320,175 @@ function operationKey() {
|
|
|
1810
2320
|
return globalThis.crypto.randomUUID();
|
|
1811
2321
|
}
|
|
1812
2322
|
function asError(cause) {
|
|
1813
|
-
return
|
|
2323
|
+
return normalizeError(cause);
|
|
1814
2324
|
}
|
|
1815
2325
|
function isOutcomeUnknownError(cause) {
|
|
1816
2326
|
return typeof cause === "object" && cause !== null && cause.outcomeUnknown === true;
|
|
1817
2327
|
}
|
|
1818
2328
|
|
|
2329
|
+
// src/hooks/use-session-conversation.ts
|
|
2330
|
+
import { useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef7 } from "react";
|
|
2331
|
+
|
|
2332
|
+
// src/hooks/use-client-config-flags.ts
|
|
2333
|
+
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
2334
|
+
var INITIAL_FLAGS = {
|
|
2335
|
+
loaded: false,
|
|
2336
|
+
uploads: false,
|
|
2337
|
+
modelSelection: false,
|
|
2338
|
+
sandboxFiles: false,
|
|
2339
|
+
defaultReasoningEffort: null,
|
|
2340
|
+
artifacts: true,
|
|
2341
|
+
sessionCreation: true,
|
|
2342
|
+
archive: true,
|
|
2343
|
+
voiceInput: null,
|
|
2344
|
+
realtimeVoice: false,
|
|
2345
|
+
realtimeVoiceOffered: false
|
|
2346
|
+
};
|
|
2347
|
+
var configReads = /* @__PURE__ */ new WeakMap();
|
|
2348
|
+
function readClientConfig(client) {
|
|
2349
|
+
let read = configReads.get(client);
|
|
2350
|
+
if (!read) {
|
|
2351
|
+
read = client.getClientConfig();
|
|
2352
|
+
configReads.set(client, read);
|
|
2353
|
+
read.catch(() => {
|
|
2354
|
+
if (configReads.get(client) === read) configReads.delete(client);
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
return read;
|
|
2358
|
+
}
|
|
2359
|
+
function useClientConfigFlags(client) {
|
|
2360
|
+
const [flags, setFlags] = useState6(INITIAL_FLAGS);
|
|
2361
|
+
useEffect6(() => {
|
|
2362
|
+
if (typeof client.getClientConfig !== "function") return;
|
|
2363
|
+
let live = true;
|
|
2364
|
+
readClientConfig(client).then(
|
|
2365
|
+
(config) => {
|
|
2366
|
+
if (live) {
|
|
2367
|
+
setFlags({
|
|
2368
|
+
loaded: true,
|
|
2369
|
+
uploads: config.fileUploads?.enabled === true,
|
|
2370
|
+
// Only an explicit offer shows end users the picker.
|
|
2371
|
+
modelSelection: config.modelSelection === true,
|
|
2372
|
+
sandboxFiles: config.sandboxFiles !== false,
|
|
2373
|
+
defaultReasoningEffort: config.defaultReasoningEffort ?? null,
|
|
2374
|
+
artifacts: config.artifacts !== false,
|
|
2375
|
+
sessionCreation: config.sessionCreation !== false,
|
|
2376
|
+
archive: config.archive !== false,
|
|
2377
|
+
voiceInput: config.voiceInput?.available === true ? config.voiceInput : null,
|
|
2378
|
+
realtimeVoice: config.realtimeVoice !== false,
|
|
2379
|
+
realtimeVoiceOffered: config.realtimeVoice === true
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
},
|
|
2383
|
+
() => void 0
|
|
2384
|
+
);
|
|
2385
|
+
return () => {
|
|
2386
|
+
live = false;
|
|
2387
|
+
};
|
|
2388
|
+
}, [client]);
|
|
2389
|
+
return flags;
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// src/hooks/use-session-conversation.ts
|
|
2393
|
+
function useSessionConversation(sessionId, options = {}) {
|
|
2394
|
+
const context = useOpenGeni(options);
|
|
2395
|
+
const scope = { client: context.client, workspaceId: context.workspaceId };
|
|
2396
|
+
const config = useClientConfigFlags(context.client);
|
|
2397
|
+
const showModelPicker = options.modelPicker ?? config.modelSelection;
|
|
2398
|
+
const catalog = useWorkspaceModelCatalog({ ...scope, enabled: showModelPicker });
|
|
2399
|
+
const feed = useSessionEvents(sessionId, scope);
|
|
2400
|
+
const eventOptions = { ...scope, events: feed.events };
|
|
2401
|
+
const detail = useSession(sessionId, eventOptions);
|
|
2402
|
+
const queue = useTurnQueue(sessionId, eventOptions);
|
|
2403
|
+
const human = useHumanInputRequests(sessionId, eventOptions);
|
|
2404
|
+
const control = useSessionControl(sessionId, scope);
|
|
2405
|
+
const approvals = useMemo4(() => projectPendingApprovals(feed.events), [feed.events]);
|
|
2406
|
+
const files = useFileAttachments(scope);
|
|
2407
|
+
const clearFiles = files.clear;
|
|
2408
|
+
const attachmentSession = useRef7(sessionId);
|
|
2409
|
+
useLayoutEffect3(() => {
|
|
2410
|
+
if (attachmentSession.current === sessionId) return;
|
|
2411
|
+
attachmentSession.current = sessionId;
|
|
2412
|
+
clearFiles();
|
|
2413
|
+
}, [clearFiles, sessionId]);
|
|
2414
|
+
const uploadsEnabled = (options.attachments ?? true) && config.uploads;
|
|
2415
|
+
const status = feed.sessionStatus ?? detail.session?.status;
|
|
2416
|
+
const terminal = status === "cancelled";
|
|
2417
|
+
const importedArchive = detail.session?.importedArchive?.readOnly === true;
|
|
2418
|
+
const host = options.composerOptions;
|
|
2419
|
+
const resolveExtras = () => typeof host?.sendExtras === "function" ? host.sendExtras() : host?.sendExtras;
|
|
2420
|
+
const releaseSentFiles = (input) => files.removeReadyFiles(
|
|
2421
|
+
(input.resources ?? []).flatMap(
|
|
2422
|
+
(resource) => resource.kind === "file" ? [resource.fileId] : []
|
|
2423
|
+
)
|
|
2424
|
+
);
|
|
2425
|
+
const composer = useComposer(sessionId, {
|
|
2426
|
+
...eventOptions,
|
|
2427
|
+
initialDraft: host?.initialDraft,
|
|
2428
|
+
effectiveControl: queue.effectiveControl ?? detail.session?.effectiveControl,
|
|
2429
|
+
sendDestination: () => queue.queue.length > 0 || status === "running" ? "queue" : "chat",
|
|
2430
|
+
sendExtras: () => {
|
|
2431
|
+
const extras = resolveExtras();
|
|
2432
|
+
return {
|
|
2433
|
+
...extras,
|
|
2434
|
+
resources: [...extras?.resources ?? [], ...uploadsEnabled ? files.readyResources : []]
|
|
2435
|
+
};
|
|
2436
|
+
},
|
|
2437
|
+
sendBlocked: () => terminal || importedArchive || uploadsEnabled && files.hasUnresolved || host?.sendBlocked?.() === true,
|
|
2438
|
+
onSubmitted: (text, input) => {
|
|
2439
|
+
releaseSentFiles(input);
|
|
2440
|
+
return host?.onSubmitted?.(text, input);
|
|
2441
|
+
},
|
|
2442
|
+
onSent: (text, input) => {
|
|
2443
|
+
releaseSentFiles(input);
|
|
2444
|
+
return host?.onSent?.(text, input);
|
|
2445
|
+
},
|
|
2446
|
+
onDeliveryError: host?.onDeliveryError
|
|
2447
|
+
});
|
|
2448
|
+
const timeline = useMemo4(
|
|
2449
|
+
() => conversationTimeline(feed.timeline, queue, composer),
|
|
2450
|
+
[feed.timeline, queue, composer]
|
|
2451
|
+
);
|
|
2452
|
+
const error = detail.error ?? feed.error ?? human.error;
|
|
2453
|
+
const loadFailed = Boolean(feed.error) && !feed.initialHistoryReady;
|
|
2454
|
+
const retry = async () => {
|
|
2455
|
+
await Promise.all([
|
|
2456
|
+
...detail.error ? [detail.refresh()] : [],
|
|
2457
|
+
...human.error ? [human.refresh()] : [],
|
|
2458
|
+
...feed.error ? [feed.jumpToLatest()] : []
|
|
2459
|
+
]);
|
|
2460
|
+
};
|
|
2461
|
+
return {
|
|
2462
|
+
...scope,
|
|
2463
|
+
sessionId,
|
|
2464
|
+
config,
|
|
2465
|
+
catalog,
|
|
2466
|
+
showModelPicker,
|
|
2467
|
+
feed,
|
|
2468
|
+
detail,
|
|
2469
|
+
queue,
|
|
2470
|
+
human,
|
|
2471
|
+
control,
|
|
2472
|
+
approvals,
|
|
2473
|
+
files,
|
|
2474
|
+
uploadsEnabled,
|
|
2475
|
+
composer,
|
|
2476
|
+
/** The same live application context for text and durable voice messages. */
|
|
2477
|
+
getModelContext: () => resolveExtras()?.modelContext,
|
|
2478
|
+
timeline,
|
|
2479
|
+
status,
|
|
2480
|
+
terminal,
|
|
2481
|
+
importedArchive,
|
|
2482
|
+
running: status === "running" || status === "recovering" || status === "waiting_capacity",
|
|
2483
|
+
error,
|
|
2484
|
+
loadFailed,
|
|
2485
|
+
retry
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
|
|
1819
2489
|
// src/hooks/use-goal.ts
|
|
1820
2490
|
import { OpenGeniApiError } from "@opengeni/sdk";
|
|
1821
|
-
import { useCallback as
|
|
2491
|
+
import { useCallback as useCallback8, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState7 } from "react";
|
|
1822
2492
|
function isGoalEvent(event) {
|
|
1823
2493
|
return event.type.startsWith("goal.");
|
|
1824
2494
|
}
|
|
@@ -1832,31 +2502,38 @@ function useGoal(sessionId, options = {}) {
|
|
|
1832
2502
|
const sharedEvents = options.events;
|
|
1833
2503
|
const sharedFeed = sharedEvents !== void 0;
|
|
1834
2504
|
const pageLive = usePageLiveActivity();
|
|
1835
|
-
const [goal, setGoal] =
|
|
1836
|
-
const [loading, setLoading] =
|
|
1837
|
-
const [error, setError] =
|
|
2505
|
+
const [goal, setGoal] = useState7(null);
|
|
2506
|
+
const [loading, setLoading] = useState7(enabled);
|
|
2507
|
+
const [error, setError] = useState7(null);
|
|
1838
2508
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
1839
|
-
const generation =
|
|
1840
|
-
const targetKeyRef =
|
|
1841
|
-
const
|
|
1842
|
-
const
|
|
2509
|
+
const generation = useRef8(0);
|
|
2510
|
+
const targetKeyRef = useRef8(null);
|
|
2511
|
+
const goalAbsentRef = useRef8(false);
|
|
2512
|
+
const pendingRefreshRef = useRef8("none");
|
|
2513
|
+
const sharedEventsRef = useRef8(sharedEvents);
|
|
2514
|
+
useLayoutEffect4(() => {
|
|
2515
|
+
sharedEventsRef.current = sharedEvents;
|
|
2516
|
+
}, [sharedEvents]);
|
|
2517
|
+
const loadAbort = useRef8(null);
|
|
2518
|
+
const scheduleRefreshRef = useRef8(() => void 0);
|
|
2519
|
+
const retireLoads = useCallback8(() => {
|
|
1843
2520
|
generation.current += 1;
|
|
1844
2521
|
loadAbort.current?.abort();
|
|
1845
2522
|
loadAbort.current = null;
|
|
1846
2523
|
}, []);
|
|
1847
|
-
const load =
|
|
2524
|
+
const load = useCallback8(async () => {
|
|
1848
2525
|
if (!sessionId) {
|
|
1849
2526
|
return;
|
|
1850
2527
|
}
|
|
1851
2528
|
const ticket = ++generation.current;
|
|
2529
|
+
pendingRefreshRef.current = "none";
|
|
1852
2530
|
loadAbort.current?.abort();
|
|
1853
2531
|
const controller = new AbortController();
|
|
1854
2532
|
loadAbort.current = controller;
|
|
1855
2533
|
try {
|
|
1856
|
-
const fetched = await client.getGoal(workspaceId, sessionId, {
|
|
1857
|
-
signal: controller.signal
|
|
1858
|
-
});
|
|
2534
|
+
const fetched = typeof client.findGoal === "function" ? await client.findGoal(workspaceId, sessionId, { signal: controller.signal }) : await client.getGoal(workspaceId, sessionId, { signal: controller.signal });
|
|
1859
2535
|
if (ticket === generation.current) {
|
|
2536
|
+
goalAbsentRef.current = fetched === null;
|
|
1860
2537
|
setGoal(fetched);
|
|
1861
2538
|
setError(null);
|
|
1862
2539
|
setLoading(false);
|
|
@@ -1866,20 +2543,40 @@ function useGoal(sessionId, options = {}) {
|
|
|
1866
2543
|
return;
|
|
1867
2544
|
}
|
|
1868
2545
|
if (cause instanceof OpenGeniApiError && cause.status === 404) {
|
|
2546
|
+
goalAbsentRef.current = true;
|
|
1869
2547
|
setGoal(null);
|
|
1870
2548
|
setError(null);
|
|
1871
2549
|
} else {
|
|
1872
|
-
setError(
|
|
2550
|
+
setError(normalizeError(cause));
|
|
1873
2551
|
}
|
|
1874
2552
|
setLoading(false);
|
|
1875
2553
|
} finally {
|
|
1876
2554
|
if (loadAbort.current === controller) loadAbort.current = null;
|
|
1877
2555
|
}
|
|
2556
|
+
if (ticket !== generation.current || pendingRefreshRef.current === "none") {
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
if (goalAbsentRef.current && pendingRefreshRef.current === "refresh") {
|
|
2560
|
+
const events = sharedEventsRef.current ?? [];
|
|
2561
|
+
let latestGoalEvent;
|
|
2562
|
+
for (let index = events.length - 1; index >= 0 && !latestGoalEvent; index -= 1) {
|
|
2563
|
+
const event = events[index];
|
|
2564
|
+
if (event && isGoalEvent(event)) latestGoalEvent = event;
|
|
2565
|
+
}
|
|
2566
|
+
if (!latestGoalEvent || latestGoalEvent.type === "goal.cleared") {
|
|
2567
|
+
pendingRefreshRef.current = "none";
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
pendingRefreshRef.current = "goal";
|
|
2571
|
+
}
|
|
2572
|
+
scheduleRefreshRef.current();
|
|
1878
2573
|
}, [client, workspaceId, sessionId]);
|
|
1879
|
-
|
|
2574
|
+
useEffect7(() => {
|
|
1880
2575
|
const targetKey = `${workspaceId} ${sessionId ?? ""}`;
|
|
1881
2576
|
if (targetKeyRef.current !== targetKey) {
|
|
1882
2577
|
targetKeyRef.current = targetKey;
|
|
2578
|
+
goalAbsentRef.current = false;
|
|
2579
|
+
pendingRefreshRef.current = "none";
|
|
1883
2580
|
setGoal(null);
|
|
1884
2581
|
setError(null);
|
|
1885
2582
|
}
|
|
@@ -1889,7 +2586,8 @@ function useGoal(sessionId, options = {}) {
|
|
|
1889
2586
|
return;
|
|
1890
2587
|
}
|
|
1891
2588
|
if (sharedFeed) {
|
|
1892
|
-
setLoading(
|
|
2589
|
+
setLoading(true);
|
|
2590
|
+
void load();
|
|
1893
2591
|
return () => {
|
|
1894
2592
|
retireLoads();
|
|
1895
2593
|
};
|
|
@@ -1927,542 +2625,382 @@ function useGoal(sessionId, options = {}) {
|
|
|
1927
2625
|
retireLoads,
|
|
1928
2626
|
sharedFeed
|
|
1929
2627
|
]);
|
|
1930
|
-
const scheduleRefresh = useDebouncedCallback(() =>
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
const pause = useCallback5(
|
|
1936
|
-
async (rationale) => {
|
|
1937
|
-
if (!sessionId) {
|
|
1938
|
-
return null;
|
|
1939
|
-
}
|
|
1940
|
-
const result = await run(
|
|
1941
|
-
() => client.updateGoal(workspaceId, sessionId, {
|
|
1942
|
-
status: "paused",
|
|
1943
|
-
...rationale !== void 0 ? { rationale } : {}
|
|
1944
|
-
})
|
|
1945
|
-
);
|
|
1946
|
-
if (result) {
|
|
1947
|
-
setGoal(result);
|
|
1948
|
-
}
|
|
1949
|
-
return result;
|
|
1950
|
-
},
|
|
1951
|
-
[client, workspaceId, sessionId, run]
|
|
1952
|
-
);
|
|
1953
|
-
const resume = useCallback5(async () => {
|
|
1954
|
-
if (!sessionId) {
|
|
1955
|
-
return null;
|
|
1956
|
-
}
|
|
1957
|
-
const result = await run(() => client.updateGoal(workspaceId, sessionId, { status: "active" }));
|
|
1958
|
-
if (result) {
|
|
1959
|
-
setGoal(result);
|
|
1960
|
-
}
|
|
1961
|
-
return result;
|
|
1962
|
-
}, [client, workspaceId, sessionId, run]);
|
|
1963
|
-
const clearGoal = useCallback5(async () => {
|
|
1964
|
-
if (!sessionId) {
|
|
2628
|
+
const scheduleRefresh = useDebouncedCallback(() => {
|
|
2629
|
+
const pending = pendingRefreshRef.current;
|
|
2630
|
+
if (pending === "none" || loadAbort.current !== null) return;
|
|
2631
|
+
if (pending === "refresh" && goalAbsentRef.current) {
|
|
2632
|
+
pendingRefreshRef.current = "none";
|
|
1965
2633
|
return;
|
|
1966
2634
|
}
|
|
1967
|
-
|
|
1968
|
-
await client.deleteGoal(workspaceId, sessionId);
|
|
1969
|
-
return true;
|
|
1970
|
-
});
|
|
1971
|
-
if (ok) {
|
|
1972
|
-
retireLoads();
|
|
1973
|
-
setGoal(null);
|
|
1974
|
-
setError(null);
|
|
1975
|
-
}
|
|
1976
|
-
}, [client, workspaceId, sessionId, run, retireLoads]);
|
|
1977
|
-
return {
|
|
1978
|
-
goal,
|
|
1979
|
-
isActive: goal?.status === "active",
|
|
1980
|
-
isPaused: goal?.status === "paused",
|
|
1981
|
-
isCompleted: goal?.status === "completed",
|
|
1982
|
-
loading,
|
|
1983
|
-
error,
|
|
1984
|
-
refresh: load,
|
|
1985
|
-
pause,
|
|
1986
|
-
resume,
|
|
1987
|
-
clearGoal,
|
|
1988
|
-
deleteGoal: clearGoal,
|
|
1989
|
-
updating: mutating,
|
|
1990
|
-
mutationError,
|
|
1991
|
-
clearMutationError
|
|
1992
|
-
};
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
// src/hooks/use-session-control.ts
|
|
1996
|
-
import { useCallback as useCallback6, useLayoutEffect as useLayoutEffect2, useRef as useRef6 } from "react";
|
|
1997
|
-
function useSessionControl(sessionId, options = {}) {
|
|
1998
|
-
const { client, workspaceId } = useEmbeddedSession(options);
|
|
1999
|
-
const approvalTargetKey = `${workspaceId}\0${sessionId ?? ""}`;
|
|
2000
|
-
const pendingApproval = useRef6(null);
|
|
2001
|
-
useLayoutEffect2(() => {
|
|
2002
|
-
if (pendingApproval.current?.targetKey !== approvalTargetKey) {
|
|
2003
|
-
pendingApproval.current = null;
|
|
2004
|
-
}
|
|
2005
|
-
}, [approvalTargetKey]);
|
|
2006
|
-
const {
|
|
2007
|
-
run: runControl,
|
|
2008
|
-
mutating: controlling,
|
|
2009
|
-
mutationError: controlError,
|
|
2010
|
-
clearMutationError: clearControlError
|
|
2011
|
-
} = useMutationRunner(approvalTargetKey);
|
|
2012
|
-
const {
|
|
2013
|
-
run: runApproval,
|
|
2014
|
-
mutating: responding,
|
|
2015
|
-
mutationError: approvalError,
|
|
2016
|
-
clearMutationError: clearApprovalError
|
|
2017
|
-
} = useMutationRunner(approvalTargetKey);
|
|
2018
|
-
const pause = useCallback6(
|
|
2019
|
-
async (reason) => {
|
|
2020
|
-
if (!sessionId) {
|
|
2021
|
-
return null;
|
|
2022
|
-
}
|
|
2023
|
-
return await runControl(
|
|
2024
|
-
() => client.pauseSession(workspaceId, sessionId, reason !== void 0 ? { reason } : {})
|
|
2025
|
-
);
|
|
2026
|
-
},
|
|
2027
|
-
[client, workspaceId, sessionId, runControl]
|
|
2028
|
-
);
|
|
2029
|
-
const resume = useCallback6(
|
|
2030
|
-
async (reason) => {
|
|
2031
|
-
if (!sessionId) return null;
|
|
2032
|
-
return await runControl(
|
|
2033
|
-
() => client.resumeSession(workspaceId, sessionId, reason !== void 0 ? { reason } : {})
|
|
2034
|
-
);
|
|
2035
|
-
},
|
|
2036
|
-
[client, workspaceId, sessionId, runControl]
|
|
2037
|
-
);
|
|
2038
|
-
const decide = useCallback6(
|
|
2039
|
-
async (approvalId, decision, message) => {
|
|
2040
|
-
if (!sessionId) {
|
|
2041
|
-
return null;
|
|
2042
|
-
}
|
|
2043
|
-
const decisionKey = JSON.stringify([approvalId, decision, message ?? null]);
|
|
2044
|
-
if (pendingApproval.current?.decisionKey !== decisionKey) {
|
|
2045
|
-
pendingApproval.current = {
|
|
2046
|
-
targetKey: approvalTargetKey,
|
|
2047
|
-
decisionKey,
|
|
2048
|
-
clientEventId: crypto.randomUUID()
|
|
2049
|
-
};
|
|
2050
|
-
}
|
|
2051
|
-
const clientEventId = pendingApproval.current.clientEventId;
|
|
2052
|
-
const accepted = await runApproval(
|
|
2053
|
-
() => client.sendApprovalDecision(workspaceId, sessionId, {
|
|
2054
|
-
approvalId,
|
|
2055
|
-
decision,
|
|
2056
|
-
...message !== void 0 ? { message } : {},
|
|
2057
|
-
clientEventId
|
|
2058
|
-
})
|
|
2059
|
-
);
|
|
2060
|
-
if (accepted !== null && pendingApproval.current?.targetKey === approvalTargetKey && pendingApproval.current.clientEventId === clientEventId) {
|
|
2061
|
-
pendingApproval.current = null;
|
|
2062
|
-
}
|
|
2063
|
-
return accepted;
|
|
2064
|
-
},
|
|
2065
|
-
[approvalTargetKey, client, workspaceId, sessionId, runApproval]
|
|
2066
|
-
);
|
|
2067
|
-
const approve = useCallback6(
|
|
2068
|
-
async (approvalId, message) => await decide(approvalId, "approve", message),
|
|
2069
|
-
[decide]
|
|
2070
|
-
);
|
|
2071
|
-
const reject = useCallback6(
|
|
2072
|
-
async (approvalId, message) => await decide(approvalId, "reject", message),
|
|
2073
|
-
[decide]
|
|
2074
|
-
);
|
|
2075
|
-
const error = approvalError ?? controlError;
|
|
2076
|
-
const clearError = useCallback6(() => {
|
|
2077
|
-
clearControlError();
|
|
2078
|
-
clearApprovalError();
|
|
2079
|
-
}, [clearControlError, clearApprovalError]);
|
|
2080
|
-
return {
|
|
2081
|
-
pause,
|
|
2082
|
-
resume,
|
|
2083
|
-
controlling,
|
|
2084
|
-
approve,
|
|
2085
|
-
reject,
|
|
2086
|
-
responding,
|
|
2087
|
-
error,
|
|
2088
|
-
clearError
|
|
2089
|
-
};
|
|
2090
|
-
}
|
|
2091
|
-
|
|
2092
|
-
// src/hooks/use-session-mcp-approval-policy.ts
|
|
2093
|
-
import { useCallback as useCallback7, useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef7, useState as useState6 } from "react";
|
|
2094
|
-
function isSessionMcpApprovalPolicyEvent(event, serverId) {
|
|
2095
|
-
if (event.type !== "session.mcp.approval_policy.updated") {
|
|
2096
|
-
return false;
|
|
2097
|
-
}
|
|
2098
|
-
if (serverId === void 0) {
|
|
2099
|
-
return true;
|
|
2100
|
-
}
|
|
2101
|
-
const payload = event.payload;
|
|
2102
|
-
return payload?.serverId === serverId;
|
|
2103
|
-
}
|
|
2104
|
-
function useSessionMcpApprovalPolicy(sessionId, serverId, options = {}) {
|
|
2105
|
-
const { client, workspaceId } = useEmbeddedSessionMcpApprovalPolicy(options);
|
|
2106
|
-
const enabled = (options.enabled ?? true) && Boolean(sessionId && serverId);
|
|
2107
|
-
const [override, setOverride] = useState6(null);
|
|
2108
|
-
const targetKey = `${workspaceId}\0${sessionId ?? ""}\0${serverId ?? ""}`;
|
|
2109
|
-
const authoritativeGeneration = useRef7(0);
|
|
2110
|
-
const mutationIdentity = useMemo4(() => ({ client, targetKey }), [client, targetKey]);
|
|
2111
|
-
const { run, mutating, mutationError, clearMutationError } = useMutationRunner(mutationIdentity);
|
|
2112
|
-
useLayoutEffect3(() => {
|
|
2113
|
-
authoritativeGeneration.current += 1;
|
|
2114
|
-
setOverride(null);
|
|
2115
|
-
}, [client, targetKey]);
|
|
2116
|
-
const load = useCallback7(async () => {
|
|
2117
|
-
const generation = authoritativeGeneration.current;
|
|
2118
|
-
if (!sessionId || !serverId) {
|
|
2119
|
-
return { targetKey, generation, server: null };
|
|
2120
|
-
}
|
|
2121
|
-
const session = await client.getSession(workspaceId, sessionId);
|
|
2122
|
-
return {
|
|
2123
|
-
targetKey,
|
|
2124
|
-
generation,
|
|
2125
|
-
server: session.mcpServers.find((server2) => server2.id === serverId) ?? null
|
|
2126
|
-
};
|
|
2127
|
-
}, [client, serverId, sessionId, targetKey, workspaceId]);
|
|
2128
|
-
const {
|
|
2129
|
-
data,
|
|
2130
|
-
loading,
|
|
2131
|
-
error: loadError,
|
|
2132
|
-
refresh
|
|
2133
|
-
} = usePolledValue(load, {
|
|
2134
|
-
enabled,
|
|
2135
|
-
pollIntervalMs: options.pollIntervalMs
|
|
2635
|
+
void load();
|
|
2136
2636
|
});
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
const matchesPolicyEvent = useCallback7(
|
|
2144
|
-
(event) => isSessionMcpApprovalPolicyEvent(event, serverId ?? void 0),
|
|
2145
|
-
[serverId]
|
|
2637
|
+
useLayoutEffect4(() => {
|
|
2638
|
+
scheduleRefreshRef.current = scheduleRefresh;
|
|
2639
|
+
}, [scheduleRefresh]);
|
|
2640
|
+
const isRefreshEvent = useCallback8(
|
|
2641
|
+
(event) => goalAbsentRef.current ? isGoalEvent(event) : isGoalRefreshEvent(event),
|
|
2642
|
+
[]
|
|
2146
2643
|
);
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
scheduleRefresh,
|
|
2153
|
-
{
|
|
2154
|
-
enabled,
|
|
2155
|
-
...options.events !== void 0 ? { events: options.events } : {}
|
|
2644
|
+
const onRefreshEvent = useCallback8(
|
|
2645
|
+
(event) => {
|
|
2646
|
+
if (isGoalEvent(event)) pendingRefreshRef.current = "goal";
|
|
2647
|
+
else if (pendingRefreshRef.current === "none") pendingRefreshRef.current = "refresh";
|
|
2648
|
+
scheduleRefresh();
|
|
2156
2649
|
},
|
|
2157
|
-
|
|
2650
|
+
[scheduleRefresh]
|
|
2158
2651
|
);
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2652
|
+
useSessionEventTrigger(client, workspaceId, sessionId, isRefreshEvent, onRefreshEvent, {
|
|
2653
|
+
enabled,
|
|
2654
|
+
...sharedEvents !== void 0 ? { events: sharedEvents } : {}
|
|
2655
|
+
});
|
|
2656
|
+
const pause = useCallback8(
|
|
2657
|
+
async (rationale) => {
|
|
2658
|
+
if (!sessionId) {
|
|
2162
2659
|
return null;
|
|
2163
2660
|
}
|
|
2164
|
-
const
|
|
2165
|
-
() => client.
|
|
2166
|
-
|
|
2661
|
+
const result = await run(
|
|
2662
|
+
() => client.updateGoal(workspaceId, sessionId, {
|
|
2663
|
+
status: "paused",
|
|
2664
|
+
...rationale !== void 0 ? { rationale } : {}
|
|
2167
2665
|
})
|
|
2168
2666
|
);
|
|
2169
|
-
if (
|
|
2170
|
-
|
|
2171
|
-
setOverride(response.server);
|
|
2172
|
-
void refresh();
|
|
2667
|
+
if (result) {
|
|
2668
|
+
setGoal(result);
|
|
2173
2669
|
}
|
|
2174
|
-
return
|
|
2670
|
+
return result;
|
|
2175
2671
|
},
|
|
2176
|
-
[client,
|
|
2672
|
+
[client, workspaceId, sessionId, run]
|
|
2177
2673
|
);
|
|
2178
|
-
const
|
|
2674
|
+
const resume = useCallback8(async () => {
|
|
2675
|
+
if (!sessionId) {
|
|
2676
|
+
return null;
|
|
2677
|
+
}
|
|
2678
|
+
const result = await run(() => client.updateGoal(workspaceId, sessionId, { status: "active" }));
|
|
2679
|
+
if (result) {
|
|
2680
|
+
setGoal(result);
|
|
2681
|
+
}
|
|
2682
|
+
return result;
|
|
2683
|
+
}, [client, workspaceId, sessionId, run]);
|
|
2684
|
+
const clearGoal = useCallback8(async () => {
|
|
2685
|
+
if (!sessionId) {
|
|
2686
|
+
return;
|
|
2687
|
+
}
|
|
2688
|
+
const ok = await run(async () => {
|
|
2689
|
+
await client.deleteGoal(workspaceId, sessionId);
|
|
2690
|
+
return true;
|
|
2691
|
+
});
|
|
2692
|
+
if (ok) {
|
|
2693
|
+
retireLoads();
|
|
2694
|
+
setGoal(null);
|
|
2695
|
+
setError(null);
|
|
2696
|
+
}
|
|
2697
|
+
}, [client, workspaceId, sessionId, run, retireLoads]);
|
|
2179
2698
|
return {
|
|
2180
|
-
|
|
2181
|
-
|
|
2699
|
+
goal,
|
|
2700
|
+
isActive: goal?.status === "active",
|
|
2701
|
+
isPaused: goal?.status === "paused",
|
|
2702
|
+
isCompleted: goal?.status === "completed",
|
|
2182
2703
|
loading,
|
|
2183
|
-
error
|
|
2184
|
-
refresh:
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2704
|
+
error,
|
|
2705
|
+
refresh: load,
|
|
2706
|
+
pause,
|
|
2707
|
+
resume,
|
|
2708
|
+
clearGoal,
|
|
2709
|
+
deleteGoal: clearGoal,
|
|
2188
2710
|
updating: mutating,
|
|
2189
|
-
|
|
2711
|
+
mutationError,
|
|
2712
|
+
clearMutationError
|
|
2190
2713
|
};
|
|
2191
2714
|
}
|
|
2192
2715
|
|
|
2193
|
-
// src/hooks/use-
|
|
2194
|
-
import {
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
const
|
|
2211
|
-
const
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
const
|
|
2216
|
-
const
|
|
2217
|
-
const
|
|
2218
|
-
const
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
readGeneration = sharedReadGeneration ?? beginRead?.() ?? ++nextReadGeneration.current;
|
|
2232
|
-
}
|
|
2233
|
-
});
|
|
2234
|
-
return {
|
|
2235
|
-
lineage,
|
|
2236
|
-
readGeneration
|
|
2237
|
-
};
|
|
2238
|
-
},
|
|
2239
|
-
[beginRead, client, workspaceId, sessionId]
|
|
2716
|
+
// src/hooks/use-new-conversation.ts
|
|
2717
|
+
import {
|
|
2718
|
+
OpenGeniApiError as OpenGeniApiError2
|
|
2719
|
+
} from "@opengeni/sdk";
|
|
2720
|
+
import { useLayoutEffect as useLayoutEffect5, useMemo as useMemo5, useRef as useRef9, useState as useState8 } from "react";
|
|
2721
|
+
var NOOP_ASYNC = async () => {
|
|
2722
|
+
};
|
|
2723
|
+
function useNewConversation(options = {}) {
|
|
2724
|
+
const context = useOpenGeni(options);
|
|
2725
|
+
const scope = { client: context.client, workspaceId: context.workspaceId };
|
|
2726
|
+
const config = useClientConfigFlags(context.client);
|
|
2727
|
+
const showModelPicker = options.modelPicker ?? config.modelSelection;
|
|
2728
|
+
const catalog = useWorkspaceModelCatalog({ ...scope, enabled: showModelPicker });
|
|
2729
|
+
const files = useFileAttachments(scope);
|
|
2730
|
+
const uploadsEnabled = (options.attachments ?? true) && config.uploads;
|
|
2731
|
+
const available = options.enabled !== false && (options.createSession !== void 0 || config.sessionCreation);
|
|
2732
|
+
const [text, setText] = useState8("");
|
|
2733
|
+
const [choice, setChoice] = useState8({});
|
|
2734
|
+
const [sending, setSending] = useState8(false);
|
|
2735
|
+
const [error, setError] = useState8(null);
|
|
2736
|
+
const [pending, setPending] = useState8(null);
|
|
2737
|
+
const [completion, setCompletion] = useState8(null);
|
|
2738
|
+
const textRef = useRef9(text);
|
|
2739
|
+
const textRevision = useRef9(0);
|
|
2740
|
+
const choiceRef = useRef9(choice);
|
|
2741
|
+
const filesRef = useRef9(files);
|
|
2742
|
+
filesRef.current = files;
|
|
2743
|
+
const pendingRef = useRef9(null);
|
|
2744
|
+
const completionRef = useRef9(null);
|
|
2745
|
+
const inFlight = useRef9(false);
|
|
2746
|
+
const lifetime = useRef9({ mounted: true, generation: 0 }).current;
|
|
2747
|
+
const identity = useMemo5(
|
|
2748
|
+
() => ({
|
|
2749
|
+
client: context.client,
|
|
2750
|
+
workspaceId: context.workspaceId,
|
|
2751
|
+
scopeKey: options.scopeKey
|
|
2752
|
+
}),
|
|
2753
|
+
[context.client, context.workspaceId, options.scopeKey]
|
|
2240
2754
|
);
|
|
2241
|
-
const
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
if (enabled && workspaceControlEvent) void refresh();
|
|
2245
|
-
}, [enabled, refresh, workspaceControlEvent]);
|
|
2246
|
-
useEffect7(() => {
|
|
2247
|
-
if (!sessionId || !enabled) return;
|
|
2248
|
-
return registerSessionReconciler(sessionId, "lineage", refresh);
|
|
2249
|
-
}, [enabled, refresh, registerSessionReconciler, sessionId]);
|
|
2250
|
-
const refreshSoon = useDebouncedCallback(() => void refresh(), 150);
|
|
2251
|
-
const delayedChildRefreshRef = useRef8(null);
|
|
2252
|
-
useEffect7(() => {
|
|
2755
|
+
const committedIdentity = useRef9(identity);
|
|
2756
|
+
useLayoutEffect5(() => {
|
|
2757
|
+
lifetime.mounted = true;
|
|
2253
2758
|
return () => {
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
delayedChildRefreshRef.current = null;
|
|
2257
|
-
}
|
|
2759
|
+
lifetime.mounted = false;
|
|
2760
|
+
lifetime.generation++;
|
|
2258
2761
|
};
|
|
2259
|
-
}, [
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2762
|
+
}, [lifetime]);
|
|
2763
|
+
useLayoutEffect5(() => {
|
|
2764
|
+
if (committedIdentity.current === identity) return;
|
|
2765
|
+
committedIdentity.current = identity;
|
|
2766
|
+
lifetime.generation++;
|
|
2767
|
+
inFlight.current = false;
|
|
2768
|
+
pendingRef.current = null;
|
|
2769
|
+
completionRef.current = null;
|
|
2770
|
+
textRef.current = "";
|
|
2771
|
+
textRevision.current = 0;
|
|
2772
|
+
choiceRef.current = {};
|
|
2773
|
+
setText("");
|
|
2774
|
+
setChoice({});
|
|
2775
|
+
setSending(false);
|
|
2776
|
+
setError(null);
|
|
2777
|
+
setPending(null);
|
|
2778
|
+
setCompletion(null);
|
|
2779
|
+
filesRef.current.clear();
|
|
2780
|
+
}, [identity, lifetime]);
|
|
2781
|
+
const ownsScope = () => lifetime.mounted && committedIdentity.current === identity;
|
|
2782
|
+
const updateText = (value) => {
|
|
2783
|
+
if (!ownsScope()) return;
|
|
2784
|
+
if (value !== textRef.current) textRevision.current++;
|
|
2785
|
+
textRef.current = value;
|
|
2786
|
+
setText(value);
|
|
2787
|
+
};
|
|
2788
|
+
const updateChoice = (patch) => {
|
|
2789
|
+
if (!ownsScope()) return;
|
|
2790
|
+
const next = { ...choiceRef.current, ...patch };
|
|
2791
|
+
const model = catalog.models.find((row) => row.id === (next.model ?? catalog.defaultModel));
|
|
2792
|
+
if (model) {
|
|
2793
|
+
if (next.reasoningEffort)
|
|
2794
|
+
next.reasoningEffort = coerceReasoningEffortForModel(model, next.reasoningEffort);
|
|
2795
|
+
if (next.latencyMode && !runnableLatencyModesForModel(model).includes(next.latencyMode))
|
|
2796
|
+
next.latencyMode = "standard";
|
|
2264
2797
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
void refresh();
|
|
2268
|
-
}, 2500);
|
|
2269
|
-
}, [refresh]);
|
|
2270
|
-
useSessionEventTrigger(
|
|
2271
|
-
client,
|
|
2272
|
-
workspaceId,
|
|
2273
|
-
sessionId,
|
|
2274
|
-
isLineageRefreshEvent,
|
|
2275
|
-
refreshSoon,
|
|
2276
|
-
// SHARED-FEED ONLY: without a caller-provided events log the trigger would
|
|
2277
|
-
// open its OWN streamEvents tail — a second live SSE connection next to the
|
|
2278
|
-
// session route's useSessionEvents. A caller with no feed opts into polling
|
|
2279
|
-
// (pollIntervalMs), never a duplicate stream.
|
|
2280
|
-
{ events: options.events, enabled: enabled && options.events !== void 0 }
|
|
2281
|
-
);
|
|
2282
|
-
useSessionEventTrigger(
|
|
2283
|
-
client,
|
|
2284
|
-
workspaceId,
|
|
2285
|
-
sessionId,
|
|
2286
|
-
isSessionCreateToolCallCreated,
|
|
2287
|
-
refreshAfterChildCreate,
|
|
2288
|
-
{ events: options.events, enabled: enabled && options.events !== void 0 }
|
|
2289
|
-
);
|
|
2290
|
-
return {
|
|
2291
|
-
lineage: state.data?.lineage ?? null,
|
|
2292
|
-
loading: state.loading,
|
|
2293
|
-
error: state.error,
|
|
2294
|
-
readGeneration: state.data?.readGeneration ?? 0,
|
|
2295
|
-
refresh
|
|
2798
|
+
choiceRef.current = next;
|
|
2799
|
+
setChoice(choiceRef.current);
|
|
2296
2800
|
};
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
};
|
|
2801
|
+
const effectivePolicy = () => {
|
|
2802
|
+
const model = choiceRef.current.model ?? catalog.defaultModel;
|
|
2803
|
+
const definition = catalog.models.find((row) => row.id === model);
|
|
2804
|
+
const effort = choiceRef.current.reasoningEffort ?? (definition ? defaultEffortForModel(definition) : config.defaultReasoningEffort ?? "medium");
|
|
2805
|
+
return showModelPicker && model ? {
|
|
2806
|
+
model,
|
|
2807
|
+
reasoningEffort: definition ? coerceReasoningEffortForModel(definition, effort) : effort,
|
|
2808
|
+
latencyMode: choiceRef.current.latencyMode ?? "standard"
|
|
2809
|
+
} : void 0;
|
|
2810
|
+
};
|
|
2811
|
+
const create = options.createSession ?? (async (initialMessage, idempotencyKey, input) => {
|
|
2812
|
+
const creator = context.client.createSession;
|
|
2813
|
+
if (typeof creator !== "function")
|
|
2814
|
+
throw new Error("New chats are not enabled for this product.");
|
|
2815
|
+
const created = await creator.call(context.client, context.workspaceId, {
|
|
2816
|
+
...input.startMode === "realtime" ? {} : { initialMessage },
|
|
2817
|
+
idempotencyKey,
|
|
2818
|
+
...input
|
|
2819
|
+
});
|
|
2820
|
+
return created.id;
|
|
2316
2821
|
});
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2822
|
+
const finishCreation = (accepted) => {
|
|
2823
|
+
if (!lifetime.mounted || lifetime.generation !== accepted.generation) return;
|
|
2824
|
+
const { attempt, sessionId } = accepted;
|
|
2825
|
+
const sentFiles = new Set(attempt.options.resources?.map((resource) => resource.fileId) ?? []);
|
|
2826
|
+
const policyChanged = ["model", "reasoningEffort", "latencyMode"].some(
|
|
2827
|
+
(field) => choiceRef.current[field] !== attempt.options[field]
|
|
2828
|
+
);
|
|
2829
|
+
const draft = {
|
|
2830
|
+
text: attempt.clearDraft && textRevision.current === attempt.textRevision ? "" : textRef.current,
|
|
2831
|
+
resources: filesRef.current.readyResources.filter(
|
|
2832
|
+
(resource) => !sentFiles.has(resource.fileId)
|
|
2833
|
+
),
|
|
2834
|
+
// Unchanged choices are already part of the created session. Do not
|
|
2835
|
+
// replace server-owned defaults with a browser's catalog estimate.
|
|
2836
|
+
...policyChanged ? { policy: effectivePolicy() } : {}
|
|
2837
|
+
};
|
|
2838
|
+
pendingRef.current = null;
|
|
2839
|
+
completionRef.current = null;
|
|
2840
|
+
setPending(null);
|
|
2841
|
+
setCompletion(null);
|
|
2842
|
+
updateText(draft.text);
|
|
2843
|
+
filesRef.current.removeReadyFiles(sentFiles);
|
|
2844
|
+
notifyObserver(options.onCreated, {
|
|
2845
|
+
sessionId,
|
|
2846
|
+
initialMessage: attempt.initialMessage,
|
|
2847
|
+
draft,
|
|
2848
|
+
...attempt.realtimeModel ? { realtimeModel: attempt.realtimeModel } : {}
|
|
2849
|
+
});
|
|
2850
|
+
};
|
|
2851
|
+
const finishRef = useRef9(finishCreation);
|
|
2852
|
+
finishRef.current = finishCreation;
|
|
2853
|
+
useLayoutEffect5(() => {
|
|
2854
|
+
if (completion && !files.hasUnresolved) finishRef.current(completion);
|
|
2855
|
+
}, [completion, files.hasUnresolved]);
|
|
2856
|
+
const deliver = async (attempt) => {
|
|
2857
|
+
if (!ownsScope() || inFlight.current || completionRef.current || !available) return false;
|
|
2858
|
+
const ownedGeneration = lifetime.generation;
|
|
2859
|
+
inFlight.current = true;
|
|
2860
|
+
pendingRef.current = attempt;
|
|
2861
|
+
setSending(true);
|
|
2862
|
+
setError(null);
|
|
2863
|
+
setPending(null);
|
|
2864
|
+
try {
|
|
2865
|
+
const sessionId = await attempt.create(
|
|
2866
|
+
attempt.initialMessage,
|
|
2867
|
+
attempt.key,
|
|
2868
|
+
structuredClone(attempt.options)
|
|
2869
|
+
);
|
|
2870
|
+
if (!lifetime.mounted || lifetime.generation !== ownedGeneration) return true;
|
|
2871
|
+
const accepted = { sessionId, attempt, generation: ownedGeneration };
|
|
2872
|
+
completionRef.current = accepted;
|
|
2873
|
+
if (filesRef.current.hasUnresolved) setCompletion(accepted);
|
|
2874
|
+
else finishCreation(accepted);
|
|
2875
|
+
return true;
|
|
2876
|
+
} catch (cause) {
|
|
2877
|
+
if (!lifetime.mounted || lifetime.generation !== ownedGeneration) return false;
|
|
2878
|
+
setError({ cause });
|
|
2879
|
+
if (cause instanceof OpenGeniApiError2 && cause.outcomeUnknown === false) {
|
|
2880
|
+
pendingRef.current = null;
|
|
2881
|
+
} else {
|
|
2882
|
+
setPending(attempt);
|
|
2334
2883
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
owningTurnId = null;
|
|
2341
|
-
}
|
|
2342
|
-
break;
|
|
2884
|
+
return false;
|
|
2885
|
+
} finally {
|
|
2886
|
+
if (lifetime.mounted && lifetime.generation === ownedGeneration) {
|
|
2887
|
+
inFlight.current = false;
|
|
2888
|
+
setSending(false);
|
|
2343
2889
|
}
|
|
2344
|
-
default:
|
|
2345
|
-
break;
|
|
2346
2890
|
}
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
enabled,
|
|
2365
|
-
pollIntervalMs: options.pollIntervalMs
|
|
2366
|
-
});
|
|
2367
|
-
const loadedRequests = state.data;
|
|
2368
|
-
const refreshRequests = state.refresh;
|
|
2369
|
-
const mutation = useMutationRunner(`${workspaceId}\0${sessionId ?? ""}`);
|
|
2370
|
-
const [respondingRequestId, setRespondingRequestId] = useState7(null);
|
|
2371
|
-
const [deadlineVersion, setDeadlineVersion] = useState7(0);
|
|
2372
|
-
const respondingRequestRef = useRef9(null);
|
|
2373
|
-
useEffect8(() => {
|
|
2374
|
-
respondingRequestRef.current = null;
|
|
2375
|
-
setRespondingRequestId(null);
|
|
2376
|
-
}, [sessionId, workspaceId]);
|
|
2377
|
-
useEffect8(() => {
|
|
2378
|
-
if (!sessionId || !enabled) return;
|
|
2379
|
-
return registerSessionReconciler(sessionId, "human-input", state.refresh);
|
|
2380
|
-
}, [enabled, registerSessionReconciler, sessionId, state.refresh]);
|
|
2381
|
-
const scheduleRefresh = useDebouncedCallback(() => void state.refresh());
|
|
2382
|
-
useSessionEventTrigger(client, workspaceId, sessionId, isHumanInputEvent, scheduleRefresh, {
|
|
2383
|
-
enabled,
|
|
2384
|
-
...options.events !== void 0 ? { events: options.events } : {}
|
|
2385
|
-
});
|
|
2386
|
-
useEffect8(() => {
|
|
2387
|
-
const now2 = Date.now();
|
|
2388
|
-
const nextDeadline = (loadedRequests ?? []).reduce((next, request) => {
|
|
2389
|
-
if (request.status !== "pending" || !request.expiresAt) return next;
|
|
2390
|
-
const deadline = Date.parse(request.expiresAt);
|
|
2391
|
-
if (!Number.isFinite(deadline) || deadline <= now2) return next;
|
|
2392
|
-
return next === null ? deadline : Math.min(next, deadline);
|
|
2393
|
-
}, null);
|
|
2394
|
-
if (nextDeadline === null) return;
|
|
2395
|
-
const timer = globalThis.setTimeout(
|
|
2396
|
-
() => {
|
|
2397
|
-
setDeadlineVersion((current) => current + 1);
|
|
2398
|
-
void refreshRequests();
|
|
2399
|
-
},
|
|
2400
|
-
Math.min(2147483647, Math.max(0, nextDeadline - now2 + 1))
|
|
2401
|
-
);
|
|
2402
|
-
return () => globalThis.clearTimeout(timer);
|
|
2403
|
-
}, [loadedRequests, refreshRequests]);
|
|
2404
|
-
const respond = useCallback9(
|
|
2405
|
-
async (requestId, response) => {
|
|
2406
|
-
if (!sessionId || respondingRequestRef.current !== null) return null;
|
|
2407
|
-
respondingRequestRef.current = requestId;
|
|
2408
|
-
setRespondingRequestId(requestId);
|
|
2409
|
-
try {
|
|
2410
|
-
const event = await mutation.run(
|
|
2411
|
-
() => client.submitHumanInputResponse(workspaceId, sessionId, requestId, response, {
|
|
2412
|
-
clientEventId: globalThis.crypto.randomUUID()
|
|
2413
|
-
})
|
|
2414
|
-
);
|
|
2415
|
-
if (event) await state.refresh();
|
|
2416
|
-
return event;
|
|
2417
|
-
} finally {
|
|
2418
|
-
if (respondingRequestRef.current === requestId) {
|
|
2419
|
-
respondingRequestRef.current = null;
|
|
2420
|
-
setRespondingRequestId(null);
|
|
2421
|
-
}
|
|
2891
|
+
};
|
|
2892
|
+
const submit = async (explicit) => {
|
|
2893
|
+
if (!ownsScope() || !available || inFlight.current || pendingRef.current || uploadsEnabled && filesRef.current.hasUnresolved)
|
|
2894
|
+
return false;
|
|
2895
|
+
const resources = uploadsEnabled ? filesRef.current.readyResources : [];
|
|
2896
|
+
const draftText = explicit ?? textRef.current;
|
|
2897
|
+
const initialMessage = draftText.trim() || (resources.length > 0 ? FILE_ONLY_MESSAGE_TEXT : "");
|
|
2898
|
+
if (!initialMessage) return false;
|
|
2899
|
+
return deliver({
|
|
2900
|
+
key: crypto.randomUUID(),
|
|
2901
|
+
initialMessage,
|
|
2902
|
+
textRevision: textRevision.current,
|
|
2903
|
+
clearDraft: explicit === void 0,
|
|
2904
|
+
create,
|
|
2905
|
+
options: {
|
|
2906
|
+
...resources.length ? { resources: structuredClone(resources) } : {},
|
|
2907
|
+
...showModelPicker ? { ...choiceRef.current } : {}
|
|
2422
2908
|
}
|
|
2909
|
+
});
|
|
2910
|
+
};
|
|
2911
|
+
const startRealtime = async (model) => {
|
|
2912
|
+
if (!ownsScope() || !available || inFlight.current || pendingRef.current || !config.realtimeVoice || !(options.realtimeVoice ?? config.realtimeVoiceOffered))
|
|
2913
|
+
return false;
|
|
2914
|
+
if (filesRef.current.hasUnresolved) return false;
|
|
2915
|
+
return deliver({
|
|
2916
|
+
key: crypto.randomUUID(),
|
|
2917
|
+
initialMessage: "",
|
|
2918
|
+
textRevision: textRevision.current,
|
|
2919
|
+
clearDraft: false,
|
|
2920
|
+
create,
|
|
2921
|
+
options: { ...showModelPicker ? { ...choiceRef.current } : {}, startMode: "realtime" },
|
|
2922
|
+
realtimeModel: model
|
|
2923
|
+
});
|
|
2924
|
+
};
|
|
2925
|
+
const composer = {
|
|
2926
|
+
value: text,
|
|
2927
|
+
setValue: updateText,
|
|
2928
|
+
hasDraftContent: () => textRef.current.length > 0 || filesRef.current.attachments.length > 0,
|
|
2929
|
+
send: submit,
|
|
2930
|
+
steer: submit,
|
|
2931
|
+
sending,
|
|
2932
|
+
canSend: available && !sending && !pending && !completion && (text.trim().length > 0 || uploadsEnabled && files.readyResources.length > 0) && !(uploadsEnabled && files.hasUnresolved),
|
|
2933
|
+
pause: NOOP_ASYNC,
|
|
2934
|
+
pausing: false,
|
|
2935
|
+
resume: NOOP_ASYNC,
|
|
2936
|
+
resumeScope: NOOP_ASYNC,
|
|
2937
|
+
resuming: false,
|
|
2938
|
+
draft: null,
|
|
2939
|
+
draftRevision: 0,
|
|
2940
|
+
draftLoading: false,
|
|
2941
|
+
draftSaving: false,
|
|
2942
|
+
draftConflict: null,
|
|
2943
|
+
policy: effectivePolicy() ?? null,
|
|
2944
|
+
setModel: (model) => updateChoice({ model }),
|
|
2945
|
+
setReasoningEffort: (reasoningEffort) => updateChoice({ reasoningEffort }),
|
|
2946
|
+
setLatencyMode: (latencyMode) => updateChoice({ latencyMode }),
|
|
2947
|
+
draftPersistence: "disabled",
|
|
2948
|
+
applyDraft: () => {
|
|
2423
2949
|
},
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2950
|
+
reloadDraft: NOOP_ASYNC,
|
|
2951
|
+
resolveDraftConflict: NOOP_ASYNC,
|
|
2952
|
+
restoredResources: [],
|
|
2953
|
+
removeRestoredResource: () => {
|
|
2954
|
+
},
|
|
2955
|
+
error: null,
|
|
2956
|
+
clearError: () => {
|
|
2957
|
+
if (ownsScope()) setError(null);
|
|
2958
|
+
}
|
|
2959
|
+
};
|
|
2428
2960
|
return {
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2961
|
+
...scope,
|
|
2962
|
+
config,
|
|
2963
|
+
files,
|
|
2964
|
+
uploadsEnabled,
|
|
2965
|
+
available,
|
|
2966
|
+
showModelPicker,
|
|
2967
|
+
catalog,
|
|
2968
|
+
composer,
|
|
2969
|
+
realtimeVoiceEnabled: config.realtimeVoice && (options.realtimeVoice ?? config.realtimeVoiceOffered),
|
|
2970
|
+
error,
|
|
2971
|
+
finishingUploads: completion !== null,
|
|
2972
|
+
pending: pending ? { idempotencyKey: pending.key, realtimeModel: pending.realtimeModel } : null,
|
|
2973
|
+
retry: () => pendingRef.current ? deliver(pendingRef.current) : Promise.resolve(false),
|
|
2974
|
+
startRealtime
|
|
2439
2975
|
};
|
|
2440
2976
|
}
|
|
2441
2977
|
|
|
2442
2978
|
export {
|
|
2443
|
-
|
|
2979
|
+
approvalsFromRequiresAction,
|
|
2980
|
+
projectPendingApprovals,
|
|
2981
|
+
invokeOlderHistoryLoaderWithReceiptCapture,
|
|
2982
|
+
createOlderHistoryLoadReceipt,
|
|
2983
|
+
conversationTimeline,
|
|
2984
|
+
useAvailableModels,
|
|
2985
|
+
useWorkspaceModelCatalog,
|
|
2986
|
+
useClientConfigFlags,
|
|
2987
|
+
useFileAttachments,
|
|
2988
|
+
isHumanInputEvent,
|
|
2989
|
+
useHumanInputRequests,
|
|
2444
2990
|
isTitleEvent,
|
|
2445
2991
|
useSession,
|
|
2992
|
+
useSessionControl,
|
|
2446
2993
|
SESSION_EVENT_BROWSER_MAX_BYTES,
|
|
2447
2994
|
SESSION_EVENT_BROWSER_MAX_COUNT,
|
|
2448
|
-
SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES,
|
|
2449
2995
|
SESSION_EVENT_BROWSER_PENDING_MAX_BYTES,
|
|
2450
2996
|
SESSION_EVENT_BROWSER_PENDING_MAX_COUNT,
|
|
2451
2997
|
useSessionEvents,
|
|
2452
2998
|
boundBrowserSessionEventWindow,
|
|
2453
|
-
useFileAttachments,
|
|
2454
2999
|
isTurnQueueEvent,
|
|
2455
3000
|
useTurnQueue,
|
|
3001
|
+
useSessionConversation,
|
|
2456
3002
|
isGoalEvent,
|
|
2457
3003
|
useGoal,
|
|
2458
|
-
|
|
2459
|
-
isSessionMcpApprovalPolicyEvent,
|
|
2460
|
-
useSessionMcpApprovalPolicy,
|
|
2461
|
-
isLineageRefreshEvent,
|
|
2462
|
-
useSessionLineage,
|
|
2463
|
-
approvalsFromRequiresAction,
|
|
2464
|
-
projectPendingApprovals,
|
|
2465
|
-
isHumanInputEvent,
|
|
2466
|
-
useHumanInputRequests
|
|
3004
|
+
useNewConversation
|
|
2467
3005
|
};
|
|
2468
|
-
//# sourceMappingURL=chunk-
|
|
3006
|
+
//# sourceMappingURL=chunk-X5UVUIMF.js.map
|