@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.
Files changed (254) hide show
  1. package/dist/lib/neutral/{AgentArticle-K7XM46OQ.mjs → AgentArticle-2BEPWUMN.mjs} +9 -7
  2. package/dist/lib/neutral/AgentArticle-2BEPWUMN.mjs.map +7 -0
  3. package/dist/lib/neutral/AssistantPlugin.mjs +1 -1
  4. package/dist/lib/neutral/{AssistantSettings-GG52BLKS.mjs → AssistantSettings-7ALY4BMS.mjs} +3 -3
  5. package/dist/lib/neutral/AssistantSettings-7ALY4BMS.mjs.map +7 -0
  6. package/dist/lib/neutral/{ChatArticle-VNVZCDUR.mjs → ChatArticle-KT46SUFU.mjs} +2 -2
  7. package/dist/lib/neutral/{ChatCompanion-LBUHYWQG.mjs → ChatCompanion-YHC43RYQ.mjs} +4 -4
  8. package/dist/lib/neutral/ChatCompanion-YHC43RYQ.mjs.map +7 -0
  9. package/dist/lib/neutral/{ChatDialog-DCA6FLOV.mjs → ChatDialog-YZDZLIQA.mjs} +5 -4
  10. package/dist/lib/neutral/ChatDialog-YZDZLIQA.mjs.map +7 -0
  11. package/dist/lib/neutral/{PlanArticle-TS5ULWYS.mjs → PlanArticle-VPK2IYWU.mjs} +8 -2
  12. package/dist/lib/neutral/PlanArticle-VPK2IYWU.mjs.map +7 -0
  13. package/dist/lib/neutral/{RoutineArticle-5NYXHRG6.mjs → RoutineArticle-FK5BXQN5.mjs} +3 -3
  14. package/dist/lib/neutral/RoutineArticle-FK5BXQN5.mjs.map +7 -0
  15. package/dist/lib/neutral/SpaceHomePrompt-HTWQKLGI.mjs +113 -0
  16. package/dist/lib/neutral/SpaceHomePrompt-HTWQKLGI.mjs.map +7 -0
  17. package/dist/lib/neutral/SpaceHomeSuggestions-6G4E7GNJ.mjs +50 -0
  18. package/dist/lib/neutral/SpaceHomeSuggestions-6G4E7GNJ.mjs.map +7 -0
  19. package/dist/lib/neutral/TracePanel-T552TAOH.mjs +12 -0
  20. package/dist/lib/neutral/TracePanel-T552TAOH.mjs.map +7 -0
  21. package/dist/lib/neutral/{TriggerStatus-X7Y5JFZJ.mjs → TriggerStatus-RBOHHDOK.mjs} +3 -3
  22. package/dist/lib/neutral/TriggerStatus-RBOHHDOK.mjs.map +7 -0
  23. package/dist/lib/neutral/{agent-service-WCAP5MLI.mjs → agent-service-WV5CSHAG.mjs} +4 -2
  24. package/dist/lib/neutral/{agent-service-WCAP5MLI.mjs.map → agent-service-WV5CSHAG.mjs.map} +3 -3
  25. package/dist/lib/neutral/{app-graph-builder-WUFHQH3Y.mjs → app-graph-builder-PTSRZXRN.mjs} +13 -13
  26. package/dist/lib/neutral/app-graph-builder-PTSRZXRN.mjs.map +7 -0
  27. package/dist/lib/neutral/{blueprint-definition-MH2QLYQH.mjs → blueprint-definition-2XPYI35X.mjs} +4 -3
  28. package/dist/lib/neutral/blueprint-definition-2XPYI35X.mjs.map +7 -0
  29. package/dist/lib/neutral/capabilities/index.mjs +8 -8
  30. package/dist/lib/neutral/capabilities/index.mjs.map +2 -2
  31. package/dist/lib/neutral/{chunk-HLANPOBA.mjs → chunk-35EL65O4.mjs} +3 -3
  32. package/dist/lib/neutral/chunk-35EL65O4.mjs.map +7 -0
  33. package/dist/lib/neutral/chunk-54W7N6M6.mjs +445 -0
  34. package/dist/lib/neutral/chunk-54W7N6M6.mjs.map +7 -0
  35. package/dist/lib/neutral/{chunk-YXRGZYYH.mjs → chunk-5KB2WRI2.mjs} +6 -6
  36. package/dist/lib/neutral/chunk-5KB2WRI2.mjs.map +7 -0
  37. package/dist/lib/neutral/{TracePanel-KTZJ6JNR.mjs → chunk-5LKNH7FD.mjs} +5 -20
  38. package/dist/lib/neutral/chunk-5LKNH7FD.mjs.map +7 -0
  39. package/dist/lib/neutral/{chunk-SMFJD7BP.mjs → chunk-7FQT4XMI.mjs} +2 -2
  40. package/dist/lib/neutral/{chunk-RKVVK3R3.mjs → chunk-H77JTXAN.mjs} +17 -9
  41. package/dist/lib/neutral/chunk-H77JTXAN.mjs.map +7 -0
  42. package/dist/lib/neutral/{chunk-QAZMOFPI.mjs → chunk-IQZJ5TTM.mjs} +4 -4
  43. package/dist/lib/neutral/chunk-IQZJ5TTM.mjs.map +7 -0
  44. package/dist/lib/neutral/chunk-ZNDQVYUN.mjs +53 -0
  45. package/dist/lib/neutral/chunk-ZNDQVYUN.mjs.map +7 -0
  46. package/dist/lib/neutral/components/index.mjs +296 -109
  47. package/dist/lib/neutral/components/index.mjs.map +3 -3
  48. package/dist/lib/neutral/containers/index.mjs +12 -8
  49. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  50. package/dist/lib/neutral/{create-chat-SGGQ6HVN.mjs → create-chat-Z3FNA6OJ.mjs} +2 -2
  51. package/dist/lib/neutral/{create-chat-SGGQ6HVN.mjs.map → create-chat-Z3FNA6OJ.mjs.map} +2 -2
  52. package/dist/lib/neutral/{create-object-U2SOFZLR.mjs → create-object-BJUDDKQQ.mjs} +2 -2
  53. package/dist/lib/neutral/execution-graph/index.mjs +156 -0
  54. package/dist/lib/neutral/execution-graph/index.mjs.map +4 -4
  55. package/dist/lib/neutral/{fork-chat-34KEF4ZJ.mjs → fork-chat-UYXYT6BT.mjs} +4 -4
  56. package/dist/lib/neutral/fork-chat-UYXYT6BT.mjs.map +7 -0
  57. package/dist/lib/neutral/hooks/index.mjs +233 -438
  58. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  59. package/dist/lib/neutral/index.mjs +3 -3
  60. package/dist/lib/neutral/markdown-extension-IJ5RQMQ4.mjs +126 -0
  61. package/dist/lib/neutral/markdown-extension-IJ5RQMQ4.mjs.map +7 -0
  62. package/dist/lib/neutral/meta.json +1 -1
  63. package/dist/lib/neutral/meta.mjs +1 -1
  64. package/dist/lib/neutral/operations/index.mjs +1 -1
  65. package/dist/lib/neutral/plugin.mjs +2 -2
  66. package/dist/lib/neutral/{react-surface-XRTBW5OJ.mjs → react-surface-ES7UHZ65.mjs} +29 -17
  67. package/dist/lib/neutral/react-surface-ES7UHZ65.mjs.map +7 -0
  68. package/dist/lib/neutral/{run-prompt-in-new-chat-D5IIE2C7.mjs → run-prompt-in-new-chat-NIAGCKQV.mjs} +11 -8
  69. package/dist/lib/neutral/run-prompt-in-new-chat-NIAGCKQV.mjs.map +7 -0
  70. package/dist/lib/neutral/{settings-W4BLWQ53.mjs → settings-7Q3RITIT.mjs} +3 -3
  71. package/dist/lib/neutral/{settings-W4BLWQ53.mjs.map → settings-7Q3RITIT.mjs.map} +3 -3
  72. package/dist/lib/neutral/{state-H3G7QCU6.mjs → state-XO2UYSSG.mjs} +2 -2
  73. package/dist/lib/neutral/{state-H3G7QCU6.mjs.map → state-XO2UYSSG.mjs.map} +3 -3
  74. package/dist/lib/neutral/testing.mjs +1 -1
  75. package/dist/lib/neutral/translations.mjs +18 -11
  76. package/dist/lib/neutral/translations.mjs.map +3 -3
  77. package/dist/lib/neutral/types/index.mjs +1 -1
  78. package/dist/types/dx.config.d.ts +28 -0
  79. package/dist/types/dx.config.d.ts.map +1 -0
  80. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
  82. package/dist/types/src/capabilities/index.d.ts +17 -57
  83. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  84. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  85. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  86. package/dist/types/src/components/Chat/Chat.d.ts +6 -3
  87. package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
  88. package/dist/types/src/components/Chat/Chat.stories.d.ts +32 -0
  89. package/dist/types/src/components/Chat/Chat.stories.d.ts.map +1 -0
  90. package/dist/types/src/components/ChatPrompt/ChatActions.d.ts.map +1 -1
  91. package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts.map +1 -1
  92. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +6 -0
  93. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -1
  94. package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts +1 -0
  95. package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts.map +1 -1
  96. package/dist/types/src/components/TaskList/TaskList.d.ts +8 -0
  97. package/dist/types/src/components/TaskList/TaskList.d.ts.map +1 -1
  98. package/dist/types/src/components/TaskList/TaskList.stories.d.ts +3 -0
  99. package/dist/types/src/components/TaskList/TaskList.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/index.d.ts +1 -0
  101. package/dist/types/src/components/index.d.ts.map +1 -1
  102. package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts +2 -2
  103. package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts.map +1 -1
  104. package/dist/types/src/containers/ChatCompanion/ChatCompanion.d.ts +2 -2
  105. package/dist/types/src/containers/ChatDialog/ChatDialog.d.ts.map +1 -1
  106. package/dist/types/src/containers/PlanArticle/PlanArticle.d.ts.map +1 -1
  107. package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts +15 -0
  108. package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts.map +1 -0
  109. package/dist/types/src/containers/SpaceHomePrompt/index.d.ts +2 -0
  110. package/dist/types/src/containers/SpaceHomePrompt/index.d.ts.map +1 -0
  111. package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts +13 -0
  112. package/dist/types/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.d.ts.map +1 -0
  113. package/dist/types/src/containers/SpaceHomeSuggestions/index.d.ts +2 -0
  114. package/dist/types/src/containers/SpaceHomeSuggestions/index.d.ts.map +1 -0
  115. package/dist/types/src/containers/TracePanel/TracePanel.d.ts.map +1 -1
  116. package/dist/types/src/containers/index.d.ts +2 -0
  117. package/dist/types/src/containers/index.d.ts.map +1 -1
  118. package/dist/types/src/execution-graph/execution-graph.d.ts +18 -0
  119. package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -1
  120. package/dist/types/src/execution-graph/index.d.ts +2 -1
  121. package/dist/types/src/execution-graph/index.d.ts.map +1 -1
  122. package/dist/types/src/execution-graph/pending-block-status.d.ts +26 -0
  123. package/dist/types/src/execution-graph/pending-block-status.d.ts.map +1 -0
  124. package/dist/types/src/execution-graph/pending-block-status.test.d.ts +2 -0
  125. package/dist/types/src/execution-graph/pending-block-status.test.d.ts.map +1 -0
  126. package/dist/types/src/extensions/prompt-extension.d.ts +1 -1
  127. package/dist/types/src/extensions/prompt-extension.d.ts.map +1 -1
  128. package/dist/types/src/feed-logger.d.ts +3 -2
  129. package/dist/types/src/feed-logger.d.ts.map +1 -1
  130. package/dist/types/src/hooks/index.d.ts +2 -0
  131. package/dist/types/src/hooks/index.d.ts.map +1 -1
  132. package/dist/types/src/hooks/useProcessEphemeralStatus.d.ts +10 -0
  133. package/dist/types/src/hooks/useProcessEphemeralStatus.d.ts.map +1 -0
  134. package/dist/types/src/hooks/useTraceMessages.d.ts +12 -0
  135. package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -0
  136. package/dist/types/src/meta.d.ts +28 -2
  137. package/dist/types/src/meta.d.ts.map +1 -1
  138. package/dist/types/src/operations/run-prompt-in-new-chat.d.ts.map +1 -1
  139. package/dist/types/src/paths.d.ts.map +1 -1
  140. package/dist/types/src/processor/processor.d.ts +23 -0
  141. package/dist/types/src/processor/processor.d.ts.map +1 -1
  142. package/dist/types/src/translations.d.ts.map +1 -1
  143. package/dist/types/src/types/Assistant.d.ts +1 -1
  144. package/dist/types/src/types/AssistantCapabilities.d.ts.map +1 -1
  145. package/dist/types/src/types/AssistantEvents.d.ts.map +1 -1
  146. package/dist/types/src/types/AssistantOperation.d.ts +7 -7
  147. package/dist/types/src/util/error-cause.d.ts +3 -0
  148. package/dist/types/src/util/error-cause.d.ts.map +1 -0
  149. package/dist/types/tsconfig.tsbuildinfo +1 -1
  150. package/dx.config.ts +38 -0
  151. package/package.json +71 -70
  152. package/src/AssistantPlugin.conversations.json +1 -1
  153. package/src/AssistantPlugin.test.ts +1 -1
  154. package/src/AssistantPlugin.ts +2 -2
  155. package/src/capabilities/agent-service.ts +5 -1
  156. package/src/capabilities/app-graph-builder.ts +15 -20
  157. package/src/capabilities/blueprint-definition.ts +2 -0
  158. package/src/capabilities/index.ts +1 -7
  159. package/src/capabilities/markdown-extension.ts +5 -1
  160. package/src/capabilities/react-surface.tsx +38 -23
  161. package/src/capabilities/settings.ts +2 -2
  162. package/src/capabilities/state.ts +1 -1
  163. package/src/components/AgentProperties/AgentProperties.tsx +1 -1
  164. package/src/components/AssistantSettings/AssistantSettings.tsx +2 -2
  165. package/src/components/Chat/Chat.stories.tsx +94 -0
  166. package/src/components/Chat/Chat.tsx +39 -6
  167. package/src/components/ChatPrompt/ChatActions.tsx +4 -2
  168. package/src/components/ChatPrompt/ChatMcpErrors.tsx +1 -1
  169. package/src/components/ChatPrompt/ChatOptions.tsx +26 -29
  170. package/src/components/ChatPrompt/ChatPrompt.tsx +1 -1
  171. package/src/components/ChatPrompt/ChatReferences.tsx +1 -1
  172. package/src/components/ChatThread/Anchor.stories.tsx +1 -1
  173. package/src/components/ChatThread/ChatThread.stories.tsx +1 -1
  174. package/src/components/ChatThread/DEBUG.md +23 -0
  175. package/src/components/ChatThread/widgets/SummaryWidget.tsx +1 -1
  176. package/src/components/ChatThread/widgets/ToolWidget.tsx +1 -1
  177. package/src/components/ProcessTree/ProcessTree.stories.tsx +7 -0
  178. package/src/components/ProcessTree/ProcessTree.tsx +191 -88
  179. package/src/components/TaskList/TaskList.stories.tsx +23 -2
  180. package/src/components/TaskList/TaskList.tsx +122 -28
  181. package/src/components/TemplateEditor/TemplateEditor.tsx +1 -1
  182. package/src/components/TemplateEditor/TemplateForm.tsx +1 -1
  183. package/src/components/ToolBlock/ToolBlock.tsx +1 -1
  184. package/src/components/index.ts +1 -0
  185. package/src/containers/AgentArticle/AgentArticle.stories.tsx +4 -4
  186. package/src/containers/AgentArticle/AgentArticle.tsx +9 -9
  187. package/src/containers/ChatArticle/ChatArticle.tsx +18 -10
  188. package/src/containers/ChatCompanion/ChatCompanion.tsx +2 -2
  189. package/src/containers/ChatDialog/ChatDialog.tsx +5 -3
  190. package/src/containers/PlanArticle/PlanArticle.tsx +5 -1
  191. package/src/containers/RoutineArticle/RoutineArticle.tsx +2 -2
  192. package/src/containers/SpaceHomePrompt/SpaceHomePrompt.tsx +105 -0
  193. package/src/containers/SpaceHomePrompt/index.ts +5 -0
  194. package/src/containers/SpaceHomeSuggestions/SpaceHomeSuggestions.tsx +69 -0
  195. package/src/containers/SpaceHomeSuggestions/index.ts +5 -0
  196. package/src/containers/TracePanel/TracePanel.tsx +3 -30
  197. package/src/containers/TriggerStatus/TriggerStatus.tsx +2 -2
  198. package/src/containers/index.ts +2 -0
  199. package/src/execution-graph/execution-graph.ts +130 -0
  200. package/src/execution-graph/index.ts +10 -0
  201. package/src/execution-graph/pending-block-status.test.ts +114 -0
  202. package/src/execution-graph/pending-block-status.ts +88 -0
  203. package/src/execution-graph/sub-agent-delegation.test.ts +16 -1
  204. package/src/extensions/prompt-extension.ts +102 -73
  205. package/src/feed-logger.ts +21 -19
  206. package/src/hooks/index.ts +2 -0
  207. package/src/hooks/useChatProcessor.ts +1 -1
  208. package/src/hooks/useChatServices.ts +2 -2
  209. package/src/hooks/useChatToolbarActions.ts +5 -5
  210. package/src/hooks/useContextBinder.ts +1 -1
  211. package/src/hooks/useProcessEphemeralStatus.ts +192 -0
  212. package/src/hooks/useTraceMessages.ts +41 -0
  213. package/src/meta.ts +3 -31
  214. package/src/operations/create-chat.ts +1 -1
  215. package/src/operations/fork-chat.ts +3 -3
  216. package/src/operations/run-prompt-in-new-chat.ts +5 -3
  217. package/src/paths.ts +2 -2
  218. package/src/processor/processor.node.test.ts +71 -1
  219. package/src/processor/processor.ts +58 -2
  220. package/src/testing/data/trace-timeline-multiple.dx.json +1 -1
  221. package/src/testing/data/trace-timeline-remote.dx.json +1 -1
  222. package/src/testing/data/trace-timeline.dx.json +0 -1
  223. package/src/translations.ts +18 -10
  224. package/src/types/AssistantCapabilities.ts +3 -3
  225. package/src/types/AssistantEvents.ts +1 -1
  226. package/src/types/AssistantOperation.ts +1 -1
  227. package/src/util/error-cause.ts +21 -0
  228. package/dist/lib/neutral/AgentArticle-K7XM46OQ.mjs.map +0 -7
  229. package/dist/lib/neutral/AssistantSettings-GG52BLKS.mjs.map +0 -7
  230. package/dist/lib/neutral/ChatCompanion-LBUHYWQG.mjs.map +0 -7
  231. package/dist/lib/neutral/ChatDialog-DCA6FLOV.mjs.map +0 -7
  232. package/dist/lib/neutral/PlanArticle-TS5ULWYS.mjs.map +0 -7
  233. package/dist/lib/neutral/RoutineArticle-5NYXHRG6.mjs.map +0 -7
  234. package/dist/lib/neutral/TracePanel-KTZJ6JNR.mjs.map +0 -7
  235. package/dist/lib/neutral/TriggerStatus-X7Y5JFZJ.mjs.map +0 -7
  236. package/dist/lib/neutral/app-graph-builder-WUFHQH3Y.mjs.map +0 -7
  237. package/dist/lib/neutral/blueprint-definition-MH2QLYQH.mjs.map +0 -7
  238. package/dist/lib/neutral/chunk-HLANPOBA.mjs.map +0 -7
  239. package/dist/lib/neutral/chunk-QAZMOFPI.mjs.map +0 -7
  240. package/dist/lib/neutral/chunk-RKVVK3R3.mjs.map +0 -7
  241. package/dist/lib/neutral/chunk-VTK5R4H3.mjs +0 -9
  242. package/dist/lib/neutral/chunk-VTK5R4H3.mjs.map +0 -7
  243. package/dist/lib/neutral/chunk-XYHPOGTK.mjs +0 -43
  244. package/dist/lib/neutral/chunk-XYHPOGTK.mjs.map +0 -7
  245. package/dist/lib/neutral/chunk-YXRGZYYH.mjs.map +0 -7
  246. package/dist/lib/neutral/fork-chat-34KEF4ZJ.mjs.map +0 -7
  247. package/dist/lib/neutral/markdown-extension-YMIFDMYF.mjs +0 -110
  248. package/dist/lib/neutral/markdown-extension-YMIFDMYF.mjs.map +0 -7
  249. package/dist/lib/neutral/react-surface-XRTBW5OJ.mjs.map +0 -7
  250. package/dist/lib/neutral/run-prompt-in-new-chat-D5IIE2C7.mjs.map +0 -7
  251. package/src/testing/trace-timeline.node.conversations.json +0 -1
  252. /package/dist/lib/neutral/{ChatArticle-VNVZCDUR.mjs.map → ChatArticle-KT46SUFU.mjs.map} +0 -0
  253. /package/dist/lib/neutral/{chunk-SMFJD7BP.mjs.map → chunk-7FQT4XMI.mjs.map} +0 -0
  254. /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
