@dxos/plugin-assistant 0.10.0 → 0.11.1
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/PLUGIN.mdl +3 -28
- package/dist/lib/AssistantPlugin.mjs +2 -0
- package/dist/lib/AssistantPlugin.node.mjs +55 -0
- package/dist/lib/AssistantPlugin.node.mjs.map +1 -0
- package/dist/lib/AssistantPlugin.workerd.mjs +43 -0
- package/dist/lib/AssistantPlugin.workerd.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +24 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-AgentArticle.mjs +52 -0
- package/dist/lib/chunk-AgentArticle.mjs.map +1 -0
- package/dist/lib/chunk-AgentProperties.mjs +35 -0
- package/dist/lib/chunk-AgentProperties.mjs.map +1 -0
- package/dist/lib/chunk-AssistantPlugin.mjs +88 -0
- package/dist/lib/chunk-AssistantPlugin.mjs.map +1 -0
- package/dist/lib/chunk-AssistantSettings.mjs +285 -0
- package/dist/lib/chunk-AssistantSettings.mjs.map +1 -0
- package/dist/lib/chunk-ChatArticle.mjs +121 -0
- package/dist/lib/chunk-ChatArticle.mjs.map +1 -0
- package/dist/lib/chunk-ChatCompanion.mjs +116 -0
- package/dist/lib/chunk-ChatCompanion.mjs.map +1 -0
- package/dist/lib/chunk-ChatDialog.mjs +73 -0
- package/dist/lib/chunk-ChatDialog.mjs.map +1 -0
- package/dist/lib/chunk-IntegrationPrompt.mjs +73 -0
- package/dist/lib/chunk-IntegrationPrompt.mjs.map +1 -0
- package/dist/lib/chunk-SpaceHomePrompt.mjs +104 -0
- package/dist/lib/chunk-SpaceHomePrompt.mjs.map +1 -0
- package/dist/lib/chunk-SpaceHomeSuggestions.mjs +60 -0
- package/dist/lib/chunk-SpaceHomeSuggestions.mjs.map +1 -0
- package/dist/lib/chunk-TracePanel.mjs +127 -0
- package/dist/lib/chunk-TracePanel.mjs.map +1 -0
- package/dist/lib/chunk-TracePanel2.mjs +7 -0
- package/dist/lib/chunk-TracePanel2.mjs.map +1 -0
- package/dist/lib/chunk-TriggerStatus.mjs +72 -0
- package/dist/lib/chunk-TriggerStatus.mjs.map +1 -0
- package/dist/lib/chunk-agent-hydrator.mjs +22 -0
- package/dist/lib/chunk-agent-hydrator.mjs.map +1 -0
- package/dist/lib/chunk-agent-service.mjs +21 -0
- package/dist/lib/chunk-agent-service.mjs.map +1 -0
- package/dist/lib/{neutral/ai-context-LIKJYMIN.mjs → chunk-ai-context.mjs} +8 -12
- package/dist/lib/chunk-ai-context.mjs.map +1 -0
- package/dist/lib/chunk-ai-service.mjs +27 -0
- package/dist/lib/chunk-ai-service.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +179 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-automation-templates.mjs +99 -0
- package/dist/lib/chunk-automation-templates.mjs.map +1 -0
- package/dist/lib/chunk-companion-chat-provisioner.mjs +123 -0
- package/dist/lib/chunk-companion-chat-provisioner.mjs.map +1 -0
- package/dist/lib/chunk-connector.mjs +60 -0
- package/dist/lib/chunk-connector.mjs.map +1 -0
- package/dist/lib/chunk-constants.mjs +9 -0
- package/dist/lib/chunk-constants.mjs.map +1 -0
- package/dist/lib/chunk-context.mjs +7 -0
- package/dist/lib/chunk-context.mjs.map +1 -0
- package/dist/lib/chunk-create-chat.mjs +53 -0
- package/dist/lib/chunk-create-chat.mjs.map +1 -0
- package/dist/lib/chunk-create-object.mjs +70 -0
- package/dist/lib/chunk-create-object.mjs.map +1 -0
- package/dist/lib/chunk-edge-model-resolver.mjs +64 -0
- package/dist/lib/chunk-edge-model-resolver.mjs.map +1 -0
- package/dist/lib/chunk-ensure-companion-chat.mjs +49 -0
- package/dist/lib/chunk-ensure-companion-chat.mjs.map +1 -0
- package/dist/lib/chunk-extensions.mjs +78 -0
- package/dist/lib/chunk-extensions.mjs.map +1 -0
- package/dist/lib/chunk-fork-chat.mjs +83 -0
- package/dist/lib/chunk-fork-chat.mjs.map +1 -0
- package/dist/lib/chunk-generate-home-suggestions.mjs +71 -0
- package/dist/lib/chunk-generate-home-suggestions.mjs.map +1 -0
- package/dist/lib/chunk-local-model-resolver.mjs +25 -0
- package/dist/lib/chunk-local-model-resolver.mjs.map +1 -0
- package/dist/lib/chunk-markdown-extension.mjs +27 -0
- package/dist/lib/chunk-markdown-extension.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-L7AR4VTA.mjs → chunk-meta.mjs} +20 -25
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +13 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-paths.mjs +8 -0
- package/dist/lib/chunk-paths.mjs.map +1 -0
- package/dist/lib/chunk-processor.mjs +432 -0
- package/dist/lib/chunk-processor.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +177 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-run-prompt-in-new-chat.mjs +96 -0
- package/dist/lib/chunk-run-prompt-in-new-chat.mjs.map +1 -0
- package/dist/lib/chunk-set-current-chat.mjs +43 -0
- package/dist/lib/chunk-set-current-chat.mjs.map +1 -0
- package/dist/lib/chunk-settings.mjs +23 -0
- package/dist/lib/chunk-settings.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +42 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-skills.mjs +19 -0
- package/dist/lib/chunk-skills.mjs.map +1 -0
- package/dist/lib/chunk-state.mjs +32 -0
- package/dist/lib/chunk-state.mjs.map +1 -0
- package/dist/lib/chunk-toggle-trace-panel-debug.mjs +18 -0
- package/dist/lib/chunk-toggle-trace-panel-debug.mjs.map +1 -0
- package/dist/lib/chunk-toolkit.mjs +12 -0
- package/dist/lib/chunk-toolkit.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +332 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/chunk-update-chat-name.mjs +63 -0
- package/dist/lib/chunk-update-chat-name.mjs.map +1 -0
- package/dist/lib/components.mjs +2616 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +17 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/execution-graph.mjs +961 -0
- package/dist/lib/execution-graph.mjs.map +1 -0
- package/dist/lib/extensions.mjs +2 -0
- package/dist/lib/hooks.mjs +674 -0
- package/dist/lib/hooks.mjs.map +1 -0
- package/dist/lib/index.mjs +5 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/plugin.workerd.mjs +2 -0
- package/dist/lib/skills.mjs +2 -0
- package/dist/lib/testing.mjs +2 -0
- package/dist/lib/translations.mjs +207 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/AssistantPlugin.d.ts.map +1 -1
- package/dist/types/src/AssistantPlugin.node.d.ts.map +1 -1
- package/dist/types/src/AssistantPlugin.workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/AssistantSurfaces.d.ts +22 -0
- package/dist/types/src/capabilities/AssistantSurfaces.d.ts.map +1 -0
- package/dist/types/src/capabilities/agent-hydrator.d.ts +1 -1
- package/dist/types/src/capabilities/agent-service.d.ts +1 -1
- package/dist/types/src/capabilities/agent-service.d.ts.map +1 -1
- package/dist/types/src/capabilities/ai-context.d.ts +1 -1
- package/dist/types/src/capabilities/ai-service.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +12 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/automation-templates.d.ts +1 -1
- package/dist/types/src/capabilities/companion-chat-provisioner.d.ts +1 -1
- package/dist/types/src/capabilities/connector.d.ts +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +1 -1
- package/dist/types/src/capabilities/edge-model-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/edge-model-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +0 -2
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/local-model-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/local-model-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown-extension.d.ts +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
- package/dist/types/src/capabilities/standalone-chats-query.test.d.ts +2 -0
- package/dist/types/src/capabilities/standalone-chats-query.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +1 -1
- package/dist/types/src/capabilities/toolkit.d.ts +1 -1
- package/dist/types/src/components/AgentProperties/AgentProperties.d.ts +4 -1
- package/dist/types/src/components/AgentProperties/AgentProperties.d.ts.map +1 -1
- package/dist/types/src/components/AgentProperties/AgentProperties.stories.d.ts.map +1 -1
- package/dist/types/src/components/Chat/Chat.d.ts +21 -8
- package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/src/components/Chat/{Chat.stories.d.ts → Error.stories.d.ts} +1 -1
- package/dist/types/src/components/Chat/Error.stories.d.ts.map +1 -0
- package/dist/types/src/components/Chat/context.d.ts +8 -0
- package/dist/types/src/components/Chat/context.d.ts.map +1 -1
- package/dist/types/src/components/Chat/events.d.ts +5 -0
- package/dist/types/src/components/Chat/events.d.ts.map +1 -1
- package/dist/types/src/components/Chat/thread.d.ts +42 -0
- package/dist/types/src/components/Chat/thread.d.ts.map +1 -0
- package/dist/types/src/components/Chat/thread.test.d.ts +2 -0
- package/dist/types/src/components/Chat/thread.test.d.ts.map +1 -0
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts +5 -3
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/index.d.ts +0 -1
- package/dist/types/src/components/ChatPrompt/index.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/Anchor.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/ChatThread.d.ts +8 -3
- package/dist/types/src/components/ChatThread/ChatThread.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/ChatThread.stories.d.ts +30 -2
- package/dist/types/src/components/ChatThread/ChatThread.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/Link.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/index.d.ts +1 -0
- package/dist/types/src/components/ChatThread/index.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/registry.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/sync/index.d.ts +3 -0
- package/dist/types/src/components/ChatThread/sync/index.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/{sync.d.ts → sync/sync.d.ts} +46 -2
- package/dist/types/src/components/ChatThread/sync/sync.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/sync/sync.test.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/sync/tool-widget-state.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/sync/tool-widget-state.test.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.d.ts +15 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.stories.d.ts +21 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.stories.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.test.d.ts +2 -0
- package/dist/types/src/components/ChatThread/widgets/BranchWidget.test.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/widgets/ReferenceWidget.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/widgets/SuggestionWidget.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/widgets/ToolWidget.d.ts +1 -2
- package/dist/types/src/components/ChatThread/widgets/ToolWidget.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/widgets/defaults.d.ts +6 -0
- package/dist/types/src/components/ChatThread/widgets/defaults.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/widgets/format-time.d.ts +2 -0
- package/dist/types/src/components/ChatThread/widgets/format-time.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/widgets/index.d.ts +4 -1
- package/dist/types/src/components/ChatThread/widgets/index.d.ts.map +1 -1
- package/dist/types/src/components/ChatThread/widgets/is-tool-message.d.ts +3 -0
- package/dist/types/src/components/ChatThread/widgets/is-tool-message.d.ts.map +1 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.d.ts +16 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.d.ts.map +1 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts +210 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/ConnectorAuthMenu/index.d.ts +2 -0
- package/dist/types/src/components/ConnectorAuthMenu/index.d.ts.map +1 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +1 -1
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -1
- package/dist/types/src/components/TaskList/TaskList.d.ts +9 -11
- package/dist/types/src/components/TaskList/TaskList.d.ts.map +1 -1
- package/dist/types/src/components/TaskList/TaskList.stories.d.ts +3 -4
- package/dist/types/src/components/TaskList/TaskList.stories.d.ts.map +1 -1
- package/dist/types/src/components/ToolBlock/ToolBlock.d.ts +1 -2
- package/dist/types/src/components/ToolBlock/ToolBlock.d.ts.map +1 -1
- package/dist/types/src/components/ToolBlock/index.d.ts +1 -0
- package/dist/types/src/components/ToolBlock/index.d.ts.map +1 -1
- package/dist/types/src/components/ToolBlock/is-tool-message.d.ts +3 -0
- package/dist/types/src/components/ToolBlock/is-tool-message.d.ts.map +1 -0
- package/dist/types/src/components/Toolbox/Toolbox.d.ts +1 -1
- package/dist/types/src/components/Toolbox/Toolbox.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/AgentArticle/AgentArticle.d.ts +5 -2
- package/dist/types/src/containers/AgentArticle/AgentArticle.d.ts.map +1 -1
- package/dist/types/src/containers/AgentArticle/AgentArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/AgentProperties/AgentProperties.d.ts +4 -1
- package/dist/types/src/containers/AgentProperties/AgentProperties.d.ts.map +1 -1
- package/dist/types/src/containers/AssistantSettings/AssistantSettings.d.ts +4 -1
- package/dist/types/src/containers/AssistantSettings/AssistantSettings.d.ts.map +1 -1
- package/dist/types/src/containers/AssistantSettings/AssistantSettings.stories.d.ts +4 -1
- package/dist/types/src/containers/AssistantSettings/AssistantSettings.stories.d.ts.map +1 -1
- package/dist/types/src/containers/AssistantSettings/OllamaModels.d.ts +4 -6
- package/dist/types/src/containers/AssistantSettings/OllamaModels.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.stories.d.ts +22 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/ChatCompanion/ChatCompanion.d.ts.map +1 -1
- package/dist/types/src/containers/ChatDialog/ChatDialog.d.ts +4 -1
- package/dist/types/src/containers/ChatDialog/ChatDialog.d.ts.map +1 -1
- package/dist/types/src/containers/IntegrationPrompt/IntegrationPrompt.d.ts +4 -7
- package/dist/types/src/containers/IntegrationPrompt/IntegrationPrompt.d.ts.map +1 -1
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts +4 -9
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts.map +1 -1
- package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts +5 -7
- package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts.map +1 -1
- package/dist/types/src/containers/TracePanel/TracePanel.d.ts +1 -1
- package/dist/types/src/containers/TracePanel/TracePanel.d.ts.map +1 -1
- package/dist/types/src/containers/TracePanel/TracePanel.stories.d.ts.map +1 -1
- package/dist/types/src/containers/TriggerStatus/TriggerStatus.d.ts +15 -1
- package/dist/types/src/containers/TriggerStatus/TriggerStatus.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +0 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/execution-graph/execution-graph.d.ts +12 -1
- package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -1
- package/dist/types/src/execution-graph/index.d.ts +1 -1
- package/dist/types/src/execution-graph/index.d.ts.map +1 -1
- package/dist/types/src/execution-graph/pending-block-status.d.ts.map +1 -1
- package/dist/types/src/execution-graph/span-tree.d.ts +17 -0
- package/dist/types/src/execution-graph/span-tree.d.ts.map +1 -1
- package/dist/types/src/feed-logger.d.ts +1 -1
- package/dist/types/src/feed-logger.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useChatProcessor.d.ts.map +1 -1
- package/dist/types/src/hooks/useChatToolbarActions.d.ts.map +1 -1
- package/dist/types/src/hooks/useContextObjects.d.ts +1 -1
- package/dist/types/src/hooks/useContextObjects.d.ts.map +1 -1
- package/dist/types/src/hooks/useSelectionContext.d.ts +13 -0
- package/dist/types/src/hooks/useSelectionContext.d.ts.map +1 -0
- package/dist/types/src/hooks/useSelectionContext.test.d.ts +2 -0
- package/dist/types/src/hooks/useSelectionContext.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/processor/index.d.ts +1 -0
- package/dist/types/src/processor/index.d.ts.map +1 -1
- package/dist/types/src/processor/processor.d.ts +5 -2
- package/dist/types/src/processor/processor.d.ts.map +1 -1
- package/dist/types/src/processor/prompt.d.ts +18 -0
- package/dist/types/src/processor/prompt.d.ts.map +1 -0
- package/dist/types/src/processor/prompt.test.d.ts +2 -0
- package/dist/types/src/processor/prompt.test.d.ts.map +1 -0
- package/dist/types/src/processor/streaming.node.test.d.ts +2 -0
- package/dist/types/src/processor/streaming.node.test.d.ts.map +1 -0
- package/dist/types/src/skills/assistant/skill.d.ts.map +1 -1
- package/dist/types/src/templates/scaffold.d.ts +1 -1
- package/dist/types/src/templates/scaffold.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts +1 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/AssistantOperation.d.ts +2 -13
- package/dist/types/src/types/AssistantOperation.d.ts.map +1 -1
- package/dist/types/src/types/ChatSurface.d.ts +2 -2
- package/dist/types/src/types/ChatSurface.d.ts.map +1 -1
- package/dist/types/src/types/Ollama.d.ts +1 -1
- package/dist/types/src/types/Ollama.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -0
- package/package.json +106 -105
- package/src/AssistantPlugin.node.ts +1 -2
- package/src/AssistantPlugin.test.ts +60 -62
- package/src/AssistantPlugin.ts +1 -10
- package/src/AssistantPlugin.workerd.ts +1 -2
- package/src/capabilities/AssistantSurfaces.tsx +86 -0
- package/src/capabilities/agent-service.ts +1 -1
- package/src/capabilities/app-graph-builder.ts +31 -17
- package/src/capabilities/companion-chat-provisioner.ts +12 -11
- package/src/capabilities/connector.ts +3 -3
- package/src/capabilities/edge-model-resolver.ts +5 -2
- package/src/capabilities/index.ts +0 -2
- package/src/capabilities/react-surface.ts +135 -0
- package/src/capabilities/skill-definition.ts +4 -0
- package/src/capabilities/standalone-chats-query.test.ts +51 -0
- package/src/capabilities/state.ts +1 -1
- package/src/components/AgentProperties/AgentProperties.stories.tsx +6 -7
- package/src/components/AgentProperties/AgentProperties.tsx +37 -30
- package/src/components/Chat/Chat.tsx +275 -59
- package/src/components/Chat/{Chat.stories.tsx → Error.stories.tsx} +1 -1
- package/src/components/Chat/context.ts +8 -0
- package/src/components/Chat/events.ts +5 -0
- package/src/components/Chat/thread.test.ts +127 -0
- package/src/components/Chat/thread.ts +87 -0
- package/src/components/ChatPrompt/ChatActions.tsx +8 -8
- package/src/components/ChatPrompt/ChatMcpErrors.tsx +2 -2
- package/src/components/ChatPrompt/ChatOptions.stories.tsx +2 -1
- package/src/components/ChatPrompt/ChatOptions.tsx +5 -5
- package/src/components/ChatPrompt/ChatPrompt.tsx +33 -6
- package/src/components/ChatPrompt/index.ts +0 -1
- package/src/components/ChatThread/Anchor.stories.tsx +2 -1
- package/src/components/ChatThread/ChatThread.stories.tsx +99 -4
- package/src/components/ChatThread/ChatThread.tsx +34 -6
- package/src/components/ChatThread/Link.tsx +1 -0
- package/src/components/ChatThread/index.ts +2 -0
- package/src/components/ChatThread/registry.tsx +28 -4
- package/src/components/ChatThread/sync/index.ts +6 -0
- package/src/components/ChatThread/{sync.test.ts → sync/sync.test.ts} +167 -7
- package/src/components/ChatThread/{sync.ts → sync/sync.ts} +97 -3
- package/src/components/ChatThread/{tool-widget-state.ts → sync/tool-widget-state.ts} +1 -3
- package/src/components/ChatThread/widgets/BranchWidget.stories.tsx +83 -0
- package/src/components/ChatThread/widgets/BranchWidget.test.ts +55 -0
- package/src/components/ChatThread/widgets/BranchWidget.tsx +61 -0
- package/src/components/ChatThread/widgets/FallbackWidget.tsx +2 -2
- package/src/components/ChatThread/widgets/ReasoningWidget.ts +1 -1
- package/src/components/ChatThread/widgets/ReferenceWidget.ts +1 -6
- package/src/components/ChatThread/widgets/SuggestionWidget.ts +12 -3
- package/src/components/ChatThread/widgets/SummaryWidget.tsx +1 -1
- package/src/components/ChatThread/widgets/ToolWidget.tsx +15 -9
- package/src/components/ChatThread/widgets/defaults.ts +7 -1
- package/src/components/ChatThread/widgets/format-time.ts +45 -0
- package/src/components/ChatThread/widgets/index.ts +4 -1
- package/src/components/ChatThread/widgets/is-tool-message.ts +13 -0
- package/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.tsx +177 -0
- package/src/components/ConnectorAuthMenu/ConnectorAuthMenu.tsx +82 -0
- package/src/components/ConnectorAuthMenu/index.ts +5 -0
- package/src/components/ProcessTree/ProcessTree.stories.tsx +1 -1
- package/src/components/TaskList/TaskList.stories.tsx +19 -26
- package/src/components/TaskList/TaskList.tsx +32 -104
- package/src/components/ToolBlock/ToolBlock.tsx +1 -5
- package/src/components/ToolBlock/index.ts +1 -0
- package/src/components/ToolBlock/is-tool-message.ts +13 -0
- package/src/components/Toolbox/Toolbox.tsx +1 -1
- package/src/components/index.ts +1 -0
- package/src/containers/AgentArticle/AgentArticle.stories.tsx +18 -11
- package/src/containers/AgentArticle/AgentArticle.tsx +27 -151
- package/src/containers/AgentProperties/AgentProperties.tsx +21 -17
- package/src/containers/AssistantSettings/AssistantSettings.tsx +2 -0
- package/src/containers/AssistantSettings/OllamaModels.tsx +6 -4
- package/src/containers/ChatArticle/ChatArticle.stories.tsx +200 -27
- package/src/containers/ChatArticle/ChatArticle.tsx +25 -5
- package/src/containers/ChatCompanion/ChatCompanion.tsx +45 -10
- package/src/containers/ChatDialog/ChatDialog.tsx +4 -1
- package/src/containers/IntegrationPrompt/IntegrationPrompt.tsx +9 -6
- package/src/containers/SpaceHomePrompt/SpaceHomePrompt.tsx +2 -0
- package/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.tsx +40 -39
- package/src/containers/TracePanel/TracePanel.stories.tsx +9 -4
- package/src/containers/TracePanel/TracePanel.tsx +22 -6
- package/src/containers/TriggerStatus/TriggerStatus.tsx +9 -16
- package/src/containers/index.ts +0 -1
- package/src/execution-graph/SPEC.md +60 -2
- package/src/execution-graph/execution-graph.ts +15 -2
- package/src/execution-graph/index.ts +1 -0
- package/src/execution-graph/pending-block-status.ts +3 -2
- package/src/execution-graph/span-tree.test.ts +87 -1
- package/src/execution-graph/span-tree.ts +95 -0
- package/src/feed-logger.ts +6 -6
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useChatProcessor.ts +2 -1
- package/src/hooks/useChatToolbarActions.ts +22 -19
- package/src/hooks/useContextObjects.ts +9 -3
- package/src/hooks/useSelectionContext.test.ts +93 -0
- package/src/hooks/useSelectionContext.ts +72 -0
- package/src/hooks/useSkillRegistry.ts +1 -1
- package/src/hooks/useTraceMessages.ts +5 -3
- package/src/operations/create-chat.ts +2 -2
- package/src/operations/fork-chat.ts +2 -2
- package/src/operations/generate-home-suggestions.test.ts +2 -2
- package/src/operations/index.ts +0 -1
- package/src/operations/prompt.node.test.ts +1 -1
- package/src/paths.ts +3 -3
- package/src/processor/index.ts +1 -0
- package/src/processor/processor.node.test.ts +1 -1
- package/src/processor/processor.ts +33 -5
- package/src/processor/prompt.test.ts +37 -0
- package/src/processor/prompt.ts +42 -0
- package/src/processor/streaming.node.test.ts +196 -0
- package/src/skills/assistant/skill.node.test.ts +2 -2
- package/src/skills/assistant/skill.ts +3 -5
- package/src/templates/routine-templates.test.ts +1 -2
- package/src/templates/scaffold.ts +3 -3
- package/src/testing/data/trace-timeline-multiple.dx.json +1 -1
- package/src/testing/data/trace-timeline-remote.dx.json +1 -1
- package/src/testing/data/trace-timeline.dx.json +1 -2
- package/src/testing/trace-timeline.node.test.ts +3 -3
- package/src/translations.ts +11 -10
- package/src/types/AssistantCapabilities.ts +1 -1
- package/src/types/AssistantOperation.ts +8 -31
- package/src/types/ChatSurface.ts +3 -3
- package/src/types/Ollama.ts +1 -1
- package/dist/lib/neutral/AgentArticle-GV6EEW3I.mjs +0 -161
- package/dist/lib/neutral/AgentArticle-GV6EEW3I.mjs.map +0 -7
- package/dist/lib/neutral/AgentProperties-LFTEYJ54.mjs +0 -40
- package/dist/lib/neutral/AgentProperties-LFTEYJ54.mjs.map +0 -7
- package/dist/lib/neutral/AssistantPlugin.mjs +0 -10
- package/dist/lib/neutral/AssistantPlugin.mjs.map +0 -7
- package/dist/lib/neutral/AssistantPlugin.node.mjs +0 -72
- package/dist/lib/neutral/AssistantPlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/AssistantPlugin.workerd.mjs +0 -13
- package/dist/lib/neutral/AssistantPlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/AssistantSettings-3N5M5VCN.mjs +0 -302
- package/dist/lib/neutral/AssistantSettings-3N5M5VCN.mjs.map +0 -7
- package/dist/lib/neutral/ChatArticle-OO7GGEFW.mjs +0 -8
- package/dist/lib/neutral/ChatArticle-OO7GGEFW.mjs.map +0 -7
- package/dist/lib/neutral/ChatCompanion-GIFJRY6I.mjs +0 -128
- package/dist/lib/neutral/ChatCompanion-GIFJRY6I.mjs.map +0 -7
- package/dist/lib/neutral/ChatDialog-5MXN4MXS.mjs +0 -74
- package/dist/lib/neutral/ChatDialog-5MXN4MXS.mjs.map +0 -7
- package/dist/lib/neutral/IntegrationPrompt-2HJQFYJE.mjs +0 -72
- package/dist/lib/neutral/IntegrationPrompt-2HJQFYJE.mjs.map +0 -7
- package/dist/lib/neutral/PlanArticle-VPK2IYWU.mjs +0 -34
- package/dist/lib/neutral/PlanArticle-VPK2IYWU.mjs.map +0 -7
- package/dist/lib/neutral/SpaceHomePrompt-ISAB76LD.mjs +0 -114
- package/dist/lib/neutral/SpaceHomePrompt-ISAB76LD.mjs.map +0 -7
- package/dist/lib/neutral/SpaceHomeSuggestions-IDH77QQR.mjs +0 -63
- package/dist/lib/neutral/SpaceHomeSuggestions-IDH77QQR.mjs.map +0 -7
- package/dist/lib/neutral/TracePanel-JKNWADJ4.mjs +0 -12
- package/dist/lib/neutral/TracePanel-JKNWADJ4.mjs.map +0 -7
- package/dist/lib/neutral/TriggerStatus-FURRBHYA.mjs +0 -95
- package/dist/lib/neutral/TriggerStatus-FURRBHYA.mjs.map +0 -7
- package/dist/lib/neutral/agent-hydrator-OBO3RHLO.mjs +0 -23
- package/dist/lib/neutral/agent-hydrator-OBO3RHLO.mjs.map +0 -7
- package/dist/lib/neutral/agent-service-XFJ4VQMT.mjs +0 -32
- package/dist/lib/neutral/agent-service-XFJ4VQMT.mjs.map +0 -7
- package/dist/lib/neutral/ai-context-LIKJYMIN.mjs.map +0 -7
- package/dist/lib/neutral/ai-service-DM6YXWUC.mjs +0 -44
- package/dist/lib/neutral/ai-service-DM6YXWUC.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-OPVOEQY7.mjs +0 -249
- package/dist/lib/neutral/app-graph-builder-OPVOEQY7.mjs.map +0 -7
- package/dist/lib/neutral/automation-templates-MADJLXGJ.mjs +0 -97
- package/dist/lib/neutral/automation-templates-MADJLXGJ.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -47
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-5IHQ52KJ.mjs +0 -9
- package/dist/lib/neutral/chunk-5IHQ52KJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6Q4OBGIK.mjs +0 -420
- package/dist/lib/neutral/chunk-6Q4OBGIK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BXI2R4OO.mjs +0 -410
- package/dist/lib/neutral/chunk-BXI2R4OO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-CMPLPDYE.mjs +0 -30
- package/dist/lib/neutral/chunk-CMPLPDYE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GPHT3HYS.mjs +0 -8
- package/dist/lib/neutral/chunk-GPHT3HYS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HKLSFB5I.mjs +0 -90
- package/dist/lib/neutral/chunk-HKLSFB5I.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-L7AR4VTA.mjs.map +0 -7
- package/dist/lib/neutral/chunk-LS72HWMM.mjs +0 -42
- package/dist/lib/neutral/chunk-LS72HWMM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OZWZGIV2.mjs +0 -12
- package/dist/lib/neutral/chunk-OZWZGIV2.mjs.map +0 -7
- package/dist/lib/neutral/chunk-QOKLFHUS.mjs +0 -13
- package/dist/lib/neutral/chunk-QOKLFHUS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SCTHQVIJ.mjs +0 -155
- package/dist/lib/neutral/chunk-SCTHQVIJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-U4LTLBAX.mjs +0 -56
- package/dist/lib/neutral/chunk-U4LTLBAX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UPKFUZ6V.mjs +0 -115
- package/dist/lib/neutral/chunk-UPKFUZ6V.mjs.map +0 -7
- package/dist/lib/neutral/chunk-V2Y4XE3O.mjs +0 -12
- package/dist/lib/neutral/chunk-V2Y4XE3O.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VTK5R4H3.mjs +0 -9
- package/dist/lib/neutral/chunk-VTK5R4H3.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XVGEJWJX.mjs +0 -133
- package/dist/lib/neutral/chunk-XVGEJWJX.mjs.map +0 -7
- package/dist/lib/neutral/companion-chat-provisioner-IQV5VIVE.mjs +0 -126
- package/dist/lib/neutral/companion-chat-provisioner-IQV5VIVE.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -2527
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/connector-ITLLTBPZ.mjs +0 -70
- package/dist/lib/neutral/connector-ITLLTBPZ.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -31
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/create-chat-YGVZZYGP.mjs +0 -56
- package/dist/lib/neutral/create-chat-YGVZZYGP.mjs.map +0 -7
- package/dist/lib/neutral/create-object-5PAEJ6KM.mjs +0 -76
- package/dist/lib/neutral/create-object-5PAEJ6KM.mjs.map +0 -7
- package/dist/lib/neutral/edge-model-resolver-WDJWDZTT.mjs +0 -55
- package/dist/lib/neutral/edge-model-resolver-WDJWDZTT.mjs.map +0 -7
- package/dist/lib/neutral/ensure-companion-chat-AMOF3C66.mjs +0 -58
- package/dist/lib/neutral/ensure-companion-chat-AMOF3C66.mjs.map +0 -7
- package/dist/lib/neutral/execution-graph/index.mjs +0 -977
- package/dist/lib/neutral/execution-graph/index.mjs.map +0 -7
- package/dist/lib/neutral/extensions/index.mjs +0 -8
- package/dist/lib/neutral/extensions/index.mjs.map +0 -7
- package/dist/lib/neutral/fork-chat-RMAAYYQF.mjs +0 -92
- package/dist/lib/neutral/fork-chat-RMAAYYQF.mjs.map +0 -7
- package/dist/lib/neutral/generate-home-suggestions-6MM2XWPV.mjs +0 -93
- package/dist/lib/neutral/generate-home-suggestions-6MM2XWPV.mjs.map +0 -7
- package/dist/lib/neutral/hooks/index.mjs +0 -877
- package/dist/lib/neutral/hooks/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -42
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/local-model-resolver-I2BENFFS.mjs +0 -24
- package/dist/lib/neutral/local-model-resolver-I2BENFFS.mjs.map +0 -7
- package/dist/lib/neutral/markdown-extension-R4TKDTIF.mjs +0 -41
- package/dist/lib/neutral/markdown-extension-R4TKDTIF.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -12
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/migrations-7DEMVBOG.mjs +0 -28
- package/dist/lib/neutral/migrations-7DEMVBOG.mjs.map +0 -7
- package/dist/lib/neutral/navigation-resolver-PYGP2DAW.mjs +0 -18
- package/dist/lib/neutral/navigation-resolver-PYGP2DAW.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-2LEN45GP.mjs +0 -8
- package/dist/lib/neutral/operation-handler-2LEN45GP.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/plugin.workerd.mjs +0 -13
- package/dist/lib/neutral/plugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-HEJEK44F.mjs +0 -171
- package/dist/lib/neutral/react-surface-HEJEK44F.mjs.map +0 -7
- package/dist/lib/neutral/resolve-navigation-targets-PBQ3OLUE.mjs +0 -28
- package/dist/lib/neutral/resolve-navigation-targets-PBQ3OLUE.mjs.map +0 -7
- package/dist/lib/neutral/run-prompt-in-new-chat-RNUJE2FM.mjs +0 -102
- package/dist/lib/neutral/run-prompt-in-new-chat-RNUJE2FM.mjs.map +0 -7
- package/dist/lib/neutral/set-current-chat-VWBPSIMZ.mjs +0 -48
- package/dist/lib/neutral/set-current-chat-VWBPSIMZ.mjs.map +0 -7
- package/dist/lib/neutral/settings-7Q3RITIT.mjs +0 -28
- package/dist/lib/neutral/settings-7Q3RITIT.mjs.map +0 -7
- package/dist/lib/neutral/skill-definition-553MQRTR.mjs +0 -8
- package/dist/lib/neutral/skill-definition-553MQRTR.mjs.map +0 -7
- package/dist/lib/neutral/skills/index.mjs +0 -8
- package/dist/lib/neutral/skills/index.mjs.map +0 -7
- package/dist/lib/neutral/state-4LGAKSSD.mjs +0 -34
- package/dist/lib/neutral/state-4LGAKSSD.mjs.map +0 -7
- package/dist/lib/neutral/testing.mjs +0 -8
- package/dist/lib/neutral/testing.mjs.map +0 -7
- package/dist/lib/neutral/toggle-trace-panel-debug-JGTB6KVJ.mjs +0 -21
- package/dist/lib/neutral/toggle-trace-panel-debug-JGTB6KVJ.mjs.map +0 -7
- package/dist/lib/neutral/toolkit-ETWLG5NT.mjs +0 -8
- package/dist/lib/neutral/toolkit-ETWLG5NT.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -217
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -24
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/lib/neutral/update-chat-name-IJJELRR6.mjs +0 -61
- package/dist/lib/neutral/update-chat-name-IJJELRR6.mjs.map +0 -7
- package/dist/types/src/capabilities/migrations.d.ts +0 -5
- package/dist/types/src/capabilities/migrations.d.ts.map +0 -1
- package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
- package/dist/types/src/components/Chat/Chat.stories.d.ts.map +0 -1
- package/dist/types/src/components/ChatPrompt/ChatStatusIndicator.d.ts +0 -10
- package/dist/types/src/components/ChatPrompt/ChatStatusIndicator.d.ts.map +0 -1
- package/dist/types/src/components/ChatThread/sync.d.ts.map +0 -1
- package/dist/types/src/components/ChatThread/sync.test.d.ts.map +0 -1
- package/dist/types/src/components/ChatThread/tool-widget-state.d.ts.map +0 -1
- package/dist/types/src/components/ChatThread/tool-widget-state.test.d.ts.map +0 -1
- package/dist/types/src/containers/PlanArticle/PlanArticle.d.ts +0 -6
- package/dist/types/src/containers/PlanArticle/PlanArticle.d.ts.map +0 -1
- package/dist/types/src/containers/PlanArticle/index.d.ts +0 -2
- package/dist/types/src/containers/PlanArticle/index.d.ts.map +0 -1
- package/dist/types/src/hooks/useFlush.d.ts +0 -6
- package/dist/types/src/hooks/useFlush.d.ts.map +0 -1
- package/dist/types/src/operations/resolve-navigation-targets.d.ts +0 -5
- package/dist/types/src/operations/resolve-navigation-targets.d.ts.map +0 -1
- package/src/AssistantPlugin.conversations.json +0 -1
- package/src/capabilities/migrations.ts +0 -28
- package/src/capabilities/navigation-resolver.ts +0 -20
- package/src/capabilities/react-surface.tsx +0 -177
- package/src/components/ChatPrompt/ChatStatusIndicator.tsx +0 -42
- package/src/components/ChatThread/DEBUG.md +0 -64
- package/src/containers/PlanArticle/PlanArticle.tsx +0 -37
- package/src/containers/PlanArticle/index.ts +0 -5
- package/src/hooks/useFlush.ts +0 -35
- package/src/operations/resolve-navigation-targets.ts +0 -44
- /package/dist/types/src/components/ChatThread/{sync.test.d.ts → sync/sync.test.d.ts} +0 -0
- /package/dist/types/src/components/ChatThread/{tool-widget-state.d.ts → sync/tool-widget-state.d.ts} +0 -0
- /package/dist/types/src/components/ChatThread/{tool-widget-state.test.d.ts → sync/tool-widget-state.test.d.ts} +0 -0
- /package/src/components/ChatThread/{tool-widget-state.test.ts → sync/tool-widget-state.test.ts} +0 -0
|
@@ -0,0 +1,2616 @@
|
|
|
1
|
+
import { n as AiUsageQuotaError } from "./chunk-processor.mjs";
|
|
2
|
+
import { n as useChatContext, t as ChatContextProvider } from "./chunk-context.mjs";
|
|
3
|
+
import { t as TracePanel } from "./chunk-TracePanel.mjs";
|
|
4
|
+
import { Operation, Process, Project, Trigger } from "@dxos/compute";
|
|
5
|
+
import { PublicKey, URI } from "@dxos/keys";
|
|
6
|
+
import { Unit, isNonNullable, keyToFallback, safeParseJson } from "@dxos/util";
|
|
7
|
+
import { McpServer } from "@dxos/assistant-toolkit";
|
|
8
|
+
import { Feed, Filter, Obj, Query, Ref, Type } from "@dxos/echo";
|
|
9
|
+
import { meta } from "#meta";
|
|
10
|
+
import { Atom } from "@effect-atom/atom";
|
|
11
|
+
import { FeedAnnotation } from "@dxos/schema";
|
|
12
|
+
import { Message, Outline } from "@dxos/types";
|
|
13
|
+
import { Assistant, ChatSurface, ServiceType } from "#types";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import React, { Fragment, forwardRef, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { useObject, useQuery } from "@dxos/echo-react";
|
|
17
|
+
import { Button, DropdownMenu, Icon, IconBlock, IconButton, Input, Message as Message$1, MicButton, Popover, ScrollArea, Select, Tag, Toast, Tooltip, composable, composableProps, setRef, toLocalizedString, useDynamicRef, useTranslation } from "@dxos/react-ui";
|
|
18
|
+
import { Form } from "@dxos/react-ui-form";
|
|
19
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
import { RegistryContext, useAtomValue } from "@effect-atom/atom-react";
|
|
21
|
+
import { Event } from "@dxos/async";
|
|
22
|
+
import { useIdentity } from "@dxos/halo-react";
|
|
23
|
+
import { log } from "@dxos/log";
|
|
24
|
+
import { Matrix, Minimap, NumericTabs, TextCrawl, TogglePanel } from "@dxos/react-ui-components";
|
|
25
|
+
import { Menu, useGraphMenuActions } from "@dxos/react-ui-menu";
|
|
26
|
+
import { useActiveSkills, useChatKeymapExtensions, useChatToolbarActions, useContextObjects, useDebug, useFilteredTypes, useSkillHandlers, useSkills } from "#hooks";
|
|
27
|
+
import { Surface, useCapabilities, useOptionalAtomCapabilityState, useOptionalCapabilities } from "@dxos/app-framework/ui";
|
|
28
|
+
import { TranscriptionCapabilities } from "@dxos/plugin-transcription";
|
|
29
|
+
import { getStyles, mx } from "@dxos/ui-theme";
|
|
30
|
+
import { Listbox, TREEGRID_PATH_SEPARATOR, Treegrid } from "@dxos/react-ui-list";
|
|
31
|
+
import { SearchList, useSearchListResults } from "@dxos/react-ui-search";
|
|
32
|
+
import { Tabs } from "@dxos/react-ui-tabs";
|
|
33
|
+
import { ChatEditor, ChatStatus, ChatStatusIndicator, commands, formatElapsed } from "@dxos/react-ui-chat";
|
|
34
|
+
import { AnchorWidget, PendingTextStreamer, cancelPendingText, editorPendingTextSink, getXmlTextChild, pendingText, pendingTextState } from "@dxos/ui-editor";
|
|
35
|
+
import { TranscriptionCapabilities as TranscriptionCapabilities$1 } from "@dxos/plugin-transcription/types";
|
|
36
|
+
import { useAudioTrack, useTranscriber } from "@dxos/react-ui-transcription";
|
|
37
|
+
import { MarkdownStream } from "@dxos/react-ui-markdown";
|
|
38
|
+
import { JsonHighlighter } from "@dxos/react-ui-syntax-highlighter";
|
|
39
|
+
import { WidgetType } from "@codemirror/view";
|
|
40
|
+
import { Domino, mx as mx$1 } from "@dxos/ui";
|
|
41
|
+
import * as Array$1 from "effect/Array";
|
|
42
|
+
import { CONNECTOR_AUTH_GROUP_ID, Connection, Connector, connectorAuthActions } from "@dxos/plugin-connector";
|
|
43
|
+
import { Graph } from "@dxos/plugin-graph";
|
|
44
|
+
import { useActionRunner } from "@dxos/plugin-graph/hooks";
|
|
45
|
+
import * as Match from "effect/Match";
|
|
46
|
+
//#region src/components/AgentProperties/AgentProperties.tsx
|
|
47
|
+
/** Mirrors the foreign keys stamped by the agent-wizard automation compiler (`sync-automation`). */
|
|
48
|
+
var AGENT_TRIGGER_EXTENSION_KEY = "org.dxos.extension.AgentTrigger";
|
|
49
|
+
var AGENT_TRIGGER_TARGET_EXTENSION_KEY = "org.dxos.extension.AgentTriggerTarget";
|
|
50
|
+
var AgentProperties = ({ agent, onSubscriptionsChanged }) => {
|
|
51
|
+
const { t } = useTranslation(meta.profile.key);
|
|
52
|
+
const db = Obj.getDatabase(agent);
|
|
53
|
+
const subscribedObjects = useQuery(db, useMemo(() => {
|
|
54
|
+
if (!db) return Filter.nothing();
|
|
55
|
+
const feedSchemas = db.graph.registry.list().filter(Type.isType).filter((type) => {
|
|
56
|
+
const annotation = FeedAnnotation.get(Type.getSchema(type));
|
|
57
|
+
return Option.isSome(annotation) && annotation.value === true;
|
|
58
|
+
});
|
|
59
|
+
return feedSchemas.length === 0 ? Filter.nothing() : Filter.or(...feedSchemas.map((schema) => Filter.type(schema)));
|
|
60
|
+
}, [db]));
|
|
61
|
+
const triggers = useQuery(db, Filter.foreignKeys(Trigger.Trigger, [{
|
|
62
|
+
source: AGENT_TRIGGER_EXTENSION_KEY,
|
|
63
|
+
id: agent.id
|
|
64
|
+
}]));
|
|
65
|
+
const subscribedUris = useMemo(() => new Set(triggers.map((trigger) => Obj.getMeta(trigger).keys.find((key) => key.source === AGENT_TRIGGER_TARGET_EXTENSION_KEY)?.id).filter((id) => id !== void 0 && !id.startsWith("timer:"))), [triggers]);
|
|
66
|
+
const handleSubscriptionChange = useCallback((object, checked) => {
|
|
67
|
+
const next = new Set(subscribedUris);
|
|
68
|
+
const uri = Obj.getURI(object);
|
|
69
|
+
if (checked) next.add(uri);
|
|
70
|
+
else next.delete(uri);
|
|
71
|
+
onSubscriptionsChanged?.([...next].map((subscription) => Ref.fromURI(URI.make(subscription))));
|
|
72
|
+
}, [subscribedUris, onSubscriptionsChanged]);
|
|
73
|
+
if (subscribedObjects.length === 0) return null;
|
|
74
|
+
return /* @__PURE__ */ jsxs(Form.Section, { children: [/* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.Label, {
|
|
75
|
+
classNames: "mt-form-gap",
|
|
76
|
+
children: t("subscriptions.label")
|
|
77
|
+
}) }), subscribedObjects.map((object) => /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsxs("div", {
|
|
78
|
+
className: "flex items-center gap-2",
|
|
79
|
+
children: [/* @__PURE__ */ jsx(Input.Checkbox, {
|
|
80
|
+
checked: subscribedUris.has(Obj.getURI(object)),
|
|
81
|
+
onCheckedChange: (checked) => {
|
|
82
|
+
handleSubscriptionChange(object, checked === true);
|
|
83
|
+
}
|
|
84
|
+
}), /* @__PURE__ */ jsx(Input.Label, { children: Obj.getLabel(object) ?? object.id })]
|
|
85
|
+
}) }, object.id))] });
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/components/ChatPrompt/ChatActions.tsx
|
|
89
|
+
var ChatActions = ({ classNames, children, docId, microphone, processing, debug, onEvent }) => {
|
|
90
|
+
const { t } = useTranslation(meta.profile.key);
|
|
91
|
+
const transcriptionAvailable = useOptionalCapabilities(TranscriptionCapabilities.RecordingSession).length > 0;
|
|
92
|
+
const [session, setSession] = useOptionalAtomCapabilityState(TranscriptionCapabilities.RecordingSession);
|
|
93
|
+
const [settings, setSettings] = useOptionalAtomCapabilityState(TranscriptionCapabilities.Settings);
|
|
94
|
+
const recording = !!session?.recording && session.id === docId;
|
|
95
|
+
const recordMode = settings?.recordMode ?? "toggle";
|
|
96
|
+
const entityExtraction = settings?.entityExtraction !== false;
|
|
97
|
+
const selectedDeviceId = settings?.audioDeviceId ?? "";
|
|
98
|
+
const [devices, setDevices] = useState([]);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!microphone || !transcriptionAvailable || !navigator.mediaDevices?.enumerateDevices) return;
|
|
101
|
+
let cancelled = false;
|
|
102
|
+
const refresh = async () => {
|
|
103
|
+
const all = await navigator.mediaDevices.enumerateDevices();
|
|
104
|
+
if (cancelled) return;
|
|
105
|
+
setDevices(all.filter((device) => device.kind === "audioinput" && device.deviceId).map((device, index) => ({
|
|
106
|
+
deviceId: device.deviceId,
|
|
107
|
+
label: device.label || `Microphone ${index + 1}`
|
|
108
|
+
})));
|
|
109
|
+
};
|
|
110
|
+
refresh();
|
|
111
|
+
navigator.mediaDevices.addEventListener("devicechange", refresh);
|
|
112
|
+
return () => {
|
|
113
|
+
cancelled = true;
|
|
114
|
+
navigator.mediaDevices.removeEventListener("devicechange", refresh);
|
|
115
|
+
};
|
|
116
|
+
}, [microphone, transcriptionAvailable]);
|
|
117
|
+
const handleToggle = useCallback(() => {
|
|
118
|
+
if (!docId) return;
|
|
119
|
+
setSession((current) => current?.recording && current.id === docId ? null : {
|
|
120
|
+
id: docId,
|
|
121
|
+
recording: true
|
|
122
|
+
});
|
|
123
|
+
}, [setSession, docId]);
|
|
124
|
+
const handlePressStart = useCallback(() => {
|
|
125
|
+
if (!docId) return;
|
|
126
|
+
setSession(() => ({
|
|
127
|
+
id: docId,
|
|
128
|
+
recording: true
|
|
129
|
+
}));
|
|
130
|
+
}, [setSession, docId]);
|
|
131
|
+
const handlePressEnd = useCallback(() => {
|
|
132
|
+
setSession((current) => current?.id === docId ? null : current);
|
|
133
|
+
}, [setSession, docId]);
|
|
134
|
+
const handleRecordModeChange = useCallback((mode) => setSettings((current) => ({
|
|
135
|
+
...current,
|
|
136
|
+
recordMode: mode
|
|
137
|
+
})), [setSettings]);
|
|
138
|
+
const handleEntityExtractionChange = useCallback((value) => setSettings((current) => ({
|
|
139
|
+
...current,
|
|
140
|
+
entityExtraction: value
|
|
141
|
+
})), [setSettings]);
|
|
142
|
+
const handleSelectDevice = useCallback((deviceId) => setSettings((current) => ({
|
|
143
|
+
...current,
|
|
144
|
+
audioDeviceId: deviceId || void 0
|
|
145
|
+
})), [setSettings]);
|
|
146
|
+
const recordLabel = recording ? t("stop-recording.label") : recordMode === "hold" ? t("hold-to-record.label") : t("start-recording.label");
|
|
147
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
148
|
+
className: mx("flex items-center", classNames),
|
|
149
|
+
children: [
|
|
150
|
+
children,
|
|
151
|
+
microphone && docId && transcriptionAvailable && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MicButton, {
|
|
152
|
+
iconOnly: true,
|
|
153
|
+
variant: "ghost",
|
|
154
|
+
label: recordLabel,
|
|
155
|
+
recording,
|
|
156
|
+
mode: recordMode,
|
|
157
|
+
onToggle: handleToggle,
|
|
158
|
+
onPressStart: handlePressStart,
|
|
159
|
+
onPressEnd: handlePressEnd,
|
|
160
|
+
"data-testid": "assistant.record"
|
|
161
|
+
}), /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [/* @__PURE__ */ jsx(DropdownMenu.Trigger, {
|
|
162
|
+
asChild: true,
|
|
163
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
164
|
+
icon: "ph--caret-down--regular",
|
|
165
|
+
iconOnly: true,
|
|
166
|
+
label: t("recording-options.label"),
|
|
167
|
+
variant: "ghost",
|
|
168
|
+
classNames: "w-4",
|
|
169
|
+
"data-testid": "assistant.record.options"
|
|
170
|
+
})
|
|
171
|
+
}), /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [/* @__PURE__ */ jsxs(DropdownMenu.Viewport, { children: [
|
|
172
|
+
/* @__PURE__ */ jsx(DropdownMenu.GroupLabel, { children: t("record-mode.label") }),
|
|
173
|
+
/* @__PURE__ */ jsx(SettingsSelectableItem, {
|
|
174
|
+
label: t("record-mode.toggle.label"),
|
|
175
|
+
selected: recordMode === "toggle",
|
|
176
|
+
onSelect: () => handleRecordModeChange("toggle")
|
|
177
|
+
}),
|
|
178
|
+
/* @__PURE__ */ jsx(SettingsSelectableItem, {
|
|
179
|
+
label: t("record-mode.hold.label"),
|
|
180
|
+
selected: recordMode === "hold",
|
|
181
|
+
onSelect: () => handleRecordModeChange("hold")
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
|
|
184
|
+
/* @__PURE__ */ jsx(DropdownMenu.GroupLabel, { children: t("audio-device.label") }),
|
|
185
|
+
/* @__PURE__ */ jsx(SettingsSelectableItem, {
|
|
186
|
+
label: t("audio-device.default.label"),
|
|
187
|
+
selected: selectedDeviceId === "",
|
|
188
|
+
onSelect: () => handleSelectDevice("")
|
|
189
|
+
}),
|
|
190
|
+
devices.map((device) => /* @__PURE__ */ jsx(SettingsSelectableItem, {
|
|
191
|
+
label: device.label,
|
|
192
|
+
selected: selectedDeviceId === device.deviceId,
|
|
193
|
+
onSelect: () => handleSelectDevice(device.deviceId)
|
|
194
|
+
}, device.deviceId)),
|
|
195
|
+
/* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
|
|
196
|
+
/* @__PURE__ */ jsxs(DropdownMenu.CheckboxItem, {
|
|
197
|
+
checked: entityExtraction,
|
|
198
|
+
onCheckedChange: handleEntityExtractionChange,
|
|
199
|
+
classNames: "gap-2",
|
|
200
|
+
"data-testid": "assistant.entity-extraction",
|
|
201
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
202
|
+
className: "grow truncate",
|
|
203
|
+
children: t("settings.entity-extraction.label")
|
|
204
|
+
}), /* @__PURE__ */ jsx(DropdownMenu.ItemIndicator, {
|
|
205
|
+
asChild: true,
|
|
206
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
207
|
+
icon: "ph--check--regular",
|
|
208
|
+
size: 4
|
|
209
|
+
})
|
|
210
|
+
})]
|
|
211
|
+
})
|
|
212
|
+
] }), /* @__PURE__ */ jsx(DropdownMenu.Arrow, {})] }) })] })] }),
|
|
213
|
+
debug && /* @__PURE__ */ jsx(IconButton, {
|
|
214
|
+
variant: "ghost",
|
|
215
|
+
icon: "ph--wrench--regular",
|
|
216
|
+
iconOnly: true,
|
|
217
|
+
label: t("debug.button"),
|
|
218
|
+
onClick: () => onEvent?.({ type: "toggle-debug" })
|
|
219
|
+
}),
|
|
220
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
221
|
+
disabled: !processing,
|
|
222
|
+
variant: "ghost",
|
|
223
|
+
classNames: processing && "text-error-text",
|
|
224
|
+
icon: processing ? "ph--square--duotone" : "ph--square--regular",
|
|
225
|
+
iconOnly: true,
|
|
226
|
+
label: t("cancel-processing.button"),
|
|
227
|
+
onClick: () => {
|
|
228
|
+
onEvent?.({ type: "cancel" });
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
var SettingsSelectableItem = ({ label, selected, onSelect }) => /* @__PURE__ */ jsxs(DropdownMenu.Item, {
|
|
235
|
+
classNames: "gap-2",
|
|
236
|
+
role: "menuitemradio",
|
|
237
|
+
"aria-checked": selected,
|
|
238
|
+
onSelect,
|
|
239
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
240
|
+
className: "grow truncate",
|
|
241
|
+
children: label
|
|
242
|
+
}), selected && /* @__PURE__ */ jsx(Icon, {
|
|
243
|
+
icon: "ph--check--regular",
|
|
244
|
+
size: 4
|
|
245
|
+
})]
|
|
246
|
+
});
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/components/ChatPrompt/ChatMcpErrors.tsx
|
|
249
|
+
/**
|
|
250
|
+
* Inline banner that lists MCP servers that failed to connect during the most recent request.
|
|
251
|
+
* The chat itself keeps working without these servers — this just lets the user see what was dropped.
|
|
252
|
+
*/
|
|
253
|
+
var ChatMcpErrors = ({ classNames, processor }) => {
|
|
254
|
+
const { t } = useTranslation(meta.profile.key);
|
|
255
|
+
const errors = useAtomValue(processor.mcpErrors);
|
|
256
|
+
const handleDismiss = useCallback(() => {
|
|
257
|
+
processor.dismissMcpErrors();
|
|
258
|
+
}, [processor]);
|
|
259
|
+
if (errors.length === 0) return null;
|
|
260
|
+
return /* @__PURE__ */ jsxs(Message$1.Root, {
|
|
261
|
+
classNames: ["m-1", classNames],
|
|
262
|
+
valence: "warning",
|
|
263
|
+
children: [/* @__PURE__ */ jsx(Message$1.Title, {
|
|
264
|
+
onClose: handleDismiss,
|
|
265
|
+
children: t("mcp-server-error.label")
|
|
266
|
+
}), /* @__PURE__ */ jsx(Message$1.Body, {
|
|
267
|
+
asChild: true,
|
|
268
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
269
|
+
className: "flex flex-col gap-0.5 text-sm",
|
|
270
|
+
children: errors.map((error) => /* @__PURE__ */ jsxs("li", {
|
|
271
|
+
className: "truncate",
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ jsx("span", {
|
|
274
|
+
className: "font-mono",
|
|
275
|
+
children: error.url
|
|
276
|
+
}),
|
|
277
|
+
" — ",
|
|
278
|
+
/* @__PURE__ */ jsx("span", { children: error.message })
|
|
279
|
+
]
|
|
280
|
+
}, `${error.url}::${error.protocol}`))
|
|
281
|
+
})
|
|
282
|
+
})]
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
//#endregion
|
|
286
|
+
//#region src/components/ChatPrompt/ChatOptions.tsx
|
|
287
|
+
var styles$1 = {
|
|
288
|
+
panel: "w-[calc(100dvw-.5rem)] sm:w-max max-w-document-width",
|
|
289
|
+
toolbar: "p-0! gap-0! border-t border-separator"
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Manages the runtime context for the chat.
|
|
293
|
+
*/
|
|
294
|
+
var ChatOptions = ({ chat, db, context, registry, presets, preset, onPresetChange }) => {
|
|
295
|
+
const { t } = useTranslation(meta.profile.key);
|
|
296
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
297
|
+
className: "flex",
|
|
298
|
+
children: [/* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, {
|
|
299
|
+
asChild: true,
|
|
300
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
301
|
+
variant: "ghost",
|
|
302
|
+
icon: "ph--plus--regular",
|
|
303
|
+
iconOnly: true,
|
|
304
|
+
label: t("context-objects.button")
|
|
305
|
+
})
|
|
306
|
+
}), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
|
|
307
|
+
side: "top",
|
|
308
|
+
classNames: styles$1.panel,
|
|
309
|
+
children: [/* @__PURE__ */ jsx(Popover.Viewport, { children: /* @__PURE__ */ jsx(ObjectsPanel, {
|
|
310
|
+
db,
|
|
311
|
+
context
|
|
312
|
+
}) }), /* @__PURE__ */ jsx(Popover.Arrow, {})]
|
|
313
|
+
}) })] }), /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(Popover.Trigger, {
|
|
314
|
+
asChild: true,
|
|
315
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
316
|
+
variant: "ghost",
|
|
317
|
+
icon: "ph--sliders-horizontal--regular",
|
|
318
|
+
iconOnly: true,
|
|
319
|
+
label: t("context-settings.button")
|
|
320
|
+
})
|
|
321
|
+
}), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
|
|
322
|
+
side: "top",
|
|
323
|
+
classNames: styles$1.panel,
|
|
324
|
+
children: [/* @__PURE__ */ jsx(Popover.Viewport, { children: /* @__PURE__ */ jsx(Tabs.Root, {
|
|
325
|
+
asChild: true,
|
|
326
|
+
orientation: "horizontal",
|
|
327
|
+
defaultValue: "view",
|
|
328
|
+
defaultActivePart: "list",
|
|
329
|
+
tabIndex: -1,
|
|
330
|
+
children: /* @__PURE__ */ jsxs(Tabs.Viewport, {
|
|
331
|
+
classNames: mx("grid grid-rows-[1fr_40px] w-full"),
|
|
332
|
+
children: [
|
|
333
|
+
/* @__PURE__ */ jsx(Tabs.Panel, {
|
|
334
|
+
tabIndex: -1,
|
|
335
|
+
classNames: "dx-focus-ring-inset overflow-hidden",
|
|
336
|
+
value: "view",
|
|
337
|
+
children: /* @__PURE__ */ jsx(ViewPanel, { chat })
|
|
338
|
+
}),
|
|
339
|
+
/* @__PURE__ */ jsx(Tabs.Panel, {
|
|
340
|
+
tabIndex: -1,
|
|
341
|
+
classNames: "dx-focus-ring-inset overflow-hidden",
|
|
342
|
+
value: "skills",
|
|
343
|
+
children: /* @__PURE__ */ jsx(SkillsPanel, {
|
|
344
|
+
registry,
|
|
345
|
+
db,
|
|
346
|
+
context
|
|
347
|
+
})
|
|
348
|
+
}),
|
|
349
|
+
/* @__PURE__ */ jsx(Tabs.Panel, {
|
|
350
|
+
tabIndex: -1,
|
|
351
|
+
classNames: "dx-focus-ring-inset overflow-hidden",
|
|
352
|
+
value: "mcp-servers",
|
|
353
|
+
children: /* @__PURE__ */ jsx(McpServersPanel, { db })
|
|
354
|
+
}),
|
|
355
|
+
/* @__PURE__ */ jsx(Tabs.Panel, {
|
|
356
|
+
tabIndex: -1,
|
|
357
|
+
classNames: "dx-focus-ring-inset overflow-hidden",
|
|
358
|
+
value: "model",
|
|
359
|
+
children: /* @__PURE__ */ jsx(ModelsPanel, {
|
|
360
|
+
presets,
|
|
361
|
+
preset,
|
|
362
|
+
onPresetChange
|
|
363
|
+
})
|
|
364
|
+
}),
|
|
365
|
+
/* @__PURE__ */ jsxs(Tabs.Tablist, {
|
|
366
|
+
classNames: [styles$1.toolbar],
|
|
367
|
+
children: [
|
|
368
|
+
/* @__PURE__ */ jsx(Tabs.IconButton, {
|
|
369
|
+
value: "view",
|
|
370
|
+
icon: "ph--eye--regular",
|
|
371
|
+
label: t("chat-view.title")
|
|
372
|
+
}),
|
|
373
|
+
/* @__PURE__ */ jsx(Tabs.IconButton, {
|
|
374
|
+
value: "skills",
|
|
375
|
+
icon: "ph--blueprint--regular",
|
|
376
|
+
label: t("options.skills.title")
|
|
377
|
+
}),
|
|
378
|
+
/* @__PURE__ */ jsx(Tabs.IconButton, {
|
|
379
|
+
value: "mcp-servers",
|
|
380
|
+
icon: "ph--plugs-connected--regular",
|
|
381
|
+
label: t("options.mcp.title")
|
|
382
|
+
}),
|
|
383
|
+
/* @__PURE__ */ jsx(Tabs.IconButton, {
|
|
384
|
+
value: "model",
|
|
385
|
+
icon: "ph--cpu--regular",
|
|
386
|
+
label: t("options.chat-model.title")
|
|
387
|
+
})
|
|
388
|
+
]
|
|
389
|
+
})
|
|
390
|
+
]
|
|
391
|
+
})
|
|
392
|
+
}) }), /* @__PURE__ */ jsx(Popover.Arrow, {})]
|
|
393
|
+
}) })] })]
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
var SkillsPanel = ({ registry, db, context }) => {
|
|
397
|
+
const { t } = useTranslation(meta.profile.key);
|
|
398
|
+
const skills = useSkills({
|
|
399
|
+
registry,
|
|
400
|
+
db
|
|
401
|
+
});
|
|
402
|
+
const activeSkills = useActiveSkills({ context });
|
|
403
|
+
const { onUpdateSkill } = useSkillHandlers({
|
|
404
|
+
db,
|
|
405
|
+
context,
|
|
406
|
+
registry
|
|
407
|
+
});
|
|
408
|
+
const { results, handleSearch } = useSearchListResults({
|
|
409
|
+
items: skills,
|
|
410
|
+
extract: (skill) => skill.name
|
|
411
|
+
});
|
|
412
|
+
return /* @__PURE__ */ jsx(SearchList.Root, {
|
|
413
|
+
onSearch: handleSearch,
|
|
414
|
+
children: /* @__PURE__ */ jsxs(SearchList.Content, {
|
|
415
|
+
classNames: "flex flex-col",
|
|
416
|
+
children: [/* @__PURE__ */ jsx(SearchList.Viewport, { children: results.map((skill) => {
|
|
417
|
+
const skillKey = Obj.getMeta(skill).key ?? skill.id;
|
|
418
|
+
const isActive = activeSkills.has(skillKey);
|
|
419
|
+
return /* @__PURE__ */ jsx(SearchList.Item, {
|
|
420
|
+
classNames: "flex items-center overflow-hidden",
|
|
421
|
+
value: skillKey,
|
|
422
|
+
label: skill.name,
|
|
423
|
+
checked: isActive,
|
|
424
|
+
onSelect: () => onUpdateSkill?.(skillKey, !isActive)
|
|
425
|
+
}, skillKey);
|
|
426
|
+
}) }), /* @__PURE__ */ jsx(SearchList.Input, {
|
|
427
|
+
placeholder: t("search.placeholder"),
|
|
428
|
+
classNames: "border-t border-separator",
|
|
429
|
+
autoFocus: true
|
|
430
|
+
})]
|
|
431
|
+
})
|
|
432
|
+
});
|
|
433
|
+
};
|
|
434
|
+
var ViewPanel = ({ chat }) => {
|
|
435
|
+
const { t } = useTranslation(meta.profile.key);
|
|
436
|
+
const [view, setView] = useObject(chat, "viewType");
|
|
437
|
+
const value = view ?? "normal";
|
|
438
|
+
return /* @__PURE__ */ jsx(Listbox.Root, {
|
|
439
|
+
value,
|
|
440
|
+
onValueChange: setView,
|
|
441
|
+
autoFocus: true,
|
|
442
|
+
children: /* @__PURE__ */ jsx(Listbox.Content, {
|
|
443
|
+
"aria-label": t("chat-view.title"),
|
|
444
|
+
children: Assistant.ChatViews.map((view) => /* @__PURE__ */ jsxs(Listbox.Item, {
|
|
445
|
+
id: view,
|
|
446
|
+
classNames: "px-2 py-1 dx-focus-ring rounded-xs",
|
|
447
|
+
children: [/* @__PURE__ */ jsx(Listbox.ItemLabel, { children: t(`chat-view.${view}.label`, { defaultValue: view }) }), /* @__PURE__ */ jsx(Listbox.Indicator, {})]
|
|
448
|
+
}, view))
|
|
449
|
+
})
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
var ModelsPanel = ({ presets, preset, onPresetChange }) => {
|
|
453
|
+
const { t } = useTranslation(meta.profile.key);
|
|
454
|
+
return /* @__PURE__ */ jsx(Listbox.Root, {
|
|
455
|
+
value: preset,
|
|
456
|
+
onValueChange: onPresetChange,
|
|
457
|
+
autoFocus: true,
|
|
458
|
+
children: /* @__PURE__ */ jsx(Listbox.Content, {
|
|
459
|
+
"aria-label": t("options.chat-model.title"),
|
|
460
|
+
children: presets?.map(({ id, label }) => /* @__PURE__ */ jsxs(Listbox.Item, {
|
|
461
|
+
id,
|
|
462
|
+
classNames: "px-2 py-1 dx-focus-ring rounded-xs",
|
|
463
|
+
children: [/* @__PURE__ */ jsx(Listbox.ItemLabel, { children: label }), /* @__PURE__ */ jsx(Listbox.Indicator, {})]
|
|
464
|
+
}, id))
|
|
465
|
+
})
|
|
466
|
+
});
|
|
467
|
+
};
|
|
468
|
+
var McpServersPanel = ({ db }) => {
|
|
469
|
+
const { t } = useTranslation(meta.profile.key);
|
|
470
|
+
const servers = useQuery(db, Filter.type(McpServer.McpServer));
|
|
471
|
+
const [adding, setAdding] = useState(false);
|
|
472
|
+
const handleAdd = useCallback((name, url, protocol, apiKey) => {
|
|
473
|
+
db.add(Obj.make(McpServer.McpServer, {
|
|
474
|
+
name,
|
|
475
|
+
url,
|
|
476
|
+
protocol,
|
|
477
|
+
apiKey,
|
|
478
|
+
enabled: true
|
|
479
|
+
}));
|
|
480
|
+
setAdding(false);
|
|
481
|
+
}, [db]);
|
|
482
|
+
const handleRemove = useCallback((server) => {
|
|
483
|
+
db.remove(server);
|
|
484
|
+
}, [db]);
|
|
485
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
486
|
+
className: "p-form-chrome",
|
|
487
|
+
children: [servers.map((server) => /* @__PURE__ */ jsx(McpServerRow, {
|
|
488
|
+
server,
|
|
489
|
+
onRemove: handleRemove
|
|
490
|
+
}, server.id)), adding ? /* @__PURE__ */ jsx(McpServerForm, {
|
|
491
|
+
onSubmit: handleAdd,
|
|
492
|
+
onCancel: () => setAdding(false)
|
|
493
|
+
}) : /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(IconButton, {
|
|
494
|
+
variant: "ghost",
|
|
495
|
+
icon: "ph--plus--regular",
|
|
496
|
+
label: t("mcp-server-add.label"),
|
|
497
|
+
onClick: () => setAdding(true)
|
|
498
|
+
}) })]
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* `useQuery` returns live objects but only re-renders on result-identity changes,
|
|
503
|
+
* so we must subscribe to the per-server `enabled` field via `useObject` to keep the
|
|
504
|
+
* switch in sync with mutations made through the returned setter.
|
|
505
|
+
*/
|
|
506
|
+
var McpServerRow = ({ server, onRemove }) => {
|
|
507
|
+
const { t } = useTranslation(meta.profile.key);
|
|
508
|
+
const [enabled, setEnabled] = useObject(server, "enabled");
|
|
509
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
510
|
+
className: "flex items-center gap-2 px-form-chrome",
|
|
511
|
+
children: [
|
|
512
|
+
/* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Label, {
|
|
513
|
+
srOnly: true,
|
|
514
|
+
children: server.name
|
|
515
|
+
}), /* @__PURE__ */ jsx(Input.Switch, {
|
|
516
|
+
checked: enabled !== false,
|
|
517
|
+
onCheckedChange: (checked) => setEnabled(!!checked)
|
|
518
|
+
})] }),
|
|
519
|
+
/* @__PURE__ */ jsx("span", {
|
|
520
|
+
className: "flex-1 truncate text-sm",
|
|
521
|
+
children: server.name
|
|
522
|
+
}),
|
|
523
|
+
/* @__PURE__ */ jsx("span", {
|
|
524
|
+
className: "truncate text-xs text-description",
|
|
525
|
+
children: server.url
|
|
526
|
+
}),
|
|
527
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
528
|
+
variant: "ghost",
|
|
529
|
+
icon: "ph--x--regular",
|
|
530
|
+
iconOnly: true,
|
|
531
|
+
label: t("mcp-server-remove.label"),
|
|
532
|
+
onClick: () => onRemove(server)
|
|
533
|
+
})
|
|
534
|
+
]
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
var McpServerForm = ({ onSubmit, onCancel }) => {
|
|
538
|
+
const { t } = useTranslation(meta.profile.key);
|
|
539
|
+
const [name, setName] = useState("");
|
|
540
|
+
const [url, setUrl] = useState("");
|
|
541
|
+
const [protocol, setProtocol] = useState("sse");
|
|
542
|
+
const [apiKey, setApiKey] = useState("");
|
|
543
|
+
const canSubmit = name.trim().length > 0 && url.trim().length > 0;
|
|
544
|
+
const handleSubmit = useCallback(() => {
|
|
545
|
+
if (canSubmit) onSubmit(name.trim(), url.trim(), protocol, apiKey.trim() || void 0);
|
|
546
|
+
}, [
|
|
547
|
+
canSubmit,
|
|
548
|
+
name,
|
|
549
|
+
url,
|
|
550
|
+
protocol,
|
|
551
|
+
apiKey,
|
|
552
|
+
onSubmit
|
|
553
|
+
]);
|
|
554
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
555
|
+
className: "space-y-2 px-form-chrome",
|
|
556
|
+
children: [
|
|
557
|
+
/* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Label, {
|
|
558
|
+
srOnly: true,
|
|
559
|
+
children: t("mcp-server-name.label")
|
|
560
|
+
}), /* @__PURE__ */ jsx(Input.TextInput, {
|
|
561
|
+
placeholder: t("mcp-server-name.placeholder"),
|
|
562
|
+
value: name,
|
|
563
|
+
onChange: (event) => setName(event.target.value),
|
|
564
|
+
autoFocus: true
|
|
565
|
+
})] }),
|
|
566
|
+
/* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Label, {
|
|
567
|
+
srOnly: true,
|
|
568
|
+
children: t("mcp-server-url.label")
|
|
569
|
+
}), /* @__PURE__ */ jsx(Input.TextInput, {
|
|
570
|
+
placeholder: t("mcp-server-url.placeholder"),
|
|
571
|
+
value: url,
|
|
572
|
+
onChange: (event) => setUrl(event.target.value)
|
|
573
|
+
})] }),
|
|
574
|
+
/* @__PURE__ */ jsxs(Select.Root, {
|
|
575
|
+
value: protocol,
|
|
576
|
+
onValueChange: (value) => setProtocol(value),
|
|
577
|
+
children: [/* @__PURE__ */ jsx(Select.TriggerButton, { placeholder: t("mcp-server-protocol.label") }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Content, { children: /* @__PURE__ */ jsxs(Select.Viewport, { children: [/* @__PURE__ */ jsx(Select.Option, {
|
|
578
|
+
value: "sse",
|
|
579
|
+
children: "SSE"
|
|
580
|
+
}), /* @__PURE__ */ jsx(Select.Option, {
|
|
581
|
+
value: "http",
|
|
582
|
+
children: "HTTP"
|
|
583
|
+
})] }) }) })]
|
|
584
|
+
}),
|
|
585
|
+
/* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Label, {
|
|
586
|
+
srOnly: true,
|
|
587
|
+
children: t("mcp-server-api-key.label")
|
|
588
|
+
}), /* @__PURE__ */ jsx(Input.TextInput, {
|
|
589
|
+
type: "password",
|
|
590
|
+
placeholder: t("mcp-server-api-key.placeholder"),
|
|
591
|
+
value: apiKey,
|
|
592
|
+
onChange: (event) => setApiKey(event.target.value)
|
|
593
|
+
})] }),
|
|
594
|
+
/* @__PURE__ */ jsxs("div", {
|
|
595
|
+
className: "flex gap-2",
|
|
596
|
+
children: [/* @__PURE__ */ jsx(IconButton, {
|
|
597
|
+
variant: "ghost",
|
|
598
|
+
icon: "ph--check--regular",
|
|
599
|
+
iconOnly: true,
|
|
600
|
+
label: t("save.button"),
|
|
601
|
+
onClick: handleSubmit,
|
|
602
|
+
disabled: !canSubmit
|
|
603
|
+
}), /* @__PURE__ */ jsx(IconButton, {
|
|
604
|
+
variant: "ghost",
|
|
605
|
+
icon: "ph--x--regular",
|
|
606
|
+
iconOnly: true,
|
|
607
|
+
label: t("cancel.button"),
|
|
608
|
+
onClick: onCancel
|
|
609
|
+
})]
|
|
610
|
+
})
|
|
611
|
+
]
|
|
612
|
+
});
|
|
613
|
+
};
|
|
614
|
+
var ANY = "__any__";
|
|
615
|
+
/** @private */
|
|
616
|
+
var ObjectsPanel = ({ db, context }) => {
|
|
617
|
+
const { t } = useTranslation(meta.profile.key);
|
|
618
|
+
const types = useFilteredTypes(db);
|
|
619
|
+
const typeOptions = useMemo(() => {
|
|
620
|
+
const options = types.map((type) => {
|
|
621
|
+
const typename = Type.getTypename(type);
|
|
622
|
+
return {
|
|
623
|
+
uri: Type.getURI(type),
|
|
624
|
+
label: t("typename.label", {
|
|
625
|
+
ns: typename,
|
|
626
|
+
defaultValue: typename
|
|
627
|
+
})
|
|
628
|
+
};
|
|
629
|
+
});
|
|
630
|
+
options.sort((a, b) => a.label.localeCompare(b.label));
|
|
631
|
+
return options;
|
|
632
|
+
}, [types, t]);
|
|
633
|
+
const [selectedUri, setSelectedUri] = useState(ANY);
|
|
634
|
+
const anyFilter = useMemo(() => Filter.or(...typeOptions.map(({ uri }) => Filter.type(uri))), [typeOptions]);
|
|
635
|
+
const objects = useQuery(db, selectedUri === ANY ? anyFilter : Filter.type(selectedUri));
|
|
636
|
+
const { objects: contextObjects, onUpdateObject } = useContextObjects({
|
|
637
|
+
db,
|
|
638
|
+
context
|
|
639
|
+
});
|
|
640
|
+
const { results, handleSearch } = useSearchListResults({
|
|
641
|
+
items: objects,
|
|
642
|
+
extract: (object) => Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id
|
|
643
|
+
});
|
|
644
|
+
return /* @__PURE__ */ jsxs(SearchList.Root, {
|
|
645
|
+
onSearch: handleSearch,
|
|
646
|
+
children: [/* @__PURE__ */ jsx(SearchList.Content, {
|
|
647
|
+
classNames: "p-form-chrome [&:has([cmdk-list-sizer]:empty)]:py-0",
|
|
648
|
+
children: /* @__PURE__ */ jsx(SearchList.Viewport, { children: results.length ? results.map((object) => {
|
|
649
|
+
const isActive = contextObjects.findIndex((obj) => obj.id === object.id) !== -1;
|
|
650
|
+
const { icon, hue } = Obj.getIcon(object) ?? {
|
|
651
|
+
icon: "ph--cube--regular",
|
|
652
|
+
hue: void 0
|
|
653
|
+
};
|
|
654
|
+
const styles = hue ? getStyles(hue) : void 0;
|
|
655
|
+
return /* @__PURE__ */ jsx(SearchList.Item, {
|
|
656
|
+
classNames: "flex items-center overflow-hidden",
|
|
657
|
+
value: object.id,
|
|
658
|
+
icon,
|
|
659
|
+
iconClassNames: styles?.text,
|
|
660
|
+
label: Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id,
|
|
661
|
+
checked: isActive,
|
|
662
|
+
onSelect: () => onUpdateObject?.(Obj.getURI(object), !isActive)
|
|
663
|
+
}, object.id);
|
|
664
|
+
}) : /* @__PURE__ */ jsx(SearchList.Item, {
|
|
665
|
+
value: "__empty__",
|
|
666
|
+
label: t("no-results.message")
|
|
667
|
+
}) })
|
|
668
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
669
|
+
className: mx("flex flex-col", styles$1.toolbar),
|
|
670
|
+
children: [/* @__PURE__ */ jsxs(Select.Root, {
|
|
671
|
+
value: selectedUri === ANY ? void 0 : selectedUri,
|
|
672
|
+
onValueChange: (val) => setSelectedUri(val),
|
|
673
|
+
children: [/* @__PURE__ */ jsx(Select.TriggerButton, { placeholder: t("type-filter.placeholder") }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
674
|
+
/* @__PURE__ */ jsx(Select.ScrollUpButton, {}),
|
|
675
|
+
/* @__PURE__ */ jsxs(Select.Viewport, { children: [/* @__PURE__ */ jsx(Select.Option, {
|
|
676
|
+
value: ANY,
|
|
677
|
+
children: t("any-type-filter.label")
|
|
678
|
+
}), typeOptions.map(({ uri, label }) => /* @__PURE__ */ jsx(Select.Option, {
|
|
679
|
+
value: uri,
|
|
680
|
+
children: label
|
|
681
|
+
}, uri))] }),
|
|
682
|
+
/* @__PURE__ */ jsx(Select.ScrollDownButton, {}),
|
|
683
|
+
/* @__PURE__ */ jsx(Select.Arrow, {})
|
|
684
|
+
] }) })]
|
|
685
|
+
}), /* @__PURE__ */ jsx(SearchList.Input, {
|
|
686
|
+
placeholder: t("search.placeholder"),
|
|
687
|
+
autoFocus: true
|
|
688
|
+
})]
|
|
689
|
+
})]
|
|
690
|
+
});
|
|
691
|
+
};
|
|
692
|
+
//#endregion
|
|
693
|
+
//#region src/components/ChatPrompt/ChatReferences.tsx
|
|
694
|
+
var ChatReferences = ({ classNames, context, db }) => {
|
|
695
|
+
const { t } = useTranslation(meta.profile.key);
|
|
696
|
+
const { objects, onUpdateObject } = useContextObjects({
|
|
697
|
+
db,
|
|
698
|
+
context
|
|
699
|
+
});
|
|
700
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
701
|
+
className: mx("flex", classNames),
|
|
702
|
+
children: objects.map((obj) => {
|
|
703
|
+
const uri = Obj.getURI(obj);
|
|
704
|
+
const typename = Obj.getTypename(obj);
|
|
705
|
+
const label = Obj.getLabel(obj) ?? (typename ? ["object-name.placeholder", { ns: typename }] : obj.id);
|
|
706
|
+
const { icon, hue } = Obj.getIcon(obj) ?? {
|
|
707
|
+
icon: DEFAULT_OBJECT_ICON,
|
|
708
|
+
hue: void 0
|
|
709
|
+
};
|
|
710
|
+
hue && getStyles(hue);
|
|
711
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
712
|
+
className: "dx-tag py-0 flex items-center gap-1",
|
|
713
|
+
"data-hue": "neutral",
|
|
714
|
+
children: [
|
|
715
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
716
|
+
icon,
|
|
717
|
+
size: 4
|
|
718
|
+
}),
|
|
719
|
+
toLocalizedString(label, t),
|
|
720
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
721
|
+
icon: "ph--x--bold",
|
|
722
|
+
iconOnly: true,
|
|
723
|
+
variant: "ghost",
|
|
724
|
+
label: t("remove-object.label"),
|
|
725
|
+
classNames: "p-0 hover:bg-transparent",
|
|
726
|
+
size: 3,
|
|
727
|
+
onClick: () => onUpdateObject?.(uri, false)
|
|
728
|
+
})
|
|
729
|
+
]
|
|
730
|
+
}, uri.toString());
|
|
731
|
+
})
|
|
732
|
+
});
|
|
733
|
+
};
|
|
734
|
+
var DEFAULT_OBJECT_ICON = "ph--cube--regular";
|
|
735
|
+
//#endregion
|
|
736
|
+
//#region src/components/ChatPrompt/useChatVoiceInput.ts
|
|
737
|
+
var RECORDER_INTERVAL_MS = 200;
|
|
738
|
+
/**
|
|
739
|
+
* Drives word-by-word streaming transcription into the chat editor via PendingTextStreamer.
|
|
740
|
+
* Reads the active RecordingSession and Settings capabilities; activates when the session id
|
|
741
|
+
* matches the given docId and the session is recording.
|
|
742
|
+
*/
|
|
743
|
+
var useChatVoiceInput = (docId, editorRef) => {
|
|
744
|
+
const { t } = useTranslation(meta.profile.key);
|
|
745
|
+
const [session] = useOptionalAtomCapabilityState(TranscriptionCapabilities$1.RecordingSession);
|
|
746
|
+
const [settings] = useOptionalAtomCapabilityState(TranscriptionCapabilities$1.Settings);
|
|
747
|
+
const active = !!session?.recording && session.id === docId;
|
|
748
|
+
const streamerRef = useRef(null);
|
|
749
|
+
useEffect(() => {
|
|
750
|
+
if (!active) return;
|
|
751
|
+
const view = editorRef.current?.view;
|
|
752
|
+
if (!view) return;
|
|
753
|
+
const streamer = new PendingTextStreamer(editorPendingTextSink(view), {
|
|
754
|
+
mode: settings?.streamMode ?? "word",
|
|
755
|
+
wordIntervalMs: settings?.wordIntervalMs ?? 80
|
|
756
|
+
});
|
|
757
|
+
streamer.start({
|
|
758
|
+
anchor: view.state.selection.main.head,
|
|
759
|
+
placeholder: t("recording.placeholder")
|
|
760
|
+
});
|
|
761
|
+
streamerRef.current = streamer;
|
|
762
|
+
return () => {
|
|
763
|
+
streamer.dispose();
|
|
764
|
+
streamerRef.current = null;
|
|
765
|
+
const currentView = editorRef.current?.view;
|
|
766
|
+
if (currentView) {
|
|
767
|
+
const pending = currentView.state.field(pendingTextState, false);
|
|
768
|
+
if (pending && pending.final.length === 0) currentView.dispatch({ effects: cancelPendingText.of() });
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
}, [
|
|
772
|
+
active,
|
|
773
|
+
settings?.streamMode,
|
|
774
|
+
settings?.wordIntervalMs
|
|
775
|
+
]);
|
|
776
|
+
const handleSegments = useCallback(async (segments) => {
|
|
777
|
+
const text = segments.map((segment) => segment.text).join(" ").trim();
|
|
778
|
+
if (text.length > 0) streamerRef.current?.push(text);
|
|
779
|
+
}, []);
|
|
780
|
+
const transcriberConfig = useMemo(() => ({ transcribeAfterChunksAmount: Math.max(1, Math.round((settings?.transcribeAfterMs ?? 4e3) / RECORDER_INTERVAL_MS)) }), [settings?.transcribeAfterMs]);
|
|
781
|
+
const recorderConfig = useMemo(() => ({ interval: RECORDER_INTERVAL_MS }), []);
|
|
782
|
+
useTranscriber({
|
|
783
|
+
audioStreamTrack: useAudioTrack(active, useMemo(() => settings?.audioDeviceId ? { deviceId: { exact: settings.audioDeviceId } } : void 0, [settings?.audioDeviceId])),
|
|
784
|
+
transcriberConfig,
|
|
785
|
+
recorderConfig,
|
|
786
|
+
onSegments: handleSegments
|
|
787
|
+
});
|
|
788
|
+
};
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region src/components/ChatPrompt/ChatPrompt.tsx
|
|
791
|
+
var ChatPrompt = ({ classNames, outline, db, chat, processor, event, online, placeholder, onPresetChange, settings = true, presets, preset, companionTo }) => {
|
|
792
|
+
const { t } = useTranslation(meta.profile.key);
|
|
793
|
+
const error = useAtomValue(processor.error).pipe(Option.getOrUndefined);
|
|
794
|
+
const streaming = useAtomValue(processor.streaming);
|
|
795
|
+
const activeRef = useDynamicRef(useAtomValue(processor.active));
|
|
796
|
+
const editorRef = useRef(null);
|
|
797
|
+
useEffect(() => {
|
|
798
|
+
return event.on((ev) => {
|
|
799
|
+
if (ev.type === "update-prompt" && !editorRef.current?.getText()?.length) {
|
|
800
|
+
editorRef.current?.setText(ev.text);
|
|
801
|
+
editorRef.current?.focus();
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
}, [event]);
|
|
805
|
+
const fallbackDocId = useId();
|
|
806
|
+
const docId = chat?.id ?? fallbackDocId;
|
|
807
|
+
useChatVoiceInput(docId, editorRef);
|
|
808
|
+
const keymapExtensions = useChatKeymapExtensions({ event });
|
|
809
|
+
const [companion] = useObject(companionTo);
|
|
810
|
+
const [instructions] = useObject(Obj.instanceOf(Project.Project, companion) ? companion.instructions : void 0);
|
|
811
|
+
const commandsRef = useDynamicRef(instructions?.commands ?? []);
|
|
812
|
+
const commandsExtension = useMemo(() => commands({ getCommands: () => commandsRef.current.map(({ sentinel, description }) => ({
|
|
813
|
+
sentinel,
|
|
814
|
+
description
|
|
815
|
+
})) }), [commandsRef]);
|
|
816
|
+
const extensions = useMemo(() => [
|
|
817
|
+
keymapExtensions,
|
|
818
|
+
pendingText(),
|
|
819
|
+
commandsExtension
|
|
820
|
+
], [keymapExtensions, commandsExtension]);
|
|
821
|
+
const handleSubmit = useCallback((text) => {
|
|
822
|
+
if (!activeRef.current) {
|
|
823
|
+
event.emit({
|
|
824
|
+
type: "submit",
|
|
825
|
+
text
|
|
826
|
+
});
|
|
827
|
+
return true;
|
|
828
|
+
}
|
|
829
|
+
}, [event]);
|
|
830
|
+
const handleEvent = useCallback((ev) => {
|
|
831
|
+
event.emit(ev);
|
|
832
|
+
}, [event]);
|
|
833
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
834
|
+
role: "group",
|
|
835
|
+
className: mx("flex flex-col w-full dx-density-md", outline && "dx-group-surface rounded-sm border border-subdued-separator transition transition-border [&:has(.cm-content:focus)]:border-separator", classNames),
|
|
836
|
+
children: [
|
|
837
|
+
/* @__PURE__ */ jsx(ChatMcpErrors, { processor }),
|
|
838
|
+
/* @__PURE__ */ jsxs("div", {
|
|
839
|
+
className: "flex p-2 gap-2",
|
|
840
|
+
children: [/* @__PURE__ */ jsx(ChatStatusIndicator, {
|
|
841
|
+
classNames: "p-1",
|
|
842
|
+
preset,
|
|
843
|
+
error,
|
|
844
|
+
processing: streaming
|
|
845
|
+
}), /* @__PURE__ */ jsx(ChatEditor, {
|
|
846
|
+
ref: editorRef,
|
|
847
|
+
autoFocus: true,
|
|
848
|
+
markdown: true,
|
|
849
|
+
lineWrapping: true,
|
|
850
|
+
classNames: "col-span-2 pt-0.5",
|
|
851
|
+
placeholder: placeholder ?? t("prompt.placeholder"),
|
|
852
|
+
extensions,
|
|
853
|
+
onSubmit: handleSubmit
|
|
854
|
+
})]
|
|
855
|
+
}),
|
|
856
|
+
db && settings && /* @__PURE__ */ jsxs("div", {
|
|
857
|
+
className: "flex items-center overflow-hidden p-1.5",
|
|
858
|
+
children: [
|
|
859
|
+
/* @__PURE__ */ jsx(ChatOptions, {
|
|
860
|
+
chat,
|
|
861
|
+
db,
|
|
862
|
+
registry: processor.registry,
|
|
863
|
+
context: processor.context,
|
|
864
|
+
preset,
|
|
865
|
+
presets,
|
|
866
|
+
onPresetChange
|
|
867
|
+
}),
|
|
868
|
+
/* @__PURE__ */ jsx("div", {
|
|
869
|
+
className: "flex h-6 grow overflow-x-auto scrollbar-none",
|
|
870
|
+
children: /* @__PURE__ */ jsx(ChatReferences, {
|
|
871
|
+
db,
|
|
872
|
+
context: processor.context
|
|
873
|
+
})
|
|
874
|
+
}),
|
|
875
|
+
/* @__PURE__ */ jsx(ChatActions, {
|
|
876
|
+
classNames: "col-span-2",
|
|
877
|
+
microphone: true,
|
|
878
|
+
docId,
|
|
879
|
+
processing: streaming,
|
|
880
|
+
onEvent: handleEvent,
|
|
881
|
+
children: online !== void 0 && /* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Label, {
|
|
882
|
+
srOnly: true,
|
|
883
|
+
children: t("online-switch.label")
|
|
884
|
+
}), /* @__PURE__ */ jsx(Input.Switch, {
|
|
885
|
+
classNames: "mx-1",
|
|
886
|
+
checked: online,
|
|
887
|
+
disabled: true
|
|
888
|
+
})] })
|
|
889
|
+
})
|
|
890
|
+
]
|
|
891
|
+
})
|
|
892
|
+
]
|
|
893
|
+
});
|
|
894
|
+
};
|
|
895
|
+
ChatPrompt.displayName = "Chat.Prompt";
|
|
896
|
+
//#endregion
|
|
897
|
+
//#region src/components/ChatPrompt/ChatStatus.tsx
|
|
898
|
+
var CHAT_STREAM_STATUS_NAME = "Chat.StreamStatus";
|
|
899
|
+
var TICK_MS = 1e3;
|
|
900
|
+
/**
|
|
901
|
+
* Live status pill rendered at the bottom of the chat thread.
|
|
902
|
+
*
|
|
903
|
+
* The block-widget host re-mounts this component each time wire's drip queue toggles
|
|
904
|
+
* (`wireDrainingEffect`) — so all visible state is derived from chat-context values that
|
|
905
|
+
* survive the unmount: the latest `stats` block on the chat context's `messages` for token counts,
|
|
906
|
+
* and `requestTiming` (start/end wall-clock timestamps) for the elapsed value.
|
|
907
|
+
*
|
|
908
|
+
* Shows:
|
|
909
|
+
* - elapsed seconds since the most recent request started (frozen at end-of-request)
|
|
910
|
+
* - last completed turn's output token count (from the most recent `stats` content block)
|
|
911
|
+
* - cumulative session total tokens across all `stats` content blocks
|
|
912
|
+
*/
|
|
913
|
+
var ChatStatus$1 = ({ classNames, icon }) => {
|
|
914
|
+
const { messages, requestTiming } = useChatContext(CHAT_STREAM_STATUS_NAME);
|
|
915
|
+
const { lastOutputTokens, sessionTotalTokens } = useMemo(() => {
|
|
916
|
+
let last;
|
|
917
|
+
let total = 0;
|
|
918
|
+
for (const message of messages) for (const block of message.blocks) if (isStats(block) && block.usage) {
|
|
919
|
+
last = block.usage.outputTokens;
|
|
920
|
+
total += block.usage.totalTokens ?? 0;
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
lastOutputTokens: last,
|
|
924
|
+
sessionTotalTokens: total
|
|
925
|
+
};
|
|
926
|
+
}, [messages]);
|
|
927
|
+
const isRunning = requestTiming != null && requestTiming.endedAt == null;
|
|
928
|
+
const show = requestTiming || lastOutputTokens || sessionTotalTokens > 0;
|
|
929
|
+
if (!show) return null;
|
|
930
|
+
return /* @__PURE__ */ jsxs(ChatStatus.Root, {
|
|
931
|
+
defaultRunning: false,
|
|
932
|
+
classNames: ["py-2 gap-2 text-sm", classNames],
|
|
933
|
+
children: [icon && /* @__PURE__ */ jsx(ChatStatus.Icon, { children: /* @__PURE__ */ jsx(Matrix, {
|
|
934
|
+
classNames: "w-5 h-5",
|
|
935
|
+
dotClassNames: "bg-primary-500",
|
|
936
|
+
dim: 4,
|
|
937
|
+
dotSize: 3,
|
|
938
|
+
count: 10,
|
|
939
|
+
interval: 500,
|
|
940
|
+
active: isRunning
|
|
941
|
+
}) }), show && /* @__PURE__ */ jsxs("div", {
|
|
942
|
+
className: "flex items-center",
|
|
943
|
+
children: [
|
|
944
|
+
requestTiming && /* @__PURE__ */ jsx(ChatStatus.Text, { children: /* @__PURE__ */ jsx(Elapsed, { timing: requestTiming }) }),
|
|
945
|
+
lastOutputTokens != null && /* @__PURE__ */ jsxs(Fragment$1, { children: [requestTiming && /* @__PURE__ */ jsx(ChatStatus.Separator, {}), /* @__PURE__ */ jsxs(ChatStatus.Text, { children: ["↓ ", Unit.Thousand(lastOutputTokens).toString()] })] }),
|
|
946
|
+
sessionTotalTokens > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [(requestTiming || lastOutputTokens != null) && /* @__PURE__ */ jsx(ChatStatus.Separator, {}), /* @__PURE__ */ jsxs(ChatStatus.Text, { children: ["Σ ", Unit.Thousand(sessionTotalTokens).toString()] })] })
|
|
947
|
+
]
|
|
948
|
+
})]
|
|
949
|
+
});
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* Wall-clock-derived elapsed display. Tick interval forces a re-render every second while
|
|
953
|
+
* the request is active so the displayed value advances; once `endedAt` is set, the value
|
|
954
|
+
* is frozen and the interval is no longer scheduled.
|
|
955
|
+
*/
|
|
956
|
+
var Elapsed = ({ timing }) => {
|
|
957
|
+
const isRunning = timing.endedAt == null;
|
|
958
|
+
const [now, setNow] = useState(Date.now());
|
|
959
|
+
useEffect(() => {
|
|
960
|
+
if (!isRunning) return;
|
|
961
|
+
const id = setInterval(() => setNow(Date.now()), TICK_MS);
|
|
962
|
+
return () => clearInterval(id);
|
|
963
|
+
}, [isRunning]);
|
|
964
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: formatElapsed((timing.endedAt ?? now) - timing.startedAt) });
|
|
965
|
+
};
|
|
966
|
+
var isStats = (block) => block._tag === "stats";
|
|
967
|
+
//#endregion
|
|
968
|
+
//#region src/components/ChatThread/sync/tool-widget-state.ts
|
|
969
|
+
/**
|
|
970
|
+
* Mirrors tool-related branches of {@link blockToMarkdown} so widget props stay in sync with message blocks.
|
|
971
|
+
*/
|
|
972
|
+
var applyToolBlockToWidgetState = (context, block) => {
|
|
973
|
+
switch (block._tag) {
|
|
974
|
+
case "toolCall":
|
|
975
|
+
context.updateWidget(block.toolCallId, { blocks: [block] });
|
|
976
|
+
break;
|
|
977
|
+
case "toolResult":
|
|
978
|
+
context.updateWidget(block.toolCallId, ({ blocks = [] } = { blocks: [] }) => ({ blocks: [...blocks, block] }));
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
/**
|
|
983
|
+
* Re-applies tool widget state after a full document replace (e.g. {@link MarkdownStreamController.setContent}),
|
|
984
|
+
* which clears accumulated widget props via `xmlTagResetEffect`.
|
|
985
|
+
*/
|
|
986
|
+
var rehydrateToolWidgetsFromMessages = (context, messages) => {
|
|
987
|
+
for (const message of messages) for (const block of message.blocks) applyToolBlockToWidgetState(context, block);
|
|
988
|
+
};
|
|
989
|
+
//#endregion
|
|
990
|
+
//#region src/components/ChatThread/sync/sync.ts
|
|
991
|
+
/**
|
|
992
|
+
* Thread context passed to renderer.
|
|
993
|
+
* This enables the renderer to "stream" content into the widget state.
|
|
994
|
+
*/
|
|
995
|
+
var MessageThreadContext = class {
|
|
996
|
+
_widgetState;
|
|
997
|
+
_handlers;
|
|
998
|
+
constructor(_widgetState, _handlers = {}) {
|
|
999
|
+
this._widgetState = _widgetState;
|
|
1000
|
+
this._handlers = _handlers;
|
|
1001
|
+
}
|
|
1002
|
+
updateWidget(id, value) {
|
|
1003
|
+
this._widgetState?.updateWidget(id, value);
|
|
1004
|
+
}
|
|
1005
|
+
getObjectLabel(_id) {
|
|
1006
|
+
return "Object";
|
|
1007
|
+
}
|
|
1008
|
+
rewind(messageId) {
|
|
1009
|
+
this._handlers.onRewind?.(messageId);
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
/**
|
|
1013
|
+
* Syncs messages with the editor.
|
|
1014
|
+
*
|
|
1015
|
+
* Reflects the AI streaming contract:
|
|
1016
|
+
* - Messages and their blocks are appended in order.
|
|
1017
|
+
* - Only the last block in `messages` may be `pending`; all earlier blocks are finalized.
|
|
1018
|
+
* - The renderer's output for a streaming block grows monotonically (see {@link BlockRenderer}).
|
|
1019
|
+
* - The document is read-only outside this syncer.
|
|
1020
|
+
*
|
|
1021
|
+
* Under those rules the syncer needs only:
|
|
1022
|
+
* - `_completed`: the flat-block index past which everything has been fully appended.
|
|
1023
|
+
* - `_trailing`: chars of the in-flight block (at index `_completed`) already appended.
|
|
1024
|
+
* - `_threadId`: identity sentinel; if `messages[0]?.id` changes, the document is replaced.
|
|
1025
|
+
*/
|
|
1026
|
+
var MessageSyncer = class {
|
|
1027
|
+
_document;
|
|
1028
|
+
_renderer;
|
|
1029
|
+
_threadId;
|
|
1030
|
+
/**
|
|
1031
|
+
* Ids of the messages rendered so far, in document order. `update` streams a suffix, so it needs to
|
|
1032
|
+
* know when the incoming list no longer extends what is on screen — a rewind drops turns, and an
|
|
1033
|
+
* append-only path would leave them rendered.
|
|
1034
|
+
*/
|
|
1035
|
+
_renderedIds = [];
|
|
1036
|
+
/** Cumulative block index (across all completed blocks in all messages). */
|
|
1037
|
+
_completed = 0;
|
|
1038
|
+
/** Chars of the in-flight block (at index `_completed`) already appended. */
|
|
1039
|
+
_trailing = 0;
|
|
1040
|
+
/** Document offset at the `_completed` boundary (length of all fully-appended blocks). */
|
|
1041
|
+
_completedOffset = 0;
|
|
1042
|
+
/** Per-message document offset ranges, keyed by message id in document order. */
|
|
1043
|
+
_spans = /* @__PURE__ */ new Map();
|
|
1044
|
+
_context;
|
|
1045
|
+
constructor(_document, _renderer, handlers = {}) {
|
|
1046
|
+
this._document = _document;
|
|
1047
|
+
this._renderer = _renderer;
|
|
1048
|
+
this._context = new MessageThreadContext(this._document, handlers);
|
|
1049
|
+
}
|
|
1050
|
+
get context() {
|
|
1051
|
+
return this._context;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Per-message document offset spans, in document order. Valid synchronously after
|
|
1055
|
+
* {@link reset} or {@link update} (the offsets are derived from the same rendered buffer
|
|
1056
|
+
* that is dispatched to the document).
|
|
1057
|
+
*/
|
|
1058
|
+
getSpans() {
|
|
1059
|
+
return Array.from(this._spans, ([id, { from, to }]) => ({
|
|
1060
|
+
id,
|
|
1061
|
+
from,
|
|
1062
|
+
to
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Replace the document with the rendering of `messages`. Use on mount, on thread switch,
|
|
1067
|
+
* and from {@link update} when it detects an identity change in `messages[0]`.
|
|
1068
|
+
*/
|
|
1069
|
+
reset(messages = []) {
|
|
1070
|
+
this._threadId = messages[0]?.id;
|
|
1071
|
+
this._renderedIds = messages.map((message) => message.id);
|
|
1072
|
+
this._completed = 0;
|
|
1073
|
+
this._trailing = 0;
|
|
1074
|
+
this._completedOffset = 0;
|
|
1075
|
+
this._spans.clear();
|
|
1076
|
+
const buffer = this._walk(messages);
|
|
1077
|
+
this._document.setContent(buffer).then(() => {
|
|
1078
|
+
rehydrateToolWidgetsFromMessages(this._context, messages);
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Whether `messages` still begins with everything already rendered, making this an append.
|
|
1083
|
+
*
|
|
1084
|
+
* A rewind removes turns from the middle or end of the thread, and the streaming path can only add
|
|
1085
|
+
* text — so anything other than an extension has to go through {@link reset}.
|
|
1086
|
+
*/
|
|
1087
|
+
#extendsRendered(messages) {
|
|
1088
|
+
if (messages.length < this._renderedIds.length) return false;
|
|
1089
|
+
return this._renderedIds.every((id, index) => messages[index]?.id === id);
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Stream the suffix of the rendered messages into the document.
|
|
1093
|
+
* Returns `true` if the document was replaced (initial mount or thread switch), `false`
|
|
1094
|
+
* if the call was a streaming append (or a no-op).
|
|
1095
|
+
*/
|
|
1096
|
+
update(messages) {
|
|
1097
|
+
if (messages[0]?.id !== this._threadId || !this.#extendsRendered(messages)) {
|
|
1098
|
+
this.reset(messages);
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
1101
|
+
this._renderedIds = messages.map((message) => message.id);
|
|
1102
|
+
const buffer = this._walk(messages);
|
|
1103
|
+
if (buffer.length > 0) this._document.append(buffer);
|
|
1104
|
+
return false;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Walk flat blocks starting at `_completed`, advancing the cursors and returning the chars
|
|
1108
|
+
* to append. Blocks before `_completed` are skipped — their renderer is never re-invoked,
|
|
1109
|
+
* which preserves single-shot side effects (e.g. tool widget state mutation).
|
|
1110
|
+
*/
|
|
1111
|
+
_walk(messages) {
|
|
1112
|
+
let buffer = "";
|
|
1113
|
+
let index = 0;
|
|
1114
|
+
let offset = this._completedOffset;
|
|
1115
|
+
outer: for (const message of messages) for (const block of message.blocks) {
|
|
1116
|
+
if (index < this._completed) {
|
|
1117
|
+
index++;
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
const rendered = this._renderer(this._context, message, block) ?? "";
|
|
1121
|
+
if (rendered.length > this._trailing) buffer += rendered.slice(this._trailing);
|
|
1122
|
+
const renderedLength = Math.max(rendered.length, this._trailing);
|
|
1123
|
+
this._saveRange(message.id, offset, offset + renderedLength);
|
|
1124
|
+
if (block.pending) {
|
|
1125
|
+
if (rendered.length > this._trailing) this._trailing = rendered.length;
|
|
1126
|
+
break outer;
|
|
1127
|
+
}
|
|
1128
|
+
this._completed = index + 1;
|
|
1129
|
+
this._trailing = 0;
|
|
1130
|
+
offset += renderedLength;
|
|
1131
|
+
this._completedOffset = offset;
|
|
1132
|
+
index++;
|
|
1133
|
+
}
|
|
1134
|
+
return buffer;
|
|
1135
|
+
}
|
|
1136
|
+
/** Record (or extend) the offset range of a message. `from` is preserved; `to` never regresses. */
|
|
1137
|
+
_saveRange(id, from, to) {
|
|
1138
|
+
const existing = this._spans.get(id);
|
|
1139
|
+
if (existing) existing.to = Math.max(existing.to, to);
|
|
1140
|
+
else this._spans.set(id, {
|
|
1141
|
+
from,
|
|
1142
|
+
to
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
//#endregion
|
|
1147
|
+
//#region src/components/ChatThread/widgets/format-time.ts
|
|
1148
|
+
/**
|
|
1149
|
+
* Relative ("5 min ago", "yesterday") within two days, absolute date beyond that. The exact
|
|
1150
|
+
* timestamp is always available via the `title` tooltip.
|
|
1151
|
+
*
|
|
1152
|
+
* Recent prompts are the ones a reader places by elapsed time; older ones by date.
|
|
1153
|
+
*/
|
|
1154
|
+
var DAY_MS = 1440 * 60 * 1e3;
|
|
1155
|
+
var formatTime = (created, now = Date.now()) => {
|
|
1156
|
+
const date = new Date(created);
|
|
1157
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1158
|
+
const elapsed = now - date.getTime();
|
|
1159
|
+
if (elapsed < 0 || elapsed >= 2 * DAY_MS) return date.toLocaleDateString(void 0, {
|
|
1160
|
+
month: "short",
|
|
1161
|
+
day: "numeric"
|
|
1162
|
+
});
|
|
1163
|
+
const format = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
|
|
1164
|
+
const minutes = Math.round(elapsed / 6e4);
|
|
1165
|
+
if (minutes < 1) return format.format(-Math.max(1, Math.round(elapsed / 1e3)), "second");
|
|
1166
|
+
if (minutes < 60) return format.format(-minutes, "minute");
|
|
1167
|
+
const hours = Math.round(minutes / 60);
|
|
1168
|
+
if (hours < 24) return format.format(-hours, "hour");
|
|
1169
|
+
return format.format(-Math.round(hours / 24), "day");
|
|
1170
|
+
};
|
|
1171
|
+
//#endregion
|
|
1172
|
+
//#region src/components/ChatThread/widgets/BranchWidget.tsx
|
|
1173
|
+
/**
|
|
1174
|
+
* Mini toolbar rendered below each user prompt, offering a soft fork ("rewind") back to that prompt
|
|
1175
|
+
* along with when it was sent.
|
|
1176
|
+
*/
|
|
1177
|
+
var BranchWidget = ({ messageId, created, context }) => {
|
|
1178
|
+
const { t } = useTranslation(meta.profile.key);
|
|
1179
|
+
const handleRewind = useCallback(() => {
|
|
1180
|
+
if (messageId) context?.rewind(messageId);
|
|
1181
|
+
}, [context, messageId]);
|
|
1182
|
+
if (!messageId) return null;
|
|
1183
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1184
|
+
role: "toolbar",
|
|
1185
|
+
className: "flex items-center p-1 gap-1 justify-end text-xs text-subdued hover:text-inherit",
|
|
1186
|
+
children: [/* @__PURE__ */ jsx(IconButton, {
|
|
1187
|
+
classNames: "min-h-0 p-1",
|
|
1188
|
+
icon: "ph--clock-counter-clockwise--regular",
|
|
1189
|
+
iconOnly: true,
|
|
1190
|
+
variant: "ghost",
|
|
1191
|
+
size: 4,
|
|
1192
|
+
label: t("rewind.label"),
|
|
1193
|
+
"data-testid": "chat.rewind",
|
|
1194
|
+
onClick: handleRewind
|
|
1195
|
+
}), created && /* @__PURE__ */ jsx("time", {
|
|
1196
|
+
dateTime: created,
|
|
1197
|
+
title: new Date(created).toLocaleString(),
|
|
1198
|
+
children: formatTime(created)
|
|
1199
|
+
})]
|
|
1200
|
+
});
|
|
1201
|
+
};
|
|
1202
|
+
//#endregion
|
|
1203
|
+
//#region src/components/ChatThread/widgets/FallbackWidget.tsx
|
|
1204
|
+
var FallbackWidget = ({ _tag, ...props }) => {
|
|
1205
|
+
return /* @__PURE__ */ jsx(TogglePanel.Root, { children: /* @__PURE__ */ jsxs(TogglePanel.Content, { children: [/* @__PURE__ */ jsx(TogglePanel.Header, {
|
|
1206
|
+
classNames: "dx-group-surface",
|
|
1207
|
+
children: _tag
|
|
1208
|
+
}), /* @__PURE__ */ jsx(TogglePanel.Body, {
|
|
1209
|
+
classNames: "dx-modal-surface",
|
|
1210
|
+
children: /* @__PURE__ */ jsx(TogglePanel.Viewport, { children: /* @__PURE__ */ jsx(JsonHighlighter, {
|
|
1211
|
+
classNames: "p-2! text-sm",
|
|
1212
|
+
data: props
|
|
1213
|
+
}) })
|
|
1214
|
+
})] }) });
|
|
1215
|
+
};
|
|
1216
|
+
FallbackWidget.displayName = "Fallback";
|
|
1217
|
+
//#endregion
|
|
1218
|
+
//#region src/components/ChatThread/widgets/defaults.ts
|
|
1219
|
+
var styles = {
|
|
1220
|
+
/**
|
|
1221
|
+
* Vertical rhythm for block widgets. Padding, never margin: CodeMirror measures a widget from its own
|
|
1222
|
+
* box, so a margin sits outside what it can see and its height model drifts from what is rendered —
|
|
1223
|
+
* the error accumulates down the document until the turn-fold gutter markers are visibly misaligned.
|
|
1224
|
+
* Note padding does not collapse between adjacent siblings the way margins do
|
|
1225
|
+
*/
|
|
1226
|
+
padding: "pt-2 pb-4",
|
|
1227
|
+
border: "border border-subdued-separator rounded-sm"
|
|
1228
|
+
};
|
|
1229
|
+
//#endregion
|
|
1230
|
+
//#region src/components/ChatThread/widgets/ReasoningWidget.ts
|
|
1231
|
+
/**
|
|
1232
|
+
* AI reasoning widget.
|
|
1233
|
+
*/
|
|
1234
|
+
var ReasoningWidget = class extends WidgetType {
|
|
1235
|
+
text;
|
|
1236
|
+
#pos;
|
|
1237
|
+
/** The timer id last registered for this instance (may differ from the map if superseded). */
|
|
1238
|
+
#ownedTimerId = null;
|
|
1239
|
+
constructor(text, pos) {
|
|
1240
|
+
super();
|
|
1241
|
+
this.text = text;
|
|
1242
|
+
this.#pos = pos === void 0 || pos === "" ? "reasoning" : String(pos);
|
|
1243
|
+
}
|
|
1244
|
+
eq(other) {
|
|
1245
|
+
return this.text === other.text && this.#pos === other.#pos;
|
|
1246
|
+
}
|
|
1247
|
+
toDOM() {
|
|
1248
|
+
return Domino.of("div").classNames(styles.padding).append(Domino.of("div").classNames("relative overflow-hidden p-px", styles.border).attributes({ "data-trail-container": "" }).append(Domino.of("div").classNames("relative z-10 dx-base-surface rounded-sm text-sm text-subdued py-1", "grid grid-cols-[24px_1fr] gap-x-0.5 items-start").append(Domino.of("div").classNames("flex h-5 w-full shrink-0 items-center justify-center self-start").append(Domino.svg("ph--brain--regular").classNames("shrink-0 size-4 opacity-70")), Domino.of("div").classNames("px-2 max-h-[5lh] overflow-y-auto dx-scrollbar-thin min-w-0").text(this.text).attributes({ "data-reasoning-text": "" })), Domino.of("div").attributes({ "data-id": this.#pos }))).root;
|
|
1249
|
+
}
|
|
1250
|
+
updateDOM(dom) {
|
|
1251
|
+
dom.querySelector("[data-reasoning-text]")?.replaceChildren(this.text);
|
|
1252
|
+
const container = dom.querySelector("[data-trail-container]");
|
|
1253
|
+
let trailHost = container?.querySelector("[data-id]");
|
|
1254
|
+
if (container && !trailHost) {
|
|
1255
|
+
trailHost = Domino.of("div").attributes({ "data-id": this.#pos }).root;
|
|
1256
|
+
container.append(trailHost);
|
|
1257
|
+
}
|
|
1258
|
+
if (trailHost?.childElementCount === 0) trailHost.append(...createTrailLayers());
|
|
1259
|
+
this.#scheduleTrailRemoval(dom);
|
|
1260
|
+
return true;
|
|
1261
|
+
}
|
|
1262
|
+
destroy(_dom) {
|
|
1263
|
+
this.#clearOwnedTrailTimer();
|
|
1264
|
+
}
|
|
1265
|
+
#scheduleTrailRemoval(dom) {
|
|
1266
|
+
const previous = trailRemovalTimers.get(this.#pos);
|
|
1267
|
+
if (previous !== void 0) clearTimeout(previous);
|
|
1268
|
+
const timerId = setTimeout(() => {
|
|
1269
|
+
if (trailRemovalTimers.get(this.#pos) !== timerId) return;
|
|
1270
|
+
trailRemovalTimers.delete(this.#pos);
|
|
1271
|
+
this.#ownedTimerId = null;
|
|
1272
|
+
dom.querySelector("[data-id]")?.remove();
|
|
1273
|
+
}, TRAIL_REMOVAL_DELAY_MS);
|
|
1274
|
+
trailRemovalTimers.set(this.#pos, timerId);
|
|
1275
|
+
this.#ownedTimerId = timerId;
|
|
1276
|
+
}
|
|
1277
|
+
#clearOwnedTrailTimer() {
|
|
1278
|
+
const active = trailRemovalTimers.get(this.#pos);
|
|
1279
|
+
if (active !== void 0 && active === this.#ownedTimerId) {
|
|
1280
|
+
clearTimeout(active);
|
|
1281
|
+
trailRemovalTimers.delete(this.#pos);
|
|
1282
|
+
}
|
|
1283
|
+
this.#ownedTimerId = null;
|
|
1284
|
+
}
|
|
1285
|
+
};
|
|
1286
|
+
var trail = [
|
|
1287
|
+
"absolute z-0 aspect-[2/1] w-16",
|
|
1288
|
+
"bg-[radial-gradient(at_100%_50%,_theme(colors.green.700),_transparent_80%)]",
|
|
1289
|
+
"[offset-anchor:100%_50%] [offset-path:border-box]"
|
|
1290
|
+
];
|
|
1291
|
+
/** Delay after the last content update before hiding the trail. */
|
|
1292
|
+
var TRAIL_REMOVAL_DELAY_MS = 1e3;
|
|
1293
|
+
/**
|
|
1294
|
+
* One pending removal timer per logical block. Streaming creates a new widget instance each tick;
|
|
1295
|
+
* `destroy` may run after the next instance has already scheduled, so we must not clear a newer timer.
|
|
1296
|
+
*/
|
|
1297
|
+
var trailRemovalTimers = /* @__PURE__ */ new Map();
|
|
1298
|
+
var createTrailLayers = () => [Domino.of("div").classNames(...trail, "animate-trail").root, Domino.of("div").classNames(...trail, "animate-trail-offset").root];
|
|
1299
|
+
//#endregion
|
|
1300
|
+
//#region src/components/ChatThread/widgets/ReferenceWidget.ts
|
|
1301
|
+
var ReferenceWidget = class extends WidgetType {
|
|
1302
|
+
text;
|
|
1303
|
+
dxn;
|
|
1304
|
+
constructor(text, dxn) {
|
|
1305
|
+
super();
|
|
1306
|
+
this.text = text;
|
|
1307
|
+
this.dxn = dxn;
|
|
1308
|
+
}
|
|
1309
|
+
eq(other) {
|
|
1310
|
+
return this.dxn === other.dxn;
|
|
1311
|
+
}
|
|
1312
|
+
toDOM() {
|
|
1313
|
+
return Domino.of("div").classNames(styles.padding).append(Domino.of("dx-anchor").classNames("dx-tag--anchor").attributes({ dxn: this.dxn }).text(this.text)).root;
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/components/ChatThread/widgets/SelectWidget.ts
|
|
1318
|
+
/**
|
|
1319
|
+
* Simple prompt widget.
|
|
1320
|
+
*/
|
|
1321
|
+
var SelectWidget = class extends WidgetType {
|
|
1322
|
+
options;
|
|
1323
|
+
constructor(options) {
|
|
1324
|
+
super();
|
|
1325
|
+
this.options = options;
|
|
1326
|
+
}
|
|
1327
|
+
eq(other) {
|
|
1328
|
+
return JSON.stringify(this.options) === JSON.stringify(other.options);
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* NOTE: Container must set var based on user's identity.
|
|
1332
|
+
*/
|
|
1333
|
+
toDOM() {
|
|
1334
|
+
return Domino.of("div").attributes({ role: "group" }).classNames(styles.padding, "flex flex-wrap gap-1").append(...this.options.map((option) => Domino.of("button").classNames("dx-button inline-block max-w-[100cqi]").attributes({
|
|
1335
|
+
"data-action": "submit",
|
|
1336
|
+
"data-value": option,
|
|
1337
|
+
"data-density": "md"
|
|
1338
|
+
}).text(option))).root;
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
//#endregion
|
|
1342
|
+
//#region src/components/ChatThread/widgets/StatsWidget.ts
|
|
1343
|
+
/**
|
|
1344
|
+
* Simple stats widget.
|
|
1345
|
+
*/
|
|
1346
|
+
var StatsWidget = class extends WidgetType {
|
|
1347
|
+
text;
|
|
1348
|
+
constructor(text) {
|
|
1349
|
+
super();
|
|
1350
|
+
this.text = text;
|
|
1351
|
+
}
|
|
1352
|
+
eq(other) {
|
|
1353
|
+
return this.text === other.text;
|
|
1354
|
+
}
|
|
1355
|
+
toDOM() {
|
|
1356
|
+
return Domino.of("div").classNames(styles.padding, "text-sm text-placeholder").text(this.text).root;
|
|
1357
|
+
}
|
|
1358
|
+
updateDOM(dom) {
|
|
1359
|
+
dom.textContent = this.text;
|
|
1360
|
+
return true;
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region src/components/ChatThread/widgets/StatusWidget.ts
|
|
1365
|
+
/**
|
|
1366
|
+
* AI status widget.
|
|
1367
|
+
*/
|
|
1368
|
+
var StatusWidget = class extends WidgetType {
|
|
1369
|
+
text;
|
|
1370
|
+
constructor(text) {
|
|
1371
|
+
super();
|
|
1372
|
+
this.text = text;
|
|
1373
|
+
}
|
|
1374
|
+
eq(other) {
|
|
1375
|
+
return this.text === other.text;
|
|
1376
|
+
}
|
|
1377
|
+
toDOM() {
|
|
1378
|
+
return Domino.of("div").classNames(styles.padding).append(Domino.of("div").classNames("relative overflow-hidden rounded-sm").append(Domino.of("div").classNames("grid grid-cols-[24px_1fr] gap-x-0.5 gap-y-0 items-start px-0.5 py-0.5 text-placeholder").append(Domino.of("div").classNames("flex h-5 w-full shrink-0 items-center justify-center self-start").append(Domino.svg("ph--info--regular").classNames("shrink-0 size-4 opacity-70")), Domino.of("div").classNames("relative min-w-0").append(Domino.of("div").classNames("relative z-10 rounded-sm text-sm leading-5").attributes({ "data-status-text": "" }).text(this.text))))).root;
|
|
1379
|
+
}
|
|
1380
|
+
updateDOM(dom) {
|
|
1381
|
+
dom.querySelector("[data-status-text]")?.replaceChildren(this.text);
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
//#endregion
|
|
1386
|
+
//#region src/components/ChatThread/widgets/SuggestionWidget.ts
|
|
1387
|
+
/**
|
|
1388
|
+
* Simple prompt widget.
|
|
1389
|
+
*/
|
|
1390
|
+
var SuggestionWidget = class extends WidgetType {
|
|
1391
|
+
text;
|
|
1392
|
+
constructor(text) {
|
|
1393
|
+
super();
|
|
1394
|
+
this.text = text;
|
|
1395
|
+
}
|
|
1396
|
+
eq(other) {
|
|
1397
|
+
return this.text === other.text;
|
|
1398
|
+
}
|
|
1399
|
+
toDOM() {
|
|
1400
|
+
return Domino.of("span").classNames(mx$1("inline-flex max-w-[calc(100cqi-8px)] py-1 pe-1 overflow-hidden")).append(Domino.of("button").attributes({
|
|
1401
|
+
"data-density": "md",
|
|
1402
|
+
"data-action": "submit",
|
|
1403
|
+
"data-value": this.text
|
|
1404
|
+
}).classNames(mx$1("dx-button gap-2 w-full overflow-hidden")).append(Domino.of("dx-icon").attributes({ icon: "ph--lightning--regular" }), Domino.of("span").classNames("flex-1 truncate min-w-0").text(this.text))).root;
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
//#endregion
|
|
1408
|
+
//#region src/components/ChatThread/widgets/SummaryWidget.tsx
|
|
1409
|
+
var SummaryWidget = ({ children }) => {
|
|
1410
|
+
const { t } = useTranslation(meta.profile.key);
|
|
1411
|
+
return /* @__PURE__ */ jsx(TogglePanel.Root, { children: /* @__PURE__ */ jsxs(TogglePanel.Content, {
|
|
1412
|
+
classNames: styles.border,
|
|
1413
|
+
children: [/* @__PURE__ */ jsx(TogglePanel.Header, {
|
|
1414
|
+
classNames: "text-sm dx-group-surface",
|
|
1415
|
+
children: t("summary.label")
|
|
1416
|
+
}), /* @__PURE__ */ jsx(TogglePanel.Body, { children: /* @__PURE__ */ jsx("div", {
|
|
1417
|
+
className: "p-1 text-sm text-subdued",
|
|
1418
|
+
children
|
|
1419
|
+
}) })]
|
|
1420
|
+
}) });
|
|
1421
|
+
};
|
|
1422
|
+
//#endregion
|
|
1423
|
+
//#region src/components/ChatThread/widgets/SurfaceWidget.tsx
|
|
1424
|
+
var __dxlog_file$3 = "/__w/dxos/dxos/packages/plugins/plugin-assistant/src/components/ChatThread/widgets/SurfaceWidget.tsx";
|
|
1425
|
+
/**
|
|
1426
|
+
* Renders an agent-requested UI surface (the `<surface>` content block) by dispatching to a
|
|
1427
|
+
* registered {@link ChatSurface} surface keyed on its `role`. The payload is carried as JSON in the
|
|
1428
|
+
* tag's text content; a malformed payload renders the surface with no data rather than throwing.
|
|
1429
|
+
*/
|
|
1430
|
+
var SurfaceWidget = ({ role, children }) => {
|
|
1431
|
+
const data = useMemo(() => {
|
|
1432
|
+
const raw = getXmlTextChild(children ?? []);
|
|
1433
|
+
if (!raw) return;
|
|
1434
|
+
try {
|
|
1435
|
+
const parsed = JSON.parse(raw);
|
|
1436
|
+
return parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
1437
|
+
} catch (err) {
|
|
1438
|
+
log.warn("failed to parse surface data", {
|
|
1439
|
+
raw,
|
|
1440
|
+
err
|
|
1441
|
+
}, {
|
|
1442
|
+
"~LogMeta": "~LogMeta",
|
|
1443
|
+
F: __dxlog_file$3,
|
|
1444
|
+
L: 31,
|
|
1445
|
+
S: void 0
|
|
1446
|
+
});
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
}, [children]);
|
|
1450
|
+
if (!role) return null;
|
|
1451
|
+
return /* @__PURE__ */ jsx(Surface.Surface, {
|
|
1452
|
+
type: ChatSurface,
|
|
1453
|
+
data: {
|
|
1454
|
+
role,
|
|
1455
|
+
data
|
|
1456
|
+
},
|
|
1457
|
+
limit: 1
|
|
1458
|
+
});
|
|
1459
|
+
};
|
|
1460
|
+
//#endregion
|
|
1461
|
+
//#region src/components/ChatThread/widgets/ToolWidget.tsx
|
|
1462
|
+
var ToolWidget = ({ view, blocks = [] }) => {
|
|
1463
|
+
const { t } = useTranslation(meta.profile.key);
|
|
1464
|
+
const items = useMemo(() => {
|
|
1465
|
+
let lastToolCall;
|
|
1466
|
+
const tools = [];
|
|
1467
|
+
return blocks.filter((block) => block._tag === "toolCall" || block._tag === "toolResult" || block._tag === "stats").map((block) => {
|
|
1468
|
+
switch (block._tag) {
|
|
1469
|
+
case "toolCall": {
|
|
1470
|
+
if (block.pending && lastToolCall?.block.toolCallId === block.toolCallId) return null;
|
|
1471
|
+
const tool = tools.find((tool) => tool.name === block.name);
|
|
1472
|
+
lastToolCall = {
|
|
1473
|
+
tool,
|
|
1474
|
+
block
|
|
1475
|
+
};
|
|
1476
|
+
return {
|
|
1477
|
+
title: tool?.description ?? [t("tool-call.label"), block.name].filter(Boolean).join(" "),
|
|
1478
|
+
icon: block.operationIcon,
|
|
1479
|
+
content: {
|
|
1480
|
+
...block,
|
|
1481
|
+
input: safeParseJson(block.input)
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
case "toolResult": {
|
|
1486
|
+
if (block.error) return {
|
|
1487
|
+
title: t("tool-error.label"),
|
|
1488
|
+
icon: lastToolCall?.block.operationIcon,
|
|
1489
|
+
content: block
|
|
1490
|
+
};
|
|
1491
|
+
const title = lastToolCall?.tool?.description ?? [t("tool-result.label"), lastToolCall?.block.name].filter(Boolean).join(" ");
|
|
1492
|
+
const icon = lastToolCall?.block.operationIcon;
|
|
1493
|
+
lastToolCall = void 0;
|
|
1494
|
+
return {
|
|
1495
|
+
title,
|
|
1496
|
+
icon,
|
|
1497
|
+
content: {
|
|
1498
|
+
...block,
|
|
1499
|
+
result: typeof block.result === "string" ? safeParseJson(block.result) : block.result
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
case "stats":
|
|
1504
|
+
if (!lastToolCall) return null;
|
|
1505
|
+
return {
|
|
1506
|
+
title: t("stats.label"),
|
|
1507
|
+
icon: lastToolCall.block.operationIcon,
|
|
1508
|
+
content: block
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
}).filter(isNonNullable);
|
|
1512
|
+
}, [blocks, t]);
|
|
1513
|
+
const handleChangeOpen = useCallback(() => {
|
|
1514
|
+
setTimeout(() => {
|
|
1515
|
+
view?.requestMeasure();
|
|
1516
|
+
}, 1e3);
|
|
1517
|
+
}, [view]);
|
|
1518
|
+
if (!items.length) return null;
|
|
1519
|
+
return /* @__PURE__ */ jsx(ToolPanel, {
|
|
1520
|
+
items,
|
|
1521
|
+
onChangeOpen: handleChangeOpen
|
|
1522
|
+
});
|
|
1523
|
+
};
|
|
1524
|
+
var DEFAULT_TOOL_ICON = "ph--wrench--regular";
|
|
1525
|
+
var ToolPanel = ({ items, onChangeOpen }) => {
|
|
1526
|
+
const tabsRef = useRef(null);
|
|
1527
|
+
const [selected, setSelected] = useState(0);
|
|
1528
|
+
const [open, setOpen] = useState(false);
|
|
1529
|
+
useEffect(() => {
|
|
1530
|
+
setSelected((prev) => Math.min(prev, Math.max(0, items.length - 1)));
|
|
1531
|
+
}, [items.length]);
|
|
1532
|
+
useEffect(() => {
|
|
1533
|
+
onChangeOpen?.(open);
|
|
1534
|
+
if (open) tabsRef.current?.focus();
|
|
1535
|
+
}, [open, onChangeOpen]);
|
|
1536
|
+
const handleSelect = useCallback((index) => {
|
|
1537
|
+
setSelected(index);
|
|
1538
|
+
}, []);
|
|
1539
|
+
const headerIcon = items[items.length - 1]?.icon ?? items[0]?.icon ?? DEFAULT_TOOL_ICON;
|
|
1540
|
+
return /* @__PURE__ */ jsx(TogglePanel.Root, {
|
|
1541
|
+
open,
|
|
1542
|
+
onChangeOpen: setOpen,
|
|
1543
|
+
children: /* @__PURE__ */ jsxs(TogglePanel.Content, { children: [/* @__PURE__ */ jsx(TogglePanel.Header, {
|
|
1544
|
+
classNames: "flex items-center gap-2 text-sm",
|
|
1545
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1546
|
+
className: "w-full grid grid-cols-[1fr_auto] items-center gap-2",
|
|
1547
|
+
children: [/* @__PURE__ */ jsx(TextCrawl, {
|
|
1548
|
+
classNames: "text-description",
|
|
1549
|
+
lines: items.map((item) => item.title),
|
|
1550
|
+
autoAdvance: true,
|
|
1551
|
+
greedy: true
|
|
1552
|
+
}, "status-roll"), /* @__PURE__ */ jsx(IconBlock, { children: /* @__PURE__ */ jsx(Icon, {
|
|
1553
|
+
icon: headerIcon,
|
|
1554
|
+
size: 4
|
|
1555
|
+
}) })]
|
|
1556
|
+
})
|
|
1557
|
+
}), /* @__PURE__ */ jsx(TogglePanel.Body, { children: /* @__PURE__ */ jsxs(TogglePanel.Viewport, {
|
|
1558
|
+
classNames: "grid grid-cols-[32px_1fr]",
|
|
1559
|
+
children: [/* @__PURE__ */ jsx(NumericTabs, {
|
|
1560
|
+
ref: tabsRef,
|
|
1561
|
+
classNames: "p-1",
|
|
1562
|
+
length: items.length,
|
|
1563
|
+
selected,
|
|
1564
|
+
onSelect: handleSelect
|
|
1565
|
+
}), /* @__PURE__ */ jsx(JsonHighlighter, {
|
|
1566
|
+
data: items[selected]?.content,
|
|
1567
|
+
classNames: "p-1 text-xs bg-transparent",
|
|
1568
|
+
replacer: {
|
|
1569
|
+
maxDepth: 3,
|
|
1570
|
+
maxArrayLen: 10,
|
|
1571
|
+
maxStringLen: 128
|
|
1572
|
+
}
|
|
1573
|
+
})]
|
|
1574
|
+
}) })] })
|
|
1575
|
+
});
|
|
1576
|
+
};
|
|
1577
|
+
//#endregion
|
|
1578
|
+
//#region src/components/ChatThread/registry.tsx
|
|
1579
|
+
var __dxlog_file$2 = "/__w/dxos/dxos/packages/plugins/plugin-assistant/src/components/ChatThread/registry.tsx";
|
|
1580
|
+
/**
|
|
1581
|
+
* Custom XML tags registry.
|
|
1582
|
+
*
|
|
1583
|
+
* NOTE: `<prompt>` has no widget — it is rendered via mark + line decorations
|
|
1584
|
+
* (`xmlBlockDecoration`) in MarkdownStream so the prompt text remains part of the document
|
|
1585
|
+
* and can be highlighted by `xmlFormatting`. It is still listed here so the markdown block
|
|
1586
|
+
* parser (`xmlBlockParsers`) knows to keep `<prompt>...</prompt>` as a single HTMLBlock
|
|
1587
|
+
* — otherwise an unregistered prompt opens a Paragraph that lazy-continues into the
|
|
1588
|
+
* following lines and breaks parsing of subsequent multi-line tags (e.g. a `<reasoning>`
|
|
1589
|
+
* block whose content contains an ordered list).
|
|
1590
|
+
*/
|
|
1591
|
+
var componentRegistry = {
|
|
1592
|
+
"prompt": { block: true },
|
|
1593
|
+
"link-preview": {
|
|
1594
|
+
block: false,
|
|
1595
|
+
urlSchemes: ["dxn:", "echo:"],
|
|
1596
|
+
factory: ({ label, dxn }) => typeof label === "string" && typeof dxn === "string" ? new AnchorWidget(label, dxn) : null
|
|
1597
|
+
},
|
|
1598
|
+
"synthetic": {
|
|
1599
|
+
block: true,
|
|
1600
|
+
factory: ({ children, range }) => {
|
|
1601
|
+
const text = getXmlTextChild(children);
|
|
1602
|
+
return text ? new ReasoningWidget(text, range.from) : null;
|
|
1603
|
+
}
|
|
1604
|
+
},
|
|
1605
|
+
"reasoning": {
|
|
1606
|
+
block: true,
|
|
1607
|
+
streaming: true,
|
|
1608
|
+
factory: ({ children, range }) => {
|
|
1609
|
+
const text = getXmlTextChild(children);
|
|
1610
|
+
return text ? new ReasoningWidget(text, range.from) : null;
|
|
1611
|
+
}
|
|
1612
|
+
},
|
|
1613
|
+
"reference": {
|
|
1614
|
+
block: false,
|
|
1615
|
+
factory: ({ children, ref }) => {
|
|
1616
|
+
const text = getXmlTextChild(children);
|
|
1617
|
+
return text && ref ? new ReferenceWidget(text, ref) : null;
|
|
1618
|
+
}
|
|
1619
|
+
},
|
|
1620
|
+
"select": {
|
|
1621
|
+
block: true,
|
|
1622
|
+
factory: ({ children }) => {
|
|
1623
|
+
const options = children?.map((option) => option._tag === "option" && getXmlTextChild(option.children)).filter(Boolean);
|
|
1624
|
+
return options?.length ? new SelectWidget(options) : null;
|
|
1625
|
+
}
|
|
1626
|
+
},
|
|
1627
|
+
"suggestion": {
|
|
1628
|
+
block: false,
|
|
1629
|
+
factory: ({ children }) => {
|
|
1630
|
+
const text = getXmlTextChild(children);
|
|
1631
|
+
return text ? new SuggestionWidget(text) : null;
|
|
1632
|
+
}
|
|
1633
|
+
},
|
|
1634
|
+
"stats": {
|
|
1635
|
+
block: true,
|
|
1636
|
+
factory: ({ children }) => {
|
|
1637
|
+
const text = getXmlTextChild(children);
|
|
1638
|
+
return text ? new StatsWidget(text) : null;
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1641
|
+
"status": {
|
|
1642
|
+
block: true,
|
|
1643
|
+
streaming: true,
|
|
1644
|
+
factory: ({ children }) => {
|
|
1645
|
+
const text = getXmlTextChild(children);
|
|
1646
|
+
return text ? new StatusWidget(text) : null;
|
|
1647
|
+
}
|
|
1648
|
+
},
|
|
1649
|
+
"branch": {
|
|
1650
|
+
block: true,
|
|
1651
|
+
Component: BranchWidget
|
|
1652
|
+
},
|
|
1653
|
+
"summary": {
|
|
1654
|
+
block: true,
|
|
1655
|
+
Component: SummaryWidget
|
|
1656
|
+
},
|
|
1657
|
+
"surface": {
|
|
1658
|
+
block: true,
|
|
1659
|
+
Component: SurfaceWidget
|
|
1660
|
+
},
|
|
1661
|
+
"toolCall": {
|
|
1662
|
+
block: true,
|
|
1663
|
+
Component: (props) => /* @__PURE__ */ jsx("div", {
|
|
1664
|
+
className: "py-2",
|
|
1665
|
+
children: /* @__PURE__ */ jsx(ToolWidget, { ...props })
|
|
1666
|
+
})
|
|
1667
|
+
},
|
|
1668
|
+
"toolResult": {
|
|
1669
|
+
block: true,
|
|
1670
|
+
Component: FallbackWidget
|
|
1671
|
+
},
|
|
1672
|
+
"toolkit": {
|
|
1673
|
+
block: true,
|
|
1674
|
+
Component: FallbackWidget
|
|
1675
|
+
},
|
|
1676
|
+
"json": {
|
|
1677
|
+
block: true,
|
|
1678
|
+
Component: FallbackWidget
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
/**
|
|
1682
|
+
* Create a {@link BlockRenderer} that filters blocks based on the chat view type.
|
|
1683
|
+
*
|
|
1684
|
+
* - `summary`: only user prompts.
|
|
1685
|
+
* - `normal`: user prompts + assistant text + tool calls + summary/select/suggestion/reference + status. Hides reasoning.
|
|
1686
|
+
* - `thinking`: same as normal plus reasoning.
|
|
1687
|
+
* - `debug`: renders every block (raw fallbacks visible).
|
|
1688
|
+
*/
|
|
1689
|
+
function createBlockRenderer(viewType) {
|
|
1690
|
+
return (context, message, block) => {
|
|
1691
|
+
if (!isBlockVisible(viewType, message, block)) return;
|
|
1692
|
+
let str = blockToMarkdownImpl(context, message, block);
|
|
1693
|
+
if (str && !block.pending) {
|
|
1694
|
+
if (block._tag === "suggestion") return str += " ";
|
|
1695
|
+
return str += "\n";
|
|
1696
|
+
}
|
|
1697
|
+
return str;
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
var isBlockVisible = (viewType, message, block) => {
|
|
1701
|
+
switch (viewType) {
|
|
1702
|
+
case "debug": return true;
|
|
1703
|
+
case "normal": return block._tag !== "reasoning";
|
|
1704
|
+
case "summary": return block._tag === "text" && block.disposition !== "synthetic";
|
|
1705
|
+
default: return true;
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
var blockToMarkdownImpl = (context, message, block) => {
|
|
1709
|
+
log("blockToMarkdown", { block: JSON.stringify(block) }, {
|
|
1710
|
+
"~LogMeta": "~LogMeta",
|
|
1711
|
+
F: __dxlog_file$2,
|
|
1712
|
+
L: 217,
|
|
1713
|
+
S: void 0
|
|
1714
|
+
});
|
|
1715
|
+
switch (block._tag) {
|
|
1716
|
+
case "text":
|
|
1717
|
+
if (message.sender.role === "user") if (block.disposition === "synthetic") return renderXMLBlock("synthetic", {
|
|
1718
|
+
content: block.text,
|
|
1719
|
+
pending: block.pending
|
|
1720
|
+
});
|
|
1721
|
+
else return `\n<prompt>${block.text}</prompt>\n${renderBranchToolbar(message)}\n`;
|
|
1722
|
+
else {
|
|
1723
|
+
const text = block.text.trim();
|
|
1724
|
+
if (text.length > 0) return text;
|
|
1725
|
+
}
|
|
1726
|
+
break;
|
|
1727
|
+
case "reference": {
|
|
1728
|
+
if (block.pending) return;
|
|
1729
|
+
const dxn = block.reference.uri;
|
|
1730
|
+
return `<reference ref="${dxn.toString()}">${context.getObjectLabel(dxn)}</reference>`;
|
|
1731
|
+
}
|
|
1732
|
+
case "suggestion":
|
|
1733
|
+
if (block.pending) return;
|
|
1734
|
+
return `<suggestion>${block.text}</suggestion>`;
|
|
1735
|
+
case "select":
|
|
1736
|
+
if (block.pending || block.options.length === 0) return;
|
|
1737
|
+
return `<select>${block.options.map((option) => `<option>${option}</option>`).join("")}</select>`;
|
|
1738
|
+
case "toolCall":
|
|
1739
|
+
applyToolBlockToWidgetState(context, block);
|
|
1740
|
+
return `<toolCall id="${block.toolCallId}" />`;
|
|
1741
|
+
case "toolResult":
|
|
1742
|
+
applyToolBlockToWidgetState(context, block);
|
|
1743
|
+
break;
|
|
1744
|
+
case "stats": return "";
|
|
1745
|
+
case "reasoning": {
|
|
1746
|
+
let text = block.reasoningText ?? block.redactedText;
|
|
1747
|
+
if (!text) return;
|
|
1748
|
+
return renderXMLBlock("reasoning", {
|
|
1749
|
+
content: text,
|
|
1750
|
+
pending: block.pending
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
case "summary": return renderXMLBlock("summary", {
|
|
1754
|
+
content: block.content,
|
|
1755
|
+
pending: block.pending
|
|
1756
|
+
});
|
|
1757
|
+
case "status": return renderXMLBlock("status", {
|
|
1758
|
+
content: block.statusText,
|
|
1759
|
+
pending: block.pending
|
|
1760
|
+
});
|
|
1761
|
+
case "surface":
|
|
1762
|
+
if (block.pending) return;
|
|
1763
|
+
return renderXMLBlock("surface", {
|
|
1764
|
+
content: JSON.stringify(block.data ?? {}),
|
|
1765
|
+
attributes: `role="${escapeXmlAttribute(block.role)}"`
|
|
1766
|
+
});
|
|
1767
|
+
default: return `<json id="${message.id}">\n${JSON.stringify(block)}\n</json>`;
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
/**
|
|
1771
|
+
* Mini toolbar below a user prompt: branch (soft fork) plus when the prompt was sent.
|
|
1772
|
+
* `messageId` rather than `id` because a tag's `id` attribute would shadow the widget's own id.
|
|
1773
|
+
*/
|
|
1774
|
+
var renderBranchToolbar = (message) => `<branch messageId="${escapeXmlAttribute(message.id)}" created="${escapeXmlAttribute(message.created)}" />`;
|
|
1775
|
+
/**
|
|
1776
|
+
* Escape text embedded in generated XML so the mixed XML parser does not treat `&`, `<`, `>` as markup.
|
|
1777
|
+
*/
|
|
1778
|
+
var escapeXmlTextContent = (raw) => raw.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1779
|
+
/** Escape a value embedded in a double-quoted XML attribute (e.g. a model-supplied surface role). */
|
|
1780
|
+
var escapeXmlAttribute = (raw) => escapeXmlTextContent(raw).replace(/"/g, """);
|
|
1781
|
+
var renderXMLBlock = (tag, opts) => {
|
|
1782
|
+
const content = escapeXmlTextContent((opts.content ?? "").replace(/\n\n/g, " ").trim());
|
|
1783
|
+
if (opts.pending) return `<${tag}${opts.attributes ? ` ${opts.attributes}` : ""}>${content}`;
|
|
1784
|
+
else return `<${tag}${opts.attributes ? ` ${opts.attributes}` : ""}>${content}</${tag}>`;
|
|
1785
|
+
};
|
|
1786
|
+
//#endregion
|
|
1787
|
+
//#region src/components/ChatThread/ChatThread.tsx
|
|
1788
|
+
var defaultOptions = {
|
|
1789
|
+
autoScroll: true,
|
|
1790
|
+
cursor: false,
|
|
1791
|
+
fader: false,
|
|
1792
|
+
typewriter: true
|
|
1793
|
+
};
|
|
1794
|
+
var ChatThread$1 = forwardRef(({ classNames, identity, messages = [], error, options = defaultOptions, footer, debug = false, extensions, viewType, onEvent, onSpans }, forwardedRef) => {
|
|
1795
|
+
const [controller, setController] = useState(null);
|
|
1796
|
+
const handleMarkdownStreamRef = useCallback((instance) => {
|
|
1797
|
+
setController(instance);
|
|
1798
|
+
setRef(forwardedRef, instance);
|
|
1799
|
+
}, [forwardedRef]);
|
|
1800
|
+
const userHue = useMemo(() => identity?.data?.hue || keyToFallback(identity?.identityKey ? PublicKey.fromHex(identity.identityKey) : PublicKey.random()).hue, [identity]);
|
|
1801
|
+
const initializedRef = useRef(false);
|
|
1802
|
+
useEffect(() => {
|
|
1803
|
+
if (!controller) {
|
|
1804
|
+
initializedRef.current = false;
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
controller.scrollToBottom(initializedRef.current ? "smooth" : "instant");
|
|
1808
|
+
initializedRef.current = true;
|
|
1809
|
+
}, [controller, error]);
|
|
1810
|
+
const onEventRef = useRef(onEvent);
|
|
1811
|
+
useEffect(() => {
|
|
1812
|
+
onEventRef.current = onEvent;
|
|
1813
|
+
}, [onEvent]);
|
|
1814
|
+
const handleRewind = useCallback((id) => onEventRef.current?.({
|
|
1815
|
+
type: "rewind",
|
|
1816
|
+
id
|
|
1817
|
+
}), []);
|
|
1818
|
+
const renderer = useMemo(() => createBlockRenderer(viewType), [viewType]);
|
|
1819
|
+
const syncer = useMemo(() => controller && new MessageSyncer(controller, renderer, { onRewind: handleRewind }), [
|
|
1820
|
+
controller,
|
|
1821
|
+
renderer,
|
|
1822
|
+
handleRewind
|
|
1823
|
+
]);
|
|
1824
|
+
useEffect(() => {
|
|
1825
|
+
if (!syncer) return;
|
|
1826
|
+
controller?.setContext(syncer.context);
|
|
1827
|
+
controller?.setContext(syncer.context);
|
|
1828
|
+
if (syncer.update(messages)) controller?.scrollToBottom("instant");
|
|
1829
|
+
onSpans?.(syncer.getSpans());
|
|
1830
|
+
}, [
|
|
1831
|
+
controller,
|
|
1832
|
+
syncer,
|
|
1833
|
+
messages,
|
|
1834
|
+
onSpans
|
|
1835
|
+
]);
|
|
1836
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1837
|
+
"data-hue": userHue,
|
|
1838
|
+
className: "contents",
|
|
1839
|
+
children: /* @__PURE__ */ jsx(MarkdownStream, {
|
|
1840
|
+
classNames,
|
|
1841
|
+
registry: componentRegistry,
|
|
1842
|
+
options,
|
|
1843
|
+
debug,
|
|
1844
|
+
extensions,
|
|
1845
|
+
footer,
|
|
1846
|
+
onEvent: useCallback(({ type, value }) => {
|
|
1847
|
+
switch (type) {
|
|
1848
|
+
case "submit":
|
|
1849
|
+
value && onEvent?.({
|
|
1850
|
+
type,
|
|
1851
|
+
text: value
|
|
1852
|
+
});
|
|
1853
|
+
break;
|
|
1854
|
+
}
|
|
1855
|
+
}, [onEvent]),
|
|
1856
|
+
ref: handleMarkdownStreamRef
|
|
1857
|
+
}, viewType)
|
|
1858
|
+
});
|
|
1859
|
+
});
|
|
1860
|
+
//#endregion
|
|
1861
|
+
//#region src/components/TaskList/TaskList.tsx
|
|
1862
|
+
/**
|
|
1863
|
+
* Renders the conversation's working checklist (the outline's markdown `- [ ]` lines).
|
|
1864
|
+
* Durable promoted tasks keep richer state; the checklist is the at-a-glance view.
|
|
1865
|
+
*/
|
|
1866
|
+
var TaskList = composable(({ outline, activeTitle, ...props }, forwardedRef) => {
|
|
1867
|
+
const [text] = useObject(outline.content);
|
|
1868
|
+
const items = useMemo(() => Outline.parseChecklist(text?.content ?? ""), [text?.content]);
|
|
1869
|
+
if (items.length === 0) return null;
|
|
1870
|
+
return /* @__PURE__ */ jsx(Listbox.Root, { children: /* @__PURE__ */ jsx(Listbox.Viewport, {
|
|
1871
|
+
...composableProps(props, { classNames: "dx-container" }),
|
|
1872
|
+
ref: forwardedRef,
|
|
1873
|
+
children: /* @__PURE__ */ jsx(Listbox.Content, {
|
|
1874
|
+
"aria-label": "Tasks",
|
|
1875
|
+
children: items.map((item) => /* @__PURE__ */ jsx(TaskListItem, {
|
|
1876
|
+
item,
|
|
1877
|
+
active: item.title === activeTitle
|
|
1878
|
+
}, item.title))
|
|
1879
|
+
})
|
|
1880
|
+
}) });
|
|
1881
|
+
});
|
|
1882
|
+
var TaskListItem = ({ item, active }) => {
|
|
1883
|
+
return /* @__PURE__ */ jsx(Listbox.Item, {
|
|
1884
|
+
id: item.title,
|
|
1885
|
+
classNames: "py-0",
|
|
1886
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1887
|
+
className: "flex items-center gap-2 min-w-0",
|
|
1888
|
+
children: [
|
|
1889
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
1890
|
+
icon: item.done ? "ph--check--regular" : "ph--circle--regular",
|
|
1891
|
+
classNames: item.done ? "text-success-text" : void 0,
|
|
1892
|
+
size: 4
|
|
1893
|
+
}),
|
|
1894
|
+
/* @__PURE__ */ jsx("span", {
|
|
1895
|
+
className: "sr-only",
|
|
1896
|
+
children: item.done ? "done" : "to do"
|
|
1897
|
+
}),
|
|
1898
|
+
/* @__PURE__ */ jsx("span", {
|
|
1899
|
+
className: "truncate flex-1",
|
|
1900
|
+
children: item.title
|
|
1901
|
+
}),
|
|
1902
|
+
active && /* @__PURE__ */ jsx(Tag, {
|
|
1903
|
+
hue: "info",
|
|
1904
|
+
children: "working"
|
|
1905
|
+
})
|
|
1906
|
+
]
|
|
1907
|
+
})
|
|
1908
|
+
});
|
|
1909
|
+
};
|
|
1910
|
+
//#endregion
|
|
1911
|
+
//#region src/components/Chat/thread.ts
|
|
1912
|
+
/**
|
|
1913
|
+
* Append order for {@link Feed.history}, which walks lineage positionally rather than by time.
|
|
1914
|
+
*
|
|
1915
|
+
* Position is authoritative but server-assigned: locally-written blocks — and every block until a
|
|
1916
|
+
* position authority acknowledges them — report `+Infinity`, and a query returns an unordered set, so
|
|
1917
|
+
* position alone leaves them in arbitrary order. `created` breaks those ties: sound locally, where one
|
|
1918
|
+
* conversation's messages come off one clock, and consulted only when position cannot decide.
|
|
1919
|
+
*/
|
|
1920
|
+
var byAppendOrder = (a, b) => {
|
|
1921
|
+
const positionA = Feed.getPosition(a);
|
|
1922
|
+
const positionB = Feed.getPosition(b);
|
|
1923
|
+
if (positionA !== positionB) return positionA < positionB ? -1 : 1;
|
|
1924
|
+
return a.created < b.created ? -1 : a.created > b.created ? 1 : 0;
|
|
1925
|
+
};
|
|
1926
|
+
/**
|
|
1927
|
+
* The turns a thread should render: those reachable from the feed's head, so a rewind's abandoned turns
|
|
1928
|
+
* disappear from the view exactly as they disappear from the model's history.
|
|
1929
|
+
*
|
|
1930
|
+
* A pending `rewindFrom` truncates the view to what precedes it — the rewound-to prompt and everything
|
|
1931
|
+
* after it, since the point of rewinding to a prompt is to re-ask it. The pointer is cleared by the next
|
|
1932
|
+
* append (which turns the fork into lineage), so a rewind that is never followed through stays visible
|
|
1933
|
+
* as a truncated thread with the prompt restored in the composer.
|
|
1934
|
+
*/
|
|
1935
|
+
var projectThread = ({ feedMessages, pendingMessages = [], rewindFrom }) => {
|
|
1936
|
+
const all = Array$1.dedupeWith([...feedMessages, ...pendingMessages], ({ id: a }, { id: b }) => a === b);
|
|
1937
|
+
const sorted = Array$1.sort(all, byAppendOrder);
|
|
1938
|
+
if (rewindFrom !== void 0) {
|
|
1939
|
+
const index = sorted.findIndex((message) => message.id === rewindFrom);
|
|
1940
|
+
if (index === 0) return { messages: [] };
|
|
1941
|
+
if (index > 0) return { messages: Feed.history(sorted, { head: sorted[index - 1].id }).items };
|
|
1942
|
+
}
|
|
1943
|
+
return { messages: Feed.history(sorted).items };
|
|
1944
|
+
};
|
|
1945
|
+
/**
|
|
1946
|
+
* What a rewind to `messageId` implies: the messages to discard from, and the prompt text to restore so
|
|
1947
|
+
* the user can edit and resend it.
|
|
1948
|
+
*
|
|
1949
|
+
* Returns `undefined` when the message is absent, so a stale click is a no-op rather than a truncation.
|
|
1950
|
+
*/
|
|
1951
|
+
var resolveRewind = (messages, messageId) => {
|
|
1952
|
+
const message = messages.find((candidate) => candidate.id === messageId);
|
|
1953
|
+
if (!message) return;
|
|
1954
|
+
return {
|
|
1955
|
+
rewindFrom: messageId,
|
|
1956
|
+
text: Message.extractText(message)
|
|
1957
|
+
};
|
|
1958
|
+
};
|
|
1959
|
+
//#endregion
|
|
1960
|
+
//#region src/components/Chat/Chat.tsx
|
|
1961
|
+
var __dxlog_file$1 = "/__w/dxos/dxos/packages/plugins/plugin-assistant/src/components/Chat/Chat.tsx";
|
|
1962
|
+
var ChatRoot = ({ children, chat, processor, db: dbFallback, onEvent, onSubmit, getContext, ...props }) => {
|
|
1963
|
+
const [debug, setDebug] = useState(false);
|
|
1964
|
+
const streaming = useAtomValue(processor.streaming);
|
|
1965
|
+
const requestTiming = useRequestTiming({ active: useAtomValue(processor.active) });
|
|
1966
|
+
const lastPrompt = useRef(void 0);
|
|
1967
|
+
const db = chat && Obj.getDatabase(chat) || dbFallback;
|
|
1968
|
+
const [feedSnapshot] = useObject(chat?.feed);
|
|
1969
|
+
const feed = Obj.getReactiveOrUndefined(feedSnapshot);
|
|
1970
|
+
const event = useMemo(() => new Event(), []);
|
|
1971
|
+
const [controller, setController] = useState(null);
|
|
1972
|
+
const [messageRanges, setMessageRanges] = useState([]);
|
|
1973
|
+
const feedMessages = useQuery(db, feed ? Query.select(Filter.type(Message.Message)).from(feed) : Query.select(Filter.nothing()));
|
|
1974
|
+
const pendingMessages = useAtomValue(processor.messages);
|
|
1975
|
+
const { messages } = useMemo(() => projectThread({
|
|
1976
|
+
feedMessages,
|
|
1977
|
+
pendingMessages,
|
|
1978
|
+
rewindFrom: feedSnapshot?.rewindFrom
|
|
1979
|
+
}), [
|
|
1980
|
+
feedMessages,
|
|
1981
|
+
pendingMessages,
|
|
1982
|
+
feedSnapshot?.rewindFrom
|
|
1983
|
+
]);
|
|
1984
|
+
const dump = useDebug({ processor });
|
|
1985
|
+
const error = useAtomValue(processor.error);
|
|
1986
|
+
useEffect(() => {
|
|
1987
|
+
if (Option.isSome(error)) event.emit({
|
|
1988
|
+
type: "error",
|
|
1989
|
+
error: error.value
|
|
1990
|
+
});
|
|
1991
|
+
}, [event, error]);
|
|
1992
|
+
useEffect(() => {
|
|
1993
|
+
return event.on((ev) => {
|
|
1994
|
+
switch (ev.type) {
|
|
1995
|
+
case "toggle-debug":
|
|
1996
|
+
setDebug((debug) => {
|
|
1997
|
+
if (debug) return false;
|
|
1998
|
+
else {
|
|
1999
|
+
dump();
|
|
2000
|
+
return true;
|
|
2001
|
+
}
|
|
2002
|
+
});
|
|
2003
|
+
break;
|
|
2004
|
+
case "submit": {
|
|
2005
|
+
const text = ev.text.trim();
|
|
2006
|
+
if (!streaming && text.length) {
|
|
2007
|
+
lastPrompt.current = ev.text;
|
|
2008
|
+
const context = getContext?.();
|
|
2009
|
+
Promise.resolve(onSubmit?.(text)).then(() => processor.request({
|
|
2010
|
+
message: text,
|
|
2011
|
+
context
|
|
2012
|
+
}));
|
|
2013
|
+
}
|
|
2014
|
+
break;
|
|
2015
|
+
}
|
|
2016
|
+
case "rewind": {
|
|
2017
|
+
const rewind = feed && resolveRewind(messages, ev.id);
|
|
2018
|
+
if (rewind) {
|
|
2019
|
+
Obj.update(feed, (feed) => {
|
|
2020
|
+
feed.rewindFrom = rewind.rewindFrom;
|
|
2021
|
+
});
|
|
2022
|
+
event.emit({
|
|
2023
|
+
type: "update-prompt",
|
|
2024
|
+
text: rewind.text
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
break;
|
|
2028
|
+
}
|
|
2029
|
+
case "retry":
|
|
2030
|
+
if (!streaming) processor.retry();
|
|
2031
|
+
break;
|
|
2032
|
+
case "cancel":
|
|
2033
|
+
processor.cancel();
|
|
2034
|
+
if (streaming) {
|
|
2035
|
+
if (lastPrompt.current) event.emit({
|
|
2036
|
+
type: "update-prompt",
|
|
2037
|
+
text: lastPrompt.current
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
onEvent?.(ev);
|
|
2043
|
+
});
|
|
2044
|
+
}, [
|
|
2045
|
+
event,
|
|
2046
|
+
dump,
|
|
2047
|
+
processor,
|
|
2048
|
+
streaming,
|
|
2049
|
+
onEvent,
|
|
2050
|
+
onSubmit,
|
|
2051
|
+
getContext,
|
|
2052
|
+
feed,
|
|
2053
|
+
messages
|
|
2054
|
+
]);
|
|
2055
|
+
return /* @__PURE__ */ jsx(ChatContextProvider, {
|
|
2056
|
+
debug,
|
|
2057
|
+
event,
|
|
2058
|
+
db,
|
|
2059
|
+
chat,
|
|
2060
|
+
messages,
|
|
2061
|
+
processor,
|
|
2062
|
+
requestTiming,
|
|
2063
|
+
controller,
|
|
2064
|
+
setController,
|
|
2065
|
+
messageRanges,
|
|
2066
|
+
setMessageRanges,
|
|
2067
|
+
...props,
|
|
2068
|
+
children
|
|
2069
|
+
});
|
|
2070
|
+
};
|
|
2071
|
+
ChatRoot.displayName = "Chat.Root";
|
|
2072
|
+
var useRequestTiming = ({ active }) => {
|
|
2073
|
+
const [requestTiming, setRequestTiming] = useState(null);
|
|
2074
|
+
useEffect(() => {
|
|
2075
|
+
if (active) setRequestTiming({
|
|
2076
|
+
startedAt: Date.now(),
|
|
2077
|
+
endedAt: null
|
|
2078
|
+
});
|
|
2079
|
+
else setRequestTiming((prev) => prev && prev.endedAt == null ? {
|
|
2080
|
+
...prev,
|
|
2081
|
+
endedAt: Date.now()
|
|
2082
|
+
} : prev);
|
|
2083
|
+
}, [active]);
|
|
2084
|
+
return requestTiming;
|
|
2085
|
+
};
|
|
2086
|
+
var CHAT_TOOLBAR_NAME = "Chat.Toolbar";
|
|
2087
|
+
var ChatToolbar = composable(({ children, attendableId, alwaysActive, companionTo, ...props }, forwardedRef) => {
|
|
2088
|
+
const { chat } = useChatContext(CHAT_TOOLBAR_NAME);
|
|
2089
|
+
const menuActions = useChatToolbarActions({
|
|
2090
|
+
chat,
|
|
2091
|
+
companionTo
|
|
2092
|
+
});
|
|
2093
|
+
return /* @__PURE__ */ jsx(Menu.Root, {
|
|
2094
|
+
...menuActions,
|
|
2095
|
+
attendableId,
|
|
2096
|
+
alwaysActive,
|
|
2097
|
+
children: /* @__PURE__ */ jsx(Menu.Toolbar, {
|
|
2098
|
+
...composableProps(props),
|
|
2099
|
+
ref: forwardedRef,
|
|
2100
|
+
children
|
|
2101
|
+
})
|
|
2102
|
+
});
|
|
2103
|
+
});
|
|
2104
|
+
ChatToolbar.displayName = CHAT_TOOLBAR_NAME;
|
|
2105
|
+
var CHAT_CONTENT_NAME = "Chat.Content";
|
|
2106
|
+
var ChatContent = composable(({ children, ...props }, forwardedRef) => {
|
|
2107
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2108
|
+
...composableProps(props, { classNames: "dx-expander flex flex-col" }),
|
|
2109
|
+
ref: forwardedRef,
|
|
2110
|
+
children
|
|
2111
|
+
});
|
|
2112
|
+
});
|
|
2113
|
+
ChatContent.displayName = CHAT_CONTENT_NAME;
|
|
2114
|
+
var PROMPT_SNIPPET_LINES = 3;
|
|
2115
|
+
var PROMPT_SNIPPET_CHARS = 280;
|
|
2116
|
+
var PROMPT_TITLE_CHARS = 100;
|
|
2117
|
+
/** First non-empty line of a message's text, truncated for the marker title. */
|
|
2118
|
+
var promptTitle = (message) => {
|
|
2119
|
+
const firstLine = Message.extractText(message).trim().split("\n").find((line) => line.trim().length) ?? "";
|
|
2120
|
+
return firstLine.length > PROMPT_TITLE_CHARS ? `${firstLine.slice(0, PROMPT_TITLE_CHARS)}…` : firstLine;
|
|
2121
|
+
};
|
|
2122
|
+
/** First few text lines of an assistant reply (tool calls, reasoning and status are excluded). */
|
|
2123
|
+
var replySnippet = (message) => {
|
|
2124
|
+
const text = Message.extractText(message).trim();
|
|
2125
|
+
if (!text.length) return;
|
|
2126
|
+
const snippet = text.split("\n").filter((line) => line.trim().length).slice(0, PROMPT_SNIPPET_LINES).join("\n");
|
|
2127
|
+
return snippet.length > PROMPT_SNIPPET_CHARS ? `${snippet.slice(0, PROMPT_SNIPPET_CHARS)}…` : snippet;
|
|
2128
|
+
};
|
|
2129
|
+
/**
|
|
2130
|
+
* Build one minimap marker per user-prompt turn: title = the prompt text, description = a
|
|
2131
|
+
* snippet of the following assistant reply, range = the turn's document span (prompt start →
|
|
2132
|
+
* next prompt start). Positions come from the syncer's per-message range table.
|
|
2133
|
+
*/
|
|
2134
|
+
var buildMarkers = (messages, ranges) => {
|
|
2135
|
+
const rangeById = new Map(ranges.map((range) => [range.id, range]));
|
|
2136
|
+
const markers = [];
|
|
2137
|
+
for (let index = 0; index < messages.length; index++) {
|
|
2138
|
+
const message = messages[index];
|
|
2139
|
+
if (message.sender.role !== "user") continue;
|
|
2140
|
+
const range = rangeById.get(message.id);
|
|
2141
|
+
if (!range) continue;
|
|
2142
|
+
let turnTo = range.to;
|
|
2143
|
+
let description;
|
|
2144
|
+
for (let next = index + 1; next < messages.length; next++) {
|
|
2145
|
+
const nextMessage = messages[next];
|
|
2146
|
+
const nextRange = rangeById.get(nextMessage.id);
|
|
2147
|
+
if (nextMessage.sender.role === "user") {
|
|
2148
|
+
if (nextRange) turnTo = nextRange.from;
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
if (nextRange) turnTo = nextRange.to;
|
|
2152
|
+
if (!description && nextMessage.sender.role === "assistant") description = replySnippet(nextMessage);
|
|
2153
|
+
}
|
|
2154
|
+
markers.push({
|
|
2155
|
+
id: message.id,
|
|
2156
|
+
title: promptTitle(message) || "Prompt",
|
|
2157
|
+
description,
|
|
2158
|
+
range: {
|
|
2159
|
+
from: range.from,
|
|
2160
|
+
to: turnTo
|
|
2161
|
+
}
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
return markers;
|
|
2165
|
+
};
|
|
2166
|
+
var CHAT_THREAD_NAME = "Chat.Thread";
|
|
2167
|
+
var ChatThread = ({ viewType, debug: debugProp, onViewUsage, ...props }) => {
|
|
2168
|
+
const { t } = useTranslation(meta.profile.key);
|
|
2169
|
+
const { debug, event, messages, processor, messageRanges, setController, setMessageRanges } = useChatContext(CHAT_THREAD_NAME);
|
|
2170
|
+
const extensions = useChatKeymapExtensions({ event });
|
|
2171
|
+
const identity = useIdentity();
|
|
2172
|
+
const error = useAtomValue(processor.error).pipe(Option.getOrUndefined);
|
|
2173
|
+
const [toastError, setToastError] = useState(void 0);
|
|
2174
|
+
const toastAction = toastError instanceof AiUsageQuotaError ? toastError.action : void 0;
|
|
2175
|
+
const debugView = viewType === "debug";
|
|
2176
|
+
const controllerRef = useRef(null);
|
|
2177
|
+
const handleControllerRef = useCallback((instance) => {
|
|
2178
|
+
controllerRef.current = instance;
|
|
2179
|
+
setController(instance);
|
|
2180
|
+
}, [setController]);
|
|
2181
|
+
const promptPositionsRef = useDynamicRef(useMemo(() => buildMarkers(messages, messageRanges).map((marker) => marker.range.from).sort((a, b) => a - b), [messages, messageRanges]));
|
|
2182
|
+
const navigateToPrompt = useCallback((direction) => {
|
|
2183
|
+
const controller = controllerRef.current;
|
|
2184
|
+
const positions = promptPositionsRef.current;
|
|
2185
|
+
if (!controller || !positions.length) return;
|
|
2186
|
+
const anchor = controller.getVisibleRange()?.from ?? 0;
|
|
2187
|
+
const epsilon = 2;
|
|
2188
|
+
const target = direction > 0 ? positions.find((pos) => pos > anchor + epsilon) : [...positions].reverse().find((pos) => pos < anchor - epsilon);
|
|
2189
|
+
if (target != null) controller.scrollTo(target, { y: "start" });
|
|
2190
|
+
}, [promptPositionsRef]);
|
|
2191
|
+
useEffect(() => {
|
|
2192
|
+
return event.on((event) => {
|
|
2193
|
+
switch (event.type) {
|
|
2194
|
+
case "rewind":
|
|
2195
|
+
console.log("rewind", event);
|
|
2196
|
+
break;
|
|
2197
|
+
case "submit":
|
|
2198
|
+
case "scroll-to-bottom":
|
|
2199
|
+
controllerRef.current?.scrollToBottom();
|
|
2200
|
+
break;
|
|
2201
|
+
case "nav-previous":
|
|
2202
|
+
navigateToPrompt(-1);
|
|
2203
|
+
break;
|
|
2204
|
+
case "nav-next":
|
|
2205
|
+
navigateToPrompt(1);
|
|
2206
|
+
break;
|
|
2207
|
+
case "error":
|
|
2208
|
+
setToastError(event.error);
|
|
2209
|
+
break;
|
|
2210
|
+
default: log.info("no handled", event, {
|
|
2211
|
+
"~LogMeta": "~LogMeta",
|
|
2212
|
+
F: __dxlog_file$1,
|
|
2213
|
+
L: 428,
|
|
2214
|
+
S: void 0
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
});
|
|
2218
|
+
}, [event, navigateToPrompt]);
|
|
2219
|
+
const handleEvent = useCallback((ev) => {
|
|
2220
|
+
event.emit(ev);
|
|
2221
|
+
}, [event]);
|
|
2222
|
+
if (!identity) return /* @__PURE__ */ jsx("div", { className: "dx-expander" });
|
|
2223
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ChatThread$1, {
|
|
2224
|
+
...props,
|
|
2225
|
+
identity,
|
|
2226
|
+
messages,
|
|
2227
|
+
error,
|
|
2228
|
+
debug: debugProp ?? (debug || debugView),
|
|
2229
|
+
viewType,
|
|
2230
|
+
extensions,
|
|
2231
|
+
onEvent: handleEvent,
|
|
2232
|
+
onSpans: setMessageRanges,
|
|
2233
|
+
ref: handleControllerRef
|
|
2234
|
+
}), /* @__PURE__ */ jsxs(Toast.Root, {
|
|
2235
|
+
type: "foreground",
|
|
2236
|
+
open: !!toastError,
|
|
2237
|
+
duration: 2e4,
|
|
2238
|
+
onOpenChange: (open) => !open && setToastError(void 0),
|
|
2239
|
+
children: [
|
|
2240
|
+
/* @__PURE__ */ jsx(Toast.Title, {
|
|
2241
|
+
icon: "ph--warning--regular",
|
|
2242
|
+
onClose: () => setToastError(void 0),
|
|
2243
|
+
children: t("ai-service-error.label")
|
|
2244
|
+
}),
|
|
2245
|
+
/* @__PURE__ */ jsx(Toast.Description, { children: toastError?.message }),
|
|
2246
|
+
toastAction && onViewUsage && /* @__PURE__ */ jsx(Toast.Actions, { children: /* @__PURE__ */ jsx(Toast.Action, {
|
|
2247
|
+
altText: t(toastAction.labelKey),
|
|
2248
|
+
asChild: true,
|
|
2249
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
2250
|
+
onClick: () => {
|
|
2251
|
+
setToastError(void 0);
|
|
2252
|
+
onViewUsage();
|
|
2253
|
+
},
|
|
2254
|
+
children: t(toastAction.labelKey)
|
|
2255
|
+
})
|
|
2256
|
+
}) })
|
|
2257
|
+
]
|
|
2258
|
+
})] });
|
|
2259
|
+
};
|
|
2260
|
+
ChatThread.displayName = CHAT_THREAD_NAME;
|
|
2261
|
+
var CHAT_MINIMAP_NAME = "Chat.Minimap";
|
|
2262
|
+
/**
|
|
2263
|
+
* Anchor-marker rail for the thread: one tick per user-prompt turn. Reads the shared controller
|
|
2264
|
+
* and the syncer's range table from context; clicking a tick scrolls the thread to that turn.
|
|
2265
|
+
*/
|
|
2266
|
+
var ChatMinimap = ({ classNames }) => {
|
|
2267
|
+
const { messages, messageRanges, controller } = useChatContext(CHAT_MINIMAP_NAME);
|
|
2268
|
+
const [visibleRange, setVisibleRange] = useState(void 0);
|
|
2269
|
+
useEffect(() => {
|
|
2270
|
+
if (!controller) return;
|
|
2271
|
+
return controller.onVisibleRangeChange(setVisibleRange);
|
|
2272
|
+
}, [controller]);
|
|
2273
|
+
const markers = useMemo(() => buildMarkers(messages, messageRanges), [messages, messageRanges]);
|
|
2274
|
+
const handleSelect = useCallback((marker) => {
|
|
2275
|
+
controller?.scrollTo(marker.range.from, { y: "start" });
|
|
2276
|
+
}, [controller]);
|
|
2277
|
+
if (!markers.length) return null;
|
|
2278
|
+
return /* @__PURE__ */ jsx(Minimap, {
|
|
2279
|
+
classNames,
|
|
2280
|
+
markers,
|
|
2281
|
+
visibleRange,
|
|
2282
|
+
onSelect: handleSelect
|
|
2283
|
+
});
|
|
2284
|
+
};
|
|
2285
|
+
ChatMinimap.displayName = CHAT_MINIMAP_NAME;
|
|
2286
|
+
var CHAT_PROMPT_NAME = "Chat.Prompt";
|
|
2287
|
+
var ChatPrompt$1 = (props) => {
|
|
2288
|
+
const { chat, db, processor, event } = useChatContext(CHAT_PROMPT_NAME);
|
|
2289
|
+
return /* @__PURE__ */ jsx(ChatPrompt, {
|
|
2290
|
+
...props,
|
|
2291
|
+
chat,
|
|
2292
|
+
db,
|
|
2293
|
+
processor,
|
|
2294
|
+
event
|
|
2295
|
+
});
|
|
2296
|
+
};
|
|
2297
|
+
ChatPrompt$1.displayName = CHAT_PROMPT_NAME;
|
|
2298
|
+
var CHAT_TASK_LIST_NAME = "Chat.TaskList";
|
|
2299
|
+
var ChatTaskList = composable(({ outline: outlineProp, ...props }, forwardedRef) => {
|
|
2300
|
+
const { chat } = useChatContext(CHAT_TASK_LIST_NAME);
|
|
2301
|
+
const outline = useAtomValue(useMemo(() => Atom.make((get) => outlineProp ?? Option.fromNullable(chat).pipe(Option.map((_) => get(Obj.atom(_))), Option.flatMapNullable((_) => _?.outline?.atom), Option.map(get), Option.getOrUndefined)), [chat, outlineProp]));
|
|
2302
|
+
if (!outline) return null;
|
|
2303
|
+
return /* @__PURE__ */ jsx(TaskList, {
|
|
2304
|
+
...props,
|
|
2305
|
+
outline,
|
|
2306
|
+
ref: forwardedRef
|
|
2307
|
+
});
|
|
2308
|
+
});
|
|
2309
|
+
ChatTaskList.displayName = CHAT_TASK_LIST_NAME;
|
|
2310
|
+
var Chat = {
|
|
2311
|
+
Root: ChatRoot,
|
|
2312
|
+
Toolbar: ChatToolbar,
|
|
2313
|
+
Content: ChatContent,
|
|
2314
|
+
Prompt: ChatPrompt$1,
|
|
2315
|
+
Status: ChatStatus$1,
|
|
2316
|
+
Thread: ChatThread,
|
|
2317
|
+
Minimap: ChatMinimap,
|
|
2318
|
+
TaskList: ChatTaskList
|
|
2319
|
+
};
|
|
2320
|
+
//#endregion
|
|
2321
|
+
//#region src/components/ConnectorAuthMenu/ConnectorAuthMenu.tsx
|
|
2322
|
+
/** Root node the connector-auth group hangs off in the component's local graph. */
|
|
2323
|
+
var NODE_ID = "connector-auth-root";
|
|
2324
|
+
/**
|
|
2325
|
+
* Standalone connector-auth menu: a trigger button that opens a dropdown of the same
|
|
2326
|
+
* {@link connectorAuthActions} owning plugins contribute to object toolbars. Existing
|
|
2327
|
+
* {@link Connection}s are offered for reuse (bind inline) alongside a "Connect X" entry per connector
|
|
2328
|
+
* with an auth flow. Renders nothing when there is nothing to offer.
|
|
2329
|
+
*/
|
|
2330
|
+
var ConnectorAuthMenu = ({ connectorIds, db, existingTarget }) => {
|
|
2331
|
+
const { t } = useTranslation(meta.profile.key);
|
|
2332
|
+
const registry = useContext(RegistryContext);
|
|
2333
|
+
const runAction = useActionRunner();
|
|
2334
|
+
const allConnectors = useCapabilities(Connector).flat();
|
|
2335
|
+
const allConnections = useQuery(db, Filter.type(Connection.Connection));
|
|
2336
|
+
const graph = useMemo(() => {
|
|
2337
|
+
if (!db) return;
|
|
2338
|
+
const actions = connectorAuthActions({
|
|
2339
|
+
connectorIds,
|
|
2340
|
+
db,
|
|
2341
|
+
spaceId: db.spaceId,
|
|
2342
|
+
existingTarget,
|
|
2343
|
+
allConnectors,
|
|
2344
|
+
allConnections
|
|
2345
|
+
});
|
|
2346
|
+
if (actions.length === 0) return;
|
|
2347
|
+
const nextGraph = Graph.make({ registry });
|
|
2348
|
+
nextGraph.pipe(Graph.addNodes([{
|
|
2349
|
+
id: NODE_ID,
|
|
2350
|
+
type: NODE_ID,
|
|
2351
|
+
data: null,
|
|
2352
|
+
properties: {},
|
|
2353
|
+
actions
|
|
2354
|
+
}]));
|
|
2355
|
+
return nextGraph;
|
|
2356
|
+
}, [
|
|
2357
|
+
registry,
|
|
2358
|
+
connectorIds,
|
|
2359
|
+
db,
|
|
2360
|
+
existingTarget,
|
|
2361
|
+
allConnectors,
|
|
2362
|
+
allConnections
|
|
2363
|
+
]);
|
|
2364
|
+
const menuActions = useGraphMenuActions(graph, CONNECTOR_AUTH_GROUP_ID);
|
|
2365
|
+
if (!graph) return null;
|
|
2366
|
+
return /* @__PURE__ */ jsxs(Menu.Root, {
|
|
2367
|
+
...menuActions,
|
|
2368
|
+
onAction: runAction,
|
|
2369
|
+
attendableId: NODE_ID,
|
|
2370
|
+
alwaysActive: true,
|
|
2371
|
+
children: [/* @__PURE__ */ jsx(Menu.Trigger, {
|
|
2372
|
+
asChild: true,
|
|
2373
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
2374
|
+
variant: "ghost",
|
|
2375
|
+
icon: "ph--plugs--regular",
|
|
2376
|
+
label: t("connect.label")
|
|
2377
|
+
})
|
|
2378
|
+
}), /* @__PURE__ */ jsx(Menu.Content, {})]
|
|
2379
|
+
});
|
|
2380
|
+
};
|
|
2381
|
+
ConnectorAuthMenu.displayName = "ConnectorAuthMenu";
|
|
2382
|
+
//#endregion
|
|
2383
|
+
//#region src/components/ProcessTree/ProcessTree.tsx
|
|
2384
|
+
var DEFAULT_DEPTH = 1;
|
|
2385
|
+
/** Extra label inset per nesting level (status icons stay aligned). */
|
|
2386
|
+
var LABEL_INDENT_REM = .5;
|
|
2387
|
+
/** Nested subprocess rows (level > 1) only surface still-active processes. */
|
|
2388
|
+
var NESTED_ACTIVE_STATES = /* @__PURE__ */ new Set([
|
|
2389
|
+
Process.State.RUNNING,
|
|
2390
|
+
Process.State.HYBERNATING,
|
|
2391
|
+
Process.State.TERMINATING
|
|
2392
|
+
]);
|
|
2393
|
+
var ProcessTree = React.memo(composable(({ processes, depth = DEFAULT_DEPTH, onProcessSelect, onProcessTerminate, ...props }, forwardedRef) => {
|
|
2394
|
+
const rows = useMemo(() => buildProcessTreeRows(processes, depth), [processes, depth]);
|
|
2395
|
+
return /* @__PURE__ */ jsx(ScrollArea.Root, {
|
|
2396
|
+
...composableProps(props, { classNames: "dx-expander" }),
|
|
2397
|
+
thin: true,
|
|
2398
|
+
ref: forwardedRef,
|
|
2399
|
+
children: /* @__PURE__ */ jsx(ScrollArea.Viewport, { children: /* @__PURE__ */ jsx(Treegrid.Root, {
|
|
2400
|
+
classNames: "grid grid-cols-[min-content_1fr_min-content_min-content]",
|
|
2401
|
+
children: rows.map(({ process, path }) => /* @__PURE__ */ jsx(ProcessTreeRowView, {
|
|
2402
|
+
process,
|
|
2403
|
+
path,
|
|
2404
|
+
onProcessSelect,
|
|
2405
|
+
onProcessTerminate
|
|
2406
|
+
}, path.join(TREEGRID_PATH_SEPARATOR)))
|
|
2407
|
+
}) })
|
|
2408
|
+
});
|
|
2409
|
+
}));
|
|
2410
|
+
var ProcessTreeRowView = ({ process, path, onProcessSelect, onProcessTerminate }) => {
|
|
2411
|
+
const duration = Unit.Duration(process.metrics.wallTime);
|
|
2412
|
+
const level = path.length;
|
|
2413
|
+
const nested = level > 1;
|
|
2414
|
+
return /* @__PURE__ */ jsxs(Treegrid.Row, {
|
|
2415
|
+
id: path.join(TREEGRID_PATH_SEPARATOR),
|
|
2416
|
+
classNames: mx("col-span-full grid grid-cols-subgrid gap-2 ps-1", onProcessSelect && "dx-hover"),
|
|
2417
|
+
children: [
|
|
2418
|
+
/* @__PURE__ */ jsxs(Treegrid.Cell, {
|
|
2419
|
+
classNames: "flex items-center gap-0.5",
|
|
2420
|
+
children: [nested && /* @__PURE__ */ jsx(Icon, {
|
|
2421
|
+
icon: "ph--arrow-elbow-down-right--regular",
|
|
2422
|
+
size: 3,
|
|
2423
|
+
classNames: "shrink-0 text-subdued"
|
|
2424
|
+
}), /* @__PURE__ */ jsx(Tooltip.Trigger, {
|
|
2425
|
+
content: process.state.toString(),
|
|
2426
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
2427
|
+
size: 4,
|
|
2428
|
+
synchronized: true,
|
|
2429
|
+
classNames: mx(process.state === Process.State.RUNNING && "animate-spin", process.state === Process.State.FAILED && "text-error-text", process.state === Process.State.SUCCEEDED && "text-success-text"),
|
|
2430
|
+
icon: Match.value(process.state).pipe(Match.when(Process.State.RUNNING, () => "ph--spinner-gap--regular"), Match.when(Process.State.SUCCEEDED, () => "ph--check-circle--regular"), Match.when(Process.State.FAILED, () => "ph--warning--regular"), Match.when(Process.State.HYBERNATING, () => "ph--spinner--regular"), Match.when(Process.State.IDLE, () => "ph--moon-stars--regular"), Match.when(Process.State.TERMINATING, () => "ph--x-circle--regular"), Match.when(Process.State.TERMINATED, () => "ph--x-circle--regular"), Match.orElse(() => "ph--spinner-gap--regular"))
|
|
2431
|
+
})
|
|
2432
|
+
})]
|
|
2433
|
+
}),
|
|
2434
|
+
/* @__PURE__ */ jsx(Treegrid.Cell, {
|
|
2435
|
+
classNames: "flex items-center truncate",
|
|
2436
|
+
style: nested ? { paddingInlineStart: `${(level - 1) * LABEL_INDENT_REM}rem` } : void 0,
|
|
2437
|
+
onClick: () => onProcessSelect?.(process),
|
|
2438
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
2439
|
+
className: mx("truncate text-sm", level === 1 && "font-medium", process.state !== Process.State.RUNNING && "text-description"),
|
|
2440
|
+
children: process.params.name ?? process.pid.toString()
|
|
2441
|
+
})
|
|
2442
|
+
}),
|
|
2443
|
+
/* @__PURE__ */ jsx(Treegrid.Cell, {
|
|
2444
|
+
classNames: "flex items-center justify-end text-xs text-description tabular-nums",
|
|
2445
|
+
children: [Process.State.FAILED, Process.State.SUCCEEDED].includes(process.state) && /* @__PURE__ */ jsx("span", {
|
|
2446
|
+
className: "whitespace-nowrap",
|
|
2447
|
+
children: duration.toString()
|
|
2448
|
+
})
|
|
2449
|
+
}),
|
|
2450
|
+
/* @__PURE__ */ jsx(Treegrid.Cell, { children: onProcessTerminate && /* @__PURE__ */ jsx(IconButton, {
|
|
2451
|
+
classNames: "min-h-0 p-1",
|
|
2452
|
+
icon: "ph--x--regular",
|
|
2453
|
+
iconOnly: true,
|
|
2454
|
+
variant: "ghost",
|
|
2455
|
+
size: 4,
|
|
2456
|
+
label: "Actions",
|
|
2457
|
+
onClick: (event) => {
|
|
2458
|
+
event.stopPropagation();
|
|
2459
|
+
onProcessTerminate?.(process);
|
|
2460
|
+
}
|
|
2461
|
+
}) })
|
|
2462
|
+
]
|
|
2463
|
+
});
|
|
2464
|
+
};
|
|
2465
|
+
var sortProcesses = (processes) => {
|
|
2466
|
+
return [
|
|
2467
|
+
...processes.filter((process) => [Process.State.RUNNING, Process.State.HYBERNATING].includes(process.state)),
|
|
2468
|
+
...processes.filter((process) => [Process.State.IDLE].includes(process.state)).slice(0, 3),
|
|
2469
|
+
...processes.filter((process) => [
|
|
2470
|
+
Process.State.SUCCEEDED,
|
|
2471
|
+
Process.State.FAILED,
|
|
2472
|
+
Process.State.TERMINATED
|
|
2473
|
+
].includes(process.state))
|
|
2474
|
+
].sort((left, right) => {
|
|
2475
|
+
const leftCompletedAt = Option.getOrElse(left.completedAt, () => Infinity);
|
|
2476
|
+
return Option.getOrElse(right.completedAt, () => Infinity) - leftCompletedAt;
|
|
2477
|
+
});
|
|
2478
|
+
};
|
|
2479
|
+
var sortNestedActive = (processes) => processes.filter((process) => NESTED_ACTIVE_STATES.has(process.state)).sort((left, right) => {
|
|
2480
|
+
const priority = (state) => state === Process.State.RUNNING ? 0 : state === Process.State.HYBERNATING ? 1 : 2;
|
|
2481
|
+
return priority(left.state) - priority(right.state);
|
|
2482
|
+
});
|
|
2483
|
+
/**
|
|
2484
|
+
* Flattens the process forest to a fixed depth. Rows are always shown expanded (no collapse).
|
|
2485
|
+
*/
|
|
2486
|
+
var buildProcessTreeRows = (processes, maxDepth) => {
|
|
2487
|
+
const pidSet = new Set(processes.map((process) => String(process.pid)));
|
|
2488
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
2489
|
+
const roots = [];
|
|
2490
|
+
for (const process of processes) {
|
|
2491
|
+
const parent = process.parentPid;
|
|
2492
|
+
if (parent === null || !pidSet.has(String(parent))) {
|
|
2493
|
+
roots.push(process);
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
const key = String(parent);
|
|
2497
|
+
const siblings = childrenByParent.get(key) ?? [];
|
|
2498
|
+
siblings.push(process);
|
|
2499
|
+
childrenByParent.set(key, siblings);
|
|
2500
|
+
}
|
|
2501
|
+
const sortedRoots = sortProcesses(roots);
|
|
2502
|
+
const rows = [];
|
|
2503
|
+
const visit = (process, path, level) => {
|
|
2504
|
+
if (level > maxDepth) return;
|
|
2505
|
+
rows.push({
|
|
2506
|
+
process,
|
|
2507
|
+
path
|
|
2508
|
+
});
|
|
2509
|
+
if (level >= maxDepth) return;
|
|
2510
|
+
const children = sortNestedActive(childrenByParent.get(String(process.pid)) ?? []);
|
|
2511
|
+
for (const child of children) visit(child, [...path, String(child.pid)], level + 1);
|
|
2512
|
+
};
|
|
2513
|
+
for (const root of sortedRoots) visit(root, [String(root.pid)], 1);
|
|
2514
|
+
return rows;
|
|
2515
|
+
};
|
|
2516
|
+
//#endregion
|
|
2517
|
+
//#region src/components/Toolbox/Toolbox.tsx
|
|
2518
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-assistant/src/components/Toolbox/Toolbox.tsx";
|
|
2519
|
+
var Toolbox = composable(({ functions, services, skills, activeSkills, ...props }, forwardedRef) => {
|
|
2520
|
+
return /* @__PURE__ */ jsx(ScrollArea.Root, {
|
|
2521
|
+
...composableProps(props),
|
|
2522
|
+
thin: true,
|
|
2523
|
+
orientation: "vertical",
|
|
2524
|
+
ref: forwardedRef,
|
|
2525
|
+
children: /* @__PURE__ */ jsxs(ScrollArea.Viewport, { children: [
|
|
2526
|
+
skills && skills.length > 0 && /* @__PURE__ */ jsx(Section, {
|
|
2527
|
+
title: "Skills",
|
|
2528
|
+
items: skills.map(({ name, description, tools }) => ({
|
|
2529
|
+
name,
|
|
2530
|
+
description,
|
|
2531
|
+
subitems: tools.map((toolId) => ({ name: `∙ ${safeToolId(toolId)}` }))
|
|
2532
|
+
}))
|
|
2533
|
+
}),
|
|
2534
|
+
activeSkills && activeSkills.length > 0 && /* @__PURE__ */ jsx(Section, {
|
|
2535
|
+
title: "Skills",
|
|
2536
|
+
items: activeSkills.map(({ target }) => ({
|
|
2537
|
+
name: target?.name ?? "",
|
|
2538
|
+
description: target?.description ?? "",
|
|
2539
|
+
subitems: target?.tools.map((toolId) => ({ name: `∙ ${safeToolId(toolId)}` }))
|
|
2540
|
+
}))
|
|
2541
|
+
}),
|
|
2542
|
+
services && services.length > 0 && /* @__PURE__ */ jsx(Section, {
|
|
2543
|
+
title: "Services",
|
|
2544
|
+
items: services.map(({ service: { serviceId, name, description } }) => ({
|
|
2545
|
+
name: name ?? serviceId,
|
|
2546
|
+
description
|
|
2547
|
+
}))
|
|
2548
|
+
}),
|
|
2549
|
+
functions && functions.length > 0 && /* @__PURE__ */ jsx(Section, {
|
|
2550
|
+
title: "Functions",
|
|
2551
|
+
items: functions.map(({ name, description }) => ({
|
|
2552
|
+
name,
|
|
2553
|
+
description
|
|
2554
|
+
}))
|
|
2555
|
+
})
|
|
2556
|
+
] })
|
|
2557
|
+
});
|
|
2558
|
+
});
|
|
2559
|
+
Toolbox.displayName = "Toolbox";
|
|
2560
|
+
var Section = ({ title, items, striped }) => {
|
|
2561
|
+
const stripeClassNames = "odd:bg-neutral-50 dark:odd:bg-neutral-800";
|
|
2562
|
+
const gridClassNames = "grid grid-cols-[8rem_1fr]";
|
|
2563
|
+
const subGridClassNames = mx("col-span-full grid grid-cols-subgrid text-xs px-2", striped && stripeClassNames);
|
|
2564
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
|
|
2565
|
+
className: "px-2 text-sm",
|
|
2566
|
+
children: title
|
|
2567
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2568
|
+
className: gridClassNames,
|
|
2569
|
+
children: items.map(({ name, description, subitems }, i) => /* @__PURE__ */ jsxs(Fragment, { children: [name && /* @__PURE__ */ jsxs("div", {
|
|
2570
|
+
className: subGridClassNames,
|
|
2571
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2572
|
+
className: "truncate text-primary-500",
|
|
2573
|
+
children: name
|
|
2574
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2575
|
+
className: "line-clamp-2",
|
|
2576
|
+
children: description
|
|
2577
|
+
})]
|
|
2578
|
+
}), subitems?.map(({ name, description }, i) => /* @__PURE__ */ jsxs("div", {
|
|
2579
|
+
className: mx(subGridClassNames, striped && stripeClassNames),
|
|
2580
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2581
|
+
className: "truncate",
|
|
2582
|
+
children: name
|
|
2583
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2584
|
+
className: "line-clamp-3 text-subdued",
|
|
2585
|
+
children: description
|
|
2586
|
+
})]
|
|
2587
|
+
}, i))] }, i))
|
|
2588
|
+
})] });
|
|
2589
|
+
};
|
|
2590
|
+
var ToolboxPanel = ({ classNames, db, processor }) => {
|
|
2591
|
+
const services = useQuery(db, Filter.type(ServiceType));
|
|
2592
|
+
const [serviceTools, setServiceTools] = useState([]);
|
|
2593
|
+
useEffect(() => {
|
|
2594
|
+
log("creating service tools...", { services: services.length }, {
|
|
2595
|
+
"~LogMeta": "~LogMeta",
|
|
2596
|
+
F: __dxlog_file,
|
|
2597
|
+
L: 123,
|
|
2598
|
+
S: void 0
|
|
2599
|
+
});
|
|
2600
|
+
queueMicrotask(async () => {});
|
|
2601
|
+
}, [services]);
|
|
2602
|
+
const functions = useQuery(db, Filter.type(Operation.PersistentOperation));
|
|
2603
|
+
return /* @__PURE__ */ jsx(Toolbox, {
|
|
2604
|
+
classNames,
|
|
2605
|
+
skills: processor?.context.getSkills(),
|
|
2606
|
+
services: serviceTools,
|
|
2607
|
+
functions
|
|
2608
|
+
});
|
|
2609
|
+
};
|
|
2610
|
+
var safeToolId = (name) => {
|
|
2611
|
+
return name.split("_").pop();
|
|
2612
|
+
};
|
|
2613
|
+
//#endregion
|
|
2614
|
+
export { AgentProperties, Chat, ChatPrompt, ConnectorAuthMenu, ProcessTree, TaskList, Toolbox, ToolboxPanel, TracePanel };
|
|
2615
|
+
|
|
2616
|
+
//# sourceMappingURL=components.mjs.map
|