@dxos/plugin-assistant 0.9.1-staging.ee54ba693a → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
6
|
|
|
7
|
+
import { Identity } from '@dxos/halo';
|
|
7
8
|
import { PublicKey } from '@dxos/keys';
|
|
8
|
-
import { type Identity } from '@dxos/react-client/halo';
|
|
9
9
|
import { type ThemedClassName, setRef } from '@dxos/react-ui';
|
|
10
10
|
import { MarkdownStream, type MarkdownStreamController, type MarkdownStreamProps } from '@dxos/react-ui-markdown';
|
|
11
11
|
import { type Message } from '@dxos/types';
|
|
@@ -14,7 +14,7 @@ import { keyToFallback } from '@dxos/util';
|
|
|
14
14
|
import { type Assistant } from '../../types';
|
|
15
15
|
import { type ChatEvent } from '../Chat';
|
|
16
16
|
import { componentRegistry, createBlockRenderer } from './registry';
|
|
17
|
-
import { MessageSyncer } from './sync';
|
|
17
|
+
import { type MessageSpan, MessageSyncer } from './sync';
|
|
18
18
|
|
|
19
19
|
const defaultOptions: MarkdownStreamProps['options'] = {
|
|
20
20
|
autoScroll: true,
|
|
@@ -25,11 +25,13 @@ const defaultOptions: MarkdownStreamProps['options'] = {
|
|
|
25
25
|
|
|
26
26
|
export type ChatThreadProps = ThemedClassName<
|
|
27
27
|
{
|
|
28
|
-
identity?: Identity;
|
|
28
|
+
identity?: Identity.Info;
|
|
29
29
|
messages?: Message.Message[];
|
|
30
30
|
error?: Error;
|
|
31
31
|
viewType?: Assistant.ChatView;
|
|
32
32
|
onEvent?: (event: ChatEvent) => void;
|
|
33
|
+
/** Publishes the syncer's per-message document spans after each update (minimap, prompt nav). */
|
|
34
|
+
onSpans?: (spans: MessageSpan[]) => void;
|
|
33
35
|
} & Pick<MarkdownStreamProps, 'options' | 'debug' | 'extensions' | 'footer'>
|
|
34
36
|
>;
|
|
35
37
|
|
|
@@ -46,6 +48,7 @@ export const ChatThread = forwardRef<MarkdownStreamController | null, ChatThread
|
|
|
46
48
|
extensions,
|
|
47
49
|
viewType,
|
|
48
50
|
onEvent,
|
|
51
|
+
onSpans,
|
|
49
52
|
},
|
|
50
53
|
forwardedRef,
|
|
51
54
|
) => {
|
|
@@ -59,7 +62,9 @@ export const ChatThread = forwardRef<MarkdownStreamController | null, ChatThread
|
|
|
59
62
|
);
|
|
60
63
|
|
|
61
64
|
const userHue = useMemo(
|
|
62
|
-
() =>
|
|
65
|
+
() =>
|
|
66
|
+
identity?.data?.hue ||
|
|
67
|
+
keyToFallback(identity?.identityKey ? PublicKey.fromHex(identity.identityKey) : PublicKey.random()).hue,
|
|
63
68
|
[identity],
|
|
64
69
|
);
|
|
65
70
|
|
|
@@ -77,18 +82,41 @@ export const ChatThread = forwardRef<MarkdownStreamController | null, ChatThread
|
|
|
77
82
|
initializedRef.current = true;
|
|
78
83
|
}, [controller, error]);
|
|
79
84
|
|
|
85
|
+
// Widget callbacks are routed through the syncer's context, so they must be referentially stable
|
|
86
|
+
// — rebuilding the syncer replaces the document.
|
|
87
|
+
const onEventRef = useRef(onEvent);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
onEventRef.current = onEvent;
|
|
90
|
+
}, [onEvent]);
|
|
91
|
+
const handleRewind = useCallback((id: string) => onEventRef.current?.({ type: 'rewind', id }), []);
|
|
92
|
+
|
|
80
93
|
// Update document.
|
|
81
94
|
const renderer = useMemo(() => createBlockRenderer(viewType), [viewType]);
|
|
82
|
-
const syncer = useMemo(
|
|
95
|
+
const syncer = useMemo(
|
|
96
|
+
() => controller && new MessageSyncer(controller, renderer, { onRewind: handleRewind }),
|
|
97
|
+
[controller, renderer, handleRewind],
|
|
98
|
+
);
|
|
83
99
|
useEffect(() => {
|
|
84
100
|
if (!syncer) {
|
|
85
101
|
return;
|
|
86
102
|
}
|
|
87
103
|
|
|
104
|
+
// Publish the context every pass: widget props read it from a CodeMirror state field, and
|
|
105
|
+
// `setContext` dispatches through `viewRef.current?` — a no-op before the view exists, so doing this
|
|
106
|
+
// once on mount silently loses it and every widget callback (e.g. rewind) dies on the optional call.
|
|
107
|
+
controller?.setContext(syncer.context);
|
|
108
|
+
|
|
109
|
+
// Publish the context every pass: widget props read it from a CodeMirror state field, and
|
|
110
|
+
// `setContext` dispatches through `viewRef.current?` — a no-op before the view exists, so doing this
|
|
111
|
+
// once on mount silently loses it and every widget callback (e.g. rewind) dies on the optional call.
|
|
112
|
+
controller?.setContext(syncer.context);
|
|
113
|
+
|
|
88
114
|
if (syncer.update(messages)) {
|
|
89
115
|
controller?.scrollToBottom('instant');
|
|
90
116
|
}
|
|
91
|
-
|
|
117
|
+
// Spans are valid synchronously after `update` (offsets are computed during the walk).
|
|
118
|
+
onSpans?.(syncer.getSpans());
|
|
119
|
+
}, [controller, syncer, messages, onSpans]);
|
|
92
120
|
|
|
93
121
|
// Event adapter.
|
|
94
122
|
const handleEvent = useCallback<NonNullable<MarkdownStreamProps['onEvent']>>(
|
|
@@ -9,9 +9,9 @@ import { ContentBlock, type Message } from '@dxos/types';
|
|
|
9
9
|
import { AnchorWidget, type XmlWidgetRegistry, getXmlTextChild } from '@dxos/ui-editor';
|
|
10
10
|
|
|
11
11
|
import { type Assistant } from '../../types';
|
|
12
|
-
import { type BlockRenderer, type MessageThreadContext } from './sync';
|
|
13
|
-
import { applyToolBlockToWidgetState } from './tool-widget-state';
|
|
12
|
+
import { type BlockRenderer, type MessageThreadContext, applyToolBlockToWidgetState } from './sync';
|
|
14
13
|
import {
|
|
14
|
+
BranchWidget,
|
|
15
15
|
FallbackWidget,
|
|
16
16
|
ReasoningWidget,
|
|
17
17
|
ReferenceWidget,
|
|
@@ -88,8 +88,9 @@ export const componentRegistry: XmlWidgetRegistry = {
|
|
|
88
88
|
return options?.length ? new SelectWidget(options) : null;
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
|
+
// Inline so a run of suggestions flows onto one wrapped line instead of one block per line.
|
|
91
92
|
'suggestion': {
|
|
92
|
-
block:
|
|
93
|
+
block: false,
|
|
93
94
|
factory: ({ children }) => {
|
|
94
95
|
const text = getXmlTextChild(children);
|
|
95
96
|
return text ? new SuggestionWidget(text) : null;
|
|
@@ -115,6 +116,10 @@ export const componentRegistry: XmlWidgetRegistry = {
|
|
|
115
116
|
// React Widgets (portaled outside of the editor)
|
|
116
117
|
//
|
|
117
118
|
|
|
119
|
+
'branch': {
|
|
120
|
+
block: true,
|
|
121
|
+
Component: BranchWidget,
|
|
122
|
+
},
|
|
118
123
|
'summary': {
|
|
119
124
|
block: true,
|
|
120
125
|
Component: SummaryWidget,
|
|
@@ -168,8 +173,16 @@ export function createBlockRenderer(viewType: Assistant.ChatView | undefined): B
|
|
|
168
173
|
if (!isBlockVisible(viewType, message, block)) {
|
|
169
174
|
return;
|
|
170
175
|
}
|
|
176
|
+
|
|
171
177
|
let str = blockToMarkdownImpl(context, message, block);
|
|
172
178
|
if (str && !block.pending) {
|
|
179
|
+
// Suggestions are inline widgets meant to flow: keeping them on one line lets a run of them wrap
|
|
180
|
+
// as chips instead of stacking one per line. A trailing space separates adjacent tags so the
|
|
181
|
+
// inline parser sees them as distinct.
|
|
182
|
+
if (block._tag === 'suggestion') {
|
|
183
|
+
return (str += ' ');
|
|
184
|
+
}
|
|
185
|
+
|
|
173
186
|
// Use a blank line as the block separator so each rendered block parses as its own
|
|
174
187
|
// markdown block. A single newline lets CommonMark absorb a following `<prompt>` (an
|
|
175
188
|
// HTML type-7 tag, which can't interrupt an open paragraph) into the previous
|
|
@@ -208,7 +221,11 @@ const blockToMarkdownImpl = (context: MessageThreadContext, message: Message.Mes
|
|
|
208
221
|
if (block.disposition === 'synthetic') {
|
|
209
222
|
return renderXMLBlock('synthetic', { content: block.text, pending: block.pending });
|
|
210
223
|
} else {
|
|
211
|
-
|
|
224
|
+
// Built by explicit concatenation, not an indented template: `trim` dedents by the minimum
|
|
225
|
+
// indent across all lines, and a multi-line prompt contributes lines at zero indent — so the
|
|
226
|
+
// source file's indentation survived into the document, where 4+ spaces is an indented code
|
|
227
|
+
// block and neither the prompt nor the toolbar parsed as an element any more.
|
|
228
|
+
return `\n<prompt>${block.text}</prompt>\n${renderBranchToolbar(message)}\n`;
|
|
212
229
|
}
|
|
213
230
|
} else {
|
|
214
231
|
const text = block.text.trim();
|
|
@@ -291,6 +308,13 @@ const blockToMarkdownImpl = (context: MessageThreadContext, message: Message.Mes
|
|
|
291
308
|
}
|
|
292
309
|
};
|
|
293
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Mini toolbar below a user prompt: branch (soft fork) plus when the prompt was sent.
|
|
313
|
+
* `messageId` rather than `id` because a tag's `id` attribute would shadow the widget's own id.
|
|
314
|
+
*/
|
|
315
|
+
const renderBranchToolbar = (message: Message.Message) =>
|
|
316
|
+
`<branch messageId="${escapeXmlAttribute(message.id)}" created="${escapeXmlAttribute(message.created)}" />`;
|
|
317
|
+
|
|
294
318
|
/**
|
|
295
319
|
* Escape text embedded in generated XML so the mixed XML parser does not treat `&`, `<`, `>` as markup.
|
|
296
320
|
*/
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// @vitest-environment jsdom
|
|
6
6
|
|
|
7
7
|
import { EditorView } from '@codemirror/view';
|
|
8
|
-
import { describe, it } from '@effect/vitest';
|
|
8
|
+
import { describe, expect, it } from '@effect/vitest';
|
|
9
9
|
import * as Effect from 'effect/Effect';
|
|
10
10
|
|
|
11
11
|
import { Obj } from '@dxos/echo';
|
|
@@ -14,8 +14,8 @@ import { type ContentBlock, type Message } from '@dxos/types';
|
|
|
14
14
|
|
|
15
15
|
import { createMessage } from '#testing';
|
|
16
16
|
|
|
17
|
-
import { createBlockRenderer } from '
|
|
18
|
-
import { type BlockRenderer, MessageSyncer, type MessageThreadContext, type TextModel } from '
|
|
17
|
+
import { createBlockRenderer } from '../registry';
|
|
18
|
+
import { type BlockRenderer, MessageSyncer, type MessageThreadContext, type TextModel } from '../sync/sync';
|
|
19
19
|
|
|
20
20
|
class TestDocument implements TextModel {
|
|
21
21
|
private readonly _view = new EditorView({ extensions: [] });
|
|
@@ -56,13 +56,13 @@ describe('reducers', () => {
|
|
|
56
56
|
];
|
|
57
57
|
|
|
58
58
|
syncer.update(messages);
|
|
59
|
-
expect(doc.content).toEqual('\n<prompt>Hello</prompt>\nHi there!\n');
|
|
59
|
+
expect(normalize(doc.content)).toEqual('\n<prompt>Hello</prompt>\n<branch />\n\nHi there!\n');
|
|
60
60
|
|
|
61
61
|
Obj.update(messages[1], (obj) => {
|
|
62
62
|
obj.blocks.push({ _tag: 'text', text: 'How can I help?' });
|
|
63
63
|
});
|
|
64
64
|
syncer.update(messages);
|
|
65
|
-
expect(doc.content).toEqual('\n<prompt>Hello</prompt>\nHi there!\nHow can I help?\n');
|
|
65
|
+
expect(normalize(doc.content)).toEqual('\n<prompt>Hello</prompt>\n<branch />\n\nHi there!\nHow can I help?\n');
|
|
66
66
|
}),
|
|
67
67
|
);
|
|
68
68
|
|
|
@@ -78,7 +78,7 @@ describe('reducers', () => {
|
|
|
78
78
|
];
|
|
79
79
|
|
|
80
80
|
syncer.update(messages);
|
|
81
|
-
expect(doc.content).toEqual('\n<prompt>Hello</prompt>\nHi there!');
|
|
81
|
+
expect(normalize(doc.content)).toEqual('\n<prompt>Hello</prompt>\n<branch />\n\nHi there!');
|
|
82
82
|
|
|
83
83
|
Obj.update(messages[1], (obj) => {
|
|
84
84
|
const block = obj.blocks[0] as Mutable<ContentBlock.Text>;
|
|
@@ -91,7 +91,43 @@ describe('reducers', () => {
|
|
|
91
91
|
obj.blocks.push({ _tag: 'text', text: 'How can I help?' });
|
|
92
92
|
});
|
|
93
93
|
syncer.update(messages);
|
|
94
|
-
expect(doc.content).toEqual(
|
|
94
|
+
expect(normalize(doc.content)).toEqual(
|
|
95
|
+
'\n<prompt>Hello</prompt>\n<branch />\n\nHi there! How are you?\nHow can I help?\n',
|
|
96
|
+
);
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
it.effect(
|
|
101
|
+
'tracks per-message document ranges',
|
|
102
|
+
Effect.fn(function* ({ expect }) {
|
|
103
|
+
const doc = new TestDocument();
|
|
104
|
+
const syncer = new MessageSyncer(doc, createBlockRenderer('thinking'));
|
|
105
|
+
|
|
106
|
+
const messages = [
|
|
107
|
+
createMessage('user', [{ _tag: 'text', text: 'Hello' }]),
|
|
108
|
+
createMessage('assistant', [{ _tag: 'text', text: 'Hi there!' }]),
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
syncer.update(messages);
|
|
112
|
+
const spans = syncer.getSpans();
|
|
113
|
+
expect(spans.map((range) => range.id)).toEqual([messages[0].id, messages[1].id]);
|
|
114
|
+
// Ranges tile the document contiguously and slice back to each message's rendered content.
|
|
115
|
+
expect(spans[0].from).toEqual(0);
|
|
116
|
+
expect(spans[1].from).toEqual(spans[0].to);
|
|
117
|
+
expect(spans[1].to).toEqual(doc.length);
|
|
118
|
+
expect(doc.content.slice(spans[0].from, spans[0].to)).toContain('<prompt>Hello</prompt>');
|
|
119
|
+
expect(doc.content.slice(spans[1].from, spans[1].to)).toContain('Hi there!');
|
|
120
|
+
|
|
121
|
+
// Appending to the last message extends its range through the append path.
|
|
122
|
+
Obj.update(messages[1], (obj) => {
|
|
123
|
+
obj.blocks.push({ _tag: 'text', text: 'How can I help?' });
|
|
124
|
+
});
|
|
125
|
+
syncer.update(messages);
|
|
126
|
+
const extended = syncer.getSpans();
|
|
127
|
+
expect(extended).toHaveLength(2);
|
|
128
|
+
expect(extended[0].to).toEqual(spans[0].to);
|
|
129
|
+
expect(extended[1].to).toEqual(doc.length);
|
|
130
|
+
expect(doc.content.slice(extended[1].from, extended[1].to)).toContain('How can I help?');
|
|
95
131
|
}),
|
|
96
132
|
);
|
|
97
133
|
|
|
@@ -255,3 +291,127 @@ describe('reducers', () => {
|
|
|
255
291
|
}),
|
|
256
292
|
);
|
|
257
293
|
});
|
|
294
|
+
|
|
295
|
+
describe('MessageSyncer tool widget rehydration', () => {
|
|
296
|
+
it.effect(
|
|
297
|
+
'restores tool widget state after reset replaces the document',
|
|
298
|
+
Effect.fnUntraced(function* (_) {
|
|
299
|
+
const updates: { id: string; value: any }[] = [];
|
|
300
|
+
class RecordingDocument extends TestDocument {
|
|
301
|
+
override updateWidget(id: string, value: any) {
|
|
302
|
+
updates.push({ id, value });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const document = new RecordingDocument();
|
|
307
|
+
const syncer = new MessageSyncer(document, createBlockRenderer('thinking'));
|
|
308
|
+
const messages = [
|
|
309
|
+
createMessage('assistant', [
|
|
310
|
+
{ _tag: 'toolCall', toolCallId: 'abc', name: 'search', input: '{}', providerExecuted: false },
|
|
311
|
+
]),
|
|
312
|
+
createMessage('user', [
|
|
313
|
+
{ _tag: 'toolResult', toolCallId: 'abc', name: 'search', result: 'ok', providerExecuted: false },
|
|
314
|
+
]),
|
|
315
|
+
] as Message.Message[];
|
|
316
|
+
|
|
317
|
+
syncer.reset(messages);
|
|
318
|
+
// `reset` rehydrates in a promise continuation after `setContent`.
|
|
319
|
+
yield* Effect.promise(() => Promise.resolve());
|
|
320
|
+
yield* Effect.promise(() => Promise.resolve());
|
|
321
|
+
|
|
322
|
+
// Reduce the dispatches the way the widget state store does: each is either a value or a
|
|
323
|
+
// function of the previous state, applied in arrival order.
|
|
324
|
+
const forTool = updates.filter((update) => update.id === 'abc');
|
|
325
|
+
expect(forTool.length).toBeGreaterThan(0);
|
|
326
|
+
const state = forTool.reduce<{ blocks: ContentBlock.Any[] }>(
|
|
327
|
+
(previous, { value }) => (typeof value === 'function' ? value(previous) : value),
|
|
328
|
+
{ blocks: [] },
|
|
329
|
+
);
|
|
330
|
+
expect(state.blocks.map((block) => block._tag)).toEqual(['toolCall', 'toolResult']);
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// Regression: the prompt was built with an indented `trim` template, which dedents by the minimum
|
|
335
|
+
// indent across all lines — so a multi-line prompt, contributing lines at zero indent, left the source
|
|
336
|
+
// file's indentation in the document. At 4+ spaces CommonMark reads an indented code block, so neither
|
|
337
|
+
// the prompt nor the toolbar parsed as an element and the turn rendered as raw text.
|
|
338
|
+
it.effect(
|
|
339
|
+
'a multi-line prompt emits unindented markup',
|
|
340
|
+
Effect.fn(function* ({ expect }) {
|
|
341
|
+
const doc = new TestDocument();
|
|
342
|
+
const syncer = new MessageSyncer(doc, createBlockRenderer('thinking'));
|
|
343
|
+
|
|
344
|
+
const prompt = createMessage('user', [{ _tag: 'text', text: 'this is a list:\n- foo\n- bar' }]);
|
|
345
|
+
syncer.update([prompt]);
|
|
346
|
+
|
|
347
|
+
const indented = doc.content.split('\n').filter((line) => /^\s+\S/.test(line));
|
|
348
|
+
expect(indented).toEqual([]);
|
|
349
|
+
expect(normalize(doc.content)).toContain('<prompt>this is a list:\n- foo\n- bar</prompt>\n<branch />');
|
|
350
|
+
}),
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
// Regression: `update` streams a suffix, so an append-only path leaves removed turns on screen. A
|
|
354
|
+
// rewind shrinks the thread, which has to fall back to a full reset.
|
|
355
|
+
it.effect(
|
|
356
|
+
'a shrinking message list replaces the document',
|
|
357
|
+
Effect.fn(function* ({ expect }) {
|
|
358
|
+
const doc = new TestDocument();
|
|
359
|
+
const syncer = new MessageSyncer(doc, createBlockRenderer('thinking'));
|
|
360
|
+
|
|
361
|
+
const prompt = createMessage('user', [{ _tag: 'text', text: 'Hello' }]);
|
|
362
|
+
const reply = createMessage('assistant', [{ _tag: 'text', text: 'Hi there!' }]);
|
|
363
|
+
syncer.update([prompt, reply]);
|
|
364
|
+
expect(doc.content).toContain('Hi there!');
|
|
365
|
+
|
|
366
|
+
// The rewind case: same first message, fewer turns.
|
|
367
|
+
const replaced = syncer.update([prompt]);
|
|
368
|
+
expect(replaced).toBe(true);
|
|
369
|
+
expect(doc.content).not.toContain('Hi there!');
|
|
370
|
+
expect(doc.content).toContain('Hello');
|
|
371
|
+
}),
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
it.effect(
|
|
375
|
+
'a message list diverging mid-thread replaces the document',
|
|
376
|
+
Effect.fn(function* ({ expect }) {
|
|
377
|
+
const doc = new TestDocument();
|
|
378
|
+
const syncer = new MessageSyncer(doc, createBlockRenderer('thinking'));
|
|
379
|
+
|
|
380
|
+
const prompt = createMessage('user', [{ _tag: 'text', text: 'Hello' }]);
|
|
381
|
+
const abandoned = createMessage('assistant', [{ _tag: 'text', text: 'Abandoned.' }]);
|
|
382
|
+
syncer.update([prompt, abandoned]);
|
|
383
|
+
|
|
384
|
+
// Same length, different second turn — the branch changed underneath us.
|
|
385
|
+
const retry = createMessage('assistant', [{ _tag: 'text', text: 'Retry.' }]);
|
|
386
|
+
expect(syncer.update([prompt, retry])).toBe(true);
|
|
387
|
+
expect(doc.content).not.toContain('Abandoned.');
|
|
388
|
+
expect(doc.content).toContain('Retry.');
|
|
389
|
+
}),
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
// Regression: widget callbacks reach the thread through the syncer's context, which the host has to
|
|
393
|
+
// publish to the editor via `setContext`. Nothing did, so a widget received `context: undefined` and
|
|
394
|
+
// the rewind button silently no-oped.
|
|
395
|
+
it.effect(
|
|
396
|
+
'exposes a context routing widget callbacks to the handlers',
|
|
397
|
+
Effect.fn(function* ({ expect }) {
|
|
398
|
+
const rewound: string[] = [];
|
|
399
|
+
const syncer = new MessageSyncer(new TestDocument(), createBlockRenderer('thinking'), {
|
|
400
|
+
onRewind: (id) => rewound.push(id),
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
expect(syncer.context).toBeDefined();
|
|
404
|
+
syncer.context.rewind('msg-1');
|
|
405
|
+
expect(rewound).toEqual(['msg-1']);
|
|
406
|
+
}),
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Canonicalizes the rendered document for comparison:
|
|
412
|
+
* - the branch toolbar's attributes, since `messageId` is a fresh ULID and `created` a wall-clock
|
|
413
|
+
* timestamp, so neither is stable across runs;
|
|
414
|
+
* - the run of leading newlines, which is presentational padding above the first block and is tuned
|
|
415
|
+
* independently — these tests are about the block sequence and the incremental append path.
|
|
416
|
+
*/
|
|
417
|
+
const normalize = (content: string) => content.replace(/<branch\b[^>]*\/>/g, '<branch />').replace(/^\n+/, '\n');
|
|
@@ -14,6 +14,17 @@ import { rehydrateToolWidgetsFromMessages } from './tool-widget-state';
|
|
|
14
14
|
*/
|
|
15
15
|
export type TextModel = Pick<MarkdownStreamController, 'length' | 'setContent' | 'append' | 'updateWidget'>;
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Document offset range occupied by a message's rendered blocks. Positions are in the same
|
|
19
|
+
* space as the CodeMirror document (i.e. what {@link MarkdownStreamController.scrollTo} and
|
|
20
|
+
* {@link MarkdownStreamController.getVisibleRange} operate on).
|
|
21
|
+
*/
|
|
22
|
+
export type MessageSpan = {
|
|
23
|
+
id: string;
|
|
24
|
+
from: number;
|
|
25
|
+
to: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
17
28
|
/**
|
|
18
29
|
* Renders a block to markdown.
|
|
19
30
|
*
|
|
@@ -29,11 +40,26 @@ export type BlockRenderer = (
|
|
|
29
40
|
block: ContentBlock.Any,
|
|
30
41
|
) => string | undefined;
|
|
31
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Callbacks a widget can invoke through {@link MessageThreadContext}.
|
|
45
|
+
*
|
|
46
|
+
* React widgets are portaled by `MarkdownStream` without its `onEvent`, so interactive widgets reach
|
|
47
|
+
* the thread through the context they already receive in their props.
|
|
48
|
+
*/
|
|
49
|
+
export type MessageThreadHandlers = {
|
|
50
|
+
/** Soft-fork the thread from the given message. */
|
|
51
|
+
onRewind?: (messageId: string) => void;
|
|
52
|
+
};
|
|
53
|
+
|
|
32
54
|
/**
|
|
33
55
|
* Thread context passed to renderer.
|
|
56
|
+
* This enables the renderer to "stream" content into the widget state.
|
|
34
57
|
*/
|
|
35
58
|
export class MessageThreadContext implements Pick<MarkdownStreamController, 'updateWidget'> {
|
|
36
|
-
constructor(
|
|
59
|
+
constructor(
|
|
60
|
+
private readonly _widgetState?: XmlWidgetStateManager,
|
|
61
|
+
private readonly _handlers: MessageThreadHandlers = {},
|
|
62
|
+
) {}
|
|
37
63
|
|
|
38
64
|
updateWidget<T>(id: string, value: StateDispatch<T>) {
|
|
39
65
|
this._widgetState?.updateWidget(id, value);
|
|
@@ -43,6 +69,10 @@ export class MessageThreadContext implements Pick<MarkdownStreamController, 'upd
|
|
|
43
69
|
getObjectLabel(_id: URI.URI) {
|
|
44
70
|
return 'Object';
|
|
45
71
|
}
|
|
72
|
+
|
|
73
|
+
rewind(messageId: string) {
|
|
74
|
+
this._handlers.onRewind?.(messageId);
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
77
|
|
|
48
78
|
/**
|
|
@@ -61,30 +91,60 @@ export class MessageThreadContext implements Pick<MarkdownStreamController, 'upd
|
|
|
61
91
|
*/
|
|
62
92
|
export class MessageSyncer {
|
|
63
93
|
private _threadId?: string;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Ids of the messages rendered so far, in document order. `update` streams a suffix, so it needs to
|
|
97
|
+
* know when the incoming list no longer extends what is on screen — a rewind drops turns, and an
|
|
98
|
+
* append-only path would leave them rendered.
|
|
99
|
+
*/
|
|
100
|
+
private _renderedIds: string[] = [];
|
|
101
|
+
|
|
102
|
+
/** Cumulative block index (across all completed blocks in all messages). */
|
|
64
103
|
private _completed = 0;
|
|
104
|
+
|
|
105
|
+
/** Chars of the in-flight block (at index `_completed`) already appended. */
|
|
65
106
|
private _trailing = 0;
|
|
66
107
|
|
|
108
|
+
/** Document offset at the `_completed` boundary (length of all fully-appended blocks). */
|
|
109
|
+
private _completedOffset = 0;
|
|
110
|
+
|
|
111
|
+
/** Per-message document offset ranges, keyed by message id in document order. */
|
|
112
|
+
private readonly _spans = new Map<string, { from: number; to: number }>();
|
|
113
|
+
|
|
67
114
|
private readonly _context: MessageThreadContext;
|
|
68
115
|
|
|
69
116
|
constructor(
|
|
70
117
|
private readonly _document: TextModel,
|
|
71
118
|
private readonly _renderer: BlockRenderer,
|
|
119
|
+
handlers: MessageThreadHandlers = {},
|
|
72
120
|
) {
|
|
73
|
-
this._context = new MessageThreadContext(this._document);
|
|
121
|
+
this._context = new MessageThreadContext(this._document, handlers);
|
|
74
122
|
}
|
|
75
123
|
|
|
76
124
|
get context() {
|
|
77
125
|
return this._context;
|
|
78
126
|
}
|
|
79
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Per-message document offset spans, in document order. Valid synchronously after
|
|
130
|
+
* {@link reset} or {@link update} (the offsets are derived from the same rendered buffer
|
|
131
|
+
* that is dispatched to the document).
|
|
132
|
+
*/
|
|
133
|
+
getSpans(): MessageSpan[] {
|
|
134
|
+
return Array.from(this._spans, ([id, { from, to }]) => ({ id, from, to }));
|
|
135
|
+
}
|
|
136
|
+
|
|
80
137
|
/**
|
|
81
138
|
* Replace the document with the rendering of `messages`. Use on mount, on thread switch,
|
|
82
139
|
* and from {@link update} when it detects an identity change in `messages[0]`.
|
|
83
140
|
*/
|
|
84
141
|
reset(messages: Message.Message[] = []): void {
|
|
85
142
|
this._threadId = messages[0]?.id;
|
|
143
|
+
this._renderedIds = messages.map((message) => message.id);
|
|
86
144
|
this._completed = 0;
|
|
87
145
|
this._trailing = 0;
|
|
146
|
+
this._completedOffset = 0;
|
|
147
|
+
this._spans.clear();
|
|
88
148
|
const buffer = this._walk(messages);
|
|
89
149
|
// Match the pre-rewrite behaviour: rendering from a steady state (initial mount with
|
|
90
150
|
// non-empty messages, or thread switch) lands the entire content via `setContent` — which
|
|
@@ -97,16 +157,30 @@ export class MessageSyncer {
|
|
|
97
157
|
});
|
|
98
158
|
}
|
|
99
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Whether `messages` still begins with everything already rendered, making this an append.
|
|
162
|
+
*
|
|
163
|
+
* A rewind removes turns from the middle or end of the thread, and the streaming path can only add
|
|
164
|
+
* text — so anything other than an extension has to go through {@link reset}.
|
|
165
|
+
*/
|
|
166
|
+
#extendsRendered(messages: Message.Message[]): boolean {
|
|
167
|
+
if (messages.length < this._renderedIds.length) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return this._renderedIds.every((id, index) => messages[index]?.id === id);
|
|
171
|
+
}
|
|
172
|
+
|
|
100
173
|
/**
|
|
101
174
|
* Stream the suffix of the rendered messages into the document.
|
|
102
175
|
* Returns `true` if the document was replaced (initial mount or thread switch), `false`
|
|
103
176
|
* if the call was a streaming append (or a no-op).
|
|
104
177
|
*/
|
|
105
178
|
update(messages: Message.Message[]): boolean {
|
|
106
|
-
if (messages[0]?.id !== this._threadId) {
|
|
179
|
+
if (messages[0]?.id !== this._threadId || !this.#extendsRendered(messages)) {
|
|
107
180
|
this.reset(messages);
|
|
108
181
|
return true;
|
|
109
182
|
}
|
|
183
|
+
this._renderedIds = messages.map((message) => message.id);
|
|
110
184
|
const buffer = this._walk(messages);
|
|
111
185
|
if (buffer.length > 0) {
|
|
112
186
|
void this._document.append(buffer);
|
|
@@ -122,6 +196,9 @@ export class MessageSyncer {
|
|
|
122
196
|
_walk(messages: Message.Message[]): string {
|
|
123
197
|
let buffer = '';
|
|
124
198
|
let index = 0;
|
|
199
|
+
// Absolute document offset at the `_completed` boundary; blocks before it were rendered on
|
|
200
|
+
// earlier calls and their offsets are already baked into `_completedOffset` (and `_ranges`).
|
|
201
|
+
let offset = this._completedOffset;
|
|
125
202
|
outer: for (const message of messages) {
|
|
126
203
|
for (const block of message.blocks) {
|
|
127
204
|
if (index < this._completed) {
|
|
@@ -132,6 +209,11 @@ export class MessageSyncer {
|
|
|
132
209
|
if (rendered.length > this._trailing) {
|
|
133
210
|
buffer += rendered.slice(this._trailing);
|
|
134
211
|
}
|
|
212
|
+
// The document never shrinks (see the `_trailing` guard below), so span/offset accounting
|
|
213
|
+
// must track the document, not a renderer output that regressed below what was appended.
|
|
214
|
+
const renderedLength = Math.max(rendered.length, this._trailing);
|
|
215
|
+
// The block occupies `[offset, offset + renderedLength)`; extend the message's range.
|
|
216
|
+
this._saveRange(message.id, offset, offset + renderedLength);
|
|
135
217
|
if (block.pending) {
|
|
136
218
|
// Stay on this block; record how far we've appended so the next call can resume.
|
|
137
219
|
// `Math.max`-style guard against a non-monotonic renderer output without shrinking the doc.
|
|
@@ -142,9 +224,21 @@ export class MessageSyncer {
|
|
|
142
224
|
}
|
|
143
225
|
this._completed = index + 1;
|
|
144
226
|
this._trailing = 0;
|
|
227
|
+
offset += renderedLength;
|
|
228
|
+
this._completedOffset = offset;
|
|
145
229
|
index++;
|
|
146
230
|
}
|
|
147
231
|
}
|
|
148
232
|
return buffer;
|
|
149
233
|
}
|
|
234
|
+
|
|
235
|
+
/** Record (or extend) the offset range of a message. `from` is preserved; `to` never regresses. */
|
|
236
|
+
private _saveRange(id: string, from: number, to: number): void {
|
|
237
|
+
const existing = this._spans.get(id);
|
|
238
|
+
if (existing) {
|
|
239
|
+
existing.to = Math.max(existing.to, to);
|
|
240
|
+
} else {
|
|
241
|
+
this._spans.set(id, { from, to });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
150
244
|
}
|
|
@@ -23,15 +23,13 @@ export const applyToolBlockToWidgetState = (context: ToolWidgetStateSink, block:
|
|
|
23
23
|
});
|
|
24
24
|
break;
|
|
25
25
|
}
|
|
26
|
+
|
|
26
27
|
case 'toolResult': {
|
|
27
28
|
context.updateWidget<{ blocks: ContentBlock.Any[] }>(block.toolCallId, ({ blocks = [] } = { blocks: [] }) => ({
|
|
28
29
|
blocks: [...blocks, block],
|
|
29
30
|
}));
|
|
30
31
|
break;
|
|
31
32
|
}
|
|
32
|
-
default: {
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
33
|
}
|
|
36
34
|
};
|
|
37
35
|
|