@schlessera/brain-ui-react 0.34.1 → 0.36.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 +89 -4
- package/dist/components/activity/activity-page.d.ts +17 -5
- package/dist/components/activity/activity-page.d.ts.map +1 -1
- package/dist/components/activity/activity-page.js +144 -50
- package/dist/components/activity/activity-page.js.map +1 -1
- package/dist/components/activity/activity-run-detail.d.ts +16 -1
- package/dist/components/activity/activity-run-detail.d.ts.map +1 -1
- package/dist/components/activity/activity-run-detail.js +47 -4
- package/dist/components/activity/activity-run-detail.js.map +1 -1
- package/dist/components/activity/activity-run-list.d.ts +7 -1
- package/dist/components/activity/activity-run-list.d.ts.map +1 -1
- package/dist/components/activity/activity-run-list.js +16 -8
- package/dist/components/activity/activity-run-list.js.map +1 -1
- package/dist/components/activity/activity-views.d.ts +63 -0
- package/dist/components/activity/activity-views.d.ts.map +1 -0
- package/dist/components/activity/activity-views.js +52 -0
- package/dist/components/activity/activity-views.js.map +1 -0
- package/dist/components/activity/approval-card.d.ts +11 -0
- package/dist/components/activity/approval-card.d.ts.map +1 -0
- package/dist/components/activity/approval-card.js +46 -0
- package/dist/components/activity/approval-card.js.map +1 -0
- package/dist/components/activity/digest-card.d.ts +3 -0
- package/dist/components/activity/digest-card.d.ts.map +1 -1
- package/dist/components/activity/digest-card.js +20 -16
- package/dist/components/activity/digest-card.js.map +1 -1
- package/dist/components/activity/digest-summary.d.ts +19 -0
- package/dist/components/activity/digest-summary.d.ts.map +1 -0
- package/dist/components/activity/digest-summary.js +20 -0
- package/dist/components/activity/digest-summary.js.map +1 -0
- package/dist/components/activity/push-switch.d.ts +25 -0
- package/dist/components/activity/push-switch.d.ts.map +1 -0
- package/dist/components/activity/push-switch.js +14 -0
- package/dist/components/activity/push-switch.js.map +1 -0
- package/dist/components/activity/push-toggle.d.ts +7 -0
- package/dist/components/activity/push-toggle.d.ts.map +1 -1
- package/dist/components/activity/push-toggle.js +72 -47
- package/dist/components/activity/push-toggle.js.map +1 -1
- package/dist/components/activity/span-bits.d.ts.map +1 -1
- package/dist/components/activity/span-bits.js +9 -7
- package/dist/components/activity/span-bits.js.map +1 -1
- package/dist/components/chat/ask-user-card.d.ts +76 -3
- package/dist/components/chat/ask-user-card.d.ts.map +1 -1
- package/dist/components/chat/ask-user-card.js +208 -149
- package/dist/components/chat/ask-user-card.js.map +1 -1
- package/dist/components/chat/ask-user-typed.d.ts +42 -0
- package/dist/components/chat/ask-user-typed.d.ts.map +1 -0
- package/dist/components/chat/ask-user-typed.js +60 -0
- package/dist/components/chat/ask-user-typed.js.map +1 -0
- package/dist/components/chat/brain-markdown-links.d.ts +2 -1
- package/dist/components/chat/brain-markdown-links.d.ts.map +1 -1
- package/dist/components/chat/brain-markdown-links.js +3 -4
- package/dist/components/chat/brain-markdown-links.js.map +1 -1
- package/dist/components/chat/brain-markdown.d.ts.map +1 -1
- package/dist/components/chat/brain-markdown.js +4 -2
- package/dist/components/chat/brain-markdown.js.map +1 -1
- package/dist/components/chat/chat-page.d.ts.map +1 -1
- package/dist/components/chat/chat-page.js +24 -9
- package/dist/components/chat/chat-page.js.map +1 -1
- package/dist/components/chat/composer-view.d.ts +75 -0
- package/dist/components/chat/composer-view.d.ts.map +1 -0
- package/dist/components/chat/composer-view.js +31 -0
- package/dist/components/chat/composer-view.js.map +1 -0
- package/dist/components/chat/composer.d.ts +4 -0
- package/dist/components/chat/composer.d.ts.map +1 -1
- package/dist/components/chat/composer.js +76 -59
- package/dist/components/chat/composer.js.map +1 -1
- package/dist/components/chat/markdown-content.d.ts +16 -1
- package/dist/components/chat/markdown-content.d.ts.map +1 -1
- package/dist/components/chat/markdown-content.js +47 -3
- package/dist/components/chat/markdown-content.js.map +1 -1
- package/dist/components/chat/mermaid-block.d.ts +4 -0
- package/dist/components/chat/mermaid-block.d.ts.map +1 -1
- package/dist/components/chat/mermaid-block.js +13 -5
- package/dist/components/chat/mermaid-block.js.map +1 -1
- package/dist/components/chat/mermaid-share.d.ts +2 -1
- package/dist/components/chat/mermaid-share.d.ts.map +1 -1
- package/dist/components/chat/mermaid-share.js +7 -8
- package/dist/components/chat/mermaid-share.js.map +1 -1
- package/dist/components/chat/mermaid-viewer.d.ts.map +1 -1
- package/dist/components/chat/mermaid-viewer.js +3 -1
- package/dist/components/chat/mermaid-viewer.js.map +1 -1
- package/dist/components/chat/message-bubble.d.ts +8 -1
- package/dist/components/chat/message-bubble.d.ts.map +1 -1
- package/dist/components/chat/message-bubble.js +53 -24
- package/dist/components/chat/message-bubble.js.map +1 -1
- package/dist/components/chat/message-share.d.ts +2 -1
- package/dist/components/chat/message-share.d.ts.map +1 -1
- package/dist/components/chat/message-share.js +6 -7
- package/dist/components/chat/message-share.js.map +1 -1
- package/dist/components/chat/renderers/bind.d.ts +39 -0
- package/dist/components/chat/renderers/bind.d.ts.map +1 -0
- package/dist/components/chat/renderers/bind.js +43 -0
- package/dist/components/chat/renderers/bind.js.map +1 -0
- package/dist/components/chat/renderers/brain-ui-tools.d.ts +3 -0
- package/dist/components/chat/renderers/brain-ui-tools.d.ts.map +1 -0
- package/dist/components/chat/renderers/brain-ui-tools.js +41 -0
- package/dist/components/chat/renderers/brain-ui-tools.js.map +1 -0
- package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
- package/dist/components/chat/renderers/claude-tools.js +3 -2
- package/dist/components/chat/renderers/claude-tools.js.map +1 -1
- package/dist/components/chat/renderers/index.d.ts +10 -2
- package/dist/components/chat/renderers/index.d.ts.map +1 -1
- package/dist/components/chat/renderers/index.js +15 -10
- package/dist/components/chat/renderers/index.js.map +1 -1
- package/dist/components/chat/session-drawer.d.ts +4 -0
- package/dist/components/chat/session-drawer.d.ts.map +1 -1
- package/dist/components/chat/session-drawer.js +55 -40
- package/dist/components/chat/session-drawer.js.map +1 -1
- package/dist/components/chat/session-list.d.ts +41 -0
- package/dist/components/chat/session-list.d.ts.map +1 -0
- package/dist/components/chat/session-list.js +10 -0
- package/dist/components/chat/session-list.js.map +1 -0
- package/dist/components/chat/share-block.d.ts.map +1 -1
- package/dist/components/chat/share-block.js +12 -11
- package/dist/components/chat/share-block.js.map +1 -1
- package/dist/components/chat/share-card.js +2 -2
- package/dist/components/chat/share-card.js.map +1 -1
- package/dist/components/chat/subagent-view.js +1 -1
- package/dist/components/chat/subagent-view.js.map +1 -1
- package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
- package/dist/components/chat/tool-call-timeline.js +37 -12
- package/dist/components/chat/tool-call-timeline.js.map +1 -1
- package/dist/components/chat/tool-cards/block-card.d.ts +28 -0
- package/dist/components/chat/tool-cards/block-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/block-card.js +103 -0
- package/dist/components/chat/tool-cards/block-card.js.map +1 -0
- package/dist/components/chat/tool-cards/image-mask-card.d.ts +70 -0
- package/dist/components/chat/tool-cards/image-mask-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/image-mask-card.js +142 -0
- package/dist/components/chat/tool-cards/image-mask-card.js.map +1 -0
- package/dist/components/chat/tool-cards/location-card.d.ts +45 -0
- package/dist/components/chat/tool-cards/location-card.d.ts.map +1 -0
- package/dist/components/chat/tool-cards/location-card.js +128 -0
- package/dist/components/chat/tool-cards/location-card.js.map +1 -0
- package/dist/components/chat/tool-views.d.ts +15 -4
- package/dist/components/chat/tool-views.d.ts.map +1 -1
- package/dist/components/chat/tool-views.js +22 -38
- package/dist/components/chat/tool-views.js.map +1 -1
- package/dist/components/chat/transcript-turn.d.ts +45 -0
- package/dist/components/chat/transcript-turn.d.ts.map +1 -0
- package/dist/components/chat/transcript-turn.js +25 -0
- package/dist/components/chat/transcript-turn.js.map +1 -0
- package/dist/components/chat/use-chat-commands.d.ts.map +1 -1
- package/dist/components/chat/use-chat-commands.js +13 -16
- package/dist/components/chat/use-chat-commands.js.map +1 -1
- package/dist/components/chat/welcome-state.d.ts +7 -0
- package/dist/components/chat/welcome-state.d.ts.map +1 -1
- package/dist/components/chat/welcome-state.js +13 -5
- package/dist/components/chat/welcome-state.js.map +1 -1
- package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
- package/dist/components/connectivity/connection-gate.js +64 -6
- package/dist/components/connectivity/connection-gate.js.map +1 -1
- package/dist/components/connectivity/login-form.d.ts +31 -0
- package/dist/components/connectivity/login-form.d.ts.map +1 -0
- package/dist/components/connectivity/login-form.js +19 -0
- package/dist/components/connectivity/login-form.js.map +1 -0
- package/dist/components/connectivity/login-screen.d.ts +5 -2
- package/dist/components/connectivity/login-screen.d.ts.map +1 -1
- package/dist/components/connectivity/login-screen.js +41 -31
- package/dist/components/connectivity/login-screen.js.map +1 -1
- package/dist/components/dev/share-harness.js +1 -1
- package/dist/components/dev/share-harness.js.map +1 -1
- package/dist/components/files/file-panel.d.ts +1 -1
- package/dist/components/files/file-panel.d.ts.map +1 -1
- package/dist/components/files/file-panel.js +74 -0
- package/dist/components/files/file-panel.js.map +1 -1
- package/dist/components/files/file-tree-view.d.ts +45 -0
- package/dist/components/files/file-tree-view.d.ts.map +1 -0
- package/dist/components/files/file-tree-view.js +51 -0
- package/dist/components/files/file-tree-view.js.map +1 -0
- package/dist/components/files/file-tree.d.ts +6 -0
- package/dist/components/files/file-tree.d.ts.map +1 -1
- package/dist/components/files/file-tree.js +39 -43
- package/dist/components/files/file-tree.js.map +1 -1
- package/dist/components/files/file-viewer-binary.d.ts.map +1 -1
- package/dist/components/files/file-viewer-binary.js +3 -2
- package/dist/components/files/file-viewer-binary.js.map +1 -1
- package/dist/components/files/file-viewer-frame.d.ts +36 -0
- package/dist/components/files/file-viewer-frame.d.ts.map +1 -0
- package/dist/components/files/file-viewer-frame.js +26 -0
- package/dist/components/files/file-viewer-frame.js.map +1 -0
- package/dist/components/files/file-viewer.d.ts +5 -0
- package/dist/components/files/file-viewer.d.ts.map +1 -1
- package/dist/components/files/file-viewer.js +26 -32
- package/dist/components/files/file-viewer.js.map +1 -1
- package/dist/components/files/frontmatter-chips.d.ts +18 -0
- package/dist/components/files/frontmatter-chips.d.ts.map +1 -0
- package/dist/components/files/frontmatter-chips.js +11 -0
- package/dist/components/files/frontmatter-chips.js.map +1 -0
- package/dist/components/files/frontmatter-panel.d.ts +5 -1
- package/dist/components/files/frontmatter-panel.d.ts.map +1 -1
- package/dist/components/files/frontmatter-panel.js +7 -6
- package/dist/components/files/frontmatter-panel.js.map +1 -1
- package/dist/components/files/staleness.d.ts +18 -0
- package/dist/components/files/staleness.d.ts.map +1 -0
- package/dist/components/files/staleness.js +27 -0
- package/dist/components/files/staleness.js.map +1 -0
- package/dist/components/graph/graph-canvas.d.ts.map +1 -1
- package/dist/components/graph/graph-canvas.js +24 -1
- package/dist/components/graph/graph-canvas.js.map +1 -1
- package/dist/components/graph/graph-controls-column.d.ts +14 -0
- package/dist/components/graph/graph-controls-column.d.ts.map +1 -0
- package/dist/components/graph/graph-controls-column.js +44 -0
- package/dist/components/graph/graph-controls-column.js.map +1 -0
- package/dist/components/graph/graph-controls.d.ts +20 -5
- package/dist/components/graph/graph-controls.d.ts.map +1 -1
- package/dist/components/graph/graph-controls.js +58 -37
- package/dist/components/graph/graph-controls.js.map +1 -1
- package/dist/components/graph/graph-form.d.ts +82 -0
- package/dist/components/graph/graph-form.d.ts.map +1 -0
- package/dist/components/graph/graph-form.js +69 -0
- package/dist/components/graph/graph-form.js.map +1 -0
- package/dist/components/graph/graph-maintenance.d.ts.map +1 -1
- package/dist/components/graph/graph-maintenance.js +6 -10
- package/dist/components/graph/graph-maintenance.js.map +1 -1
- package/dist/components/graph/graph-node-rail.d.ts +13 -0
- package/dist/components/graph/graph-node-rail.d.ts.map +1 -0
- package/dist/components/graph/graph-node-rail.js +92 -0
- package/dist/components/graph/graph-node-rail.js.map +1 -0
- package/dist/components/graph/graph-page.d.ts +7 -0
- package/dist/components/graph/graph-page.d.ts.map +1 -1
- package/dist/components/graph/graph-page.js +102 -12
- package/dist/components/graph/graph-page.js.map +1 -1
- package/dist/components/graph/graph-scene.d.ts.map +1 -1
- package/dist/components/graph/graph-scene.js +100 -24
- package/dist/components/graph/graph-scene.js.map +1 -1
- package/dist/components/graph/lib/graph-helpers.d.ts +42 -12
- package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -1
- package/dist/components/graph/lib/graph-helpers.js +33 -41
- package/dist/components/graph/lib/graph-helpers.js.map +1 -1
- package/dist/components/graph/node-card.d.ts +28 -0
- package/dist/components/graph/node-card.d.ts.map +1 -0
- package/dist/components/graph/node-card.js +7 -0
- package/dist/components/graph/node-card.js.map +1 -0
- package/dist/components/graph/node-popover.d.ts +6 -2
- package/dist/components/graph/node-popover.d.ts.map +1 -1
- package/dist/components/graph/node-popover.js +13 -31
- package/dist/components/graph/node-popover.js.map +1 -1
- package/dist/components/graph/use-graph-theme.d.ts +32 -4
- package/dist/components/graph/use-graph-theme.d.ts.map +1 -1
- package/dist/components/graph/use-graph-theme.js +44 -32
- package/dist/components/graph/use-graph-theme.js.map +1 -1
- package/dist/components/graph/use-node-actions.d.ts +26 -0
- package/dist/components/graph/use-node-actions.d.ts.map +1 -0
- package/dist/components/graph/use-node-actions.js +54 -0
- package/dist/components/graph/use-node-actions.js.map +1 -0
- package/dist/components/images/image-share.d.ts +2 -1
- package/dist/components/images/image-share.d.ts.map +1 -1
- package/dist/components/images/image-share.js +3 -3
- package/dist/components/images/image-share.js.map +1 -1
- package/dist/components/images/image-viewer.d.ts.map +1 -1
- package/dist/components/images/image-viewer.js +3 -1
- package/dist/components/images/image-viewer.js.map +1 -1
- package/dist/components/images/mask-editor.d.ts.map +1 -1
- package/dist/components/images/mask-editor.js +7 -5
- package/dist/components/images/mask-editor.js.map +1 -1
- package/dist/components/layout/app-shell.d.ts.map +1 -1
- package/dist/components/layout/app-shell.js +5 -1
- package/dist/components/layout/app-shell.js.map +1 -1
- package/dist/components/layout/desktop-palette.d.ts +23 -0
- package/dist/components/layout/desktop-palette.d.ts.map +1 -0
- package/dist/components/layout/desktop-palette.js +132 -0
- package/dist/components/layout/desktop-palette.js.map +1 -0
- package/dist/components/layout/key-cap.d.ts +9 -0
- package/dist/components/layout/key-cap.d.ts.map +1 -0
- package/dist/components/layout/key-cap.js +10 -0
- package/dist/components/layout/key-cap.js.map +1 -0
- package/dist/components/layout/mobile-tab-bar.d.ts +13 -0
- package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
- package/dist/components/layout/mobile-tab-bar.js +58 -47
- package/dist/components/layout/mobile-tab-bar.js.map +1 -1
- package/dist/components/layout/shortcut-switch.d.ts +13 -0
- package/dist/components/layout/shortcut-switch.d.ts.map +1 -0
- package/dist/components/layout/shortcut-switch.js +22 -0
- package/dist/components/layout/shortcut-switch.js.map +1 -0
- package/dist/components/layout/side-rail.d.ts +24 -0
- package/dist/components/layout/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail.js +65 -27
- package/dist/components/layout/side-rail.js.map +1 -1
- package/dist/components/layout/slide-panel.d.ts +12 -2
- package/dist/components/layout/slide-panel.d.ts.map +1 -1
- package/dist/components/layout/slide-panel.js +11 -2
- package/dist/components/layout/slide-panel.js.map +1 -1
- package/dist/components/layout/theme.d.ts +22 -0
- package/dist/components/layout/theme.d.ts.map +1 -0
- package/dist/components/layout/theme.js +44 -0
- package/dist/components/layout/theme.js.map +1 -0
- package/dist/components/quick-actions/add-form.d.ts +44 -0
- package/dist/components/quick-actions/add-form.d.ts.map +1 -0
- package/dist/components/quick-actions/add-form.js +30 -0
- package/dist/components/quick-actions/add-form.js.map +1 -0
- package/dist/components/quick-actions/add-modal.d.ts +7 -0
- package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/add-modal.js +66 -20
- package/dist/components/quick-actions/add-modal.js.map +1 -1
- package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/search-modal.js +48 -19
- package/dist/components/quick-actions/search-modal.js.map +1 -1
- package/dist/components/quick-actions/streaming-modal.d.ts +6 -0
- package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/streaming-modal.js +42 -17
- package/dist/components/quick-actions/streaming-modal.js.map +1 -1
- package/dist/components/quick-actions/streaming-output.d.ts +38 -0
- package/dist/components/quick-actions/streaming-output.d.ts.map +1 -0
- package/dist/components/quick-actions/streaming-output.js +22 -0
- package/dist/components/quick-actions/streaming-output.js.map +1 -0
- package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
- package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -1
- package/dist/components/quick-actions/whatsup-modal.js +36 -10
- package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
- package/dist/components/settings/devices-agents-tab.d.ts +10 -0
- package/dist/components/settings/devices-agents-tab.d.ts.map +1 -0
- package/dist/components/settings/devices-agents-tab.js +131 -0
- package/dist/components/settings/devices-agents-tab.js.map +1 -0
- package/dist/components/settings/models-list.d.ts +39 -0
- package/dist/components/settings/models-list.d.ts.map +1 -0
- package/dist/components/settings/models-list.js +72 -0
- package/dist/components/settings/models-list.js.map +1 -0
- package/dist/components/settings/models-tab.d.ts +4 -0
- package/dist/components/settings/models-tab.d.ts.map +1 -1
- package/dist/components/settings/models-tab.js +52 -102
- package/dist/components/settings/models-tab.js.map +1 -1
- package/dist/components/settings/one-time-agent-credential.d.ts +3 -0
- package/dist/components/settings/one-time-agent-credential.d.ts.map +1 -0
- package/dist/components/settings/one-time-agent-credential.js +55 -0
- package/dist/components/settings/one-time-agent-credential.js.map +1 -0
- package/dist/components/settings/passkey-list.d.ts +35 -0
- package/dist/components/settings/passkey-list.d.ts.map +1 -0
- package/dist/components/settings/passkey-list.js +34 -0
- package/dist/components/settings/passkey-list.js.map +1 -0
- package/dist/components/settings/passkey-tab.d.ts +3 -0
- package/dist/components/settings/passkey-tab.d.ts.map +1 -1
- package/dist/components/settings/passkey-tab.js +53 -45
- package/dist/components/settings/passkey-tab.js.map +1 -1
- package/dist/components/settings/pi-accounts-list.d.ts +27 -0
- package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
- package/dist/components/settings/pi-accounts-list.js +15 -0
- package/dist/components/settings/pi-accounts-list.js.map +1 -0
- package/dist/components/settings/pi-accounts.d.ts +3 -0
- package/dist/components/settings/pi-accounts.d.ts.map +1 -1
- package/dist/components/settings/pi-accounts.js +73 -55
- package/dist/components/settings/pi-accounts.js.map +1 -1
- package/dist/components/settings/principal-list.d.ts +37 -0
- package/dist/components/settings/principal-list.d.ts.map +1 -0
- package/dist/components/settings/principal-list.js +18 -0
- package/dist/components/settings/principal-list.js.map +1 -0
- package/dist/components/settings/settings-panel.d.ts +10 -3
- package/dist/components/settings/settings-panel.d.ts.map +1 -1
- package/dist/components/settings/settings-panel.js +80 -6
- package/dist/components/settings/settings-panel.js.map +1 -1
- package/dist/components/settings/skills-list.d.ts +53 -0
- package/dist/components/settings/skills-list.d.ts.map +1 -0
- package/dist/components/settings/skills-list.js +28 -0
- package/dist/components/settings/skills-list.js.map +1 -0
- package/dist/components/settings/skills-tab.d.ts.map +1 -1
- package/dist/components/settings/skills-tab.js +65 -38
- package/dist/components/settings/skills-tab.js.map +1 -1
- package/dist/components/settings/tool-permissions-list.d.ts +18 -0
- package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
- package/dist/components/settings/tool-permissions-list.js +6 -0
- package/dist/components/settings/tool-permissions-list.js.map +1 -0
- package/dist/components/settings/tool-permissions.d.ts +2 -1
- package/dist/components/settings/tool-permissions.d.ts.map +1 -1
- package/dist/components/settings/tool-permissions.js +33 -16
- package/dist/components/settings/tool-permissions.js.map +1 -1
- package/dist/components/settings/web-search-chain.d.ts +41 -0
- package/dist/components/settings/web-search-chain.d.ts.map +1 -0
- package/dist/components/settings/web-search-chain.js +47 -0
- package/dist/components/settings/web-search-chain.js.map +1 -0
- package/dist/components/settings/web-search-settings.d.ts +4 -7
- package/dist/components/settings/web-search-settings.d.ts.map +1 -1
- package/dist/components/settings/web-search-settings.js +54 -76
- package/dist/components/settings/web-search-settings.js.map +1 -1
- package/dist/components/share/share-menu.d.ts.map +1 -1
- package/dist/components/share/share-menu.js +24 -4
- package/dist/components/share/share-menu.js.map +1 -1
- package/dist/components/voice/dictation-sheet.js +3 -3
- package/dist/components/voice/dictation-sheet.js.map +1 -1
- package/dist/components/voice/mic-button.js +1 -1
- package/dist/components/voice/mic-button.js.map +1 -1
- package/dist/components/voice/review-card.js +1 -1
- package/dist/components/voice/review-card.js.map +1 -1
- package/dist/config.d.ts +5 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -5
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +12 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +421 -0
- package/dist/connection.js.map +1 -0
- package/dist/default-root.d.ts +3 -0
- package/dist/default-root.d.ts.map +1 -0
- package/dist/default-root.js +16 -0
- package/dist/default-root.js.map +1 -0
- package/dist/hooks/use-color-scheme.d.ts +14 -0
- package/dist/hooks/use-color-scheme.d.ts.map +1 -0
- package/dist/hooks/use-color-scheme.js +37 -0
- package/dist/hooks/use-color-scheme.js.map +1 -0
- package/dist/hooks/use-hash-routes.d.ts.map +1 -1
- package/dist/hooks/use-hash-routes.js +4 -2
- package/dist/hooks/use-hash-routes.js.map +1 -1
- package/dist/hooks/use-media-query.d.ts +7 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +34 -0
- package/dist/hooks/use-media-query.js.map +1 -0
- package/dist/hooks/use-share-intake.d.ts.map +1 -1
- package/dist/hooks/use-share-intake.js +37 -12
- package/dist/hooks/use-share-intake.js.map +1 -1
- package/dist/hooks/use-vpn-status.d.ts +1 -1
- package/dist/hooks/use-vpn-status.d.ts.map +1 -1
- package/dist/hooks/use-vpn-status.js +20 -16
- package/dist/hooks/use-vpn-status.js.map +1 -1
- package/dist/hooks/use-websocket.d.ts +5 -24
- package/dist/hooks/use-websocket.d.ts.map +1 -1
- package/dist/hooks/use-websocket.js +11 -382
- package/dist/hooks/use-websocket.js.map +1 -1
- package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
- package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/activity.js +4 -5
- package/dist/hooks/websocket-handlers/activity.js.map +1 -1
- package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
- package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/chat.js +27 -5
- package/dist/hooks/websocket-handlers/chat.js.map +1 -1
- package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/connection.js +4 -6
- package/dist/hooks/websocket-handlers/connection.js.map +1 -1
- package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
- package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/mask.js +2 -3
- package/dist/hooks/websocket-handlers/mask.js.map +1 -1
- package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
- package/dist/hooks/websocket-handlers/provider.js +4 -6
- package/dist/hooks/websocket-handlers/provider.js.map +1 -1
- package/dist/hooks/websocket-handlers/types.d.ts +6 -2
- package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +321 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +243 -213
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/backend.d.ts +19 -2
- package/dist/lib/backend.d.ts.map +1 -1
- package/dist/lib/backend.js +15 -9
- package/dist/lib/backend.js.map +1 -1
- package/dist/lib/diff.d.ts +8 -10
- package/dist/lib/diff.d.ts.map +1 -1
- package/dist/lib/diff.js +26 -53
- package/dist/lib/diff.js.map +1 -1
- package/dist/lib/format-time.d.ts +3 -0
- package/dist/lib/format-time.d.ts.map +1 -0
- package/dist/lib/format-time.js +25 -0
- package/dist/lib/format-time.js.map +1 -0
- package/dist/lib/light-dark.d.ts +37 -0
- package/dist/lib/light-dark.d.ts.map +1 -0
- package/dist/lib/light-dark.js +83 -0
- package/dist/lib/light-dark.js.map +1 -0
- package/dist/lib/mermaid-theme.d.ts +7 -2
- package/dist/lib/mermaid-theme.d.ts.map +1 -1
- package/dist/lib/mermaid-theme.js +125 -203
- package/dist/lib/mermaid-theme.js.map +1 -1
- package/dist/lib/passkeys.d.ts +6 -3
- package/dist/lib/passkeys.d.ts.map +1 -1
- package/dist/lib/passkeys.js +10 -4
- package/dist/lib/passkeys.js.map +1 -1
- package/dist/lib/push-registration.d.ts +10 -0
- package/dist/lib/push-registration.d.ts.map +1 -0
- package/dist/lib/push-registration.js +44 -0
- package/dist/lib/push-registration.js.map +1 -0
- package/dist/lib/share-intake.d.ts +2 -1
- package/dist/lib/share-intake.d.ts.map +1 -1
- package/dist/lib/share-intake.js +3 -3
- package/dist/lib/share-intake.js.map +1 -1
- package/dist/lib/share.d.ts +4 -3
- package/dist/lib/share.d.ts.map +1 -1
- package/dist/lib/share.js +6 -7
- package/dist/lib/share.js.map +1 -1
- package/dist/lib/single-key.d.ts +30 -0
- package/dist/lib/single-key.d.ts.map +1 -0
- package/dist/lib/single-key.js +45 -0
- package/dist/lib/single-key.js.map +1 -0
- package/dist/lib/tool-names.d.ts +8 -6
- package/dist/lib/tool-names.d.ts.map +1 -1
- package/dist/lib/tool-names.js +17 -7
- package/dist/lib/tool-names.js.map +1 -1
- package/dist/root-context.d.ts +229 -0
- package/dist/root-context.d.ts.map +1 -0
- package/dist/root-context.js +33 -0
- package/dist/root-context.js.map +1 -0
- package/dist/root.d.ts +38 -0
- package/dist/root.d.ts.map +1 -0
- package/dist/root.js +47 -0
- package/dist/root.js.map +1 -0
- package/dist/stores/activity-state.d.ts +29 -0
- package/dist/stores/activity-state.d.ts.map +1 -0
- package/dist/stores/activity-state.js +282 -0
- package/dist/stores/activity-state.js.map +1 -0
- package/dist/stores/activity-store.d.ts +10 -41
- package/dist/stores/activity-store.d.ts.map +1 -1
- package/dist/stores/activity-store.js +9 -271
- package/dist/stores/activity-store.js.map +1 -1
- package/dist/stores/chat-state.d.ts +212 -0
- package/dist/stores/chat-state.d.ts.map +1 -0
- package/dist/stores/chat-state.js +466 -0
- package/dist/stores/chat-state.js.map +1 -0
- package/dist/stores/chat-store.d.ts +4 -162
- package/dist/stores/chat-store.d.ts.map +1 -1
- package/dist/stores/chat-store.js +7 -418
- package/dist/stores/chat-store.js.map +1 -1
- package/dist/stores/connection-state.d.ts +40 -0
- package/dist/stores/connection-state.d.ts.map +1 -0
- package/dist/stores/connection-state.js +30 -0
- package/dist/stores/connection-state.js.map +1 -0
- package/dist/stores/connection-store.d.ts +4 -40
- package/dist/stores/connection-store.d.ts.map +1 -1
- package/dist/stores/connection-store.js +7 -27
- package/dist/stores/connection-store.js.map +1 -1
- package/dist/stores/create-stores.d.ts +23 -0
- package/dist/stores/create-stores.d.ts.map +1 -0
- package/dist/stores/create-stores.js +28 -0
- package/dist/stores/create-stores.js.map +1 -0
- package/dist/stores/file-state.d.ts +53 -0
- package/dist/stores/file-state.d.ts.map +1 -0
- package/dist/stores/file-state.js +341 -0
- package/dist/stores/file-state.js.map +1 -0
- package/dist/stores/file-store.d.ts +4 -52
- package/dist/stores/file-store.d.ts.map +1 -1
- package/dist/stores/file-store.js +7 -300
- package/dist/stores/file-store.js.map +1 -1
- package/dist/stores/graph-state.d.ts +95 -0
- package/dist/stores/graph-state.d.ts.map +1 -0
- package/dist/stores/graph-state.js +252 -0
- package/dist/stores/graph-state.js.map +1 -0
- package/dist/stores/graph-store.d.ts +7 -83
- package/dist/stores/graph-store.d.ts.map +1 -1
- package/dist/stores/graph-store.js +8 -249
- package/dist/stores/graph-store.js.map +1 -1
- package/dist/stores/mask-state.d.ts +21 -0
- package/dist/stores/mask-state.d.ts.map +1 -0
- package/dist/stores/mask-state.js +9 -0
- package/dist/stores/mask-state.js.map +1 -0
- package/dist/stores/mask-store.d.ts +4 -21
- package/dist/stores/mask-store.d.ts.map +1 -1
- package/dist/stores/mask-store.js +7 -6
- package/dist/stores/mask-store.js.map +1 -1
- package/dist/stores/principal-state.d.ts +16 -0
- package/dist/stores/principal-state.d.ts.map +1 -0
- package/dist/stores/principal-state.js +31 -0
- package/dist/stores/principal-state.js.map +1 -0
- package/dist/stores/principal-store.d.ts +5 -0
- package/dist/stores/principal-store.d.ts.map +1 -0
- package/dist/stores/principal-store.js +8 -0
- package/dist/stores/principal-store.js.map +1 -0
- package/dist/stores/provider-state.d.ts +24 -0
- package/dist/stores/provider-state.d.ts.map +1 -0
- package/dist/stores/provider-state.js +68 -0
- package/dist/stores/provider-state.js.map +1 -0
- package/dist/stores/provider-store.d.ts +4 -23
- package/dist/stores/provider-store.d.ts.map +1 -1
- package/dist/stores/provider-store.js +7 -64
- package/dist/stores/provider-store.js.map +1 -1
- package/dist/stores/share-state.d.ts +29 -0
- package/dist/stores/share-state.d.ts.map +1 -0
- package/dist/stores/share-state.js +21 -0
- package/dist/stores/share-state.js.map +1 -0
- package/dist/stores/share-store.d.ts +4 -28
- package/dist/stores/share-store.d.ts.map +1 -1
- package/dist/stores/share-store.js +7 -18
- package/dist/stores/share-store.js.map +1 -1
- package/dist/stores/store-environment.d.ts +10 -0
- package/dist/stores/store-environment.d.ts.map +1 -0
- package/dist/stores/store-environment.js +2 -0
- package/dist/stores/store-environment.js.map +1 -0
- package/dist/stores/ui-state.d.ts +71 -0
- package/dist/stores/ui-state.d.ts.map +1 -0
- package/dist/stores/ui-state.js +58 -0
- package/dist/stores/ui-state.js.map +1 -0
- package/dist/stores/ui-store.d.ts +4 -45
- package/dist/stores/ui-store.d.ts.map +1 -1
- package/dist/stores/ui-store.js +7 -36
- package/dist/stores/ui-store.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +150 -97
- package/dist/voice/asr-clients.d.ts +2 -1
- package/dist/voice/asr-clients.d.ts.map +1 -1
- package/dist/voice/asr-clients.js +16 -17
- package/dist/voice/asr-clients.js.map +1 -1
- package/dist/voice/use-dictation.d.ts.map +1 -1
- package/dist/voice/use-dictation.js +12 -8
- package/dist/voice/use-dictation.js.map +1 -1
- package/dist/voice/voice-state.d.ts +25 -0
- package/dist/voice/voice-state.d.ts.map +1 -0
- package/dist/voice/voice-state.js +29 -0
- package/dist/voice/voice-state.js.map +1 -0
- package/dist/voice/voice-store.d.ts +4 -25
- package/dist/voice/voice-store.d.ts.map +1 -1
- package/dist/voice/voice-store.js +7 -26
- package/dist/voice/voice-store.js.map +1 -1
- package/package.json +3 -2
- package/src/components/activity/activity-page.tsx +334 -160
- package/src/components/activity/activity-run-detail.tsx +81 -47
- package/src/components/activity/activity-run-list.tsx +27 -59
- package/src/components/activity/activity-views.tsx +155 -0
- package/src/components/activity/approval-card.tsx +80 -0
- package/src/components/activity/digest-card.tsx +25 -61
- package/src/components/activity/digest-summary.tsx +52 -0
- package/src/components/activity/push-switch.tsx +62 -0
- package/src/components/activity/push-toggle.tsx +51 -81
- package/src/components/activity/span-bits.tsx +8 -7
- package/src/components/chat/ask-user-card.tsx +292 -356
- package/src/components/chat/ask-user-typed.ts +77 -0
- package/src/components/chat/brain-markdown-links.tsx +4 -4
- package/src/components/chat/brain-markdown.tsx +4 -2
- package/src/components/chat/chat-page.tsx +38 -9
- package/src/components/chat/composer-view.tsx +194 -0
- package/src/components/chat/composer.tsx +117 -296
- package/src/components/chat/markdown-content.tsx +53 -2
- package/src/components/chat/mermaid-block.tsx +13 -5
- package/src/components/chat/mermaid-share.ts +8 -7
- package/src/components/chat/mermaid-viewer.tsx +3 -1
- package/src/components/chat/message-bubble.tsx +78 -94
- package/src/components/chat/message-share.ts +7 -7
- package/src/components/chat/renderers/bind.tsx +94 -0
- package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
- package/src/components/chat/renderers/claude-tools.tsx +3 -2
- package/src/components/chat/renderers/index.ts +15 -10
- package/src/components/chat/session-drawer.tsx +60 -138
- package/src/components/chat/session-list.tsx +113 -0
- package/src/components/chat/share-block.tsx +16 -12
- package/src/components/chat/share-card.tsx +2 -2
- package/src/components/chat/subagent-view.tsx +4 -4
- package/src/components/chat/tool-call-timeline.tsx +59 -22
- package/src/components/chat/tool-cards/block-card.tsx +145 -0
- package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
- package/src/components/chat/tool-cards/location-card.tsx +159 -0
- package/src/components/chat/tool-views.tsx +23 -73
- package/src/components/chat/transcript-turn.tsx +108 -0
- package/src/components/chat/use-chat-commands.ts +14 -16
- package/src/components/chat/welcome-state.tsx +36 -91
- package/src/components/connectivity/connection-gate.tsx +80 -9
- package/src/components/connectivity/login-form.tsx +122 -0
- package/src/components/connectivity/login-screen.tsx +45 -100
- package/src/components/dev/share-harness.tsx +2 -2
- package/src/components/files/file-panel.tsx +168 -0
- package/src/components/files/file-tree-view.tsx +127 -0
- package/src/components/files/file-tree.tsx +55 -109
- package/src/components/files/file-viewer-binary.tsx +3 -2
- package/src/components/files/file-viewer-frame.tsx +113 -0
- package/src/components/files/file-viewer.tsx +40 -95
- package/src/components/files/frontmatter-chips.tsx +42 -0
- package/src/components/files/frontmatter-panel.tsx +6 -71
- package/src/components/files/staleness.ts +29 -0
- package/src/components/graph/graph-canvas.tsx +24 -1
- package/src/components/graph/graph-controls-column.tsx +92 -0
- package/src/components/graph/graph-controls.tsx +83 -127
- package/src/components/graph/graph-form.tsx +183 -0
- package/src/components/graph/graph-maintenance.tsx +9 -14
- package/src/components/graph/graph-node-rail.tsx +147 -0
- package/src/components/graph/graph-page.tsx +189 -49
- package/src/components/graph/graph-scene.tsx +200 -30
- package/src/components/graph/lib/graph-helpers.ts +65 -43
- package/src/components/graph/node-card.tsx +64 -0
- package/src/components/graph/node-popover.tsx +28 -117
- package/src/components/graph/use-graph-theme.ts +69 -32
- package/src/components/graph/use-node-actions.ts +56 -0
- package/src/components/images/image-share.ts +4 -2
- package/src/components/images/image-viewer.tsx +3 -1
- package/src/components/images/mask-editor.tsx +7 -4
- package/src/components/layout/app-shell.tsx +7 -1
- package/src/components/layout/desktop-palette.tsx +151 -0
- package/src/components/layout/key-cap.tsx +15 -0
- package/src/components/layout/mobile-tab-bar.tsx +80 -157
- package/src/components/layout/shortcut-switch.tsx +32 -0
- package/src/components/layout/side-rail.tsx +70 -150
- package/src/components/layout/slide-panel.tsx +29 -2
- package/src/components/layout/theme.tsx +67 -0
- package/src/components/quick-actions/add-form.tsx +188 -0
- package/src/components/quick-actions/add-modal.tsx +68 -144
- package/src/components/quick-actions/search-modal.tsx +49 -19
- package/src/components/quick-actions/streaming-modal.tsx +44 -71
- package/src/components/quick-actions/streaming-output.tsx +112 -0
- package/src/components/quick-actions/whatsup-modal.tsx +38 -60
- package/src/components/settings/devices-agents-tab.tsx +139 -0
- package/src/components/settings/models-list.tsx +299 -0
- package/src/components/settings/models-tab.tsx +63 -337
- package/src/components/settings/one-time-agent-credential.tsx +131 -0
- package/src/components/settings/passkey-list.tsx +201 -0
- package/src/components/settings/passkey-tab.tsx +53 -197
- package/src/components/settings/pi-accounts-list.tsx +128 -0
- package/src/components/settings/pi-accounts.tsx +71 -170
- package/src/components/settings/principal-list.tsx +172 -0
- package/src/components/settings/settings-panel.tsx +245 -19
- package/src/components/settings/skills-list.tsx +276 -0
- package/src/components/settings/skills-tab.tsx +82 -269
- package/src/components/settings/tool-permissions-list.tsx +54 -0
- package/src/components/settings/tool-permissions.tsx +27 -46
- package/src/components/settings/web-search-chain.tsx +300 -0
- package/src/components/settings/web-search-settings.tsx +58 -328
- package/src/components/share/share-menu.tsx +19 -4
- package/src/components/voice/dictation-sheet.tsx +5 -5
- package/src/components/voice/mic-button.tsx +1 -1
- package/src/components/voice/review-card.tsx +1 -1
- package/src/config.ts +21 -7
- package/src/connection.ts +443 -0
- package/src/default-root.ts +16 -0
- package/src/hooks/use-color-scheme.ts +36 -0
- package/src/hooks/use-hash-routes.ts +4 -2
- package/src/hooks/use-media-query.ts +32 -0
- package/src/hooks/use-share-intake.ts +32 -12
- package/src/hooks/use-vpn-status.ts +23 -15
- package/src/hooks/use-websocket.ts +12 -426
- package/src/hooks/websocket-handlers/activity.ts +4 -5
- package/src/hooks/websocket-handlers/chat.ts +26 -5
- package/src/hooks/websocket-handlers/connection.ts +4 -6
- package/src/hooks/websocket-handlers/mask.ts +2 -3
- package/src/hooks/websocket-handlers/provider.ts +4 -6
- package/src/hooks/websocket-handlers/types.ts +6 -2
- package/src/index.ts +7 -3
- package/src/lib/api-client.ts +446 -365
- package/src/lib/backend.ts +20 -10
- package/src/lib/diff.ts +28 -62
- package/src/lib/format-time.ts +20 -0
- package/src/lib/light-dark.ts +83 -0
- package/src/lib/mermaid-theme.ts +183 -214
- package/src/lib/passkeys.ts +12 -4
- package/src/lib/push-registration.ts +46 -0
- package/src/lib/share-intake.ts +6 -3
- package/src/lib/share.ts +7 -4
- package/src/lib/single-key.ts +47 -0
- package/src/lib/tool-names.ts +31 -8
- package/src/root-context.tsx +40 -0
- package/src/root.ts +83 -0
- package/src/stores/activity-state.ts +295 -0
- package/src/stores/activity-store.ts +11 -285
- package/src/stores/chat-state.ts +795 -0
- package/src/stores/chat-store.ts +11 -705
- package/src/stores/connection-state.ts +78 -0
- package/src/stores/connection-store.ts +11 -76
- package/src/stores/create-stores.ts +31 -0
- package/src/stores/file-state.ts +399 -0
- package/src/stores/file-store.ts +9 -360
- package/src/stores/graph-state.ts +368 -0
- package/src/stores/graph-store.ts +10 -355
- package/src/stores/mask-state.ts +30 -0
- package/src/stores/mask-store.ts +10 -27
- package/src/stores/principal-state.ts +42 -0
- package/src/stores/principal-store.ts +11 -0
- package/src/stores/provider-state.ts +103 -0
- package/src/stores/provider-store.ts +10 -95
- package/src/stores/share-state.ts +56 -0
- package/src/stores/share-store.ts +11 -54
- package/src/stores/store-environment.ts +10 -0
- package/src/stores/ui-state.ts +143 -0
- package/src/stores/ui-store.ts +11 -93
- package/src/styles.css +4 -1
- package/src/theme.css +150 -97
- package/src/voice/asr-clients.ts +17 -17
- package/src/voice/use-dictation.ts +11 -8
- package/src/voice/voice-state.ts +57 -0
- package/src/voice/voice-store.ts +11 -55
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
import { createStore } from "zustand/vanilla";
|
|
2
|
+
import type {
|
|
3
|
+
MessageBlock,
|
|
4
|
+
MessageSource,
|
|
5
|
+
MessagePart,
|
|
6
|
+
AskUserQuestion,
|
|
7
|
+
AskUserAnnotation,
|
|
8
|
+
} from "@schlessera/brain-ui-sdk/protocol";
|
|
9
|
+
import type { StoreApi } from "zustand/vanilla";
|
|
10
|
+
import type { ProviderState } from "./provider-state.js";
|
|
11
|
+
import type { StoreEnvironment } from "./store-environment.js";
|
|
12
|
+
|
|
13
|
+
export type { MessagePart };
|
|
14
|
+
|
|
15
|
+
export interface ChatMessage {
|
|
16
|
+
id: string;
|
|
17
|
+
role: "user" | "assistant";
|
|
18
|
+
content: string;
|
|
19
|
+
thinking?: string;
|
|
20
|
+
toolCalls: ToolCall[];
|
|
21
|
+
/**
|
|
22
|
+
* Chronological thinking/text/tool segments, in arrival order. `content`,
|
|
23
|
+
* `thinking` and `toolCalls` remain the aggregated views (used for sharing
|
|
24
|
+
* and tool state); `parts` drives rendering order.
|
|
25
|
+
*/
|
|
26
|
+
parts: MessagePart[];
|
|
27
|
+
isStreaming: boolean;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
source?: MessageSource;
|
|
30
|
+
/** AskUserQuestion exchanges raised during this assistant turn. */
|
|
31
|
+
askUserExchanges?: AskUserExchange[];
|
|
32
|
+
/**
|
|
33
|
+
* Image attachments on a user message. Live messages carry a local
|
|
34
|
+
* `previewUrl` (object URL, revoked on clear). History-loaded messages
|
|
35
|
+
* carry no data — only `attachmentCount` — since base64 is never replayed.
|
|
36
|
+
*/
|
|
37
|
+
attachments?: MessageAttachment[];
|
|
38
|
+
/** Attachment count for history-loaded messages without preview data. */
|
|
39
|
+
attachmentCount?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Blocks the surface classified out of this message's text (D42), each
|
|
42
|
+
* anchored to a text part and a span in it. Arrive after the turn's
|
|
43
|
+
* result, or with the replayed history; absent means plain markdown.
|
|
44
|
+
*/
|
|
45
|
+
blocks?: MessageBlock[];
|
|
46
|
+
/** The host-minted turn that produced this assistant message, when known. */
|
|
47
|
+
turnId?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface MessageAttachment {
|
|
51
|
+
previewUrl: string;
|
|
52
|
+
mediaType: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ToolCall {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
input: Record<string, unknown>;
|
|
59
|
+
inputJson: string;
|
|
60
|
+
output?: string;
|
|
61
|
+
isError?: boolean;
|
|
62
|
+
status: "streaming" | "pending_approval" | "approved" | "denied" | "complete";
|
|
63
|
+
/**
|
|
64
|
+
* What the pending approval is for: "tool" may be remembered via "Always
|
|
65
|
+
* allow"; "command" (a destructive-bash confirmation) is per-use only.
|
|
66
|
+
*/
|
|
67
|
+
approvalKind?: "tool" | "command";
|
|
68
|
+
/**
|
|
69
|
+
* Execution timing for the duration badge. `startedAt` is (re)stamped when
|
|
70
|
+
* the input finishes streaming or an approval is granted — so approval
|
|
71
|
+
* wait time doesn't inflate the reported duration. `endedAt` is stamped by
|
|
72
|
+
* the tool result. History-loaded messages carry no timing.
|
|
73
|
+
*/
|
|
74
|
+
startedAt?: number;
|
|
75
|
+
endedAt?: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface AskUserExchange {
|
|
79
|
+
requestId: string;
|
|
80
|
+
questions: AskUserQuestion[];
|
|
81
|
+
/** Filled in once the user submits. Keyed by question text. */
|
|
82
|
+
answers?: Record<string, string>;
|
|
83
|
+
annotations?: Record<string, AskUserAnnotation>;
|
|
84
|
+
cancelled?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* The user answered in the composer instead of choosing an option, and the
|
|
87
|
+
* composer text was bound to the question (D38 §1: the card then quotes what
|
|
88
|
+
* it took, with a neutral border). Live-only: the `ask_user` tool output the
|
|
89
|
+
* server persists is `{answers, annotations}` and carries no such flag, so a
|
|
90
|
+
* resumed transcript rebuilds a typed exchange as a plain `answered` one.
|
|
91
|
+
*/
|
|
92
|
+
typed?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* When the answer was submitted, from this client's clock. Absent on
|
|
95
|
+
* history-loaded exchanges — the persisted tool output carries no time, and
|
|
96
|
+
* the card shows none rather than one it made up.
|
|
97
|
+
*/
|
|
98
|
+
answeredAt?: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* One session's live transcript state. Every session the user has viewed (or
|
|
103
|
+
* that bound from the draft) keeps its own buffer, so frames from a background
|
|
104
|
+
* session accumulate in THAT session's transcript instead of being discarded —
|
|
105
|
+
* the multi-session contract the old single-active-buffer store violated.
|
|
106
|
+
*/
|
|
107
|
+
export interface SessionChat {
|
|
108
|
+
messages: ChatMessage[];
|
|
109
|
+
isStreaming: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* The currently-pending ask-user exchange in this session (no answers yet).
|
|
112
|
+
* Mirrors the same exchange that lives on the streaming assistant message;
|
|
113
|
+
* held here for fast lookup by hooks/components.
|
|
114
|
+
*/
|
|
115
|
+
askUser: AskUserExchange | null;
|
|
116
|
+
/** LRU stamp for buffer eviction. */
|
|
117
|
+
lastTouched: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Buffer key: a server sessionId, or null for the DRAFT buffer — the new
|
|
122
|
+
* conversation that has no server identity yet. `session_info` re-keys the
|
|
123
|
+
* draft onto its real sessionId via bindDraftSession().
|
|
124
|
+
*/
|
|
125
|
+
export type ChatKey = string | null;
|
|
126
|
+
|
|
127
|
+
/** Retained transcript buffers beyond the active one (LRU-evicted). */
|
|
128
|
+
const MAX_BUFFERS = 8;
|
|
129
|
+
|
|
130
|
+
export interface ChatState {
|
|
131
|
+
/** Per-session transcript buffers, keyed by server sessionId. */
|
|
132
|
+
buffers: Record<string, SessionChat>;
|
|
133
|
+
/** The unbound new-conversation buffer, if one is in progress. */
|
|
134
|
+
draft: SessionChat | null;
|
|
135
|
+
/**
|
|
136
|
+
* Correlation id for the conversation the draft is currently starting.
|
|
137
|
+
*
|
|
138
|
+
* A client starting a conversation has no session id, so it used to adopt
|
|
139
|
+
* the FIRST `session_info` for an unknown session — which could be an older
|
|
140
|
+
* background turn's, or another client's, silently binding the user's draft
|
|
141
|
+
* to someone else's transcript. The id is sent on `chat_message` and echoed
|
|
142
|
+
* on `session_info`; adoption now requires a match. Null when no draft turn
|
|
143
|
+
* is in flight.
|
|
144
|
+
*/
|
|
145
|
+
pendingDraftId: string | null;
|
|
146
|
+
/** The session in view; null = the draft / new-chat view. */
|
|
147
|
+
activeSessionId: string | null;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Live run-state per session id, for the session-list badges. Maintained for
|
|
151
|
+
* every session frame regardless of whether a buffer exists. "idle" is the
|
|
152
|
+
* absence of a running/queued turn.
|
|
153
|
+
*/
|
|
154
|
+
runStates: Record<string, "streaming" | "queued" | "idle">;
|
|
155
|
+
/**
|
|
156
|
+
* Backend that owns each session, from `session_info` (or the session list
|
|
157
|
+
* for history sessions). Scopes tool-call renderer resolution per backend;
|
|
158
|
+
* absence falls back to the deployment default.
|
|
159
|
+
*/
|
|
160
|
+
backendIds: Record<string, string>;
|
|
161
|
+
/**
|
|
162
|
+
* Per-session note attached to a `queued` status — the host sends one once a
|
|
163
|
+
* session's follow-up queue grows heavy. Cleared when the session leaves the
|
|
164
|
+
* queued state, so a stale warning cannot outlive the queue it described.
|
|
165
|
+
*/
|
|
166
|
+
queueNotes: Record<string, string>;
|
|
167
|
+
|
|
168
|
+
// Buffer mutations (key: sessionId, or null for the draft)
|
|
169
|
+
addUserMessage: (
|
|
170
|
+
key: ChatKey,
|
|
171
|
+
text: string,
|
|
172
|
+
source?: MessageSource,
|
|
173
|
+
attachments?: MessageAttachment[]
|
|
174
|
+
) => void;
|
|
175
|
+
startAssistantMessage: (key: ChatKey, turnId?: string) => void;
|
|
176
|
+
appendText: (key: ChatKey, text: string) => void;
|
|
177
|
+
appendThinking: (key: ChatKey, text: string) => void;
|
|
178
|
+
startToolCall: (key: ChatKey, toolUseId: string, toolName: string) => void;
|
|
179
|
+
appendToolInput: (key: ChatKey, partialJson: string) => void;
|
|
180
|
+
completeToolCall: (
|
|
181
|
+
key: ChatKey,
|
|
182
|
+
toolUseId: string,
|
|
183
|
+
toolName: string,
|
|
184
|
+
input: Record<string, unknown>
|
|
185
|
+
) => void;
|
|
186
|
+
requestToolApproval: (
|
|
187
|
+
key: ChatKey,
|
|
188
|
+
toolUseId: string,
|
|
189
|
+
toolName: string,
|
|
190
|
+
input: Record<string, unknown>,
|
|
191
|
+
description?: string,
|
|
192
|
+
kind?: "tool" | "command"
|
|
193
|
+
) => void;
|
|
194
|
+
resolveToolApproval: (key: ChatKey, toolUseId: string, approved: boolean) => void;
|
|
195
|
+
setToolResult: (key: ChatKey, toolUseId: string, output: string, isError: boolean) => void;
|
|
196
|
+
setAskUserRequest: (key: ChatKey, requestId: string, questions: AskUserQuestion[]) => void;
|
|
197
|
+
submitAskUserAnswers: (
|
|
198
|
+
key: ChatKey,
|
|
199
|
+
requestId: string,
|
|
200
|
+
answers: Record<string, string>,
|
|
201
|
+
annotations?: Record<string, AskUserAnnotation>,
|
|
202
|
+
/** `true` when the answer was taken from the composer, not an option. */
|
|
203
|
+
typed?: boolean
|
|
204
|
+
) => void;
|
|
205
|
+
cancelAskUser: (key: ChatKey, requestId: string) => void;
|
|
206
|
+
clearAskUser: (key: ChatKey) => void;
|
|
207
|
+
finishAssistantMessage: (key: ChatKey) => void;
|
|
208
|
+
/**
|
|
209
|
+
* Attach classified blocks (D42) to the assistant message of `turnId`, or,
|
|
210
|
+
* when the turn is unknown, to the last assistant message only if it has
|
|
211
|
+
* finished — never to a newer message still streaming.
|
|
212
|
+
*/
|
|
213
|
+
setMessageBlocks: (key: ChatKey, blocks: MessageBlock[], turnId?: string) => void;
|
|
214
|
+
/**
|
|
215
|
+
* Record the host-minted turn on the streaming assistant message, from
|
|
216
|
+
* the first scoped frame. The composer opens the message optimistically
|
|
217
|
+
* before any turn exists, so the id arrives with the deltas.
|
|
218
|
+
*/
|
|
219
|
+
stampTurn: (key: ChatKey, turnId: string) => void;
|
|
220
|
+
setStreaming: (key: ChatKey, streaming: boolean) => void;
|
|
221
|
+
/** Replace a session's transcript (first replayed history chunk). Creates the buffer. */
|
|
222
|
+
setMessages: (key: ChatKey, messages: ChatMessage[]) => void;
|
|
223
|
+
/** Concatenate a continuation chunk of replayed history. Creates the buffer. */
|
|
224
|
+
appendMessages: (key: ChatKey, messages: ChatMessage[]) => void;
|
|
225
|
+
|
|
226
|
+
// Session lifecycle
|
|
227
|
+
/**
|
|
228
|
+
* Adopt the draft buffer as `sessionId` (the server just named the session).
|
|
229
|
+
* If the draft view is active, the view follows. No-op draft = empty buffer.
|
|
230
|
+
*/
|
|
231
|
+
bindDraftSession: (sessionId: string) => void;
|
|
232
|
+
/** Mint and remember the correlation id for a draft turn about to be sent. */
|
|
233
|
+
startDraftTurn: () => string;
|
|
234
|
+
/** Switch the view to a session (creating an empty buffer if none), or to the draft (null). */
|
|
235
|
+
setActiveSession: (sessionId: string | null) => void;
|
|
236
|
+
/** New chat: drop the draft, unbind the view, unpin the provider. */
|
|
237
|
+
clearMessages: () => void;
|
|
238
|
+
setRunState: (
|
|
239
|
+
sessionId: string,
|
|
240
|
+
state: "streaming" | "queued" | "idle",
|
|
241
|
+
note?: string
|
|
242
|
+
) => void;
|
|
243
|
+
/** Record which backend owns a session (idempotent). */
|
|
244
|
+
setSessionBackend: (sessionId: string, backendId: string) => void;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function emptyChat(): SessionChat {
|
|
248
|
+
return { messages: [], isStreaming: false, askUser: null, lastTouched: Date.now() };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Frozen empty buffer for selectors when nothing is in view. */
|
|
252
|
+
const EMPTY_CHAT: SessionChat = Object.freeze({
|
|
253
|
+
messages: Object.freeze([]) as unknown as ChatMessage[],
|
|
254
|
+
isStreaming: false,
|
|
255
|
+
askUser: null,
|
|
256
|
+
lastTouched: 0,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
/** The buffer currently in view (draft when no session is bound). */
|
|
260
|
+
export function activeChat(state: ChatState): SessionChat {
|
|
261
|
+
if (state.activeSessionId) return state.buffers[state.activeSessionId] ?? EMPTY_CHAT;
|
|
262
|
+
return state.draft ?? EMPTY_CHAT;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** True when ANY buffer is streaming (service-worker busy check, etc.). */
|
|
266
|
+
export function anyStreaming(state: ChatState): boolean {
|
|
267
|
+
if (state.draft?.isStreaming) return true;
|
|
268
|
+
return Object.values(state.buffers).some((b) => b.isStreaming);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Append text to the last part if it has the same kind, else start a new part. */
|
|
272
|
+
function appendPart(
|
|
273
|
+
parts: MessagePart[],
|
|
274
|
+
kind: "thinking" | "text",
|
|
275
|
+
text: string
|
|
276
|
+
): MessagePart[] {
|
|
277
|
+
const last = parts[parts.length - 1];
|
|
278
|
+
if (last && last.kind === kind) {
|
|
279
|
+
return [...parts.slice(0, -1), { kind, text: last.text + text }];
|
|
280
|
+
}
|
|
281
|
+
return [...parts, { kind, text }];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Free object URLs held by live message previews before dropping them. */
|
|
285
|
+
function revokeAttachmentUrls(messages: ChatMessage[]) {
|
|
286
|
+
for (const m of messages) {
|
|
287
|
+
for (const a of m.attachments ?? []) {
|
|
288
|
+
if (a.previewUrl.startsWith("blob:")) URL.revokeObjectURL(a.previewUrl);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Every tool call waiting on the user, across every buffer (D37: an approval
|
|
295
|
+
* that arrived while you were reading something else cannot only exist as a
|
|
296
|
+
* scroll position — the Actions pane lists it beside the inbox). The key is
|
|
297
|
+
* the buffer's, so the decision can be resolved on the right transcript.
|
|
298
|
+
*/
|
|
299
|
+
export function pendingApprovals(state: Pick<ChatState, "buffers" | "draft">): Array<{ key: ChatKey; tool: ToolCall }> {
|
|
300
|
+
const out: Array<{ key: ChatKey; tool: ToolCall }> = [];
|
|
301
|
+
const scan = (key: ChatKey, chat: SessionChat | null) => {
|
|
302
|
+
if (!chat) return;
|
|
303
|
+
for (const message of chat.messages) {
|
|
304
|
+
for (const tool of message.toolCalls) if (tool.status === "pending_approval") out.push({ key, tool });
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
for (const [id, chat] of Object.entries(state.buffers)) scan(id, chat);
|
|
308
|
+
scan(null, state.draft);
|
|
309
|
+
return out;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Evict least-recently-touched non-active buffers beyond MAX_BUFFERS. */
|
|
313
|
+
function evictStale(
|
|
314
|
+
buffers: Record<string, SessionChat>,
|
|
315
|
+
activeSessionId: string | null
|
|
316
|
+
): Record<string, SessionChat> {
|
|
317
|
+
const ids = Object.keys(buffers);
|
|
318
|
+
if (ids.length <= MAX_BUFFERS) return buffers;
|
|
319
|
+
const evictable = ids
|
|
320
|
+
.filter((id) => id !== activeSessionId && !buffers[id].isStreaming)
|
|
321
|
+
.sort((a, b) => buffers[a].lastTouched - buffers[b].lastTouched);
|
|
322
|
+
const next = { ...buffers };
|
|
323
|
+
for (const id of evictable.slice(0, ids.length - MAX_BUFFERS)) {
|
|
324
|
+
revokeAttachmentUrls(next[id].messages);
|
|
325
|
+
delete next[id];
|
|
326
|
+
}
|
|
327
|
+
return next;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function createChatStore(env: StoreEnvironment, provider: StoreApi<ProviderState>) {
|
|
331
|
+
let messageCounter = 0;
|
|
332
|
+
function nextId() {
|
|
333
|
+
return `msg-${++messageCounter}-${Date.now()}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const SESSION_ID_KEY = env.storageKey("brain-sessionId");
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Persist the active session id to localStorage when a DOM is present (the
|
|
340
|
+
* browser). A no-op in non-DOM environments (tests, SSR) so creating the store
|
|
341
|
+
* never throws on a missing `localStorage`.
|
|
342
|
+
*/
|
|
343
|
+
function persistSessionId(id: string | null) {
|
|
344
|
+
const storage = env.storage();
|
|
345
|
+
if (!storage) return;
|
|
346
|
+
if (id) env.storage()?.setItem(SESSION_ID_KEY, id);
|
|
347
|
+
else env.storage()?.removeItem(SESSION_ID_KEY);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function readPersistedSessionId(): string | null {
|
|
351
|
+
const storage = env.storage();
|
|
352
|
+
if (!storage) return null;
|
|
353
|
+
return storage.getItem(SESSION_ID_KEY);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
return createStore<ChatState>((set, get) => {
|
|
358
|
+
/**
|
|
359
|
+
* Immutably update one buffer. Draft mutations (key null) create the draft
|
|
360
|
+
* on demand; session mutations require an existing buffer — a frame for an
|
|
361
|
+
* evicted/never-opened session must not materialize a partial transcript
|
|
362
|
+
* (the view heals via session_resume instead).
|
|
363
|
+
*/
|
|
364
|
+
function mutateBuffer(
|
|
365
|
+
key: ChatKey,
|
|
366
|
+
fn: (chat: SessionChat) => Partial<SessionChat>,
|
|
367
|
+
createIfMissing = false
|
|
368
|
+
): void {
|
|
369
|
+
set((state) => {
|
|
370
|
+
if (key === null) {
|
|
371
|
+
const draft = state.draft ?? emptyChat();
|
|
372
|
+
return { draft: { ...draft, ...fn(draft), lastTouched: Date.now() } };
|
|
373
|
+
}
|
|
374
|
+
const existing = state.buffers[key] ?? (createIfMissing ? emptyChat() : undefined);
|
|
375
|
+
if (!existing) return state;
|
|
376
|
+
return {
|
|
377
|
+
buffers: {
|
|
378
|
+
...state.buffers,
|
|
379
|
+
[key]: { ...existing, ...fn(existing), lastTouched: Date.now() },
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** Update the last message of a buffer when it is an assistant message. */
|
|
386
|
+
function mutateLastAssistant(
|
|
387
|
+
key: ChatKey,
|
|
388
|
+
fn: (msg: ChatMessage) => ChatMessage,
|
|
389
|
+
extra?: (chat: SessionChat) => Partial<SessionChat>
|
|
390
|
+
): void {
|
|
391
|
+
mutateBuffer(key, (chat) => {
|
|
392
|
+
const msgs = [...chat.messages];
|
|
393
|
+
// The last ASSISTANT message, not the last message.
|
|
394
|
+
//
|
|
395
|
+
// A follow-up sent mid-stream appends a user message to the end of the
|
|
396
|
+
// buffer while the assistant is still streaming into the message before
|
|
397
|
+
// it. Indexing the end therefore aimed every subsequent delta at the
|
|
398
|
+
// user's own message, where `role === "assistant"` failed and the write
|
|
399
|
+
// was silently discarded — the turn kept running and its output stopped
|
|
400
|
+
// appearing. Scanning backwards costs nothing at these lengths and
|
|
401
|
+
// leaves single-message behaviour identical.
|
|
402
|
+
let index = -1;
|
|
403
|
+
for (let i = msgs.length - 1;i >= 0;i--) {
|
|
404
|
+
if (msgs[i].role === "assistant") {
|
|
405
|
+
index = i;
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
let out: Partial<SessionChat> = {};
|
|
410
|
+
if (index !== -1) {
|
|
411
|
+
msgs[index] = fn(msgs[index]);
|
|
412
|
+
out = { messages: msgs };
|
|
413
|
+
}
|
|
414
|
+
return extra ? { ...out, ...extra(chat) } : out;
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
buffers: {},
|
|
420
|
+
draft: null,
|
|
421
|
+
pendingDraftId: null,
|
|
422
|
+
// localStorage (not sessionStorage) so the active session id survives the
|
|
423
|
+
// PWA process being killed on mobile — that durability is what lets a cold
|
|
424
|
+
// relaunch re-request the full transcript instead of showing nothing.
|
|
425
|
+
activeSessionId: readPersistedSessionId(),
|
|
426
|
+
runStates: {},
|
|
427
|
+
queueNotes: {},
|
|
428
|
+
backendIds: {},
|
|
429
|
+
|
|
430
|
+
// createIfMissing: a user-initiated send must never be dropped, even when
|
|
431
|
+
// the active session's buffer hasn't been materialized yet (cold start
|
|
432
|
+
// racing the history replay).
|
|
433
|
+
addUserMessage: (key, text, source, attachments) =>
|
|
434
|
+
mutateBuffer(
|
|
435
|
+
key,
|
|
436
|
+
(chat) => ({
|
|
437
|
+
messages: [
|
|
438
|
+
...chat.messages,
|
|
439
|
+
{
|
|
440
|
+
id: nextId(),
|
|
441
|
+
role: "user",
|
|
442
|
+
content: text,
|
|
443
|
+
toolCalls: [],
|
|
444
|
+
parts: [],
|
|
445
|
+
isStreaming: false,
|
|
446
|
+
timestamp: Date.now(),
|
|
447
|
+
source: source ?? "typed",
|
|
448
|
+
...(attachments && attachments.length > 0
|
|
449
|
+
? { attachments, attachmentCount: attachments.length }
|
|
450
|
+
: {}),
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
}),
|
|
454
|
+
true
|
|
455
|
+
),
|
|
456
|
+
|
|
457
|
+
startAssistantMessage: (key, turnId) =>
|
|
458
|
+
mutateBuffer(key, (chat) => ({
|
|
459
|
+
messages: [
|
|
460
|
+
...chat.messages,
|
|
461
|
+
{
|
|
462
|
+
id: nextId(),
|
|
463
|
+
role: "assistant",
|
|
464
|
+
content: "",
|
|
465
|
+
thinking: "",
|
|
466
|
+
toolCalls: [],
|
|
467
|
+
parts: [],
|
|
468
|
+
isStreaming: true,
|
|
469
|
+
timestamp: Date.now(),
|
|
470
|
+
...(turnId ? { turnId } : {}),
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
isStreaming: true,
|
|
474
|
+
})),
|
|
475
|
+
|
|
476
|
+
appendText: (key, text) =>
|
|
477
|
+
mutateLastAssistant(key, (last) => ({
|
|
478
|
+
...last,
|
|
479
|
+
content: last.content + text,
|
|
480
|
+
parts: appendPart(last.parts, "text", text),
|
|
481
|
+
})),
|
|
482
|
+
|
|
483
|
+
appendThinking: (key, text) =>
|
|
484
|
+
mutateLastAssistant(key, (last) => ({
|
|
485
|
+
...last,
|
|
486
|
+
thinking: (last.thinking || "") + text,
|
|
487
|
+
parts: appendPart(last.parts, "thinking", text),
|
|
488
|
+
})),
|
|
489
|
+
|
|
490
|
+
startToolCall: (key, toolUseId, toolName) =>
|
|
491
|
+
mutateLastAssistant(key, (last) => ({
|
|
492
|
+
...last,
|
|
493
|
+
parts: [...last.parts, { kind: "tool", toolIndex: last.toolCalls.length }],
|
|
494
|
+
toolCalls: [
|
|
495
|
+
...last.toolCalls,
|
|
496
|
+
{
|
|
497
|
+
id: toolUseId,
|
|
498
|
+
name: toolName,
|
|
499
|
+
input: {},
|
|
500
|
+
inputJson: "",
|
|
501
|
+
status: "streaming",
|
|
502
|
+
startedAt: Date.now(),
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
})),
|
|
506
|
+
|
|
507
|
+
appendToolInput: (key, partialJson) =>
|
|
508
|
+
mutateLastAssistant(key, (last) => {
|
|
509
|
+
if (last.toolCalls.length === 0) return last;
|
|
510
|
+
const tools = [...last.toolCalls];
|
|
511
|
+
const lastTool = tools[tools.length - 1];
|
|
512
|
+
tools[tools.length - 1] = {
|
|
513
|
+
...lastTool,
|
|
514
|
+
inputJson: lastTool.inputJson + partialJson,
|
|
515
|
+
};
|
|
516
|
+
return { ...last, toolCalls: tools };
|
|
517
|
+
}),
|
|
518
|
+
|
|
519
|
+
completeToolCall: (key, toolUseId, toolName, input) =>
|
|
520
|
+
mutateLastAssistant(key, (last) => ({
|
|
521
|
+
...last,
|
|
522
|
+
toolCalls: last.toolCalls.map((t) =>
|
|
523
|
+
t.id === toolUseId || (t.name === toolName && t.status === "streaming")
|
|
524
|
+
? {
|
|
525
|
+
...t,
|
|
526
|
+
id: toolUseId,
|
|
527
|
+
input,
|
|
528
|
+
status: "complete" as const,
|
|
529
|
+
// Input finished streaming — execution starts about now
|
|
530
|
+
startedAt: Date.now(),
|
|
531
|
+
}
|
|
532
|
+
: t
|
|
533
|
+
),
|
|
534
|
+
})),
|
|
535
|
+
|
|
536
|
+
requestToolApproval: (key, toolUseId, toolName, input, _description, kind) =>
|
|
537
|
+
mutateLastAssistant(key, (last) => {
|
|
538
|
+
// Check if tool call already exists (from streaming)
|
|
539
|
+
const existingIdx = last.toolCalls.findIndex(
|
|
540
|
+
(t) => t.id === toolUseId || (t.name === toolName && t.status === "streaming")
|
|
541
|
+
);
|
|
542
|
+
const tools = [...last.toolCalls];
|
|
543
|
+
const toolCall: ToolCall = {
|
|
544
|
+
id: toolUseId,
|
|
545
|
+
name: toolName,
|
|
546
|
+
input,
|
|
547
|
+
inputJson: JSON.stringify(input, null, 2),
|
|
548
|
+
status: "pending_approval",
|
|
549
|
+
...(kind ? { approvalKind: kind } : {}),
|
|
550
|
+
};
|
|
551
|
+
let parts = last.parts;
|
|
552
|
+
if (existingIdx >= 0) {
|
|
553
|
+
tools[existingIdx] = toolCall;
|
|
554
|
+
} else {
|
|
555
|
+
// Approval request for a tool that never streamed a start event —
|
|
556
|
+
// give it a chronological slot too.
|
|
557
|
+
parts = [...parts, { kind: "tool", toolIndex: tools.length }];
|
|
558
|
+
tools.push(toolCall);
|
|
559
|
+
}
|
|
560
|
+
return { ...last, toolCalls: tools, parts };
|
|
561
|
+
}),
|
|
562
|
+
|
|
563
|
+
resolveToolApproval: (key, toolUseId, approved) =>
|
|
564
|
+
mutateLastAssistant(key, (last) => ({
|
|
565
|
+
...last,
|
|
566
|
+
toolCalls: last.toolCalls.map((t) =>
|
|
567
|
+
t.id === toolUseId
|
|
568
|
+
? {
|
|
569
|
+
...t,
|
|
570
|
+
status: approved ? ("approved" as const) : ("denied" as const),
|
|
571
|
+
// Don't let approval wait time inflate the duration badge
|
|
572
|
+
...(approved ? { startedAt: Date.now() } : {}),
|
|
573
|
+
}
|
|
574
|
+
: t
|
|
575
|
+
),
|
|
576
|
+
})),
|
|
577
|
+
|
|
578
|
+
setToolResult: (key, toolUseId, output, isError) =>
|
|
579
|
+
mutateLastAssistant(key, (last) => ({
|
|
580
|
+
...last,
|
|
581
|
+
toolCalls: last.toolCalls.map((t) =>
|
|
582
|
+
t.id === toolUseId
|
|
583
|
+
? {
|
|
584
|
+
...t,
|
|
585
|
+
output,
|
|
586
|
+
isError,
|
|
587
|
+
status: "complete" as const,
|
|
588
|
+
endedAt: Date.now(),
|
|
589
|
+
}
|
|
590
|
+
: t
|
|
591
|
+
),
|
|
592
|
+
})),
|
|
593
|
+
|
|
594
|
+
setAskUserRequest: (key, requestId, questions) =>
|
|
595
|
+
mutateBuffer(key, (chat) => {
|
|
596
|
+
const exchange: AskUserExchange = { requestId, questions };
|
|
597
|
+
const msgs = [...chat.messages];
|
|
598
|
+
const lastIdx = msgs.length - 1;
|
|
599
|
+
const last = msgs[lastIdx];
|
|
600
|
+
if (last?.role === "assistant") {
|
|
601
|
+
msgs[lastIdx] = {
|
|
602
|
+
...last,
|
|
603
|
+
askUserExchanges: [...(last.askUserExchanges ?? []), exchange],
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
return { messages: msgs, askUser: exchange };
|
|
607
|
+
}),
|
|
608
|
+
|
|
609
|
+
submitAskUserAnswers: (key, requestId, answers, annotations, typed) =>
|
|
610
|
+
mutateBuffer(key, (chat) => {
|
|
611
|
+
const answeredAt = Date.now();
|
|
612
|
+
const update = (e: AskUserExchange): AskUserExchange =>
|
|
613
|
+
e.requestId === requestId
|
|
614
|
+
? { ...e, answers, annotations, answeredAt, ...(typed ? { typed: true } : {}) }
|
|
615
|
+
: e;
|
|
616
|
+
const msgs = chat.messages.map((m) =>
|
|
617
|
+
m.askUserExchanges?.some((e) => e.requestId === requestId)
|
|
618
|
+
? { ...m, askUserExchanges: m.askUserExchanges.map(update) }
|
|
619
|
+
: m
|
|
620
|
+
);
|
|
621
|
+
const askUser =
|
|
622
|
+
chat.askUser?.requestId === requestId ? update(chat.askUser) : chat.askUser;
|
|
623
|
+
return { messages: msgs, askUser };
|
|
624
|
+
}),
|
|
625
|
+
|
|
626
|
+
cancelAskUser: (key, requestId) =>
|
|
627
|
+
mutateBuffer(key, (chat) => {
|
|
628
|
+
const update = (e: AskUserExchange): AskUserExchange =>
|
|
629
|
+
e.requestId === requestId ? { ...e, cancelled: true } : e;
|
|
630
|
+
const msgs = chat.messages.map((m) =>
|
|
631
|
+
m.askUserExchanges?.some((e) => e.requestId === requestId)
|
|
632
|
+
? { ...m, askUserExchanges: m.askUserExchanges.map(update) }
|
|
633
|
+
: m
|
|
634
|
+
);
|
|
635
|
+
const askUser =
|
|
636
|
+
chat.askUser?.requestId === requestId ? update(chat.askUser) : chat.askUser;
|
|
637
|
+
return { messages: msgs, askUser };
|
|
638
|
+
}),
|
|
639
|
+
|
|
640
|
+
clearAskUser: (key) => mutateBuffer(key, () => ({ askUser: null })),
|
|
641
|
+
|
|
642
|
+
finishAssistantMessage: (key) =>
|
|
643
|
+
mutateLastAssistant(
|
|
644
|
+
key,
|
|
645
|
+
(last) => ({ ...last, isStreaming: false }),
|
|
646
|
+
() => ({ isStreaming: false })
|
|
647
|
+
),
|
|
648
|
+
|
|
649
|
+
setMessageBlocks: (key, blocks, turnId) =>
|
|
650
|
+
mutateBuffer(key, (chat) => {
|
|
651
|
+
const msgs = [...chat.messages];
|
|
652
|
+
let index = -1;
|
|
653
|
+
if (turnId) {
|
|
654
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
655
|
+
if (msgs[i].role === "assistant" && msgs[i].turnId === turnId) {
|
|
656
|
+
index = i;
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (index === -1) {
|
|
662
|
+
// No message carries the turn (an optimistic message opened by
|
|
663
|
+
// the composer, or a frame without one): the last assistant
|
|
664
|
+
// message, but only once it has finished — never a follow-up
|
|
665
|
+
// still streaming.
|
|
666
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
667
|
+
if (msgs[i].role === "assistant") {
|
|
668
|
+
if (!msgs[i].isStreaming) index = i;
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (index === -1) return {};
|
|
674
|
+
msgs[index] = { ...msgs[index], blocks };
|
|
675
|
+
return { messages: msgs };
|
|
676
|
+
}),
|
|
677
|
+
|
|
678
|
+
stampTurn: (key, turnId) =>
|
|
679
|
+
mutateLastAssistant(key, (last) =>
|
|
680
|
+
last.isStreaming && !last.turnId ? { ...last, turnId } : last
|
|
681
|
+
),
|
|
682
|
+
|
|
683
|
+
setStreaming: (key, streaming) => mutateBuffer(key, () => ({ isStreaming: streaming })),
|
|
684
|
+
|
|
685
|
+
setMessages: (key, messages) =>
|
|
686
|
+
set((state) => {
|
|
687
|
+
if (key === null) {
|
|
688
|
+
if (state.draft) revokeAttachmentUrls(state.draft.messages);
|
|
689
|
+
return {
|
|
690
|
+
draft: { ...emptyChat(), messages },
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const existing = state.buffers[key];
|
|
694
|
+
if (existing) revokeAttachmentUrls(existing.messages);
|
|
695
|
+
const buffers = {
|
|
696
|
+
...state.buffers,
|
|
697
|
+
[key]: { ...emptyChat(), messages },
|
|
698
|
+
};
|
|
699
|
+
return { buffers: evictStale(buffers, state.activeSessionId) };
|
|
700
|
+
}),
|
|
701
|
+
|
|
702
|
+
appendMessages: (key, messages) =>
|
|
703
|
+
set((state) => {
|
|
704
|
+
if (key === null) {
|
|
705
|
+
const draft = state.draft ?? emptyChat();
|
|
706
|
+
return { draft: { ...draft, messages: [...draft.messages, ...messages] } };
|
|
707
|
+
}
|
|
708
|
+
const existing = state.buffers[key] ?? emptyChat();
|
|
709
|
+
return {
|
|
710
|
+
buffers: {
|
|
711
|
+
...state.buffers,
|
|
712
|
+
[key]: {
|
|
713
|
+
...existing,
|
|
714
|
+
messages: [...existing.messages, ...messages],
|
|
715
|
+
lastTouched: Date.now(),
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
};
|
|
719
|
+
}),
|
|
720
|
+
|
|
721
|
+
startDraftTurn: () => {
|
|
722
|
+
const id =
|
|
723
|
+
typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
724
|
+
? crypto.randomUUID()
|
|
725
|
+
: `draft-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
726
|
+
set({ pendingDraftId: id });
|
|
727
|
+
return id;
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
bindDraftSession: (sessionId) =>
|
|
731
|
+
set((state) => {
|
|
732
|
+
const adopted = state.buffers[sessionId] ?? state.draft ?? emptyChat();
|
|
733
|
+
const buffers = evictStale(
|
|
734
|
+
{ ...state.buffers, [sessionId]: { ...adopted, lastTouched: Date.now() } },
|
|
735
|
+
sessionId
|
|
736
|
+
);
|
|
737
|
+
const followView = state.activeSessionId === null;
|
|
738
|
+
if (followView) persistSessionId(sessionId);
|
|
739
|
+
return {
|
|
740
|
+
buffers,
|
|
741
|
+
draft: null,
|
|
742
|
+
pendingDraftId: null,
|
|
743
|
+
...(followView ? { activeSessionId: sessionId } : {}),
|
|
744
|
+
};
|
|
745
|
+
}),
|
|
746
|
+
|
|
747
|
+
setActiveSession: (sessionId) =>
|
|
748
|
+
set((state) => {
|
|
749
|
+
persistSessionId(sessionId);
|
|
750
|
+
if (sessionId === null) return { activeSessionId: null };
|
|
751
|
+
const existing = state.buffers[sessionId];
|
|
752
|
+
const buffers = existing
|
|
753
|
+
? state.buffers
|
|
754
|
+
: evictStale({ ...state.buffers, [sessionId]: emptyChat() }, sessionId);
|
|
755
|
+
return { activeSessionId: sessionId, buffers };
|
|
756
|
+
}),
|
|
757
|
+
|
|
758
|
+
setRunState: (sessionId, runState, note) =>
|
|
759
|
+
set((state) => {
|
|
760
|
+
const noteChanged = (state.queueNotes[sessionId] ?? undefined) !== note;
|
|
761
|
+
if (state.runStates[sessionId] === runState && !noteChanged) return state;
|
|
762
|
+
|
|
763
|
+
const runStates = { ...state.runStates };
|
|
764
|
+
if (runState === "idle") delete runStates[sessionId];
|
|
765
|
+
else runStates[sessionId] = runState;
|
|
766
|
+
|
|
767
|
+
// The note belongs to the queued state; anything else ends it. A
|
|
768
|
+
// `queued` frame with no note also clears, so a queue that drained back
|
|
769
|
+
// under the warn mark stops claiming it is heavy.
|
|
770
|
+
const queueNotes = { ...state.queueNotes };
|
|
771
|
+
if (runState === "queued" && note) queueNotes[sessionId] = note;
|
|
772
|
+
else delete queueNotes[sessionId];
|
|
773
|
+
|
|
774
|
+
return { runStates, queueNotes };
|
|
775
|
+
}),
|
|
776
|
+
|
|
777
|
+
setSessionBackend: (sessionId, backendId) =>
|
|
778
|
+
set((state) =>
|
|
779
|
+
state.backendIds[sessionId] === backendId
|
|
780
|
+
? state
|
|
781
|
+
: { backendIds: { ...state.backendIds, [sessionId]: backendId } }
|
|
782
|
+
),
|
|
783
|
+
|
|
784
|
+
clearMessages: () => {
|
|
785
|
+
const state = get();
|
|
786
|
+
if (state.draft) revokeAttachmentUrls(state.draft.messages);
|
|
787
|
+
persistSessionId(null);
|
|
788
|
+
// Starting fresh: unpin the provider so the picker unlocks.
|
|
789
|
+
provider.getState().setPinned(null);
|
|
790
|
+
set({ draft: null, activeSessionId: null });
|
|
791
|
+
},
|
|
792
|
+
};
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
}
|