veryfront 0.1.997 → 0.1.998
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/esm/cli/templates/manifest.js +1 -1
- package/esm/deno.d.ts +7 -0
- package/esm/deno.js +11 -3
- package/esm/deps/esm.sh/react-dom@19.2.4.d.ts +2 -0
- package/esm/deps/esm.sh/react-dom@19.2.4.d.ts.map +1 -0
- package/esm/deps/esm.sh/react-dom@19.2.4.js +3 -0
- package/esm/react/react-dom.d.ts +3 -0
- package/esm/react/react-dom.d.ts.map +1 -0
- package/esm/react/react-dom.js +2 -0
- package/esm/src/agent/ag-ui/host-support.d.ts.map +1 -1
- package/esm/src/agent/ag-ui/host-support.js +12 -0
- package/esm/src/agent/react/index.d.ts +4 -2
- package/esm/src/agent/react/index.d.ts.map +1 -1
- package/esm/src/agent/react/index.js +2 -1
- package/esm/src/agent/react/use-agent-metadata.d.ts +5 -0
- package/esm/src/agent/react/use-agent-metadata.d.ts.map +1 -1
- package/esm/src/agent/react/use-agent-metadata.js +18 -9
- package/esm/src/agent/react/use-agents.d.ts +33 -0
- package/esm/src/agent/react/use-agents.d.ts.map +1 -0
- package/esm/src/agent/react/use-agents.js +72 -0
- package/esm/src/agent/react/use-chat/index.d.ts +1 -1
- package/esm/src/agent/react/use-chat/index.d.ts.map +1 -1
- package/esm/src/agent/react/use-chat/types.d.ts +3 -2
- package/esm/src/agent/react/use-chat/types.d.ts.map +1 -1
- package/esm/src/agent/react/use-chat/use-chat.d.ts +12 -1
- package/esm/src/agent/react/use-chat/use-chat.d.ts.map +1 -1
- package/esm/src/agent/react/use-chat/use-chat.js +47 -7
- package/esm/src/agent/react/use-chat/utils.d.ts.map +1 -1
- package/esm/src/agent/react/use-chat/utils.js +4 -0
- package/esm/src/agent/runtime/message-adapter.d.ts.map +1 -1
- package/esm/src/agent/runtime/message-adapter.js +3 -1
- package/esm/src/agent/runtime/text-generation-runtime-message-converter.d.ts.map +1 -1
- package/esm/src/agent/runtime/text-generation-runtime-message-converter.js +6 -2
- package/esm/src/chat/index.d.ts +17 -7
- package/esm/src/chat/index.d.ts.map +1 -1
- package/esm/src/chat/index.js +33 -7
- package/esm/src/chat/protocol.d.ts +13 -1
- package/esm/src/chat/protocol.d.ts.map +1 -1
- package/esm/src/chat/upload-handler.d.ts +55 -0
- package/esm/src/chat/upload-handler.d.ts.map +1 -0
- package/esm/src/chat/upload-handler.js +180 -0
- package/esm/src/discovery/import-rewriter.d.ts +1 -1
- package/esm/src/discovery/import-rewriter.d.ts.map +1 -1
- package/esm/src/discovery/import-rewriter.js +2 -0
- package/esm/src/discovery/transpiler.d.ts.map +1 -1
- package/esm/src/discovery/transpiler.js +2 -0
- package/esm/src/react/components/chat/agent-card.d.ts +84 -11
- package/esm/src/react/components/chat/agent-card.d.ts.map +1 -1
- package/esm/src/react/components/chat/agent-card.js +151 -57
- package/esm/src/react/components/chat/agent-picker.d.ts +166 -0
- package/esm/src/react/components/chat/agent-picker.d.ts.map +1 -0
- package/esm/src/react/components/chat/agent-picker.js +183 -0
- package/esm/src/react/components/chat/chat/components/animations.js +1 -1
- package/esm/src/react/components/chat/chat/components/attachment-pill.d.ts +125 -3
- package/esm/src/react/components/chat/chat/components/attachment-pill.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/attachment-pill.js +209 -25
- package/esm/src/react/components/chat/chat/components/attachments-panel.d.ts +149 -0
- package/esm/src/react/components/chat/chat/components/attachments-panel.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/components/attachments-panel.js +187 -0
- package/esm/src/react/components/chat/chat/components/branch-picker.d.ts +13 -2
- package/esm/src/react/components/chat/chat/components/branch-picker.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/branch-picker.js +6 -8
- package/esm/src/react/components/chat/chat/components/chat-messages-skeleton.d.ts +20 -0
- package/esm/src/react/components/chat/chat/components/chat-messages-skeleton.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/components/chat-messages-skeleton.js +31 -0
- package/esm/src/react/components/chat/chat/components/code-block.d.ts +9 -1
- package/esm/src/react/components/chat/chat/components/code-block.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/code-block.js +14 -6
- package/esm/src/react/components/chat/chat/components/drop-zone.d.ts +11 -4
- package/esm/src/react/components/chat/chat/components/drop-zone.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/drop-zone.js +10 -8
- package/esm/src/react/components/chat/chat/components/empty-state.d.ts +2 -1
- package/esm/src/react/components/chat/chat/components/empty-state.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/empty-state.js +7 -8
- package/esm/src/react/components/chat/chat/components/inference-badge.d.ts +6 -2
- package/esm/src/react/components/chat/chat/components/inference-badge.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/inference-badge.js +5 -4
- package/esm/src/react/components/chat/chat/components/inline-citation.d.ts +9 -1
- package/esm/src/react/components/chat/chat/components/inline-citation.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/inline-citation.js +19 -20
- package/esm/src/react/components/chat/chat/components/message-actions.d.ts +28 -5
- package/esm/src/react/components/chat/chat/components/message-actions.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/message-actions.js +24 -36
- package/esm/src/react/components/chat/chat/components/message-edit-form.d.ts +7 -2
- package/esm/src/react/components/chat/chat/components/message-edit-form.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/message-edit-form.js +5 -5
- package/esm/src/react/components/chat/chat/components/message-feedback.d.ts +11 -1
- package/esm/src/react/components/chat/chat/components/message-feedback.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/message-feedback.js +9 -11
- package/esm/src/react/components/chat/chat/components/quick-actions.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/quick-actions.js +3 -1
- package/esm/src/react/components/chat/chat/components/reasoning.d.ts +66 -3
- package/esm/src/react/components/chat/chat/components/reasoning.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/reasoning.js +95 -21
- package/esm/src/react/components/chat/chat/components/sidebar.d.ts +178 -12
- package/esm/src/react/components/chat/chat/components/sidebar.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/sidebar.js +228 -45
- package/esm/src/react/components/chat/chat/components/skill-badge.d.ts +6 -1
- package/esm/src/react/components/chat/chat/components/skill-badge.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/skill-badge.js +6 -5
- package/esm/src/react/components/chat/chat/components/skill-tool.d.ts +37 -0
- package/esm/src/react/components/chat/chat/components/skill-tool.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/components/skill-tool.js +46 -0
- package/esm/src/react/components/chat/chat/components/sources.d.ts +55 -3
- package/esm/src/react/components/chat/chat/components/sources.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/sources.js +50 -16
- package/esm/src/react/components/chat/chat/components/step-indicator.d.ts +42 -3
- package/esm/src/react/components/chat/chat/components/step-indicator.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/step-indicator.js +55 -12
- package/esm/src/react/components/chat/chat/components/tab-switcher.d.ts +1 -1
- package/esm/src/react/components/chat/chat/components/tab-switcher.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/tab-switcher.js +3 -3
- package/esm/src/react/components/chat/chat/components/tool-ui.d.ts +96 -3
- package/esm/src/react/components/chat/chat/components/tool-ui.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/components/tool-ui.js +158 -36
- package/esm/src/react/components/chat/chat/composition/api.d.ts +4 -2
- package/esm/src/react/components/chat/chat/composition/api.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/api.js +4 -2
- package/esm/src/react/components/chat/chat/composition/chat-composer.d.ts +112 -5
- package/esm/src/react/components/chat/chat/composition/chat-composer.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/chat-composer.js +251 -61
- package/esm/src/react/components/chat/chat/composition/chat-empty-state.d.ts +78 -0
- package/esm/src/react/components/chat/chat/composition/chat-empty-state.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/composition/chat-empty-state.js +63 -0
- package/esm/src/react/components/chat/chat/composition/chat-empty.d.ts +4 -1
- package/esm/src/react/components/chat/chat/composition/chat-empty.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/chat-empty.js +11 -10
- package/esm/src/react/components/chat/chat/composition/chat-message-list.d.ts +11 -3
- package/esm/src/react/components/chat/chat/composition/chat-message-list.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/chat-message-list.js +81 -111
- package/esm/src/react/components/chat/chat/composition/chat-root.d.ts +4 -0
- package/esm/src/react/components/chat/chat/composition/chat-root.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/chat-root.js +3 -1
- package/esm/src/react/components/chat/chat/composition/error-banner.d.ts +4 -0
- package/esm/src/react/components/chat/chat/composition/error-banner.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/error-banner.js +10 -7
- package/esm/src/react/components/chat/chat/composition/message.d.ts +123 -5
- package/esm/src/react/components/chat/chat/composition/message.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/message.js +332 -53
- package/esm/src/react/components/chat/chat/composition/model-avatar.d.ts +6 -1
- package/esm/src/react/components/chat/chat/composition/model-avatar.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/composition/model-avatar.js +3 -4
- package/esm/src/react/components/chat/chat/composition/pending-message.d.ts +31 -0
- package/esm/src/react/components/chat/chat/composition/pending-message.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/composition/pending-message.js +31 -0
- package/esm/src/react/components/chat/chat/contexts/chat-context.d.ts +4 -0
- package/esm/src/react/components/chat/chat/contexts/chat-context.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/contexts/composer-context.d.ts +1 -0
- package/esm/src/react/components/chat/chat/contexts/composer-context.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/contexts/conversations-context.d.ts +29 -0
- package/esm/src/react/components/chat/chat/contexts/conversations-context.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/contexts/conversations-context.js +39 -0
- package/esm/src/react/components/chat/chat/contexts/index.d.ts +1 -1
- package/esm/src/react/components/chat/chat/contexts/index.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/contexts/index.js +1 -1
- package/esm/src/react/components/chat/chat/contexts/message-context.d.ts +2 -0
- package/esm/src/react/components/chat/chat/contexts/message-context.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/hooks/use-clipboard.d.ts +10 -0
- package/esm/src/react/components/chat/chat/hooks/use-clipboard.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-clipboard.js +34 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversation.d.ts +21 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversation.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversation.js +54 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversations.d.ts +67 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversations.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-conversations.js +317 -0
- package/esm/src/react/components/chat/chat/hooks/use-drop-zone.d.ts +27 -0
- package/esm/src/react/components/chat/chat/hooks/use-drop-zone.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-drop-zone.js +50 -0
- package/esm/src/react/components/chat/chat/hooks/use-stick-to-bottom.d.ts +49 -0
- package/esm/src/react/components/chat/chat/hooks/use-stick-to-bottom.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-stick-to-bottom.js +120 -0
- package/esm/src/react/components/chat/chat/hooks/use-upload.d.ts +34 -0
- package/esm/src/react/components/chat/chat/hooks/use-upload.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-upload.js +147 -0
- package/esm/src/react/components/chat/chat/hooks/use-uploads-registry.d.ts +37 -0
- package/esm/src/react/components/chat/chat/hooks/use-uploads-registry.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/hooks/use-uploads-registry.js +178 -0
- package/esm/src/react/components/chat/chat/index.d.ts +171 -31
- package/esm/src/react/components/chat/chat/index.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/index.js +371 -77
- package/esm/src/react/components/chat/chat/persistence/conversation-store.d.ts +63 -0
- package/esm/src/react/components/chat/chat/persistence/conversation-store.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/persistence/conversation-store.js +1 -0
- package/esm/src/react/components/chat/chat/persistence/local-conversation-store.d.ts +13 -0
- package/esm/src/react/components/chat/chat/persistence/local-conversation-store.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/persistence/local-conversation-store.js +102 -0
- package/esm/src/react/components/chat/chat/persistence/memory-conversation-store.d.ts +11 -0
- package/esm/src/react/components/chat/chat/persistence/memory-conversation-store.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat/persistence/memory-conversation-store.js +33 -0
- package/esm/src/react/components/chat/chat/utils/message-parts.d.ts +4 -1
- package/esm/src/react/components/chat/chat/utils/message-parts.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/utils/message-parts.js +4 -0
- package/esm/src/react/components/chat/chat-actions.d.ts +164 -0
- package/esm/src/react/components/chat/chat-actions.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat-actions.js +191 -0
- package/esm/src/react/components/chat/chat-agent-picker.d.ts +50 -0
- package/esm/src/react/components/chat/chat-agent-picker.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat-agent-picker.js +40 -0
- package/esm/src/react/components/chat/chat-theme-scope.d.ts +26 -0
- package/esm/src/react/components/chat/chat-theme-scope.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat-theme-scope.js +27 -0
- package/esm/src/react/components/chat/chat-tokens-style.d.ts +21 -0
- package/esm/src/react/components/chat/chat-tokens-style.d.ts.map +1 -0
- package/esm/src/react/components/chat/chat-tokens-style.js +24 -0
- package/esm/src/react/components/chat/chat.d.ts +5 -5
- package/esm/src/react/components/chat/chat.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat.js +5 -5
- package/esm/src/react/components/chat/color-mode.d.ts +46 -0
- package/esm/src/react/components/chat/color-mode.d.ts.map +1 -0
- package/esm/src/react/components/chat/color-mode.js +123 -0
- package/esm/src/react/components/chat/error-boundary.js +2 -2
- package/esm/src/react/components/chat/icons/index.d.ts +8 -0
- package/esm/src/react/components/chat/icons/index.d.ts.map +1 -1
- package/esm/src/react/components/chat/icons/index.js +64 -0
- package/esm/src/react/components/chat/markdown.d.ts +24 -1
- package/esm/src/react/components/chat/markdown.d.ts.map +1 -1
- package/esm/src/react/components/chat/markdown.js +122 -38
- package/esm/src/react/components/chat/model-selector.d.ts +130 -8
- package/esm/src/react/components/chat/model-selector.d.ts.map +1 -1
- package/esm/src/react/components/chat/model-selector.js +148 -121
- package/esm/src/react/components/chat/theme.d.ts +9 -12
- package/esm/src/react/components/chat/theme.d.ts.map +1 -1
- package/esm/src/react/components/chat/theme.js +149 -93
- package/esm/src/react/components/chat/ui/alert.d.ts +30 -0
- package/esm/src/react/components/chat/ui/alert.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/alert.js +35 -0
- package/esm/src/react/components/chat/ui/app-shell.d.ts +155 -0
- package/esm/src/react/components/chat/ui/app-shell.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/app-shell.js +276 -0
- package/esm/src/react/components/chat/ui/avatar.d.ts +24 -0
- package/esm/src/react/components/chat/ui/avatar.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/avatar.js +44 -0
- package/esm/src/react/components/chat/ui/badge.d.ts +24 -0
- package/esm/src/react/components/chat/ui/badge.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/badge.js +30 -0
- package/esm/src/react/components/chat/ui/button.d.ts +44 -0
- package/esm/src/react/components/chat/ui/button.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/button.js +108 -0
- package/esm/src/react/components/chat/ui/card.d.ts +42 -0
- package/esm/src/react/components/chat/ui/card.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/card.js +55 -0
- package/esm/src/react/components/chat/ui/checkbox.d.ts +28 -0
- package/esm/src/react/components/chat/ui/checkbox.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/checkbox.js +36 -0
- package/esm/src/react/components/chat/ui/code-block.d.ts +89 -0
- package/esm/src/react/components/chat/ui/code-block.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/code-block.js +277 -0
- package/esm/src/react/components/chat/ui/collapsible.d.ts +30 -0
- package/esm/src/react/components/chat/ui/collapsible.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/collapsible.js +44 -0
- package/esm/src/react/components/chat/ui/command.d.ts +65 -0
- package/esm/src/react/components/chat/ui/command.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/command.js +121 -0
- package/esm/src/react/components/chat/ui/cva.d.ts +36 -0
- package/esm/src/react/components/chat/ui/cva.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/cva.js +45 -0
- package/esm/src/react/components/chat/ui/dialog.d.ts +55 -0
- package/esm/src/react/components/chat/ui/dialog.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/dialog.js +116 -0
- package/esm/src/react/components/chat/ui/drawer.d.ts +41 -0
- package/esm/src/react/components/chat/ui/drawer.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/drawer.js +92 -0
- package/esm/src/react/components/chat/ui/dropdown-menu.d.ts +63 -0
- package/esm/src/react/components/chat/ui/dropdown-menu.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/dropdown-menu.js +76 -0
- package/esm/src/react/components/chat/ui/file-type.d.ts +26 -0
- package/esm/src/react/components/chat/ui/file-type.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/file-type.js +235 -0
- package/esm/src/react/components/chat/ui/floating.d.ts +29 -0
- package/esm/src/react/components/chat/ui/floating.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/floating.js +90 -0
- package/esm/src/react/components/chat/ui/icon-button.d.ts +19 -0
- package/esm/src/react/components/chat/ui/icon-button.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/icon-button.js +20 -0
- package/esm/src/react/components/chat/ui/index.d.ts +43 -0
- package/esm/src/react/components/chat/ui/index.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/index.js +42 -0
- package/esm/src/react/components/chat/ui/input.d.ts +27 -0
- package/esm/src/react/components/chat/ui/input.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/input.js +41 -0
- package/esm/src/react/components/chat/ui/label.d.ts +29 -0
- package/esm/src/react/components/chat/ui/label.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/label.js +40 -0
- package/esm/src/react/components/chat/ui/list.d.ts +47 -0
- package/esm/src/react/components/chat/ui/list.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/list.js +40 -0
- package/esm/src/react/components/chat/ui/pill.d.ts +26 -0
- package/esm/src/react/components/chat/ui/pill.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/pill.js +39 -0
- package/esm/src/react/components/chat/ui/popover.d.ts +47 -0
- package/esm/src/react/components/chat/ui/popover.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/popover.js +68 -0
- package/esm/src/react/components/chat/ui/progress-bar.d.ts +20 -0
- package/esm/src/react/components/chat/ui/progress-bar.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/progress-bar.js +31 -0
- package/esm/src/react/components/chat/ui/radio.d.ts +25 -0
- package/esm/src/react/components/chat/ui/radio.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/radio.js +29 -0
- package/esm/src/react/components/chat/ui/scroll-fade.d.ts +23 -0
- package/esm/src/react/components/chat/ui/scroll-fade.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/scroll-fade.js +40 -0
- package/esm/src/react/components/chat/ui/select.d.ts +64 -0
- package/esm/src/react/components/chat/ui/select.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/select.js +148 -0
- package/esm/src/react/components/chat/ui/shimmer.d.ts +25 -0
- package/esm/src/react/components/chat/ui/shimmer.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/shimmer.js +24 -0
- package/esm/src/react/components/chat/ui/skeleton.d.ts +14 -0
- package/esm/src/react/components/chat/ui/skeleton.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/skeleton.js +12 -0
- package/esm/src/react/components/chat/ui/slot.d.ts +21 -0
- package/esm/src/react/components/chat/ui/slot.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/slot.js +70 -0
- package/esm/src/react/components/chat/ui/status.d.ts +28 -0
- package/esm/src/react/components/chat/ui/status.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/status.js +23 -0
- package/esm/src/react/components/chat/ui/switch.d.ts +34 -0
- package/esm/src/react/components/chat/ui/switch.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/switch.js +58 -0
- package/esm/src/react/components/chat/ui/tabs.d.ts +44 -0
- package/esm/src/react/components/chat/ui/tabs.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/tabs.js +51 -0
- package/esm/src/react/components/chat/ui/tag.d.ts +22 -0
- package/esm/src/react/components/chat/ui/tag.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/tag.js +27 -0
- package/esm/src/react/components/chat/ui/textarea.d.ts +22 -0
- package/esm/src/react/components/chat/ui/textarea.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/textarea.js +35 -0
- package/esm/src/react/components/chat/ui/tooltip.d.ts +40 -0
- package/esm/src/react/components/chat/ui/tooltip.d.ts.map +1 -0
- package/esm/src/react/components/chat/ui/tooltip.js +132 -0
- package/esm/src/react/primitives/input-box.d.ts.map +1 -1
- package/esm/src/react/primitives/input-box.js +17 -4
- package/esm/src/server/handlers/dev/framework-candidates.generated.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/framework-candidates.generated.js +9437 -1064
- package/esm/src/server/handlers/dev/projects/html-shell.d.ts +1 -1
- package/esm/src/server/handlers/dev/projects/html-shell.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/projects/html-shell.js +1 -12
- package/esm/src/server/handlers/request/public-agents-list.handler.d.ts +18 -0
- package/esm/src/server/handlers/request/public-agents-list.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/public-agents-list.handler.js +44 -0
- package/esm/src/server/runtime-handler/index.d.ts +1 -1
- package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
- package/esm/src/server/runtime-handler/index.js +3 -0
- package/esm/src/studio/bridge/bridge-bundle.generated.d.ts +1 -1
- package/esm/src/studio/bridge/bridge-bundle.generated.d.ts.map +1 -1
- package/esm/src/studio/bridge/bridge-bundle.generated.js +3 -2
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/blob/local-storage.d.ts +32 -0
- package/esm/src/workflow/blob/local-storage.d.ts.map +1 -0
- package/esm/src/workflow/blob/local-storage.js +179 -0
- package/esm/src/workflow/blob/types.d.ts +5 -0
- package/esm/src/workflow/blob/types.d.ts.map +1 -1
- package/esm/src/workflow/blob/veryfront-cloud-storage.d.ts +11 -0
- package/esm/src/workflow/blob/veryfront-cloud-storage.d.ts.map +1 -1
- package/esm/src/workflow/blob/veryfront-cloud-storage.js +36 -0
- package/package.json +5 -1
- package/esm/src/react/components/chat/chat/components/uploads-panel.d.ts +0 -20
- package/esm/src/react/components/chat/chat/components/uploads-panel.d.ts.map +0 -1
- package/esm/src/react/components/chat/chat/components/uploads-panel.js +0 -49
- package/esm/src/react/components/chat/chat/contexts/thread-list-context.d.ts +0 -28
- package/esm/src/react/components/chat/chat/contexts/thread-list-context.d.ts.map +0 -1
- package/esm/src/react/components/chat/chat/contexts/thread-list-context.js +0 -27
- package/esm/src/react/components/chat/chat/hooks/use-threads.d.ts +0 -28
- package/esm/src/react/components/chat/chat/hooks/use-threads.d.ts.map +0 -1
- package/esm/src/react/components/chat/chat/hooks/use-threads.js +0 -151
- package/esm/src/react/components/chat/chat-with-sidebar.d.ts +0 -110
- package/esm/src/react/components/chat/chat-with-sidebar.d.ts.map +0 -1
- package/esm/src/react/components/chat/chat-with-sidebar.js +0 -167
- package/esm/src/react/components/chat/message.d.ts +0 -42
- package/esm/src/react/components/chat/message.d.ts.map +0 -1
- package/esm/src/react/components/chat/message.js +0 -69
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer-context.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/composer-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,kCAAkC,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IAEnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,IAAI,CAAC;IAGjF,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IAGnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAGpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAID,gCAAgC;AAChC,wBAAgB,kBAAkB,IAAI,oBAAoB,CAQzD;AAED,gDAAgD;AAChD,wBAAgB,0BAA0B,IAAI,oBAAoB,GAAG,IAAI,CAExE;AAED,wCAAwC;AACxC,eAAO,MAAM,uBAAuB,6CAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"composer-context.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/composer-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,kCAAkC,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IAEnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,IAAI,CAAC;IAGjF,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IAGnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAGpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAID,gCAAgC;AAChC,wBAAgB,kBAAkB,IAAI,oBAAoB,CAQzD;AAED,gDAAgD;AAChD,wBAAgB,0BAA0B,IAAI,oBAAoB,GAAG,IAAI,CAExE;AAED,wCAAwC;AACxC,eAAO,MAAM,uBAAuB,6CAA2B,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConversationsContext — the shared {@link useConversations} instance for a
|
|
3
|
+
* multi-conversation app. Put {@link ConversationsProvider} in your layout so
|
|
4
|
+
* the sidebar, the chat page, and `<Chat>` all read one source of truth; never
|
|
5
|
+
* call `useConversations()` again below it (a second call is a second,
|
|
6
|
+
* disconnected store).
|
|
7
|
+
*
|
|
8
|
+
* @module react/components/chat/contexts/conversations-context
|
|
9
|
+
*/
|
|
10
|
+
import * as React from "../../../../../../react/react.js";
|
|
11
|
+
import { type UseConversationsOptions, type UseConversationsResult } from "../hooks/use-conversations.js";
|
|
12
|
+
/** Read the shared conversations state. Throws when used outside a provider. */
|
|
13
|
+
export declare function useConversationsContext(): UseConversationsResult;
|
|
14
|
+
/** Read the shared conversations state, or `null` when there is no provider. */
|
|
15
|
+
export declare function useConversationsContextOptional(): UseConversationsResult | null;
|
|
16
|
+
/** Low-level context provider (value supplied by the caller). */
|
|
17
|
+
export declare const ConversationsContextProvider: React.Provider<UseConversationsResult | null>;
|
|
18
|
+
/** Props accepted by {@link ConversationsProvider}. */
|
|
19
|
+
export interface ConversationsProviderProps extends UseConversationsOptions {
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* ConversationsProvider — calls {@link useConversations} once with your
|
|
24
|
+
* `store` / `id` / `onSelect` and shares it via {@link ConversationsContext}.
|
|
25
|
+
* Declare persistence + router wiring here, once, at the app layout; children
|
|
26
|
+
* read it with {@link useConversationsContext}.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ConversationsProvider({ children, ...options }: ConversationsProviderProps): React.ReactElement;
|
|
29
|
+
//# sourceMappingURL=conversations-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversations-context.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/conversations-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,KAAK,MAAM,kCAAkC,CAAC;AAE1D,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AAIvC,gFAAgF;AAChF,wBAAgB,uBAAuB,IAAI,sBAAsB,CAQhE;AAED,gFAAgF;AAChF,wBAAgB,+BAA+B,IAAI,sBAAsB,GAAG,IAAI,CAE/E;AAED,iEAAiE;AACjE,eAAO,MAAM,4BAA4B,+CAAgC,CAAC;AAE1E,uDAAuD;AACvD,MAAM,WAAW,0BAA2B,SAAQ,uBAAuB;IACzE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,0BAA0B,GACnD,KAAK,CAAC,YAAY,CAOpB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConversationsContext — the shared {@link useConversations} instance for a
|
|
3
|
+
* multi-conversation app. Put {@link ConversationsProvider} in your layout so
|
|
4
|
+
* the sidebar, the chat page, and `<Chat>` all read one source of truth; never
|
|
5
|
+
* call `useConversations()` again below it (a second call is a second,
|
|
6
|
+
* disconnected store).
|
|
7
|
+
*
|
|
8
|
+
* @module react/components/chat/contexts/conversations-context
|
|
9
|
+
*/
|
|
10
|
+
import * as React from "../../../../../../react/react.js";
|
|
11
|
+
import { COMPONENT_ERROR } from "../../../../../errors/error-registry.js";
|
|
12
|
+
import { useConversations, } from "../hooks/use-conversations.js";
|
|
13
|
+
const ConversationsContext = React.createContext(null);
|
|
14
|
+
/** Read the shared conversations state. Throws when used outside a provider. */
|
|
15
|
+
export function useConversationsContext() {
|
|
16
|
+
const context = React.useContext(ConversationsContext);
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw COMPONENT_ERROR.create({
|
|
19
|
+
detail: "useConversationsContext must be used within a ConversationsProvider",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return context;
|
|
23
|
+
}
|
|
24
|
+
/** Read the shared conversations state, or `null` when there is no provider. */
|
|
25
|
+
export function useConversationsContextOptional() {
|
|
26
|
+
return React.useContext(ConversationsContext);
|
|
27
|
+
}
|
|
28
|
+
/** Low-level context provider (value supplied by the caller). */
|
|
29
|
+
export const ConversationsContextProvider = ConversationsContext.Provider;
|
|
30
|
+
/**
|
|
31
|
+
* ConversationsProvider — calls {@link useConversations} once with your
|
|
32
|
+
* `store` / `id` / `onSelect` and shares it via {@link ConversationsContext}.
|
|
33
|
+
* Declare persistence + router wiring here, once, at the app layout; children
|
|
34
|
+
* read it with {@link useConversationsContext}.
|
|
35
|
+
*/
|
|
36
|
+
export function ConversationsProvider({ children, ...options }) {
|
|
37
|
+
const conversations = useConversations(options);
|
|
38
|
+
return (React.createElement(ConversationsContextProvider, { value: conversations }, children));
|
|
39
|
+
}
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
export { ChatContextProvider, type ChatContextValue, useChatContext, useChatContextOptional, } from "./chat-context.js";
|
|
10
10
|
export { MessageContextProvider, type MessageContextValue, useMessageContext, useMessageContextOptional, } from "./message-context.js";
|
|
11
11
|
export { ComposerContextProvider, type ComposerContextValue, useComposerContext, useComposerContextOptional, } from "./composer-context.js";
|
|
12
|
-
export {
|
|
12
|
+
export { ConversationsContextProvider, ConversationsProvider, type ConversationsProviderProps, useConversationsContext, useConversationsContextOptional, } from "./conversations-context.js";
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,cAAc,EACd,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,cAAc,EACd,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,4BAA4B,EAC5B,qBAAqB,EACrB,KAAK,0BAA0B,EAC/B,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,4BAA4B,CAAC"}
|
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
export { ChatContextProvider, useChatContext, useChatContextOptional, } from "./chat-context.js";
|
|
10
10
|
export { MessageContextProvider, useMessageContext, useMessageContextOptional, } from "./message-context.js";
|
|
11
11
|
export { ComposerContextProvider, useComposerContext, useComposerContextOptional, } from "./composer-context.js";
|
|
12
|
-
export {
|
|
12
|
+
export { ConversationsContextProvider, ConversationsProvider, useConversationsContext, useConversationsContextOptional, } from "./conversations-context.js";
|
|
@@ -21,6 +21,8 @@ export interface MessageContextValue {
|
|
|
21
21
|
onBranchPrev?: () => void;
|
|
22
22
|
onBranchNext?: () => void;
|
|
23
23
|
onCopy: () => Promise<void>;
|
|
24
|
+
/** True briefly after `onCopy` — lifted here so composed layouts keep the tick. */
|
|
25
|
+
copied: boolean;
|
|
24
26
|
onEdit?: (content: string) => void;
|
|
25
27
|
onRegenerate?: () => void;
|
|
26
28
|
onFeedback?: (value: FeedbackValue) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-context.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/message-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,kCAAkC,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAG1B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CACjC;AAID,+BAA+B;AAC/B,wBAAgB,iBAAiB,IAAI,mBAAmB,CAQvD;AAED,+CAA+C;AAC/C,wBAAgB,yBAAyB,IAAI,mBAAmB,GAAG,IAAI,CAEtE;AAED,uCAAuC;AACvC,eAAO,MAAM,sBAAsB,4CAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"message-context.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/contexts/message-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,kCAAkC,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAG1B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,mFAAmF;IACnF,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CACjC;AAID,+BAA+B;AAC/B,wBAAgB,iBAAiB,IAAI,mBAAmB,CAQvD;AAED,+CAA+C;AAC/C,wBAAgB,yBAAyB,IAAI,mBAAmB,GAAG,IAAI,CAEtE;AAED,uCAAuC;AACvC,eAAO,MAAM,sBAAsB,4CAA0B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Result of {@link useClipboard}. */
|
|
2
|
+
export interface UseClipboardResult {
|
|
3
|
+
/** True for `timeout` ms after a successful copy. */
|
|
4
|
+
copied: boolean;
|
|
5
|
+
/** Copy `text` to the clipboard (with a `document.execCommand` fallback). */
|
|
6
|
+
copy: (text: string) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/** Copy-to-clipboard with a transient `copied` flag. */
|
|
9
|
+
export declare function useClipboard(timeout?: number): UseClipboardResult;
|
|
10
|
+
//# sourceMappingURL=use-clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-clipboard.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/hooks/use-clipboard.ts"],"names":[],"mappings":"AAcA,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,OAAO,SAAO,GAAG,kBAAkB,CAqB/D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useClipboard — copy text with a transient "copied" flag and a legacy fallback.
|
|
3
|
+
*
|
|
4
|
+
* Extracted so both the message action bar and the code-block copy button share
|
|
5
|
+
* one implementation, and so the `copied` tick can be lifted into MessageContext
|
|
6
|
+
* (a composed layout keeps the affordance instead of losing it on eject).
|
|
7
|
+
*
|
|
8
|
+
* @module react/components/chat/chat/hooks/use-clipboard
|
|
9
|
+
*/
|
|
10
|
+
import * as dntShim from "../../../../../../_dnt.shims.js";
|
|
11
|
+
import * as React from "../../../../../../react/react.js";
|
|
12
|
+
/** Copy-to-clipboard with a transient `copied` flag. */
|
|
13
|
+
export function useClipboard(timeout = 2000) {
|
|
14
|
+
const [copied, setCopied] = React.useState(false);
|
|
15
|
+
const copy = React.useCallback(async (text) => {
|
|
16
|
+
try {
|
|
17
|
+
await navigator.clipboard.writeText(text);
|
|
18
|
+
}
|
|
19
|
+
catch (_) {
|
|
20
|
+
/* expected: clipboard API unavailable in older/insecure contexts */
|
|
21
|
+
const textarea = document.createElement("textarea");
|
|
22
|
+
textarea.value = text;
|
|
23
|
+
document.body.appendChild(textarea);
|
|
24
|
+
textarea.select();
|
|
25
|
+
document.execCommand("copy");
|
|
26
|
+
document.body.removeChild(textarea);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
setCopied(true);
|
|
30
|
+
dntShim.setTimeout(() => setCopied(false), timeout);
|
|
31
|
+
}
|
|
32
|
+
}, [timeout]);
|
|
33
|
+
return { copied, copy };
|
|
34
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Conversation, ConversationStore } from "../persistence/conversation-store.js";
|
|
2
|
+
/** Options for {@link useConversation}. */
|
|
3
|
+
export interface UseConversationOptions {
|
|
4
|
+
/** Async persistence adapter. Default: `localConversationStore(storageKey)`.
|
|
5
|
+
* Ignored when a surrounding `ConversationsProvider` already holds the id. */
|
|
6
|
+
store?: ConversationStore;
|
|
7
|
+
/** Convenience storage key for the default localStorage adapter. */
|
|
8
|
+
storageKey?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Result of {@link useConversation}. */
|
|
11
|
+
export interface UseConversationResult {
|
|
12
|
+
/** The full conversation (with messages), or `null` while loading / not found. */
|
|
13
|
+
conversation: Conversation | null;
|
|
14
|
+
/** True while the conversation is loading from the store. */
|
|
15
|
+
isLoading: boolean;
|
|
16
|
+
/** Re-fetch from the store. */
|
|
17
|
+
reload: () => void;
|
|
18
|
+
}
|
|
19
|
+
/** Load one full conversation by id, over a swappable async store. */
|
|
20
|
+
export declare function useConversation(id: string | null | undefined, options?: UseConversationOptions): UseConversationResult;
|
|
21
|
+
//# sourceMappingURL=use-conversation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-conversation.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/hooks/use-conversation.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAI5F,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC;mFAC+E;IAC/E,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yCAAyC;AACzC,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC7B,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,CA4CvB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useConversation — load a single full {@link Conversation} (with messages) by
|
|
3
|
+
* id, over the same swappable {@link ConversationStore} as {@link useConversations}.
|
|
4
|
+
* The singular companion to the list hook: use it to preview or open one
|
|
5
|
+
* conversation without mounting the whole list.
|
|
6
|
+
*
|
|
7
|
+
* Inside a {@link ConversationsProvider} it short-circuits when the requested id
|
|
8
|
+
* is already the active conversation (no redundant load); otherwise it fetches
|
|
9
|
+
* from the store. Pass your own `store` to point it anywhere, or omit it to use
|
|
10
|
+
* the default localStorage adapter.
|
|
11
|
+
*
|
|
12
|
+
* @module react/components/chat/hooks/use-conversation
|
|
13
|
+
*/
|
|
14
|
+
import * as React from "../../../../../../react/react.js";
|
|
15
|
+
import { localConversationStore } from "../persistence/local-conversation-store.js";
|
|
16
|
+
import { useConversationsContextOptional } from "../contexts/conversations-context.js";
|
|
17
|
+
/** Load one full conversation by id, over a swappable async store. */
|
|
18
|
+
export function useConversation(id, options = {}) {
|
|
19
|
+
const { storageKey } = options;
|
|
20
|
+
// Inside a provider, reuse its already-loaded active conversation when it
|
|
21
|
+
// matches — avoids a redundant round-trip and stays in sync with edits.
|
|
22
|
+
const context = useConversationsContextOptional();
|
|
23
|
+
const fromContext = context?.active && context.active.id === id ? context.active : null;
|
|
24
|
+
const store = React.useMemo(() => options.store ?? localConversationStore(storageKey), [options.store, storageKey]);
|
|
25
|
+
const [conversation, setConversation] = React.useState(fromContext);
|
|
26
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
27
|
+
const [reloadToken, setReloadToken] = React.useState(0);
|
|
28
|
+
const reload = React.useCallback(() => setReloadToken((token) => token + 1), []);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (!id) {
|
|
31
|
+
setConversation(null);
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// The provider already has this conversation — mirror it, no fetch.
|
|
36
|
+
if (fromContext) {
|
|
37
|
+
setConversation(fromContext);
|
|
38
|
+
setIsLoading(false);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
let cancelled = false;
|
|
42
|
+
setIsLoading(true);
|
|
43
|
+
void store.load(id).then((loaded) => {
|
|
44
|
+
if (cancelled)
|
|
45
|
+
return;
|
|
46
|
+
setConversation(loaded);
|
|
47
|
+
setIsLoading(false);
|
|
48
|
+
});
|
|
49
|
+
return () => {
|
|
50
|
+
cancelled = true;
|
|
51
|
+
};
|
|
52
|
+
}, [id, store, fromContext, reloadToken]);
|
|
53
|
+
return { conversation, isLoading, reload };
|
|
54
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ChatMessage } from "../../../../../agent/react/index.js";
|
|
2
|
+
import type { Conversation, ConversationStore, ConversationSummary } from "../persistence/conversation-store.js";
|
|
3
|
+
/** Default title for a fresh, untitled conversation. */
|
|
4
|
+
export declare const DEFAULT_CONVERSATION_TITLE = "New Chat";
|
|
5
|
+
/** A fresh, empty conversation. `now`/`id` are injectable for tests. */
|
|
6
|
+
export declare function createEmptyConversation(opts?: {
|
|
7
|
+
agentId?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
now?: number;
|
|
10
|
+
}): Conversation;
|
|
11
|
+
/** First user message text, trimmed to a title-sized slug. `""` if none. */
|
|
12
|
+
export declare function deriveTitle(messages: ChatMessage[]): string;
|
|
13
|
+
/** Derive a summary from a full conversation (mirrors the adapters). */
|
|
14
|
+
export declare function conversationSummary(c: Conversation): ConversationSummary;
|
|
15
|
+
/** Insert or replace a summary, newest (`updatedAt`) first. */
|
|
16
|
+
export declare function upsertSummary(summaries: ConversationSummary[], summary: ConversationSummary): ConversationSummary[];
|
|
17
|
+
/** The id to select after removing `removedId` — the newest remaining, or null. */
|
|
18
|
+
export declare function nextActiveAfterRemove(summaries: ConversationSummary[], removedId: string): string | null;
|
|
19
|
+
/** Fields a conversation can be patched with. */
|
|
20
|
+
export interface ConversationPatch {
|
|
21
|
+
title?: string;
|
|
22
|
+
messages?: ChatMessage[];
|
|
23
|
+
agentId?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Options for {@link useConversations}. */
|
|
26
|
+
export interface UseConversationsOptions {
|
|
27
|
+
/** Controlled active id — YOU own the source (e.g. `router.query.thread`).
|
|
28
|
+
* Omit to let the hook manage active internally (uncontrolled). */
|
|
29
|
+
id?: string | null;
|
|
30
|
+
/** Fired when active should change (select / after create / after remove).
|
|
31
|
+
* Wire it to your router. Omit → internal active state. */
|
|
32
|
+
onSelect?: (id: string | null) => void;
|
|
33
|
+
/** Async persistence adapter. Default: `localConversationStore(storageKey)`.
|
|
34
|
+
* Keep it referentially stable (module-level factory or `useMemo`). */
|
|
35
|
+
store?: ConversationStore;
|
|
36
|
+
/** Convenience storage key for the default localStorage adapter. */
|
|
37
|
+
storageKey?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Result of {@link useConversations}. */
|
|
40
|
+
export interface UseConversationsResult {
|
|
41
|
+
/** All conversations as summaries (no messages), newest first. */
|
|
42
|
+
conversations: ConversationSummary[];
|
|
43
|
+
/** The full active conversation (with messages), or `null`. */
|
|
44
|
+
active: Conversation | null;
|
|
45
|
+
activeId: string | null;
|
|
46
|
+
/** True while the initial list is loading from the store. */
|
|
47
|
+
isLoading: boolean;
|
|
48
|
+
select: (id?: string | null) => void;
|
|
49
|
+
create: (agentId?: string) => Conversation;
|
|
50
|
+
rename: (id: string, title: string) => void;
|
|
51
|
+
remove: (id: string) => void;
|
|
52
|
+
update: (id: string, patch: ConversationPatch) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Upsert a whole conversation (create-or-update). The store default for
|
|
55
|
+
* `<Chat onUpdate>` — hand it the emitted `{ id, messages, title, updatedAt }`
|
|
56
|
+
* and it lands in the list + persists. The conversation arrives fully formed
|
|
57
|
+
* (title already derived by the emitter), so this stays dumb about titling.
|
|
58
|
+
*/
|
|
59
|
+
save: (conversation: Conversation) => void;
|
|
60
|
+
/** Persist a live chat's messages + auto-title from the first user message. */
|
|
61
|
+
bind: (id: string, chat: {
|
|
62
|
+
messages: ChatMessage[];
|
|
63
|
+
}) => void;
|
|
64
|
+
}
|
|
65
|
+
/** List + active + persistence for conversations, over a swappable async store. */
|
|
66
|
+
export declare function useConversations(options?: UseConversationsOptions): UseConversationsResult;
|
|
67
|
+
//# sourceMappingURL=use-conversations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-conversations.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/hooks/use-conversations.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,sCAAsC,CAAC;AAG9C,wDAAwD;AACxD,eAAO,MAAM,0BAA0B,aAAa,CAAC;AAiBrD,wEAAwE;AACxE,wBAAgB,uBAAuB,CACrC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,YAAY,CAUd;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAS3D;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,CASxE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAC3B,SAAS,EAAE,mBAAmB,EAAE,EAChC,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,EAAE,CAIvB;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,mBAAmB,EAAE,EAChC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAGf;AAMD,iDAAiD;AACjD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;wEACoE;IACpE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB;gEAC4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvC;4EACwE;IACxE,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0CAA0C;AAC1C,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,+DAA+D;IAC/D,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACrC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;IAC3C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACvD;;;;;OAKG;IACH,IAAI,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IAC3C,+EAA+E;IAC/E,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CAC/D;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAyP9F"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useConversations — the conversation list + active-thread hook, backed by a
|
|
3
|
+
* swappable async {@link ConversationStore}. Owns what the havana example used
|
|
4
|
+
* to hand-roll in userland: load/persist, auto-title, create/remove/select, and
|
|
5
|
+
* per-message binding.
|
|
6
|
+
*
|
|
7
|
+
* The active id is **controlled** — pass `id` (from your router) + `onSelect`
|
|
8
|
+
* and the hook stays router-agnostic; omit them and it manages active itself.
|
|
9
|
+
* Persistence is async and pluggable; batching (debounced saves) lives here so
|
|
10
|
+
* adapters stay dumb.
|
|
11
|
+
*
|
|
12
|
+
* @module react/components/chat/hooks/use-conversations
|
|
13
|
+
*/
|
|
14
|
+
import * as dntShim from "../../../../../../_dnt.shims.js";
|
|
15
|
+
import * as React from "../../../../../../react/react.js";
|
|
16
|
+
import { localConversationStore } from "../persistence/local-conversation-store.js";
|
|
17
|
+
/** Default title for a fresh, untitled conversation. */
|
|
18
|
+
export const DEFAULT_CONVERSATION_TITLE = "New Chat";
|
|
19
|
+
const AUTOTITLE_MAX = 40;
|
|
20
|
+
const SAVE_DEBOUNCE_MS = 300;
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Pure helpers — the state transitions, extracted so they're unit-testable
|
|
23
|
+
// without a React renderer (the hook is a thin wrapper over these).
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
function randomId() {
|
|
26
|
+
const c = dntShim.dntGlobalThis.crypto;
|
|
27
|
+
const rand = c && "randomUUID" in c
|
|
28
|
+
? c.randomUUID().slice(0, 8)
|
|
29
|
+
: Math.random().toString(36).slice(2, 10);
|
|
30
|
+
return `c_${rand}`;
|
|
31
|
+
}
|
|
32
|
+
/** A fresh, empty conversation. `now`/`id` are injectable for tests. */
|
|
33
|
+
export function createEmptyConversation(opts = {}) {
|
|
34
|
+
const now = opts.now ?? Date.now();
|
|
35
|
+
return {
|
|
36
|
+
id: opts.id ?? randomId(),
|
|
37
|
+
title: DEFAULT_CONVERSATION_TITLE,
|
|
38
|
+
messages: [],
|
|
39
|
+
...(opts.agentId ? { agentId: opts.agentId } : {}),
|
|
40
|
+
createdAt: now,
|
|
41
|
+
updatedAt: now,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** First user message text, trimmed to a title-sized slug. `""` if none. */
|
|
45
|
+
export function deriveTitle(messages) {
|
|
46
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
47
|
+
if (!firstUser)
|
|
48
|
+
return "";
|
|
49
|
+
const text = firstUser.parts
|
|
50
|
+
.filter((p) => p.type === "text")
|
|
51
|
+
.map((p) => p.text)
|
|
52
|
+
.join("")
|
|
53
|
+
.trim();
|
|
54
|
+
return text.length > AUTOTITLE_MAX ? `${text.slice(0, AUTOTITLE_MAX).trimEnd()}…` : text;
|
|
55
|
+
}
|
|
56
|
+
/** Derive a summary from a full conversation (mirrors the adapters). */
|
|
57
|
+
export function conversationSummary(c) {
|
|
58
|
+
return {
|
|
59
|
+
id: c.id,
|
|
60
|
+
title: c.title,
|
|
61
|
+
...(c.agentId ? { agentId: c.agentId } : {}),
|
|
62
|
+
messageCount: c.messages.length,
|
|
63
|
+
createdAt: c.createdAt,
|
|
64
|
+
updatedAt: c.updatedAt,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Insert or replace a summary, newest (`updatedAt`) first. */
|
|
68
|
+
export function upsertSummary(summaries, summary) {
|
|
69
|
+
return [...summaries.filter((s) => s.id !== summary.id), summary].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
70
|
+
}
|
|
71
|
+
/** The id to select after removing `removedId` — the newest remaining, or null. */
|
|
72
|
+
export function nextActiveAfterRemove(summaries, removedId) {
|
|
73
|
+
const remaining = summaries.filter((s) => s.id !== removedId);
|
|
74
|
+
return remaining[0]?.id ?? null;
|
|
75
|
+
}
|
|
76
|
+
/** List + active + persistence for conversations, over a swappable async store. */
|
|
77
|
+
export function useConversations(options = {}) {
|
|
78
|
+
const { id: controlledId, onSelect, storageKey } = options;
|
|
79
|
+
const isControlled = controlledId !== undefined;
|
|
80
|
+
const store = React.useMemo(() => options.store ?? localConversationStore(storageKey), [options.store, storageKey]);
|
|
81
|
+
const [summaries, setSummaries] = React.useState([]);
|
|
82
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
83
|
+
const [active, setActive] = React.useState(null);
|
|
84
|
+
const [internalActiveId, setInternalActiveId] = React.useState(null);
|
|
85
|
+
const activeId = isControlled ? (controlledId ?? null) : internalActiveId;
|
|
86
|
+
// Keep the latest values reachable from stable callbacks without re-creating them.
|
|
87
|
+
const summariesRef = React.useRef(summaries);
|
|
88
|
+
summariesRef.current = summaries;
|
|
89
|
+
const activeRef = React.useRef(active);
|
|
90
|
+
activeRef.current = active;
|
|
91
|
+
const select = React.useCallback((id) => {
|
|
92
|
+
const next = id ?? null;
|
|
93
|
+
if (isControlled)
|
|
94
|
+
onSelect?.(next);
|
|
95
|
+
else
|
|
96
|
+
setInternalActiveId(next);
|
|
97
|
+
}, [isControlled, onSelect]);
|
|
98
|
+
// Debounced persistence — a burst of streaming message updates collapses to
|
|
99
|
+
// one save. Flushed on unmount so nothing is lost.
|
|
100
|
+
const saveTimer = React.useRef(undefined);
|
|
101
|
+
const pendingSave = React.useRef(null);
|
|
102
|
+
const flushSave = React.useCallback(() => {
|
|
103
|
+
clearTimeout(saveTimer.current);
|
|
104
|
+
if (pendingSave.current) {
|
|
105
|
+
void store.save(pendingSave.current);
|
|
106
|
+
pendingSave.current = null;
|
|
107
|
+
}
|
|
108
|
+
}, [store]);
|
|
109
|
+
const discardPendingSave = React.useCallback((id) => {
|
|
110
|
+
if (pendingSave.current?.id !== id)
|
|
111
|
+
return;
|
|
112
|
+
clearTimeout(saveTimer.current);
|
|
113
|
+
pendingSave.current = null;
|
|
114
|
+
}, []);
|
|
115
|
+
const scheduleSave = React.useCallback((conversation) => {
|
|
116
|
+
// A pending save for a *different* conversation must be flushed, not
|
|
117
|
+
// clobbered: switching threads inside the debounce window would
|
|
118
|
+
// otherwise drop the previous thread's final messages.
|
|
119
|
+
if (pendingSave.current && pendingSave.current.id !== conversation.id) {
|
|
120
|
+
flushSave();
|
|
121
|
+
}
|
|
122
|
+
pendingSave.current = conversation;
|
|
123
|
+
clearTimeout(saveTimer.current);
|
|
124
|
+
saveTimer.current = dntShim.setTimeout(flushSave, SAVE_DEBOUNCE_MS);
|
|
125
|
+
}, [flushSave]);
|
|
126
|
+
React.useEffect(() => flushSave, [flushSave]);
|
|
127
|
+
const create = React.useCallback((agentId) => {
|
|
128
|
+
// Reuse an existing untouched draft instead of piling up "New Chat" rows —
|
|
129
|
+
// clicking "New chat" (or an auto-create) when a blank draft already exists
|
|
130
|
+
// just re-opens it.
|
|
131
|
+
const draft = summariesRef.current.find((s) => s.messageCount === 0 && s.title === DEFAULT_CONVERSATION_TITLE);
|
|
132
|
+
if (draft) {
|
|
133
|
+
const reused = activeRef.current?.id === draft.id ? activeRef.current : {
|
|
134
|
+
id: draft.id,
|
|
135
|
+
title: draft.title,
|
|
136
|
+
...(draft.agentId ? { agentId: draft.agentId } : {}),
|
|
137
|
+
messages: [],
|
|
138
|
+
createdAt: draft.createdAt,
|
|
139
|
+
updatedAt: draft.updatedAt,
|
|
140
|
+
};
|
|
141
|
+
setActive(reused);
|
|
142
|
+
select(draft.id);
|
|
143
|
+
return reused;
|
|
144
|
+
}
|
|
145
|
+
const conversation = createEmptyConversation({ agentId });
|
|
146
|
+
void store.save(conversation);
|
|
147
|
+
setSummaries((prev) => upsertSummary(prev, conversationSummary(conversation)));
|
|
148
|
+
setActive(conversation);
|
|
149
|
+
select(conversation.id);
|
|
150
|
+
return conversation;
|
|
151
|
+
}, [store, select]);
|
|
152
|
+
// Initial load: pull the list; auto-create a draft only when there's nothing
|
|
153
|
+
// to open, otherwise land on the most-recent conversation (so a reload
|
|
154
|
+
// restores where you were instead of spawning a fresh "New Chat"). Runs once
|
|
155
|
+
// per store.
|
|
156
|
+
const didInit = React.useRef(false);
|
|
157
|
+
React.useEffect(() => {
|
|
158
|
+
didInit.current = false;
|
|
159
|
+
let cancelled = false;
|
|
160
|
+
setIsLoading(true);
|
|
161
|
+
void store.list().then((list) => {
|
|
162
|
+
if (cancelled)
|
|
163
|
+
return;
|
|
164
|
+
setSummaries(list);
|
|
165
|
+
setIsLoading(false);
|
|
166
|
+
if (!didInit.current) {
|
|
167
|
+
if (list.length === 0)
|
|
168
|
+
create();
|
|
169
|
+
else if (!isControlled && activeRef.current == null) {
|
|
170
|
+
const firstId = list[0]?.id ?? null;
|
|
171
|
+
select(firstId);
|
|
172
|
+
if (firstId) {
|
|
173
|
+
void store.load(firstId).then((conversation) => {
|
|
174
|
+
if (!cancelled)
|
|
175
|
+
setActive(conversation);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
didInit.current = true;
|
|
181
|
+
});
|
|
182
|
+
const unsubscribe = store.subscribe?.(() => {
|
|
183
|
+
void store.list().then((list) => !cancelled && setSummaries(list));
|
|
184
|
+
});
|
|
185
|
+
return () => {
|
|
186
|
+
cancelled = true;
|
|
187
|
+
unsubscribe?.();
|
|
188
|
+
};
|
|
189
|
+
// `create` is stable enough; intentionally keyed on the store only.
|
|
190
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
191
|
+
}, [store]);
|
|
192
|
+
// Load the full active conversation when the active id changes. Skip when we
|
|
193
|
+
// already hold it (optimistic create/update set `active` directly).
|
|
194
|
+
React.useEffect(() => {
|
|
195
|
+
if (!activeId) {
|
|
196
|
+
setActive(null);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (activeRef.current?.id === activeId)
|
|
200
|
+
return;
|
|
201
|
+
let cancelled = false;
|
|
202
|
+
void store.load(activeId).then((conversation) => {
|
|
203
|
+
if (!cancelled)
|
|
204
|
+
setActive(conversation);
|
|
205
|
+
});
|
|
206
|
+
return () => {
|
|
207
|
+
cancelled = true;
|
|
208
|
+
};
|
|
209
|
+
}, [activeId, store]);
|
|
210
|
+
const update = React.useCallback((id, patch) => {
|
|
211
|
+
const now = Date.now();
|
|
212
|
+
setSummaries((prev) => {
|
|
213
|
+
const existing = prev.find((s) => s.id === id);
|
|
214
|
+
if (!existing)
|
|
215
|
+
return prev;
|
|
216
|
+
return upsertSummary(prev, {
|
|
217
|
+
...existing,
|
|
218
|
+
...(patch.title !== undefined ? { title: patch.title } : {}),
|
|
219
|
+
...(patch.agentId !== undefined ? { agentId: patch.agentId } : {}),
|
|
220
|
+
...(patch.messages ? { messageCount: patch.messages.length } : {}),
|
|
221
|
+
updatedAt: now,
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
if (activeRef.current?.id === id) {
|
|
225
|
+
const next = { ...activeRef.current, ...patch, updatedAt: now };
|
|
226
|
+
setActive(next);
|
|
227
|
+
scheduleSave(next);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Non-active edit (e.g. rename from the sidebar) — load, patch, save now.
|
|
231
|
+
void store.load(id).then((conversation) => {
|
|
232
|
+
if (conversation)
|
|
233
|
+
void store.save({ ...conversation, ...patch, updatedAt: now });
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}, [store, scheduleSave]);
|
|
237
|
+
const save = React.useCallback((conversation) => {
|
|
238
|
+
const summary = conversationSummary(conversation);
|
|
239
|
+
// Streaming emits once per token; the list (and everything reading this
|
|
240
|
+
// context) only cares when something it shows (title, count, order)
|
|
241
|
+
// actually changes. Returning `prev` bails out of the re-render.
|
|
242
|
+
setSummaries((prev) => {
|
|
243
|
+
const existing = prev.find((s) => s.id === summary.id);
|
|
244
|
+
if (existing && existing.title === summary.title &&
|
|
245
|
+
existing.messageCount === summary.messageCount)
|
|
246
|
+
return prev;
|
|
247
|
+
return upsertSummary(prev, summary);
|
|
248
|
+
});
|
|
249
|
+
// Keep the in-memory active thread in sync when it's the one being saved,
|
|
250
|
+
// so a re-open reads the just-saved messages instead of the loaded blob.
|
|
251
|
+
// Same churn gate: mid-stream token growth is captured by the debounced
|
|
252
|
+
// store write below; `active` consumers only read it on remount.
|
|
253
|
+
if (activeRef.current?.id === conversation.id) {
|
|
254
|
+
const current = activeRef.current;
|
|
255
|
+
if (current.title !== conversation.title ||
|
|
256
|
+
current.messages.length !== conversation.messages.length)
|
|
257
|
+
setActive(conversation);
|
|
258
|
+
}
|
|
259
|
+
scheduleSave(conversation);
|
|
260
|
+
}, [scheduleSave]);
|
|
261
|
+
const bind = React.useCallback((id, chat) => {
|
|
262
|
+
const current = activeRef.current?.id === id
|
|
263
|
+
? activeRef.current
|
|
264
|
+
: summariesRef.current.find((s) => s.id === id);
|
|
265
|
+
const patch = { messages: chat.messages };
|
|
266
|
+
// Auto-title an untitled conversation from its first user message.
|
|
267
|
+
if (current && current.title === DEFAULT_CONVERSATION_TITLE) {
|
|
268
|
+
const title = deriveTitle(chat.messages);
|
|
269
|
+
if (title)
|
|
270
|
+
patch.title = title;
|
|
271
|
+
}
|
|
272
|
+
update(id, patch);
|
|
273
|
+
}, [update]);
|
|
274
|
+
const rename = React.useCallback((id, title) => {
|
|
275
|
+
update(id, { title });
|
|
276
|
+
}, [update]);
|
|
277
|
+
const remove = React.useCallback((id) => {
|
|
278
|
+
discardPendingSave(id);
|
|
279
|
+
void store.delete(id);
|
|
280
|
+
const next = nextActiveAfterRemove(summariesRef.current, id);
|
|
281
|
+
setSummaries((prev) => prev.filter((s) => s.id !== id));
|
|
282
|
+
if (id === activeId) {
|
|
283
|
+
if (next)
|
|
284
|
+
select(next);
|
|
285
|
+
else
|
|
286
|
+
create();
|
|
287
|
+
}
|
|
288
|
+
}, [store, activeId, select, create, discardPendingSave]);
|
|
289
|
+
// Memoized so `ConversationsProvider` can pass this straight through as a
|
|
290
|
+
// context value: consumers re-render only when the state above changes, not
|
|
291
|
+
// on every render of the provider.
|
|
292
|
+
return React.useMemo(() => ({
|
|
293
|
+
conversations: summaries,
|
|
294
|
+
active,
|
|
295
|
+
activeId,
|
|
296
|
+
isLoading,
|
|
297
|
+
select,
|
|
298
|
+
create,
|
|
299
|
+
rename,
|
|
300
|
+
remove,
|
|
301
|
+
update,
|
|
302
|
+
save,
|
|
303
|
+
bind,
|
|
304
|
+
}), [
|
|
305
|
+
summaries,
|
|
306
|
+
active,
|
|
307
|
+
activeId,
|
|
308
|
+
isLoading,
|
|
309
|
+
select,
|
|
310
|
+
create,
|
|
311
|
+
rename,
|
|
312
|
+
remove,
|
|
313
|
+
update,
|
|
314
|
+
save,
|
|
315
|
+
bind,
|
|
316
|
+
]);
|
|
317
|
+
}
|