- * CodeMirror extension that adds a green "run" button to ```prompt fenced code blocks.
18
- */
19
- export const promptRunExtension = ({ onRun }: PromptExtensionOptions): Extension => {
20
- return [
21
- ViewPlugin.fromClass(
22
- class {
23
- decorations: DecorationSet;
24
-
25
- constructor(view: EditorView) {
26
- this.decorations = this.buildDecorations(view);
27
- }
28
-
29
- update(update: ViewUpdate) {
30
- if (update.docChanged || update.viewportChanged || update.selectionSet || update.focusChanged) {
31
- this.decorations = this.buildDecorations(update.view);
32
- }
33
- }
34
-
35
- buildDecorations(view: EditorView): DecorationSet {
36
- const decorations: Array<{ from: number; to: number; decoration: Decoration }> = [];
37
-
38
- syntaxTree(view.state).iterate({
39
- enter: (node) => {
40
- if (node.name === 'FencedCode') {
41
- const info = node.node.getChild('CodeInfo');
42
- if (info) {
43
- const type = view.state.sliceDoc(info.from, info.to);
44
- const text = node.node.getChild('CodeText');
45
- if (type === 'prompt' && text) {
46
- const content = view.state.sliceDoc(text.from, text.to).trim();
47
- if (content.length > 0) {
48
- const widget = new PromptRunWidget(content, onRun);
49
- decorations.push({
50
- from: node.from,
51
- to: node.from,
52
- decoration: Decoration.widget({ widget, side: -1 }),
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
- return Decoration.set(
62
- decorations.sort((a, b) => a.from - b.from || a.to - b.to).map((d) => d.decoration.range(d.from, d.to)),
63
- );
64
- }
65
- },
66
- {
67
- decorations: (v) => v.decorations,
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: (promptText: string) => void,
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('div')
91
- .classNames('relative')
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('button')
94
- .classNames('dx-button absolute right-0 top-4')
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('svg', Domino.SVG)
102
- .classNames('w-4 h-4 cursor-pointer')
103
- .append(
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
  }
@@ -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 { EID, type EntityId } from '@dxos/keys';
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.queues);
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.fromURI(this._getTraceQueueEchoId(event.invocationId)),
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._getTraceEventQueue(event.invocationId).append([
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._getTraceEventQueue(event.invocationId).append([
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._getTraceEventQueue(event.invocationId).append([
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
- // TODO(burdon): The per-invocation trace event queues address feeds by raw queue DXN
142
- // (no backing Feed.Feed object). Migration to Feed.append is blocked on either
143
- // (a) materializing a Feed object per invocation, or (b) a lower-level
144
- // FeedService.appendByDxn primitive. Tracked as Phase 6 work in echo/AUDIT.md.
145
- private _getTraceEventQueue(invocationId: EntityId): Queue<TraceEvent> {
146
- const echoUri = this._getTraceQueueEchoId(invocationId);
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
  }
@@ -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.queues);
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 { getPersonalSpace } from '@dxos/app-toolkit';
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.id }],
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.id }],
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.id }],
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.id }],
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.id }],
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.queues);
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
+ };