@dxos/plugin-assistant 0.9.0 → 0.9.1-main.c7dcc2e112
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/dist/lib/neutral/{AgentArticle-K7XM46OQ.mjs → AgentArticle-2BEPWUMN.mjs} +9 -7
- package/dist/lib/neutral/AgentArticle-2BEPWUMN.mjs.map +7 -0
- package/dist/lib/neutral/AssistantPlugin.mjs +1 -1
- package/dist/lib/neutral/{AssistantSettings-GG52BLKS.mjs → AssistantSettings-7ALY4BMS.mjs} +3 -3
- package/dist/lib/neutral/AssistantSettings-7ALY4BMS.mjs.map +7 -0
- package/dist/lib/neutral/{ChatArticle-VNVZCDUR.mjs → ChatArticle-KT46SUFU.mjs} +2 -2
- package/dist/lib/neutral/{ChatCompanion-LBUHYWQG.mjs → ChatCompanion-YHC43RYQ.mjs} +4 -4
- package/dist/lib/neutral/ChatCompanion-YHC43RYQ.mjs.map +7 -0
- package/dist/lib/neutral/{ChatDialog-DCA6FLOV.mjs → ChatDialog-YZDZLIQA.mjs} +5 -4
- package/dist/lib/neutral/ChatDialog-YZDZLIQA.mjs.map +7 -0
- package/dist/lib/neutral/{PlanArticle-TS5ULWYS.mjs → PlanArticle-VPK2IYWU.mjs} +8 -2
- package/dist/lib/neutral/PlanArticle-VPK2IYWU.mjs.map +7 -0
- package/dist/lib/neutral/{RoutineArticle-5NYXHRG6.mjs → RoutineArticle-FK5BXQN5.mjs} +3 -3
- package/dist/lib/neutral/RoutineArticle-FK5BXQN5.mjs.map +7 -0
- package/dist/lib/neutral/SpaceHomePrompt-HTWQKLGI.mjs +113 -0
- package/dist/lib/neutral/SpaceHomePrompt-HTWQKLGI.mjs.map +7 -0
- package/dist/lib/neutral/SpaceHomeSuggestions-6G4E7GNJ.mjs +50 -0
- package/dist/lib/neutral/SpaceHomeSuggestions-6G4E7GNJ.mjs.map +7 -0
- package/dist/lib/neutral/TracePanel-T552TAOH.mjs +12 -0
- package/dist/lib/neutral/TracePanel-T552TAOH.mjs.map +7 -0
- package/dist/lib/neutral/{TriggerStatus-X7Y5JFZJ.mjs → TriggerStatus-RBOHHDOK.mjs} +3 -3
- package/dist/lib/neutral/TriggerStatus-RBOHHDOK.mjs.map +7 -0
- package/dist/lib/neutral/{agent-service-WCAP5MLI.mjs → agent-service-WV5CSHAG.mjs} +4 -2
- package/dist/lib/neutral/{agent-service-WCAP5MLI.mjs.map → agent-service-WV5CSHAG.mjs.map} +3 -3
- package/dist/lib/neutral/{app-graph-builder-WUFHQH3Y.mjs → app-graph-builder-PTSRZXRN.mjs} +13 -13
- package/dist/lib/neutral/app-graph-builder-PTSRZXRN.mjs.map +7 -0
- package/dist/lib/neutral/{blueprint-definition-MH2QLYQH.mjs → blueprint-definition-2XPYI35X.mjs} +4 -3
- package/dist/lib/neutral/blueprint-definition-2XPYI35X.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +8 -8
- package/dist/lib/neutral/capabilities/index.mjs.map +2 -2
- package/dist/lib/neutral/{chunk-HLANPOBA.mjs → chunk-35EL65O4.mjs} +3 -3
- package/dist/lib/neutral/chunk-35EL65O4.mjs.map +7 -0
- package/dist/lib/neutral/chunk-54W7N6M6.mjs +445 -0
- package/dist/lib/neutral/chunk-54W7N6M6.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YXRGZYYH.mjs → chunk-5KB2WRI2.mjs} +6 -6
- package/dist/lib/neutral/chunk-5KB2WRI2.mjs.map +7 -0
- package/dist/lib/neutral/{TracePanel-KTZJ6JNR.mjs → chunk-5LKNH7FD.mjs} +5 -20
- package/dist/lib/neutral/chunk-5LKNH7FD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-SMFJD7BP.mjs → chunk-7FQT4XMI.mjs} +2 -2
- package/dist/lib/neutral/{chunk-RKVVK3R3.mjs → chunk-H77JTXAN.mjs} +17 -9
- package/dist/lib/neutral/chunk-H77JTXAN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-QAZMOFPI.mjs → chunk-IQZJ5TTM.mjs} +4 -4
- package/dist/lib/neutral/chunk-IQZJ5TTM.mjs.map +7 -0
- package/dist/lib/neutral/chunk-ZNDQVYUN.mjs +53 -0
- package/dist/lib/neutral/chunk-ZNDQVYUN.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +296 -109
- package/dist/lib/neutral/components/index.mjs.map +3 -3
- package/dist/lib/neutral/containers/index.mjs +12 -8
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/{create-chat-SGGQ6HVN.mjs → create-chat-Z3FNA6OJ.mjs} +2 -2
- package/dist/lib/neutral/{create-chat-SGGQ6HVN.mjs.map → create-chat-Z3FNA6OJ.mjs.map} +2 -2
- package/dist/lib/neutral/{create-object-U2SOFZLR.mjs → create-object-BJUDDKQQ.mjs} +2 -2
- package/dist/lib/neutral/execution-graph/index.mjs +156 -0
- package/dist/lib/neutral/execution-graph/index.mjs.map +4 -4
- package/dist/lib/neutral/{fork-chat-34KEF4ZJ.mjs → fork-chat-UYXYT6BT.mjs} +4 -4
- package/dist/lib/neutral/fork-chat-UYXYT6BT.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +233 -438
- package/dist/lib/neutral/hooks/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +3 -3
- package/dist/lib/neutral/markdown-extension-IJ5RQMQ4.mjs +126 -0
- package/dist/lib/neutral/markdown-extension-IJ5RQMQ4.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/meta.mjs +1 -1
- package/dist/lib/neutral/operations/index.mjs +1 -1
- package/dist/lib/neutral/plugin.mjs +2 -2
- package/dist/lib/neutral/{react-surface-XRTBW5OJ.mjs → react-surface-ES7UHZ65.mjs} +29 -17
- package/dist/lib/neutral/react-surface-ES7UHZ65.mjs.map +7 -0
- package/dist/lib/neutral/{run-prompt-in-new-chat-D5IIE2C7.mjs → run-prompt-in-new-chat-NIAGCKQV.mjs} +11 -8
- package/dist/lib/neutral/run-prompt-in-new-chat-NIAGCKQV.mjs.map +7 -0
- package/dist/lib/neutral/{settings-W4BLWQ53.mjs → settings-7Q3RITIT.mjs} +3 -3
- package/dist/lib/neutral/{settings-W4BLWQ53.mjs.map → settings-7Q3RITIT.mjs.map} +3 -3
- package/dist/lib/neutral/{state-H3G7QCU6.mjs → state-XO2UYSSG.mjs} +2 -2
- package/dist/lib/neutral/{state-H3G7QCU6.mjs.map → state-XO2UYSSG.mjs.map} +3 -3
- package/dist/lib/neutral/testing.mjs +1 -1
- package/dist/lib/neutral/translations.mjs +18 -11
- package/dist/lib/neutral/translations.mjs.map +3 -3
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +17 -57
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/Chat/Chat.d.ts +6 -3
- package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/src/components/Chat/Chat.stories.d.ts +32 -0
- package/dist/types/src/components/Chat/Chat.stories.d.ts.map +1 -0
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts.map +1 -1
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +6 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -1
- package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts +1 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/TaskList/TaskList.d.ts +8 -0
- package/dist/types/src/components/TaskList/TaskList.d.ts.map +1 -1
- package/dist/types/src/components/TaskList/TaskList.stories.d.ts +3 -0
- package/dist/types/src/components/TaskList/TaskList.stories.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/ChatArticle/ChatArticle.d.ts +2 -2
- package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ChatCompanion/ChatCompanion.d.ts +2 -2
- package/dist/types/src/containers/ChatDialog/ChatDialog.d.ts.map +1 -1
- package/dist/types/src/containers/PlanArticle/PlanArticle.d.ts.map +1 -1
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts +15 -0
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts.map +1 -0
- package/dist/types/src/containers/SpaceHomePrompt/index.d.ts +2 -0
- package/dist/types/src/containers/SpaceHomePrompt/index.d.ts.map +1 -0
- package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts +13 -0
- package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts.map +1 -0
- package/dist/types/src/containers/SpaceHomeSuggestions/index.d.ts +2 -0
- package/dist/types/src/containers/SpaceHomeSuggestions/index.d.ts.map +1 -0
- package/dist/types/src/containers/TracePanel/TracePanel.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +2 -0
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/execution-graph/execution-graph.d.ts +18 -0
- package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -1
- package/dist/types/src/execution-graph/index.d.ts +2 -1
- package/dist/types/src/execution-graph/index.d.ts.map +1 -1
- package/dist/types/src/execution-graph/pending-block-status.d.ts +26 -0
- package/dist/types/src/execution-graph/pending-block-status.d.ts.map +1 -0
- package/dist/types/src/execution-graph/pending-block-status.test.d.ts +2 -0
- package/dist/types/src/execution-graph/pending-block-status.test.d.ts.map +1 -0
- package/dist/types/src/extensions/prompt-extension.d.ts +1 -1
- package/dist/types/src/extensions/prompt-extension.d.ts.map +1 -1
- package/dist/types/src/feed-logger.d.ts +3 -2
- package/dist/types/src/feed-logger.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useProcessEphemeralStatus.d.ts +10 -0
- package/dist/types/src/hooks/useProcessEphemeralStatus.d.ts.map +1 -0
- package/dist/types/src/hooks/useTraceMessages.d.ts +12 -0
- package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +28 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/run-prompt-in-new-chat.d.ts.map +1 -1
- package/dist/types/src/paths.d.ts.map +1 -1
- package/dist/types/src/processor/processor.d.ts +23 -0
- package/dist/types/src/processor/processor.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Assistant.d.ts +1 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/AssistantEvents.d.ts.map +1 -1
- package/dist/types/src/types/AssistantOperation.d.ts +7 -7
- package/dist/types/src/util/error-cause.d.ts +3 -0
- package/dist/types/src/util/error-cause.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +38 -0
- package/package.json +71 -70
- package/src/AssistantPlugin.conversations.json +1 -1
- package/src/AssistantPlugin.test.ts +1 -1
- package/src/AssistantPlugin.ts +2 -2
- package/src/capabilities/agent-service.ts +5 -1
- package/src/capabilities/app-graph-builder.ts +15 -20
- package/src/capabilities/blueprint-definition.ts +2 -0
- package/src/capabilities/index.ts +1 -7
- package/src/capabilities/markdown-extension.ts +5 -1
- package/src/capabilities/react-surface.tsx +38 -23
- package/src/capabilities/settings.ts +2 -2
- package/src/capabilities/state.ts +1 -1
- package/src/components/AgentProperties/AgentProperties.tsx +1 -1
- package/src/components/AssistantSettings/AssistantSettings.tsx +2 -2
- package/src/components/Chat/Chat.stories.tsx +94 -0
- package/src/components/Chat/Chat.tsx +39 -6
- package/src/components/ChatPrompt/ChatActions.tsx +4 -2
- package/src/components/ChatPrompt/ChatMcpErrors.tsx +1 -1
- package/src/components/ChatPrompt/ChatOptions.tsx +26 -29
- package/src/components/ChatPrompt/ChatPrompt.tsx +1 -1
- package/src/components/ChatPrompt/ChatReferences.tsx +1 -1
- package/src/components/ChatThread/Anchor.stories.tsx +1 -1
- package/src/components/ChatThread/ChatThread.stories.tsx +1 -1
- package/src/components/ChatThread/DEBUG.md +23 -0
- package/src/components/ChatThread/widgets/SummaryWidget.tsx +1 -1
- package/src/components/ChatThread/widgets/ToolWidget.tsx +1 -1
- package/src/components/ProcessTree/ProcessTree.stories.tsx +7 -0
- package/src/components/ProcessTree/ProcessTree.tsx +191 -88
- package/src/components/TaskList/TaskList.stories.tsx +23 -2
- package/src/components/TaskList/TaskList.tsx +122 -28
- package/src/components/TemplateEditor/TemplateEditor.tsx +1 -1
- package/src/components/TemplateEditor/TemplateForm.tsx +1 -1
- package/src/components/ToolBlock/ToolBlock.tsx +1 -1
- package/src/components/index.ts +1 -0
- package/src/containers/AgentArticle/AgentArticle.stories.tsx +4 -4
- package/src/containers/AgentArticle/AgentArticle.tsx +9 -9
- package/src/containers/ChatArticle/ChatArticle.tsx +18 -10
- package/src/containers/ChatCompanion/ChatCompanion.tsx +2 -2
- package/src/containers/ChatDialog/ChatDialog.tsx +5 -3
- package/src/containers/PlanArticle/PlanArticle.tsx +5 -1
- package/src/containers/RoutineArticle/RoutineArticle.tsx +2 -2
- package/src/containers/SpaceHomePrompt/SpaceHomePrompt.tsx +105 -0
- package/src/containers/SpaceHomePrompt/index.ts +5 -0
- package/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.tsx +69 -0
- package/src/containers/SpaceHomeSuggestions/index.ts +5 -0
- package/src/containers/TracePanel/TracePanel.tsx +3 -30
- package/src/containers/TriggerStatus/TriggerStatus.tsx +2 -2
- package/src/containers/index.ts +2 -0
- package/src/execution-graph/execution-graph.ts +130 -0
- package/src/execution-graph/index.ts +10 -0
- package/src/execution-graph/pending-block-status.test.ts +114 -0
- package/src/execution-graph/pending-block-status.ts +88 -0
- package/src/execution-graph/sub-agent-delegation.test.ts +16 -1
- package/src/extensions/prompt-extension.ts +102 -73
- package/src/feed-logger.ts +21 -19
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useChatProcessor.ts +1 -1
- package/src/hooks/useChatServices.ts +2 -2
- package/src/hooks/useChatToolbarActions.ts +5 -5
- package/src/hooks/useContextBinder.ts +1 -1
- package/src/hooks/useProcessEphemeralStatus.ts +192 -0
- package/src/hooks/useTraceMessages.ts +41 -0
- package/src/meta.ts +3 -31
- package/src/operations/create-chat.ts +1 -1
- package/src/operations/fork-chat.ts +3 -3
- package/src/operations/run-prompt-in-new-chat.ts +5 -3
- package/src/paths.ts +2 -2
- package/src/processor/processor.node.test.ts +71 -1
- package/src/processor/processor.ts +58 -2
- 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 +0 -1
- package/src/translations.ts +18 -10
- package/src/types/AssistantCapabilities.ts +3 -3
- package/src/types/AssistantEvents.ts +1 -1
- package/src/types/AssistantOperation.ts +1 -1
- package/src/util/error-cause.ts +21 -0
- package/dist/lib/neutral/AgentArticle-K7XM46OQ.mjs.map +0 -7
- package/dist/lib/neutral/AssistantSettings-GG52BLKS.mjs.map +0 -7
- package/dist/lib/neutral/ChatCompanion-LBUHYWQG.mjs.map +0 -7
- package/dist/lib/neutral/ChatDialog-DCA6FLOV.mjs.map +0 -7
- package/dist/lib/neutral/PlanArticle-TS5ULWYS.mjs.map +0 -7
- package/dist/lib/neutral/RoutineArticle-5NYXHRG6.mjs.map +0 -7
- package/dist/lib/neutral/TracePanel-KTZJ6JNR.mjs.map +0 -7
- package/dist/lib/neutral/TriggerStatus-X7Y5JFZJ.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-WUFHQH3Y.mjs.map +0 -7
- package/dist/lib/neutral/blueprint-definition-MH2QLYQH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HLANPOBA.mjs.map +0 -7
- package/dist/lib/neutral/chunk-QAZMOFPI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-RKVVK3R3.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-XYHPOGTK.mjs +0 -43
- package/dist/lib/neutral/chunk-XYHPOGTK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YXRGZYYH.mjs.map +0 -7
- package/dist/lib/neutral/fork-chat-34KEF4ZJ.mjs.map +0 -7
- package/dist/lib/neutral/markdown-extension-YMIFDMYF.mjs +0 -110
- package/dist/lib/neutral/markdown-extension-YMIFDMYF.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-XRTBW5OJ.mjs.map +0 -7
- package/dist/lib/neutral/run-prompt-in-new-chat-D5IIE2C7.mjs.map +0 -7
- package/src/testing/trace-timeline.node.conversations.json +0 -1
- /package/dist/lib/neutral/{ChatArticle-VNVZCDUR.mjs.map → ChatArticle-KT46SUFU.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-SMFJD7BP.mjs.map → chunk-7FQT4XMI.mjs.map} +0 -0
- /package/dist/lib/neutral/{create-object-U2SOFZLR.mjs.map → create-object-BJUDDKQQ.mjs.map} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { syntaxTree } from '@codemirror/language';
|
|
6
|
-
import { type Extension } from '@codemirror/state';
|
|
6
|
+
import { Facet, type Extension, type Range } from '@codemirror/state';
|
|
7
7
|
import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';
|
|
8
8
|
|
|
9
9
|
import { Domino } from '@dxos/ui';
|
|
@@ -13,73 +13,104 @@ export type PromptExtensionOptions = {
|
|
|
13
13
|
onRun: (promptText: string) => void;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
16
|
+
type OnRun = (text: string) => void;
|
|
17
|
+
|
|
18
|
+
// Module-level facet so the plugin singleton can read the latest handler.
|
|
19
|
+
const promptHandlerFacet = Facet.define<OnRun, OnRun | null>({
|
|
20
|
+
combine: (handlers) => handlers[0] ?? null,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Module-level singleton — CM6 deduplicates by reference equality, preventing duplicate buttons
|
|
24
|
+
// when the extension is contributed more than once.
|
|
25
|
+
const promptPlugin = ViewPlugin.fromClass(
|
|
26
|
+
class {
|
|
27
|
+
decorations: DecorationSet;
|
|
28
|
+
|
|
29
|
+
constructor(view: EditorView) {
|
|
30
|
+
this.decorations = this.buildDecorations(view);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
update(update: ViewUpdate) {
|
|
34
|
+
if (
|
|
35
|
+
update.docChanged ||
|
|
36
|
+
update.viewportChanged ||
|
|
37
|
+
update.selectionSet ||
|
|
38
|
+
update.focusChanged ||
|
|
39
|
+
update.startState.facet(promptHandlerFacet) !== update.state.facet(promptHandlerFacet)
|
|
40
|
+
) {
|
|
41
|
+
this.decorations = this.buildDecorations(update.view);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
buildDecorations(view: EditorView): DecorationSet {
|
|
46
|
+
const onRun = view.state.facet(promptHandlerFacet);
|
|
47
|
+
if (!onRun) {
|
|
48
|
+
return Decoration.none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const ranges: Range<Decoration>[] = [];
|
|
52
|
+
|
|
53
|
+
syntaxTree(view.state).iterate({
|
|
54
|
+
enter: (node) => {
|
|
55
|
+
if (node.name === 'FencedCode') {
|
|
56
|
+
const info = node.node.getChild('CodeInfo');
|
|
57
|
+
if (info) {
|
|
58
|
+
const type = view.state.sliceDoc(info.from, info.to);
|
|
59
|
+
const text = node.node.getChild('CodeText');
|
|
60
|
+
if (type === 'prompt' && text) {
|
|
61
|
+
const content = view.state.sliceDoc(text.from, text.to).trim();
|
|
62
|
+
if (content.length > 0) {
|
|
63
|
+
// Mark the header line as a positioned container for the button overlay.
|
|
64
|
+
ranges.push(Decoration.line({ class: 'cm-prompt-header' }).range(node.from, node.from));
|
|
65
|
+
ranges.push(
|
|
66
|
+
Decoration.widget({ widget: new PromptRunWidget(content, onRun), side: -1 }).range(
|
|
67
|
+
node.from,
|
|
68
|
+
node.from,
|
|
69
|
+
),
|
|
70
|
+
);
|
|
56
71
|
}
|
|
57
72
|
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// sort=true lets CM6 order by startSide (line decorations before widgets at the same position).
|
|
79
|
+
return Decoration.set(ranges, true);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
decorations: (v) => v.decorations,
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// Base theme wires up the positioned container on the header line.
|
|
88
|
+
const promptTheme = EditorView.baseTheme({
|
|
89
|
+
'.cm-prompt-header': {
|
|
90
|
+
position: 'relative',
|
|
91
|
+
overflow: 'visible',
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* CodeMirror extension that adds a "run" button to ```prompt fenced code blocks.
|
|
97
|
+
*/
|
|
98
|
+
export const promptRunExtension = ({ onRun }: PromptExtensionOptions): Extension => [
|
|
99
|
+
promptHandlerFacet.of(onRun),
|
|
100
|
+
promptPlugin,
|
|
101
|
+
promptTheme,
|
|
102
|
+
];
|
|
72
103
|
|
|
73
104
|
class PromptRunWidget extends WidgetType {
|
|
74
105
|
constructor(
|
|
75
106
|
private readonly prompt: string,
|
|
76
|
-
private readonly onClick:
|
|
107
|
+
private readonly onClick: OnRun,
|
|
77
108
|
) {
|
|
78
109
|
super();
|
|
79
110
|
}
|
|
80
111
|
|
|
81
112
|
override eq(other: this) {
|
|
82
|
-
return this.prompt === other.prompt;
|
|
113
|
+
return this.prompt === other.prompt && this.onClick === other.onClick;
|
|
83
114
|
}
|
|
84
115
|
|
|
85
116
|
override ignoreEvent() {
|
|
@@ -87,24 +118,22 @@ class PromptRunWidget extends WidgetType {
|
|
|
87
118
|
}
|
|
88
119
|
|
|
89
120
|
override toDOM() {
|
|
90
|
-
return Domino.of('
|
|
91
|
-
.classNames(
|
|
121
|
+
return Domino.of('button')
|
|
122
|
+
.classNames(
|
|
123
|
+
'dx-button h-6 w-6 min-h-0 p-1 absolute top-0 right-0 bg-green-bg hover:bg-green-surface text-green-fg',
|
|
124
|
+
)
|
|
125
|
+
.on('mousedown', (event) => {
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
event.stopPropagation();
|
|
128
|
+
this.onClick(this.prompt);
|
|
129
|
+
})
|
|
92
130
|
.append(
|
|
93
|
-
Domino.of('
|
|
94
|
-
.classNames('
|
|
95
|
-
.on('mousedown', (event) => {
|
|
96
|
-
event.preventDefault();
|
|
97
|
-
event.stopPropagation();
|
|
98
|
-
this.onClick(this.prompt);
|
|
99
|
-
})
|
|
131
|
+
Domino.of('svg', Domino.SVG)
|
|
132
|
+
.classNames('w-4 h-4 cursor-pointer')
|
|
100
133
|
.append(
|
|
101
|
-
Domino.of('
|
|
102
|
-
.
|
|
103
|
-
|
|
104
|
-
Domino.of('use', Domino.SVG).attributes({
|
|
105
|
-
href: Domino.icon('ph--play--regular'),
|
|
106
|
-
}),
|
|
107
|
-
),
|
|
134
|
+
Domino.of('use', Domino.SVG).attributes({
|
|
135
|
+
href: Domino.icon('ph--sparkle--regular'),
|
|
136
|
+
}),
|
|
108
137
|
),
|
|
109
138
|
).root;
|
|
110
139
|
}
|
package/src/feed-logger.ts
CHANGED
|
@@ -8,24 +8,25 @@ import * as Layer from 'effect/Layer';
|
|
|
8
8
|
import { createFeedServiceLayer, type Space, getSpace } from '@dxos/client/echo';
|
|
9
9
|
import { Sequence, type SequenceEvent, type SequenceLogger } from '@dxos/conductor';
|
|
10
10
|
import { Feed, Obj, Ref } from '@dxos/echo';
|
|
11
|
-
import { type Queue } from '@dxos/echo-client';
|
|
12
11
|
import { EffectEx } from '@dxos/effect';
|
|
13
12
|
import { InvocationTraceEndEvent, InvocationTraceEventType, InvocationTraceStartEvent } from '@dxos/functions-runtime';
|
|
14
13
|
import { TraceEvent } from '@dxos/functions-runtime';
|
|
15
14
|
import { InvocationOutcome } from '@dxos/functions-runtime';
|
|
16
15
|
import { invariant } from '@dxos/invariant';
|
|
17
|
-
import {
|
|
16
|
+
import { type EntityId } from '@dxos/keys';
|
|
18
17
|
|
|
19
18
|
export class QueueLogger implements SequenceLogger {
|
|
20
19
|
private _space: Space;
|
|
21
20
|
private _invocationTraceFeed: Feed.Feed;
|
|
22
21
|
private _feedServiceLayer: Layer.Layer<Feed.FeedService>;
|
|
22
|
+
/** Per-invocation trace feeds, keyed by invocationId. Created on `begin` and looked up for subsequent events. */
|
|
23
|
+
private _invocationFeeds = new Map<EntityId, Feed.Feed>();
|
|
23
24
|
|
|
24
25
|
constructor(private readonly sequence: Sequence.Sequence) {
|
|
25
26
|
const space = getSpace(sequence);
|
|
26
27
|
invariant(space, 'Space not found');
|
|
27
28
|
this._space = space;
|
|
28
|
-
this._feedServiceLayer = createFeedServiceLayer(space.
|
|
29
|
+
this._feedServiceLayer = createFeedServiceLayer(space.db);
|
|
29
30
|
|
|
30
31
|
const existingFeedRef = this._space.properties.invocationTraceFeed;
|
|
31
32
|
|
|
@@ -47,18 +48,22 @@ export class QueueLogger implements SequenceLogger {
|
|
|
47
48
|
|
|
48
49
|
log(event: SequenceEvent) {
|
|
49
50
|
switch (event.type) {
|
|
50
|
-
case 'begin':
|
|
51
|
+
case 'begin': {
|
|
52
|
+
// Create a per-invocation trace feed and store it so subsequent events can append to it.
|
|
53
|
+
const invocationFeed = this._space.db.add(Feed.make({ namespace: 'trace' }));
|
|
54
|
+
this._invocationFeeds.set(event.invocationId, invocationFeed);
|
|
51
55
|
void this._appendToTraceFeed([
|
|
52
56
|
Obj.make(InvocationTraceStartEvent, {
|
|
53
57
|
type: InvocationTraceEventType.START,
|
|
54
58
|
invocationId: event.invocationId,
|
|
55
59
|
timestamp: Date.now(),
|
|
56
60
|
input: {},
|
|
57
|
-
invocationTraceFeed: Ref.
|
|
61
|
+
invocationTraceFeed: Ref.make(invocationFeed),
|
|
58
62
|
invocationTarget: Ref.make(this.sequence),
|
|
59
63
|
}),
|
|
60
64
|
]);
|
|
61
65
|
break;
|
|
66
|
+
}
|
|
62
67
|
case 'end':
|
|
63
68
|
void this._appendToTraceFeed([
|
|
64
69
|
Obj.make(InvocationTraceEndEvent, {
|
|
@@ -68,10 +73,12 @@ export class QueueLogger implements SequenceLogger {
|
|
|
68
73
|
outcome: InvocationOutcome.SUCCESS,
|
|
69
74
|
}),
|
|
70
75
|
]);
|
|
76
|
+
// Clean up the per-invocation feed reference once the invocation is complete.
|
|
77
|
+
this._invocationFeeds.delete(event.invocationId);
|
|
71
78
|
break;
|
|
72
79
|
case 'step-start':
|
|
73
80
|
case 'step-complete':
|
|
74
|
-
void this.
|
|
81
|
+
void this._appendToInvocationFeed(event.invocationId, [
|
|
75
82
|
Obj.make(TraceEvent, {
|
|
76
83
|
outcome: event.type,
|
|
77
84
|
truncated: false,
|
|
@@ -89,7 +96,7 @@ export class QueueLogger implements SequenceLogger {
|
|
|
89
96
|
]);
|
|
90
97
|
break;
|
|
91
98
|
case 'message':
|
|
92
|
-
void this.
|
|
99
|
+
void this._appendToInvocationFeed(event.invocationId, [
|
|
93
100
|
Obj.make(TraceEvent, {
|
|
94
101
|
outcome: event.type,
|
|
95
102
|
truncated: false,
|
|
@@ -107,7 +114,7 @@ export class QueueLogger implements SequenceLogger {
|
|
|
107
114
|
]);
|
|
108
115
|
break;
|
|
109
116
|
case 'block':
|
|
110
|
-
void this.
|
|
117
|
+
void this._appendToInvocationFeed(event.invocationId, [
|
|
111
118
|
Obj.make(TraceEvent, {
|
|
112
119
|
outcome: event.type,
|
|
113
120
|
truncated: false,
|
|
@@ -127,10 +134,6 @@ export class QueueLogger implements SequenceLogger {
|
|
|
127
134
|
}
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
private _getTraceQueueEchoId(invocationId: EntityId): EID.EID {
|
|
131
|
-
return EID.make({ spaceId: this._space.id, entityId: invocationId });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
137
|
private _appendToTraceFeed(items: any[]): Promise<void> {
|
|
135
138
|
return Feed.append(this._invocationTraceFeed, items).pipe(
|
|
136
139
|
Effect.provide(this._feedServiceLayer),
|
|
@@ -138,12 +141,11 @@ export class QueueLogger implements SequenceLogger {
|
|
|
138
141
|
);
|
|
139
142
|
}
|
|
140
143
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return this._space.queues.get(echoUri);
|
|
144
|
+
private _appendToInvocationFeed(invocationId: EntityId, items: any[]): Promise<void> {
|
|
145
|
+
const invocationFeed = this._invocationFeeds.get(invocationId);
|
|
146
|
+
if (!invocationFeed) {
|
|
147
|
+
return Promise.resolve();
|
|
148
|
+
}
|
|
149
|
+
return this._space.db.appendToFeed(invocationFeed, items);
|
|
148
150
|
}
|
|
149
151
|
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -16,5 +16,7 @@ export * from './useFlush';
|
|
|
16
16
|
export * from './useOnline';
|
|
17
17
|
export * from './usePresets';
|
|
18
18
|
export * from './useReferencesProvider';
|
|
19
|
+
export * from './useTraceMessages';
|
|
20
|
+
export * from './useProcessEphemeralStatus';
|
|
19
21
|
|
|
20
22
|
export { type AiChatProcessor } from '../processor';
|
|
@@ -57,7 +57,7 @@ export const useChatProcessor = ({
|
|
|
57
57
|
if (!feedTarget) {
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
|
-
const feedServiceLayer = createFeedServiceLayer(space.
|
|
60
|
+
const feedServiceLayer = createFeedServiceLayer(space.db);
|
|
61
61
|
const runtime = await EffectEx.runAndForwardErrors(
|
|
62
62
|
Effect.runtime<Feed.FeedService>().pipe(Effect.provide(feedServiceLayer)),
|
|
63
63
|
);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Capabilities } from '@dxos/app-framework';
|
|
6
6
|
import { useCapability } from '@dxos/app-framework/ui';
|
|
7
|
-
import {
|
|
7
|
+
import { AppSpace } from '@dxos/app-toolkit';
|
|
8
8
|
import { type Key } from '@dxos/echo';
|
|
9
9
|
import { useClient } from '@dxos/react-client';
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ export type UseChatServicesProps = {
|
|
|
21
21
|
*/
|
|
22
22
|
export const useChatServices = ({ id }: UseChatServicesProps) => {
|
|
23
23
|
const client = useClient();
|
|
24
|
-
id ??= getPersonalSpace(client)?.id;
|
|
24
|
+
id ??= AppSpace.getPersonalSpace(client)?.id;
|
|
25
25
|
|
|
26
26
|
const runtime = useCapability(Capabilities.ProcessManagerRuntime);
|
|
27
27
|
return id ? runtime : undefined;
|
|
@@ -35,12 +35,12 @@ export const useChatToolbarActions = ({ chat, companionTo }: ChatToolbarActionsP
|
|
|
35
35
|
|
|
36
36
|
const builder = MenuBuilder.make()
|
|
37
37
|
.root({
|
|
38
|
-
label: ['chat-toolbar.title', { ns: meta.
|
|
38
|
+
label: ['chat-toolbar.title', { ns: meta.profile.key }],
|
|
39
39
|
})
|
|
40
40
|
.action(
|
|
41
41
|
'new',
|
|
42
42
|
{
|
|
43
|
-
label: ['new-thread.button', { ns: meta.
|
|
43
|
+
label: ['new-thread.button', { ns: meta.profile.key }],
|
|
44
44
|
icon: 'ph--plus--regular',
|
|
45
45
|
type: 'new',
|
|
46
46
|
disabled: !companionTo,
|
|
@@ -56,7 +56,7 @@ export const useChatToolbarActions = ({ chat, companionTo }: ChatToolbarActionsP
|
|
|
56
56
|
.action(
|
|
57
57
|
'rename',
|
|
58
58
|
{
|
|
59
|
-
label: ['rename-thread.button', { ns: meta.
|
|
59
|
+
label: ['rename-thread.button', { ns: meta.profile.key }],
|
|
60
60
|
icon: 'ph--magic-wand--regular',
|
|
61
61
|
type: 'rename',
|
|
62
62
|
disabled: !chat,
|
|
@@ -70,7 +70,7 @@ export const useChatToolbarActions = ({ chat, companionTo }: ChatToolbarActionsP
|
|
|
70
70
|
.action(
|
|
71
71
|
'branch',
|
|
72
72
|
{
|
|
73
|
-
label: ['branch-thread.menu', { ns: meta.
|
|
73
|
+
label: ['branch-thread.menu', { ns: meta.profile.key }],
|
|
74
74
|
icon: 'ph--git-branch--regular',
|
|
75
75
|
type: 'branch',
|
|
76
76
|
disabled: !chat || !db,
|
|
@@ -86,7 +86,7 @@ export const useChatToolbarActions = ({ chat, companionTo }: ChatToolbarActionsP
|
|
|
86
86
|
builder.group(
|
|
87
87
|
'chats',
|
|
88
88
|
{
|
|
89
|
-
label: ['chat-history.label', { ns: meta.
|
|
89
|
+
label: ['chat-history.label', { ns: meta.profile.key }],
|
|
90
90
|
icon: 'ph--clock-counter-clockwise--regular',
|
|
91
91
|
selectCardinality: 'single',
|
|
92
92
|
variant: 'dropdownMenu',
|
|
@@ -26,7 +26,7 @@ export const useContextBinder = (
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const feedServiceLayer = createFeedServiceLayer(space.
|
|
29
|
+
const feedServiceLayer = createFeedServiceLayer(space.db);
|
|
30
30
|
const runtime = await EffectEx.runAndForwardErrors(
|
|
31
31
|
Effect.runtime<Feed.FeedService>().pipe(Effect.provide(feedServiceLayer)),
|
|
32
32
|
);
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Atom } from '@effect-atom/atom';
|
|
6
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Fiber from 'effect/Fiber';
|
|
9
|
+
import * as Stream from 'effect/Stream';
|
|
10
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
11
|
+
|
|
12
|
+
import { Capabilities } from '@dxos/app-framework';
|
|
13
|
+
import { useOptionalCapability } from '@dxos/app-framework/ui';
|
|
14
|
+
import { Process, ServiceResolver, type Trace } from '@dxos/compute';
|
|
15
|
+
import { ProcessManager } from '@dxos/compute-runtime';
|
|
16
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
17
|
+
|
|
18
|
+
import { resolveEphemeralStatusUpdate } from '#execution-graph';
|
|
19
|
+
|
|
20
|
+
const atomEmpty = Atom.make(() => [] as const);
|
|
21
|
+
|
|
22
|
+
const ACTIVE_PROCESS_STATES = new Set<Process.State>([Process.State.RUNNING, Process.State.HYBERNATING]);
|
|
23
|
+
|
|
24
|
+
/** Durable trace lines that represent finished work, not in-flight status. */
|
|
25
|
+
export const isTerminalActivityLine = (line: string): boolean =>
|
|
26
|
+
line.endsWith(' - Success') || line.endsWith(' - Error') || line === 'Agent completed request';
|
|
27
|
+
|
|
28
|
+
const collectDescendantPids = (processes: readonly Process.Info[], rootPid: string): Set<string> => {
|
|
29
|
+
const pids = new Set([rootPid]);
|
|
30
|
+
let expanded = true;
|
|
31
|
+
while (expanded) {
|
|
32
|
+
expanded = false;
|
|
33
|
+
for (const process of processes) {
|
|
34
|
+
const pid = String(process.pid);
|
|
35
|
+
const parentPid = process.parentPid ? String(process.parentPid) : undefined;
|
|
36
|
+
if (parentPid && pids.has(parentPid) && !pids.has(pid)) {
|
|
37
|
+
pids.add(pid);
|
|
38
|
+
expanded = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return pids;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const resolveSubscribePids = (agentPid: Process.ID, processes: readonly Process.Info[]): Process.ID[] => {
|
|
46
|
+
const rootPid = String(agentPid);
|
|
47
|
+
const descendants = collectDescendantPids(processes, rootPid);
|
|
48
|
+
const activePids = processes
|
|
49
|
+
.filter((process) => descendants.has(String(process.pid)) && ACTIVE_PROCESS_STATES.has(process.state))
|
|
50
|
+
.map((process) => process.pid);
|
|
51
|
+
|
|
52
|
+
if (activePids.length > 0) {
|
|
53
|
+
return activePids;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return [agentPid];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const attachActiveHandle = (
|
|
60
|
+
processManager: ProcessManager.Manager,
|
|
61
|
+
pid: Process.ID,
|
|
62
|
+
): Effect.Effect<ProcessManager.Handle<any, any> | undefined> =>
|
|
63
|
+
Effect.gen(function* () {
|
|
64
|
+
const maxAttempts = 15;
|
|
65
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
66
|
+
const handle = yield* processManager.attach(pid).pipe(Effect.catchAll(() => Effect.succeed(undefined)));
|
|
67
|
+
if (handle && ACTIVE_PROCESS_STATES.has(handle.status.state)) {
|
|
68
|
+
return handle;
|
|
69
|
+
}
|
|
70
|
+
if (handle) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
yield* Effect.sleep(100);
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Subscribes to ephemeral trace events for a delegated sub-agent process subtree
|
|
80
|
+
* and surfaces the latest pending text or tool-call block as a status line.
|
|
81
|
+
*/
|
|
82
|
+
export const useProcessEphemeralStatus = (
|
|
83
|
+
agentPid: Process.ID | undefined,
|
|
84
|
+
space: Space | undefined,
|
|
85
|
+
): string | undefined => {
|
|
86
|
+
// Optional capabilities: the live status is a progressive enhancement, so the component still
|
|
87
|
+
// renders (e.g. in standalone stories) when there is no plugin manager / process runtime.
|
|
88
|
+
const runtime = useOptionalCapability(Capabilities.ProcessManagerRuntime);
|
|
89
|
+
const monitor = useOptionalCapability(Capabilities.ProcessMonitor);
|
|
90
|
+
const processes = useAtomValue(monitor?.processTreeAtom ?? atomEmpty);
|
|
91
|
+
const [status, setStatus] = useState<string | undefined>();
|
|
92
|
+
const fibersRef = useRef<Fiber.RuntimeFiber<void, unknown>[]>([]);
|
|
93
|
+
|
|
94
|
+
const subscribePidsKey = useMemo(() => {
|
|
95
|
+
if (!agentPid) {
|
|
96
|
+
return '';
|
|
97
|
+
}
|
|
98
|
+
return resolveSubscribePids(agentPid, processes)
|
|
99
|
+
.map((pid) => String(pid))
|
|
100
|
+
.sort()
|
|
101
|
+
.join('|');
|
|
102
|
+
}, [agentPid, processes]);
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!agentPid || !space?.id || !runtime || !subscribePidsKey) {
|
|
106
|
+
setStatus(undefined);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const pids = subscribePidsKey.split('|').map((pid) => Process.ID.make(pid));
|
|
111
|
+
let disposed = false;
|
|
112
|
+
let replaying = true;
|
|
113
|
+
let replayStatus: string | undefined;
|
|
114
|
+
const endReplay = () => {
|
|
115
|
+
replaying = false;
|
|
116
|
+
if (!disposed) {
|
|
117
|
+
setStatus(replayStatus);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
queueMicrotask(endReplay);
|
|
121
|
+
fibersRef.current = [];
|
|
122
|
+
|
|
123
|
+
const handleEphemeralMessage = (message: Trace.Message) => {
|
|
124
|
+
const update = resolveEphemeralStatusUpdate(message);
|
|
125
|
+
if (update === 'unchanged') {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (replaying) {
|
|
130
|
+
replayStatus = update.line;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
setStatus(update.line);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const layer = ServiceResolver.provide({ space: space.id }, ProcessManager.ProcessManagerService);
|
|
137
|
+
|
|
138
|
+
const subscribe = (pid: Process.ID) =>
|
|
139
|
+
Effect.gen(function* () {
|
|
140
|
+
// `attachActiveHandle` polls, so a teardown can land mid-resolve; bail before forking a
|
|
141
|
+
// daemon that the cleanup pass below would never see (and thus never interrupt).
|
|
142
|
+
if (disposed) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const processManager = yield* ProcessManager.ProcessManagerService;
|
|
146
|
+
const handle = yield* attachActiveHandle(processManager, pid);
|
|
147
|
+
if (!handle || disposed) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// `forkDaemon` keeps the stream fiber alive after `runPromise(forEach)` returns;
|
|
152
|
+
// scoped `fork` is interrupted when the subscribe effect's parent scope closes.
|
|
153
|
+
const fiber = yield* handle.subscribeEphemeral().pipe(
|
|
154
|
+
Stream.runForEach((message) =>
|
|
155
|
+
Effect.sync(() => {
|
|
156
|
+
if (disposed) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
handleEphemeralMessage(message);
|
|
160
|
+
}),
|
|
161
|
+
),
|
|
162
|
+
Effect.forkDaemon,
|
|
163
|
+
);
|
|
164
|
+
if (disposed) {
|
|
165
|
+
yield* Fiber.interrupt(fiber);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
fibersRef.current.push(fiber);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
void runtime
|
|
172
|
+
.runPromise(
|
|
173
|
+
Effect.forEach(pids, subscribe, { concurrency: 'unbounded', discard: true }).pipe(Effect.provide(layer)),
|
|
174
|
+
)
|
|
175
|
+
.catch(() => {
|
|
176
|
+
if (!disposed) {
|
|
177
|
+
setStatus(undefined);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return () => {
|
|
182
|
+
disposed = true;
|
|
183
|
+
const fibers = fibersRef.current;
|
|
184
|
+
fibersRef.current = [];
|
|
185
|
+
for (const fiber of fibers) {
|
|
186
|
+
void runtime.runPromise(Fiber.interrupt(fiber).pipe(Effect.provide(layer)));
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}, [agentPid, runtime, space?.id, subscribePidsKey]);
|
|
190
|
+
|
|
191
|
+
return status;
|
|
192
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Atom } from '@effect-atom/atom';
|
|
6
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
7
|
+
import { pipe } from 'effect/Function';
|
|
8
|
+
import { useMemo } from 'react';
|
|
9
|
+
|
|
10
|
+
import { Trace } from '@dxos/compute';
|
|
11
|
+
import { Filter, Query } from '@dxos/echo';
|
|
12
|
+
import { FeedTraceSink } from '@dxos/functions-runtime';
|
|
13
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
14
|
+
|
|
15
|
+
const atomEmpty = Atom.make(() => [] as const);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Atom of raw trace messages for a space — the input to `buildExecutionGraph`.
|
|
19
|
+
*/
|
|
20
|
+
export const getTraceMessagesAtom = (space: Space): Atom.Atom<readonly Trace.Message[]> =>
|
|
21
|
+
pipe(
|
|
22
|
+
space.db.query(FeedTraceSink.query).atom,
|
|
23
|
+
Atom.map(
|
|
24
|
+
(feeds) =>
|
|
25
|
+
// TODO(dmaretskyi): Single query with limit(1) and feed traversal when query supports it.
|
|
26
|
+
space.db.query(
|
|
27
|
+
feeds.length > 0
|
|
28
|
+
? Query.type(Trace.Message).from(feeds[0])
|
|
29
|
+
: (Query.select(Filter.nothing()) as Query.Query<never>),
|
|
30
|
+
).atom,
|
|
31
|
+
),
|
|
32
|
+
(atom) => Atom.make((get) => get(get(atom))),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Subscribes to the space invocation trace feed.
|
|
37
|
+
*/
|
|
38
|
+
export const useTraceMessages = (space?: Space): readonly Trace.Message[] => {
|
|
39
|
+
const atom = useMemo(() => (space ? getTraceMessagesAtom(space) : atomEmpty), [space]);
|
|
40
|
+
return useAtomValue(atom);
|
|
41
|
+
};
|