@schlessera/brain-ui-react 0.35.0 → 0.37.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 +82 -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 +148 -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 +29 -0
- package/dist/components/activity/approval-card.d.ts.map +1 -0
- package/dist/components/activity/approval-card.js +73 -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 +11 -0
- package/dist/components/activity/span-bits.d.ts.map +1 -1
- package/dist/components/activity/span-bits.js +50 -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 +27 -11
- 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 +32 -32
- 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 +45 -14
- 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 +19 -2
- package/dist/components/chat/tool-views.d.ts.map +1 -1
- package/dist/components/chat/tool-views.js +28 -22
- 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 +27 -21
- 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 +4 -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 +28 -0
- package/dist/components/layout/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail.js +72 -27
- package/dist/components/layout/side-rail.js.map +1 -1
- package/dist/components/layout/slide-panel.d.ts +25 -2
- package/dist/components/layout/slide-panel.d.ts.map +1 -1
- package/dist/components/layout/slide-panel.js +13 -4
- 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 +32 -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 +23 -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 +8 -5
- 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 +53 -18
- 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 +51 -10
- package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
- package/dist/components/settings/devices-agents-tab.d.ts +6 -1
- package/dist/components/settings/devices-agents-tab.d.ts.map +1 -1
- package/dist/components/settings/devices-agents-tab.js +55 -20
- package/dist/components/settings/devices-agents-tab.js.map +1 -1
- 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.js +1 -1
- package/dist/components/settings/one-time-agent-credential.js.map +1 -1
- 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 +71 -10
- 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-fine-pointer.d.ts +12 -0
- package/dist/hooks/use-fine-pointer.d.ts.map +1 -0
- package/dist/hooks/use-fine-pointer.js +15 -0
- package/dist/hooks/use-fine-pointer.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 +9 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +38 -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.map +1 -1
- package/dist/hooks/use-vpn-status.js +17 -18
- 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 -384
- 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 +28 -6
- 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 +289 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +243 -224
- 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/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 +4 -1
- package/dist/lib/push-registration.d.ts.map +1 -1
- package/dist/lib/push-registration.js +20 -2
- package/dist/lib/push-registration.js.map +1 -1
- 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 +233 -0
- package/dist/stores/chat-state.d.ts.map +1 -0
- package/dist/stores/chat-state.js +477 -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 -336
- 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 +4 -15
- package/dist/stores/principal-store.d.ts.map +1 -1
- package/dist/stores/principal-store.js +7 -28
- package/dist/stores/principal-store.js.map +1 -1
- 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 +341 -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 +117 -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 +60 -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 +41 -11
- 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 +41 -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 +75 -26
- 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 +30 -60
- 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 +32 -24
- 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 +5 -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 +77 -150
- package/src/components/layout/slide-panel.tsx +49 -6
- package/src/components/layout/theme.tsx +67 -0
- package/src/components/quick-actions/add-form.tsx +196 -0
- package/src/components/quick-actions/add-modal.tsx +32 -153
- package/src/components/quick-actions/search-modal.tsx +15 -5
- package/src/components/quick-actions/streaming-modal.tsx +57 -72
- package/src/components/quick-actions/streaming-output.tsx +112 -0
- package/src/components/quick-actions/whatsup-modal.tsx +53 -59
- package/src/components/settings/devices-agents-tab.tsx +60 -152
- 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 +1 -1
- 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 +239 -25
- 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-fine-pointer.ts +15 -0
- package/src/hooks/use-hash-routes.ts +4 -2
- package/src/hooks/use-media-query.ts +35 -0
- package/src/hooks/use-share-intake.ts +32 -12
- package/src/hooks/use-vpn-status.ts +18 -17
- package/src/hooks/use-websocket.ts +12 -428
- package/src/hooks/websocket-handlers/activity.ts +4 -5
- package/src/hooks/websocket-handlers/chat.ts +28 -6
- 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 +426 -384
- package/src/lib/backend.ts +20 -10
- package/src/lib/diff.ts +28 -62
- 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 +19 -2
- 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 +822 -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 -390
- 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 +10 -37
- 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
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useBrainUiRoot } from "../../root-context.js";
|
|
2
|
+
import { useState, useEffect, useRef, type KeyboardEvent } from "react";
|
|
2
3
|
import {
|
|
3
4
|
Check,
|
|
4
5
|
X,
|
|
@@ -9,17 +10,20 @@ import {
|
|
|
9
10
|
AlertTriangle,
|
|
10
11
|
FileText,
|
|
11
12
|
} from "lucide-react";
|
|
12
|
-
import {
|
|
13
|
-
import { useChatStore, type ToolCall } from "../../stores/chat-store.js";
|
|
13
|
+
import { type ToolSemantics } from "@schlessera/brain-ui-sdk/client";
|
|
14
|
+
import { offersAlwaysAllow, useChatStore, type ToolCall } from "../../stores/chat-store.js";
|
|
14
15
|
import { cn } from "../../lib/utils.js";
|
|
15
16
|
import { motion, AnimatePresence } from "framer-motion";
|
|
16
|
-
import { getToolLabel, getTouchedFile, formatDuration, formatTokenCount } from "./tool-views.js";
|
|
17
|
+
import { effectOf, getToolLabel, getTouchedFile, formatDuration, formatTokenCount } from "./tool-views.js";
|
|
17
18
|
import { registerBuiltinRenderers, GENERIC_RENDERER } from "./renderers/index.js";
|
|
18
19
|
import { riskHints } from "./risk-hints.js";
|
|
19
20
|
import { useShallow } from "zustand/react/shallow";
|
|
21
|
+
import { focusAfterDecision, singleKey } from "../../lib/single-key.js";
|
|
22
|
+
import { KeyCap } from "../layout/key-cap.js";
|
|
20
23
|
import { useActivityStore, spanForTool, childSpans } from "../../stores/activity-store.js";
|
|
21
24
|
import { useUIStore } from "../../stores/ui-store.js";
|
|
22
25
|
import { useNow } from "../../hooks/use-now.js";
|
|
26
|
+
import { useFinePointer } from "../../hooks/use-fine-pointer.js";
|
|
23
27
|
import { SpanStatusDot } from "../activity/span-bits.js";
|
|
24
28
|
|
|
25
29
|
// Sessions that predate backend stamping (old servers, cleared stores) scope
|
|
@@ -46,7 +50,8 @@ export function ToolCallTimeline({
|
|
|
46
50
|
live?: boolean;
|
|
47
51
|
}) {
|
|
48
52
|
// Resolution happens below during this render, before effects can run.
|
|
49
|
-
|
|
53
|
+
const root = useBrainUiRoot();
|
|
54
|
+
registerBuiltinRenderers(root.renderers);
|
|
50
55
|
|
|
51
56
|
// Collapse the whole run to a summary row once the turn is over. History
|
|
52
57
|
// messages mount collapsed; a live timeline collapses when streaming ends.
|
|
@@ -108,12 +113,13 @@ function TimelineSummaryRow({
|
|
|
108
113
|
backendId: string;
|
|
109
114
|
onExpand: () => void;
|
|
110
115
|
}) {
|
|
116
|
+
const root = useBrainUiRoot();
|
|
111
117
|
const steps = toolCalls.length;
|
|
112
118
|
const files = new Set(
|
|
113
119
|
toolCalls
|
|
114
120
|
.map(
|
|
115
121
|
(t) =>
|
|
116
|
-
|
|
122
|
+
root.renderers.resolve(t, backendId)?.touchedFile?.(t) ?? getTouchedFile(t)
|
|
117
123
|
)
|
|
118
124
|
.filter(Boolean)
|
|
119
125
|
).size;
|
|
@@ -156,6 +162,7 @@ function ToolCallEntry({
|
|
|
156
162
|
backendId: string;
|
|
157
163
|
onApproval: (toolUseId: string, approved: boolean, always?: boolean) => void;
|
|
158
164
|
}) {
|
|
165
|
+
const root = useBrainUiRoot();
|
|
159
166
|
const [expanded, setExpanded] = useState(
|
|
160
167
|
toolCall.status === "pending_approval"
|
|
161
168
|
);
|
|
@@ -175,13 +182,35 @@ function ToolCallEntry({
|
|
|
175
182
|
: toolCall;
|
|
176
183
|
// Resolve the renderer for this tool (backend-scoped exact -> global exact ->
|
|
177
184
|
// shape-sniffing predicate). Falls back to the generic renderer.
|
|
178
|
-
const renderer =
|
|
185
|
+
const renderer = root.renderers.resolve(toolCall, backendId) ?? GENERIC_RENDERER;
|
|
179
186
|
const Icon = renderer.icon ?? FileText;
|
|
180
187
|
const label =
|
|
181
188
|
typeof renderer.label === "function"
|
|
182
189
|
? renderer.label(toolCall)
|
|
183
190
|
: renderer.label ?? getToolLabel(toolCall.name);
|
|
184
191
|
const isPending = toolCall.status === "pending_approval";
|
|
192
|
+
const keys = useUIStore((s) => s.singleKeyShortcuts);
|
|
193
|
+
// The caps are printed only while a fine pointer is present (#86); the letters
|
|
194
|
+
// themselves follow the Settings switch alone, so a paired keyboard works
|
|
195
|
+
// even if the pointer query stays coarse.
|
|
196
|
+
const finePointer = useFinePointer();
|
|
197
|
+
const printKeys = keys && finePointer;
|
|
198
|
+
/**
|
|
199
|
+
* A decision hands focus on before the card goes (D36): the next pending
|
|
200
|
+
* approval in the transcript, else the composer — the thing the reader
|
|
201
|
+
* continues with, since a chat has no empty-state heading to land on.
|
|
202
|
+
*/
|
|
203
|
+
function decide(card: HTMLElement | null, approved: boolean, always?: boolean) {
|
|
204
|
+
if (card) focusAfterDecision(card, "[data-approval-card]", "textarea[data-composer]");
|
|
205
|
+
onApproval(toolCall.id, approved, always);
|
|
206
|
+
}
|
|
207
|
+
function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>) {
|
|
208
|
+
if (!keys) return;
|
|
209
|
+
const key = singleKey(event);
|
|
210
|
+
if (key !== "a" && key !== "d") return;
|
|
211
|
+
event.preventDefault();
|
|
212
|
+
decide(event.currentTarget, key === "a");
|
|
213
|
+
}
|
|
185
214
|
const summary = renderer.summary?.(timed) ?? null;
|
|
186
215
|
const meta = renderer.meta?.(timed) ?? null;
|
|
187
216
|
const Input = renderer.Input;
|
|
@@ -204,17 +233,18 @@ function ToolCallEntry({
|
|
|
204
233
|
|
|
205
234
|
return (
|
|
206
235
|
<div className="relative">
|
|
207
|
-
{/* Timeline dot
|
|
236
|
+
{/* Timeline dot: a bare mark with no content, so it takes the MARK
|
|
237
|
+
weight — a fill sits at 1.3-1.8:1 on paper at any diameter. */}
|
|
208
238
|
<div
|
|
209
239
|
className={cn(
|
|
210
240
|
"absolute -left-[21px] top-2 h-2.5 w-2.5 rounded-full border-2 border-background",
|
|
211
|
-
toolCall.status === "streaming" && "bg-primary animate-pulse",
|
|
241
|
+
toolCall.status === "streaming" && "bg-primary-mark animate-pulse",
|
|
212
242
|
toolCall.status === "pending_approval" &&
|
|
213
|
-
"bg-primary",
|
|
214
|
-
toolCall.status === "approved" && "bg-accent",
|
|
215
|
-
toolCall.status === "denied" && "bg-destructive",
|
|
243
|
+
"bg-primary-mark",
|
|
244
|
+
toolCall.status === "approved" && "bg-accent-mark",
|
|
245
|
+
toolCall.status === "denied" && "bg-destructive-mark",
|
|
216
246
|
toolCall.status === "complete" &&
|
|
217
|
-
(toolCall.isError ? "bg-destructive" : "bg-accent"),
|
|
247
|
+
(toolCall.isError ? "bg-destructive-mark" : "bg-accent-mark"),
|
|
218
248
|
!["streaming", "pending_approval", "approved", "denied", "complete"].includes(toolCall.status) && "bg-muted-foreground"
|
|
219
249
|
)}
|
|
220
250
|
style={
|
|
@@ -275,13 +305,18 @@ function ToolCallEntry({
|
|
|
275
305
|
className={cn(
|
|
276
306
|
"mt-1 rounded-lg p-3 space-y-2",
|
|
277
307
|
isPending
|
|
278
|
-
? "border-2 border-primary/40 bg-primary/5"
|
|
308
|
+
? "border-2 border-primary/40 bg-primary-fill/5"
|
|
279
309
|
: "border border-border-subtle bg-surface"
|
|
280
310
|
)}
|
|
281
311
|
>
|
|
282
312
|
{/* Tool input */}
|
|
283
313
|
{Input && <Input tool={toolCall} />}
|
|
284
314
|
|
|
315
|
+
{/* What a confirmed command will do, in words (#112) */}
|
|
316
|
+
{isPending && effectOf(toolCall) && (
|
|
317
|
+
<p className="text-[11px] text-muted-foreground">{effectOf(toolCall)}</p>
|
|
318
|
+
)}
|
|
319
|
+
|
|
285
320
|
{/* Risk hints — advisory only, never blocks approval */}
|
|
286
321
|
{isPending && (
|
|
287
322
|
<RiskHints toolCall={toolCall} semantics={renderer.semantics} />
|
|
@@ -289,32 +324,45 @@ function ToolCallEntry({
|
|
|
289
324
|
|
|
290
325
|
{/* Approval buttons. "Always allow" only for grantable tool
|
|
291
326
|
requests — a destructive-command confirmation (kind
|
|
292
|
-
"command") stays per-use
|
|
327
|
+
"command") stays per-use, and a grant the host said it
|
|
328
|
+
will not keep (#147) is not offered. */}
|
|
293
329
|
{isPending && (
|
|
294
|
-
|
|
330
|
+
// The card is the focus scope for `a` / `d` (D36): the keys
|
|
331
|
+
// act only while it, or a button inside it, holds focus, and
|
|
332
|
+
// they are printed on the buttons they belong to.
|
|
333
|
+
<div
|
|
334
|
+
data-approval-card=""
|
|
335
|
+
role="group"
|
|
336
|
+
aria-label={`Approval: ${label}`}
|
|
337
|
+
tabIndex={0}
|
|
338
|
+
onKeyDown={onCardKeyDown}
|
|
339
|
+
className="flex flex-wrap gap-2 rounded-md outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
|
|
340
|
+
>
|
|
295
341
|
<button
|
|
296
|
-
onClick={() =>
|
|
297
|
-
className="flex items-center gap-1.5 rounded-lg bg-primary px-4 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:brightness-110"
|
|
342
|
+
onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), true)}
|
|
343
|
+
className="flex items-center gap-1.5 rounded-lg bg-primary-fill px-4 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:brightness-110"
|
|
298
344
|
>
|
|
299
345
|
<Check className="h-3 w-3" />
|
|
300
346
|
Allow
|
|
347
|
+
{printKeys && <KeyCap>a</KeyCap>}
|
|
301
348
|
</button>
|
|
302
|
-
{toolCall
|
|
349
|
+
{offersAlwaysAllow(toolCall) && (
|
|
303
350
|
<button
|
|
304
|
-
onClick={() =>
|
|
351
|
+
onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), true, true)}
|
|
305
352
|
title={`Allow ${toolCall.name} without asking from now on (revocable in Settings → Models)`}
|
|
306
|
-
className="flex items-center gap-1.5 rounded-lg border border-primary/40 px-4 py-1.5 text-xs font-medium text-primary transition-colors hover:bg-primary/10"
|
|
353
|
+
className="flex items-center gap-1.5 rounded-lg border border-primary/40 px-4 py-1.5 text-xs font-medium text-primary transition-colors hover:bg-primary-fill/10"
|
|
307
354
|
>
|
|
308
355
|
<Check className="h-3 w-3" />
|
|
309
356
|
Always allow
|
|
310
357
|
</button>
|
|
311
358
|
)}
|
|
312
359
|
<button
|
|
313
|
-
onClick={() =>
|
|
314
|
-
className="flex items-center gap-1.5 rounded-lg border border-destructive/30 px-4 py-1.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10"
|
|
360
|
+
onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), false)}
|
|
361
|
+
className="flex items-center gap-1.5 rounded-lg border border-destructive/30 px-4 py-1.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive-fill/10"
|
|
315
362
|
>
|
|
316
363
|
<X className="h-3 w-3" />
|
|
317
364
|
Deny
|
|
365
|
+
{printKeys && <KeyCap>d</KeyCap>}
|
|
318
366
|
</button>
|
|
319
367
|
</div>
|
|
320
368
|
)}
|
|
@@ -389,7 +437,7 @@ function RiskHints({
|
|
|
389
437
|
const hints = riskHints(toolCall, semantics);
|
|
390
438
|
if (hints.length === 0) return null;
|
|
391
439
|
return (
|
|
392
|
-
<div className="space-y-0.5 text-[11px] text-
|
|
440
|
+
<div className="space-y-0.5 text-[11px] text-primary">
|
|
393
441
|
{hints.map((hint) => (
|
|
394
442
|
<div key={hint} className="flex items-center gap-1.5">
|
|
395
443
|
<AlertTriangle className="h-3 w-3 shrink-0" />
|
|
@@ -410,11 +458,11 @@ function StatusIndicator({
|
|
|
410
458
|
switch (status) {
|
|
411
459
|
case "streaming":
|
|
412
460
|
return (
|
|
413
|
-
<span className="inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-primary" />
|
|
461
|
+
<span className="inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-primary-mark" />
|
|
414
462
|
);
|
|
415
463
|
case "pending_approval":
|
|
416
464
|
return (
|
|
417
|
-
<span className="rounded bg-primary/20 px-1.5 py-0.5 text-[10px] font-medium text-primary">
|
|
465
|
+
<span className="rounded bg-primary-fill/20 px-1.5 py-0.5 text-[10px] font-medium text-primary">
|
|
418
466
|
Approval needed
|
|
419
467
|
</span>
|
|
420
468
|
);
|
|
@@ -430,3 +478,4 @@ function StatusIndicator({
|
|
|
430
478
|
);
|
|
431
479
|
}
|
|
432
480
|
}
|
|
481
|
+
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `show_block` result: one of the kit's answer blocks, drawn inline (D41).
|
|
3
|
+
*
|
|
4
|
+
* A switch typed by the contract's payload, handing each variant to its kit
|
|
5
|
+
* component. That typing is the drift check the contract promised: a schema
|
|
6
|
+
* field the kit does not accept fails here, and the kit's own tone unions are
|
|
7
|
+
* asserted equal to the schema's lists in `tests/block-contract.test-d.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Icons come from the model as strings; the kit's `Icon` renders an empty
|
|
10
|
+
* box for a key it does not know, so unknown keys are dropped before the
|
|
11
|
+
* prop is handed on. Optional TEXT props are the other translation: the kit
|
|
12
|
+
* ports the design's demo defaults, so a `QuoteCard` with no `source` names
|
|
13
|
+
* a forecast from the Odysseus fixture world and a `ContactCard` with no
|
|
14
|
+
* `label` is Penelope, and omitted `facts` or `ticks` draw a demo list. Each
|
|
15
|
+
* of those components honours an empty string or an empty array as
|
|
16
|
+
* "cleared", so an omitted field is handed on as `""` or `[]` rather than
|
|
17
|
+
* `undefined`. Everything else is passed through untouched: the schema
|
|
18
|
+
* already rejected what the kit cannot draw.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
BarList,
|
|
23
|
+
ComparisonTable,
|
|
24
|
+
ContactCard,
|
|
25
|
+
DataTable,
|
|
26
|
+
ICONS,
|
|
27
|
+
QuoteCard,
|
|
28
|
+
Receipt,
|
|
29
|
+
ScheduleList,
|
|
30
|
+
StatTiles,
|
|
31
|
+
StepList,
|
|
32
|
+
TimelineList,
|
|
33
|
+
TrendChart,
|
|
34
|
+
type IconName,
|
|
35
|
+
} from "@schlessera/brain-ui-kit";
|
|
36
|
+
import type { Block, ShowBlockPayload } from "@schlessera/brain-ui-sdk/client";
|
|
37
|
+
|
|
38
|
+
/** A kit icon key, or nothing when the model named one the kit lacks. */
|
|
39
|
+
export function kitIcon(name: string | undefined): IconName | undefined {
|
|
40
|
+
// An own-property check: `"constructor" in ICONS` is true through the
|
|
41
|
+
// prototype, and the kit would then try to render a function that is not
|
|
42
|
+
// a component.
|
|
43
|
+
return name !== undefined && Object.hasOwn(ICONS, name) ? (name as IconName) : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** An omitted optional text prop, cleared rather than left to the kit's demo default. */
|
|
47
|
+
const text = (value: string | undefined): string => value ?? "";
|
|
48
|
+
|
|
49
|
+
/** The collapsed one-liner for the trace: `comparison · 3 columns · 4 rows`. */
|
|
50
|
+
export function blockSummary({ block }: ShowBlockPayload): string {
|
|
51
|
+
const count = (n: number, noun: string) => `${n} ${noun}${n === 1 ? "" : "s"}`;
|
|
52
|
+
switch (block.kind) {
|
|
53
|
+
case "comparison":
|
|
54
|
+
return `comparison · ${count(block.columns.length, "column")} · ${count(block.rows.length, "row")}`;
|
|
55
|
+
case "stats":
|
|
56
|
+
return `stats · ${count(block.tiles.length, "tile")}`;
|
|
57
|
+
case "trend":
|
|
58
|
+
return `trend · ${block.label ?? block.value ?? count(block.values.length, "point")}`;
|
|
59
|
+
case "table":
|
|
60
|
+
return `table · ${count(block.columns.length, "column")} · ${count(block.rows.length, "row")}`;
|
|
61
|
+
case "bars":
|
|
62
|
+
return `bars · ${count(block.rows.length, "row")}`;
|
|
63
|
+
case "receipt":
|
|
64
|
+
return `receipt · ${block.title ?? count(block.rows.length, "row")}`;
|
|
65
|
+
case "steps":
|
|
66
|
+
return `steps · ${count(block.steps.length, "step")}`;
|
|
67
|
+
case "timeline":
|
|
68
|
+
return `timeline · ${count(block.items.length, "event")}`;
|
|
69
|
+
case "schedule":
|
|
70
|
+
return `schedule · ${count(block.groups.length, "day")}`;
|
|
71
|
+
case "quote":
|
|
72
|
+
return `quote · ${block.source ?? "unattributed"}`;
|
|
73
|
+
case "contact":
|
|
74
|
+
return `contact · ${block.label}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function BlockView({ block }: { block: Block }) {
|
|
79
|
+
switch (block.kind) {
|
|
80
|
+
case "comparison": {
|
|
81
|
+
const { kind: _kind, footnote, ...props } = block;
|
|
82
|
+
return <ComparisonTable {...props} footnote={text(footnote)} />;
|
|
83
|
+
}
|
|
84
|
+
case "stats":
|
|
85
|
+
return (
|
|
86
|
+
<StatTiles
|
|
87
|
+
tiles={block.tiles.map((tile) => ({ ...tile, icon: kitIcon(tile.icon) }))}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
case "trend": {
|
|
91
|
+
const { kind: _kind, label, value, ticks, ...props } = block;
|
|
92
|
+
return <TrendChart {...props} label={text(label)} value={text(value)} ticks={ticks ?? []} />;
|
|
93
|
+
}
|
|
94
|
+
case "table": {
|
|
95
|
+
const { kind: _kind, ...props } = block;
|
|
96
|
+
return <DataTable {...props} />;
|
|
97
|
+
}
|
|
98
|
+
case "bars":
|
|
99
|
+
return <BarList rows={block.rows} />;
|
|
100
|
+
case "receipt": {
|
|
101
|
+
const { kind: _kind, title, titleIcon, footnote, ...props } = block;
|
|
102
|
+
return (
|
|
103
|
+
<Receipt
|
|
104
|
+
{...props}
|
|
105
|
+
title={text(title)}
|
|
106
|
+
titleIcon={kitIcon(titleIcon)}
|
|
107
|
+
footnote={text(footnote)}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
case "steps": {
|
|
112
|
+
const { kind: _kind, ...props } = block;
|
|
113
|
+
return <StepList {...props} />;
|
|
114
|
+
}
|
|
115
|
+
case "timeline":
|
|
116
|
+
return <TimelineList items={block.items} />;
|
|
117
|
+
case "schedule":
|
|
118
|
+
return <ScheduleList groups={block.groups} />;
|
|
119
|
+
case "quote": {
|
|
120
|
+
const { kind: _kind, icon, source, locator, note, ...props } = block;
|
|
121
|
+
return (
|
|
122
|
+
<QuoteCard
|
|
123
|
+
{...props}
|
|
124
|
+
source={text(source)}
|
|
125
|
+
locator={text(locator)}
|
|
126
|
+
note={text(note)}
|
|
127
|
+
icon={kitIcon(icon)}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
case "contact": {
|
|
132
|
+
const { kind: _kind, contactKind, role, facts, ...props } = block;
|
|
133
|
+
return <ContactCard {...props} kind={contactKind} role={text(role)} facts={facts ?? []} />;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Bound to `SHOW_BLOCK_CONTRACT`; receives the parsed payload as props. */
|
|
139
|
+
export function BlockCard({ block }: ShowBlockPayload) {
|
|
140
|
+
return (
|
|
141
|
+
<div data-block={block.kind}>
|
|
142
|
+
<BlockView block={block} />
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `request_image_mask` result: a receipt, not a path (D38 §2).
|
|
3
|
+
*
|
|
4
|
+
* The source thumb — hatched, as everywhere: no remote image loads inline for
|
|
5
|
+
* the source — stacked ABOVE a kit `Receipt` (the truncation rule: a receipt
|
|
6
|
+
* value column under ~160px means change the layout, not the break rule).
|
|
7
|
+
*
|
|
8
|
+
* Typed `ImageMaskPayload`, so the rows are the fields the handler actually
|
|
9
|
+
* sends: `imagePath`, `maskPath`, `bytes`. The design also draws a region and
|
|
10
|
+
* a coverage row; the payload carries neither. The seventh drop's ruling 8
|
|
11
|
+
* settles what happens then: **state the absence**. The receipt's `region`
|
|
12
|
+
* row reads "region not recorded", in gold, rather than disappearing — a
|
|
13
|
+
* load-bearing fact that vanishes cannot be told apart from a whole-image
|
|
14
|
+
* mask, and a later answer citing that receipt would be citing a gap. A
|
|
15
|
+
* caller that does supply a region (the view test) gets the figures.
|
|
16
|
+
*
|
|
17
|
+
* And the mask itself is DRAWN over the thumb whenever its bytes exist: the
|
|
18
|
+
* PNG the handler wrote is fetched from the files API and laid over the
|
|
19
|
+
* hatch, with the teal region fill beneath it so the transparent (editable)
|
|
20
|
+
* pixels show as the user's answer. When the bytes do not exist the thumb
|
|
21
|
+
* shows the source alone with a mono line saying the mask was not rendered.
|
|
22
|
+
*
|
|
23
|
+
* Failure is a fact about the evidence, not a dialog: a declined or failed
|
|
24
|
+
* mask comes back as a tool error with a message, and `ImageMaskFallback`
|
|
25
|
+
* states it in a red boxed mono `Callout` from the result's own words.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { useState, type CSSProperties } from "react";
|
|
29
|
+
import { Callout, Receipt, Surface, color, font, type ReceiptRow } from "@schlessera/brain-ui-kit";
|
|
30
|
+
import type { ImageMaskPayload, ToolCallView } from "@schlessera/brain-ui-sdk/client";
|
|
31
|
+
import { useBrainUiRoot } from "../../../root-context.js";
|
|
32
|
+
import { ClampedPre } from "../tool-views.js";
|
|
33
|
+
|
|
34
|
+
/** A normalised rectangle over the source image: every value in 0..1. */
|
|
35
|
+
export interface MaskRegion {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
w: number;
|
|
39
|
+
h: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const THUMB_W = 160;
|
|
43
|
+
const THUMB_H = 100;
|
|
44
|
+
|
|
45
|
+
export const REGION_NOT_RECORDED = "region not recorded";
|
|
46
|
+
export const MASK_NOT_RENDERED = "mask not rendered";
|
|
47
|
+
|
|
48
|
+
/** The kit's image placeholder: raised stripes on the surface, no pixels. */
|
|
49
|
+
const HATCH = `repeating-linear-gradient(135deg,${color.raised} 0 6px,var(--bk-hatch-stripe) 6px 12px)`;
|
|
50
|
+
|
|
51
|
+
function bytesLabel(bytes: number): string {
|
|
52
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
53
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
54
|
+
return `${bytes} B`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The mask file exists with content: the handler reports the PNG's byte length. */
|
|
58
|
+
export function hasMaskBytes(payload: Pick<ImageMaskPayload, "bytes">): boolean {
|
|
59
|
+
return typeof payload.bytes === "number" && payload.bytes > 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The thumb: the hatched source, the drawn region when a caller has one, and
|
|
64
|
+
* the mask image over both when `maskUrl` is given. Exported for the view
|
|
65
|
+
* test; the bound card computes `maskUrl` from the payload.
|
|
66
|
+
*/
|
|
67
|
+
export function MaskThumb({
|
|
68
|
+
region,
|
|
69
|
+
label,
|
|
70
|
+
maskUrl,
|
|
71
|
+
maskShown,
|
|
72
|
+
onMaskLoad,
|
|
73
|
+
onMaskError,
|
|
74
|
+
}: {
|
|
75
|
+
region?: MaskRegion;
|
|
76
|
+
label: string;
|
|
77
|
+
maskUrl?: string;
|
|
78
|
+
/** The teal fill sits under the mask only once the PNG has loaded: until
|
|
79
|
+
* then, or after a failure, a full teal frame would read as a whole-image
|
|
80
|
+
* mask that was never drawn. */
|
|
81
|
+
maskShown?: boolean;
|
|
82
|
+
onMaskLoad?: () => void;
|
|
83
|
+
onMaskError?: () => void;
|
|
84
|
+
}) {
|
|
85
|
+
const frame: CSSProperties = {
|
|
86
|
+
position: "relative",
|
|
87
|
+
width: "100%",
|
|
88
|
+
maxWidth: THUMB_W * 2,
|
|
89
|
+
aspectRatio: `${THUMB_W} / ${THUMB_H}`,
|
|
90
|
+
borderRadius: 9,
|
|
91
|
+
border: `1px solid ${color.edge}`,
|
|
92
|
+
background: HATCH,
|
|
93
|
+
overflow: "hidden",
|
|
94
|
+
};
|
|
95
|
+
const drawn: CSSProperties | undefined = region
|
|
96
|
+
? {
|
|
97
|
+
position: "absolute",
|
|
98
|
+
left: `${region.x * 100}%`,
|
|
99
|
+
top: `${region.y * 100}%`,
|
|
100
|
+
width: `${region.w * 100}%`,
|
|
101
|
+
height: `${region.h * 100}%`,
|
|
102
|
+
border: "1.5px dashed var(--bk-teal-ink)",
|
|
103
|
+
background: "var(--bk-mask-region-fill)",
|
|
104
|
+
borderRadius: 3,
|
|
105
|
+
boxSizing: "border-box",
|
|
106
|
+
}
|
|
107
|
+
: undefined;
|
|
108
|
+
// The teal fill sits under the mask: where the PNG is transparent — the
|
|
109
|
+
// editable region, the user's own answer — the teal shows through.
|
|
110
|
+
const fill: CSSProperties = { position: "absolute", inset: 0, background: "var(--bk-mask-region-fill)" };
|
|
111
|
+
const overlay: CSSProperties = {
|
|
112
|
+
position: "absolute",
|
|
113
|
+
inset: 0,
|
|
114
|
+
width: "100%",
|
|
115
|
+
height: "100%",
|
|
116
|
+
objectFit: "contain",
|
|
117
|
+
};
|
|
118
|
+
return (
|
|
119
|
+
<div role="img" aria-label={label} style={frame} data-mask-thumb>
|
|
120
|
+
{drawn ? <div style={drawn} data-mask-region /> : null}
|
|
121
|
+
{maskUrl ? (
|
|
122
|
+
<>
|
|
123
|
+
{maskShown ? <div style={fill} aria-hidden="true" /> : null}
|
|
124
|
+
<img
|
|
125
|
+
src={maskUrl}
|
|
126
|
+
alt=""
|
|
127
|
+
style={{ ...overlay, visibility: maskShown ? "visible" : "hidden" }}
|
|
128
|
+
data-mask-overlay
|
|
129
|
+
data-mask-shown={maskShown ? "" : undefined}
|
|
130
|
+
onLoad={onMaskLoad}
|
|
131
|
+
onError={onMaskError}
|
|
132
|
+
/>
|
|
133
|
+
</>
|
|
134
|
+
) : null}
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** The rows the receipt prints. The region row is always there: figures when
|
|
140
|
+
* a caller has them, the stated absence when the payload carries none. */
|
|
141
|
+
export function maskReceiptRows(payload: ImageMaskPayload, region?: MaskRegion): ReceiptRow[] {
|
|
142
|
+
const rows: ReceiptRow[] = [];
|
|
143
|
+
if (region) {
|
|
144
|
+
rows.push({
|
|
145
|
+
k: "region",
|
|
146
|
+
v: `${pct(region.x)},${pct(region.y)} → ${pct(region.x + region.w)},${pct(region.y + region.h)}`,
|
|
147
|
+
tone: "teal",
|
|
148
|
+
});
|
|
149
|
+
rows.push({ k: "covers", v: `${pct(region.w * region.h)} of the image`, tone: "teal" });
|
|
150
|
+
} else {
|
|
151
|
+
rows.push({ k: "region", v: REGION_NOT_RECORDED, tone: "gold" });
|
|
152
|
+
}
|
|
153
|
+
rows.push({ k: "source", v: payload.imagePath });
|
|
154
|
+
rows.push({ k: "mask", v: `${payload.maskPath} · ${bytesLabel(payload.bytes)}` });
|
|
155
|
+
return rows;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function pct(fraction: number): string {
|
|
159
|
+
return `${Math.round(fraction * 100)}%`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function ImageMaskResultCard(payload: ImageMaskPayload & { region?: MaskRegion }) {
|
|
163
|
+
const root = useBrainUiRoot();
|
|
164
|
+
const region = payload.region;
|
|
165
|
+
const hasBytes = hasMaskBytes(payload);
|
|
166
|
+
const maskUrl = hasBytes
|
|
167
|
+
? `${root.apiBase()}/files/content?path=${encodeURIComponent(payload.maskPath)}&raw=1`
|
|
168
|
+
: undefined;
|
|
169
|
+
// The bytes say a mask was written; only the browser can say it loaded.
|
|
170
|
+
// A file gone since, or a path the raw route refuses, must not leave a
|
|
171
|
+
// full teal frame standing in for a mask nobody can see.
|
|
172
|
+
const [maskState, setMaskState] = useState<"loading" | "shown" | "failed">("loading");
|
|
173
|
+
const rendered = hasBytes && maskState === "shown";
|
|
174
|
+
const note: CSSProperties = { font: `400 10.5px/1.5 ${font.mono}`, color: color.inkMute };
|
|
175
|
+
return (
|
|
176
|
+
<Surface tone="teal" label="Mask drawn" labelIcon="confirm" meta="by you" pad={12}>
|
|
177
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
|
|
178
|
+
<MaskThumb
|
|
179
|
+
region={region}
|
|
180
|
+
maskUrl={maskUrl}
|
|
181
|
+
maskShown={rendered}
|
|
182
|
+
onMaskLoad={() => setMaskState("shown")}
|
|
183
|
+
onMaskError={() => setMaskState("failed")}
|
|
184
|
+
label={
|
|
185
|
+
rendered
|
|
186
|
+
? `Mask ${payload.maskPath} over the source ${payload.imagePath}`
|
|
187
|
+
: `Source ${payload.imagePath}; the mask is in ${payload.maskPath}`
|
|
188
|
+
}
|
|
189
|
+
/>
|
|
190
|
+
{!hasBytes || maskState === "failed" ? <div style={note}>{MASK_NOT_RENDERED}</div> : null}
|
|
191
|
+
<Receipt keyWidth={58} rows={maskReceiptRows(payload, region)} />
|
|
192
|
+
</div>
|
|
193
|
+
</Surface>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* No payload: the user declined, the editor failed, or an older server
|
|
199
|
+
* answered with a sentence. An error is stated as a fact in red; anything
|
|
200
|
+
* else is shown as the text it is.
|
|
201
|
+
*/
|
|
202
|
+
export function ImageMaskFallback({ tool }: { tool: ToolCallView }) {
|
|
203
|
+
if (!tool.output) return null;
|
|
204
|
+
if (!tool.isError) return <ClampedPre text={tool.output} />;
|
|
205
|
+
const source = typeof tool.input.imagePath === "string" ? tool.input.imagePath : null;
|
|
206
|
+
return (
|
|
207
|
+
<Callout
|
|
208
|
+
tone="red"
|
|
209
|
+
variant="boxed"
|
|
210
|
+
mono
|
|
211
|
+
text={`no mask drawn${source ? ` on ${source}` : ""} · ${tool.output.trim()}`}
|
|
212
|
+
/>
|
|
213
|
+
);
|
|
214
|
+
}
|