@dxos/plugin-assistant 0.10.0 → 0.11.1

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