@dxos/plugin-assistant 0.8.0 → 0.8.1-main.013e445

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 (240) hide show
  1. package/dist/lib/browser/{AssistantDialog-TX6YYBUG.mjs → AssistantDialog-EIUUSXDS.mjs} +11 -10
  2. package/dist/lib/browser/AssistantDialog-EIUUSXDS.mjs.map +7 -0
  3. package/dist/lib/browser/{ChatContainer-AT3OAUT3.mjs → ChatContainer-NHHA6CSP.mjs} +5 -5
  4. package/dist/lib/browser/TemplateContainer-7IQ6V5AD.mjs +78 -0
  5. package/dist/lib/browser/TemplateContainer-7IQ6V5AD.mjs.map +7 -0
  6. package/dist/lib/browser/ai-client-BAPVMSNX.mjs +35 -0
  7. package/dist/lib/browser/ai-client-BAPVMSNX.mjs.map +7 -0
  8. package/dist/lib/browser/{app-graph-builder-AXAIFOGV.mjs → app-graph-builder-DTCUWBKB.mjs} +57 -13
  9. package/dist/lib/browser/app-graph-builder-DTCUWBKB.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-G7B54APW.mjs → chunk-25APJ3ZK.mjs} +34 -12
  11. package/dist/lib/browser/chunk-25APJ3ZK.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-EUMPBC4T.mjs → chunk-6FTPLBSC.mjs} +2 -2
  13. package/dist/lib/browser/{chunk-NV7SVHMV.mjs → chunk-AF7VQAKS.mjs} +1 -1
  14. package/dist/lib/browser/{chunk-NV7SVHMV.mjs.map → chunk-AF7VQAKS.mjs.map} +2 -2
  15. package/dist/lib/browser/{chunk-NFVIZS3B.mjs → chunk-KGIACFAX.mjs} +351 -207
  16. package/dist/lib/browser/chunk-KGIACFAX.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-VZ4W6SHE.mjs → chunk-SVUCJXGN.mjs} +2 -2
  18. package/dist/lib/browser/chunk-SVUCJXGN.mjs.map +7 -0
  19. package/dist/lib/browser/{chunk-FRIKXDDQ.mjs → chunk-X6ALDUA5.mjs} +26 -4
  20. package/dist/lib/browser/chunk-X6ALDUA5.mjs.map +7 -0
  21. package/dist/lib/browser/index.mjs +25 -27
  22. package/dist/lib/browser/index.mjs.map +3 -3
  23. package/dist/lib/browser/{intent-resolver-QRVRZL6K.mjs → intent-resolver-U57FXP3I.mjs} +6 -3
  24. package/dist/lib/browser/{intent-resolver-QRVRZL6K.mjs.map → intent-resolver-U57FXP3I.mjs.map} +3 -3
  25. package/dist/lib/browser/meta.json +1 -1
  26. package/dist/lib/browser/{react-surface-JLXNWOI6.mjs → react-surface-YNN5NYJW.mjs} +10 -9
  27. package/dist/lib/browser/react-surface-YNN5NYJW.mjs.map +7 -0
  28. package/dist/lib/browser/{settings-JTT62IHD.mjs → settings-VAW6UWFL.mjs} +3 -3
  29. package/dist/lib/browser/types/index.mjs +6 -2
  30. package/dist/lib/node/{AssistantDialog-U4GBPZD6.cjs → AssistantDialog-GT7R7MKH.cjs} +17 -16
  31. package/dist/lib/node/AssistantDialog-GT7R7MKH.cjs.map +7 -0
  32. package/dist/lib/node/{ChatContainer-CVHXNHGA.cjs → ChatContainer-JUZOEZZ7.cjs} +10 -10
  33. package/dist/lib/node/TemplateContainer-VPAZRFQA.cjs +104 -0
  34. package/dist/lib/node/TemplateContainer-VPAZRFQA.cjs.map +7 -0
  35. package/dist/lib/node/{ai-client-YANJEPO3.cjs → ai-client-5ESLYXAV.cjs} +19 -8
  36. package/dist/lib/node/ai-client-5ESLYXAV.cjs.map +7 -0
  37. package/dist/lib/node/{app-graph-builder-D7SHQTZS.cjs → app-graph-builder-3P6WSON2.cjs} +63 -20
  38. package/dist/lib/node/app-graph-builder-3P6WSON2.cjs.map +7 -0
  39. package/dist/lib/node/{chunk-IXJCGW7U.cjs → chunk-G2HY3UJ4.cjs} +40 -18
  40. package/dist/lib/node/chunk-G2HY3UJ4.cjs.map +7 -0
  41. package/dist/lib/node/{chunk-XUTDR7HI.cjs → chunk-JAB6KLPP.cjs} +356 -216
  42. package/dist/lib/node/chunk-JAB6KLPP.cjs.map +7 -0
  43. package/dist/lib/node/{chunk-37GI4NYH.cjs → chunk-KLSNCP34.cjs} +33 -9
  44. package/dist/lib/node/chunk-KLSNCP34.cjs.map +7 -0
  45. package/dist/lib/node/{chunk-NV4TQQSU.cjs → chunk-N3SW6DJ6.cjs} +6 -6
  46. package/dist/lib/node/{chunk-GNPXCHFT.cjs → chunk-U6J2GO7I.cjs} +4 -4
  47. package/dist/lib/node/{chunk-GNPXCHFT.cjs.map → chunk-U6J2GO7I.cjs.map} +2 -2
  48. package/dist/lib/node/{chunk-ZGH6F5YA.cjs → chunk-VRXFIS4X.cjs} +6 -6
  49. package/dist/lib/node/chunk-VRXFIS4X.cjs.map +7 -0
  50. package/dist/lib/node/index.cjs +75 -77
  51. package/dist/lib/node/index.cjs.map +3 -3
  52. package/dist/lib/node/{intent-resolver-YMMAFVOB.cjs → intent-resolver-YIFAMM3B.cjs} +13 -10
  53. package/dist/lib/node/{intent-resolver-YMMAFVOB.cjs.map → intent-resolver-YIFAMM3B.cjs.map} +3 -3
  54. package/dist/lib/node/meta.json +1 -1
  55. package/dist/lib/node/{react-surface-BSUZQ3HZ.cjs → react-surface-IDGIN55C.cjs} +25 -24
  56. package/dist/lib/node/react-surface-IDGIN55C.cjs.map +7 -0
  57. package/dist/lib/node/{settings-4YEO7KXF.cjs → settings-2FEYGLYU.cjs} +8 -8
  58. package/dist/lib/node/types/index.cjs +15 -11
  59. package/dist/lib/node/types/index.cjs.map +2 -2
  60. package/dist/lib/node-esm/{AssistantDialog-5AT5JAZL.mjs → AssistantDialog-JMBFM6QH.mjs} +11 -10
  61. package/dist/lib/node-esm/AssistantDialog-JMBFM6QH.mjs.map +7 -0
  62. package/dist/lib/node-esm/{ChatContainer-VR766C4M.mjs → ChatContainer-ZNN5CMVL.mjs} +5 -5
  63. package/dist/lib/node-esm/TemplateContainer-YLA6BJY6.mjs +79 -0
  64. package/dist/lib/node-esm/TemplateContainer-YLA6BJY6.mjs.map +7 -0
  65. package/dist/lib/node-esm/ai-client-XYZ5N7CR.mjs +36 -0
  66. package/dist/lib/node-esm/ai-client-XYZ5N7CR.mjs.map +7 -0
  67. package/dist/lib/node-esm/{app-graph-builder-H2GC2AZA.mjs → app-graph-builder-PMAQLTTN.mjs} +57 -13
  68. package/dist/lib/node-esm/app-graph-builder-PMAQLTTN.mjs.map +7 -0
  69. package/dist/lib/node-esm/{chunk-77ARTFBA.mjs → chunk-2CIYX3SD.mjs} +2 -2
  70. package/dist/lib/node-esm/chunk-2CIYX3SD.mjs.map +7 -0
  71. package/dist/lib/node-esm/{chunk-LBQGJE5T.mjs → chunk-J63VQFQO.mjs} +2 -2
  72. package/dist/lib/node-esm/{chunk-7SV6X6XU.mjs → chunk-N6BVC2C2.mjs} +1 -1
  73. package/dist/lib/node-esm/{chunk-7SV6X6XU.mjs.map → chunk-N6BVC2C2.mjs.map} +2 -2
  74. package/dist/lib/node-esm/{chunk-CJ4Y3QW5.mjs → chunk-NMMRHHAR.mjs} +26 -4
  75. package/dist/lib/node-esm/chunk-NMMRHHAR.mjs.map +7 -0
  76. package/dist/lib/node-esm/{chunk-7JENJTLB.mjs → chunk-PK5JCOYB.mjs} +351 -207
  77. package/dist/lib/node-esm/chunk-PK5JCOYB.mjs.map +7 -0
  78. package/dist/lib/node-esm/{chunk-AMQMVQJO.mjs → chunk-SMUINDXQ.mjs} +34 -12
  79. package/dist/lib/node-esm/chunk-SMUINDXQ.mjs.map +7 -0
  80. package/dist/lib/node-esm/index.mjs +25 -27
  81. package/dist/lib/node-esm/index.mjs.map +3 -3
  82. package/dist/lib/node-esm/{intent-resolver-MR7BOKEW.mjs → intent-resolver-SQ4HLL5L.mjs} +6 -3
  83. package/dist/lib/node-esm/{intent-resolver-MR7BOKEW.mjs.map → intent-resolver-SQ4HLL5L.mjs.map} +3 -3
  84. package/dist/lib/node-esm/meta.json +1 -1
  85. package/dist/lib/node-esm/{react-surface-IGVYAOGL.mjs → react-surface-424JZTZ4.mjs} +10 -9
  86. package/dist/lib/node-esm/react-surface-424JZTZ4.mjs.map +7 -0
  87. package/dist/lib/node-esm/{settings-S7P5RWQI.mjs → settings-VHR5KT4J.mjs} +3 -3
  88. package/dist/lib/node-esm/types/index.mjs +6 -2
  89. package/dist/types/src/AssistantPlugin.d.ts.map +1 -1
  90. package/dist/types/src/capabilities/ai-client.d.ts +2 -2
  91. package/dist/types/src/capabilities/ai-client.d.ts.map +1 -1
  92. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/capabilities.d.ts +3 -2
  94. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  95. package/dist/types/src/capabilities/index.d.ts +1 -1
  96. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  97. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  98. package/dist/types/src/components/AmbientDialog/AmbientDialog.d.ts +5 -4
  99. package/dist/types/src/components/AmbientDialog/AmbientDialog.d.ts.map +1 -1
  100. package/dist/types/src/components/AssistantDialog.d.ts.map +1 -1
  101. package/dist/types/src/components/AssistantSettings/AssistantSettings.d.ts +2 -1
  102. package/dist/types/src/components/AssistantSettings/AssistantSettings.d.ts.map +1 -1
  103. package/dist/types/src/components/ChatContainer.d.ts +2 -1
  104. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  105. package/dist/types/src/components/Prompt/Prompt.d.ts +3 -0
  106. package/dist/types/src/components/Prompt/Prompt.d.ts.map +1 -1
  107. package/dist/types/src/components/Prompt/Prompt.stories.d.ts +1 -0
  108. package/dist/types/src/components/Prompt/Prompt.stories.d.ts.map +1 -1
  109. package/dist/types/src/components/Prompt/PromptBar.d.ts +3 -2
  110. package/dist/types/src/components/Prompt/PromptBar.d.ts.map +1 -1
  111. package/dist/types/src/components/Prompt/references.d.ts +30 -0
  112. package/dist/types/src/components/Prompt/references.d.ts.map +1 -0
  113. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts +2 -1
  114. package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts.map +1 -1
  115. package/dist/types/src/components/TemplateContainer.d.ts +2 -1
  116. package/dist/types/src/components/TemplateContainer.d.ts.map +1 -1
  117. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts +2 -1
  118. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts.map +1 -1
  119. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts +2 -1
  120. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts.map +1 -1
  121. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts +3 -2
  122. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts.map +1 -1
  123. package/dist/types/src/components/Thread/Thread.d.ts +12 -1
  124. package/dist/types/src/components/Thread/Thread.d.ts.map +1 -1
  125. package/dist/types/src/components/Thread/ThreadContainer.d.ts +1 -0
  126. package/dist/types/src/components/Thread/ThreadContainer.d.ts.map +1 -1
  127. package/dist/types/src/components/Thread/ThreadContainer.stories.d.ts +2 -1
  128. package/dist/types/src/components/Thread/ThreadContainer.stories.d.ts.map +1 -1
  129. package/dist/types/src/components/Thread/ThreadMessage.d.ts.map +1 -1
  130. package/dist/types/src/components/Toolbox/Toolbox.d.ts +4 -3
  131. package/dist/types/src/components/Toolbox/Toolbox.d.ts.map +1 -1
  132. package/dist/types/src/components/index.d.ts +2 -2
  133. package/dist/types/src/components/index.d.ts.map +1 -1
  134. package/dist/types/src/hooks/email.d.ts.map +1 -1
  135. package/dist/types/src/hooks/index.d.ts +1 -0
  136. package/dist/types/src/hooks/index.d.ts.map +1 -1
  137. package/dist/types/src/hooks/invocation-handler.d.ts +1 -1
  138. package/dist/types/src/hooks/invocation-handler.d.ts.map +1 -1
  139. package/dist/types/src/hooks/processor.d.ts +10 -15
  140. package/dist/types/src/hooks/processor.d.ts.map +1 -1
  141. package/dist/types/src/hooks/useChatProcessor.d.ts +9 -2
  142. package/dist/types/src/hooks/useChatProcessor.d.ts.map +1 -1
  143. package/dist/types/src/hooks/useContextProvider.d.ts +17 -0
  144. package/dist/types/src/hooks/useContextProvider.d.ts.map +1 -0
  145. package/dist/types/src/hooks/useMessageQueue.d.ts +4 -4
  146. package/dist/types/src/hooks/useMessageQueue.d.ts.map +1 -1
  147. package/dist/types/src/meta.d.ts +2 -8
  148. package/dist/types/src/meta.d.ts.map +1 -1
  149. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  150. package/dist/types/src/tools/function.d.ts +1 -1
  151. package/dist/types/src/tools/function.d.ts.map +1 -1
  152. package/dist/types/src/translations.d.ts +23 -12
  153. package/dist/types/src/translations.d.ts.map +1 -1
  154. package/dist/types/src/types/service.d.ts +1 -1
  155. package/dist/types/src/types/service.d.ts.map +1 -1
  156. package/dist/types/src/types/template.d.ts +36 -0
  157. package/dist/types/src/types/template.d.ts.map +1 -1
  158. package/dist/types/src/types/types.d.ts +3 -1
  159. package/dist/types/src/types/types.d.ts.map +1 -1
  160. package/package.json +56 -56
  161. package/src/AssistantPlugin.tsx +11 -4
  162. package/src/capabilities/ai-client.ts +23 -4
  163. package/src/capabilities/app-graph-builder.ts +48 -4
  164. package/src/capabilities/capabilities.ts +4 -2
  165. package/src/capabilities/intent-resolver.ts +1 -1
  166. package/src/capabilities/react-surface.tsx +3 -2
  167. package/src/components/AmbientDialog/AmbientDialog.tsx +11 -11
  168. package/src/components/AssistantDialog.tsx +7 -1
  169. package/src/components/AssistantSettings/AssistantSettings.tsx +39 -5
  170. package/src/components/Prompt/Prompt.stories.tsx +34 -0
  171. package/src/components/Prompt/Prompt.tsx +28 -18
  172. package/src/components/Prompt/PromptBar.tsx +18 -7
  173. package/src/components/Prompt/references.ts +180 -0
  174. package/src/components/TemplateContainer.tsx +79 -4
  175. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +1 -1
  176. package/src/components/TemplateEditor/TemplateForm.stories.tsx +1 -1
  177. package/src/components/TemplateEditor/TemplateForm.tsx +1 -1
  178. package/src/components/Thread/Thread.tsx +21 -0
  179. package/src/components/Thread/ThreadContainer.stories.tsx +7 -12
  180. package/src/components/Thread/ThreadContainer.tsx +7 -4
  181. package/src/components/Thread/ThreadMessage.tsx +17 -9
  182. package/src/components/Toolbox/Toolbox.tsx +1 -1
  183. package/src/components/index.ts +3 -0
  184. package/src/hooks/email.ts +3 -3
  185. package/src/hooks/index.ts +1 -0
  186. package/src/hooks/invocation-handler.ts +3 -5
  187. package/src/hooks/processor.ts +60 -110
  188. package/src/hooks/useChatProcessor.tsx +25 -17
  189. package/src/hooks/useContextProvider.ts +55 -0
  190. package/src/hooks/useLocalTriggerManager.ts +1 -1
  191. package/src/hooks/useMessageQueue.ts +2 -4
  192. package/src/meta.ts +2 -2
  193. package/src/testing/test-functions.ts +2 -2
  194. package/src/tools/function.ts +2 -2
  195. package/src/tools/openapi.test.ts +4 -4
  196. package/src/translations.ts +10 -5
  197. package/src/types/service.ts +1 -1
  198. package/src/types/template.ts +22 -0
  199. package/src/types/types.ts +3 -1
  200. package/dist/lib/browser/AssistantDialog-TX6YYBUG.mjs.map +0 -7
  201. package/dist/lib/browser/TemplateContainer-B7MQNUPY.mjs +0 -23
  202. package/dist/lib/browser/TemplateContainer-B7MQNUPY.mjs.map +0 -7
  203. package/dist/lib/browser/ai-client-RTCGRKZE.mjs +0 -22
  204. package/dist/lib/browser/ai-client-RTCGRKZE.mjs.map +0 -7
  205. package/dist/lib/browser/app-graph-builder-AXAIFOGV.mjs.map +0 -7
  206. package/dist/lib/browser/chunk-FRIKXDDQ.mjs.map +0 -7
  207. package/dist/lib/browser/chunk-G7B54APW.mjs.map +0 -7
  208. package/dist/lib/browser/chunk-NFVIZS3B.mjs.map +0 -7
  209. package/dist/lib/browser/chunk-VZ4W6SHE.mjs.map +0 -7
  210. package/dist/lib/browser/react-surface-JLXNWOI6.mjs.map +0 -7
  211. package/dist/lib/node/AssistantDialog-U4GBPZD6.cjs.map +0 -7
  212. package/dist/lib/node/TemplateContainer-R4BZZP3E.cjs +0 -53
  213. package/dist/lib/node/TemplateContainer-R4BZZP3E.cjs.map +0 -7
  214. package/dist/lib/node/ai-client-YANJEPO3.cjs.map +0 -7
  215. package/dist/lib/node/app-graph-builder-D7SHQTZS.cjs.map +0 -7
  216. package/dist/lib/node/chunk-37GI4NYH.cjs.map +0 -7
  217. package/dist/lib/node/chunk-IXJCGW7U.cjs.map +0 -7
  218. package/dist/lib/node/chunk-XUTDR7HI.cjs.map +0 -7
  219. package/dist/lib/node/chunk-ZGH6F5YA.cjs.map +0 -7
  220. package/dist/lib/node/react-surface-BSUZQ3HZ.cjs.map +0 -7
  221. package/dist/lib/node-esm/AssistantDialog-5AT5JAZL.mjs.map +0 -7
  222. package/dist/lib/node-esm/TemplateContainer-WSHTZBB5.mjs +0 -24
  223. package/dist/lib/node-esm/TemplateContainer-WSHTZBB5.mjs.map +0 -7
  224. package/dist/lib/node-esm/ai-client-66IBZVCX.mjs +0 -23
  225. package/dist/lib/node-esm/ai-client-66IBZVCX.mjs.map +0 -7
  226. package/dist/lib/node-esm/app-graph-builder-H2GC2AZA.mjs.map +0 -7
  227. package/dist/lib/node-esm/chunk-77ARTFBA.mjs.map +0 -7
  228. package/dist/lib/node-esm/chunk-7JENJTLB.mjs.map +0 -7
  229. package/dist/lib/node-esm/chunk-AMQMVQJO.mjs.map +0 -7
  230. package/dist/lib/node-esm/chunk-CJ4Y3QW5.mjs.map +0 -7
  231. package/dist/lib/node-esm/react-surface-IGVYAOGL.mjs.map +0 -7
  232. /package/dist/lib/browser/{ChatContainer-AT3OAUT3.mjs.map → ChatContainer-NHHA6CSP.mjs.map} +0 -0
  233. /package/dist/lib/browser/{chunk-EUMPBC4T.mjs.map → chunk-6FTPLBSC.mjs.map} +0 -0
  234. /package/dist/lib/browser/{settings-JTT62IHD.mjs.map → settings-VAW6UWFL.mjs.map} +0 -0
  235. /package/dist/lib/node/{ChatContainer-CVHXNHGA.cjs.map → ChatContainer-JUZOEZZ7.cjs.map} +0 -0
  236. /package/dist/lib/node/{chunk-NV4TQQSU.cjs.map → chunk-N3SW6DJ6.cjs.map} +0 -0
  237. /package/dist/lib/node/{settings-4YEO7KXF.cjs.map → settings-2FEYGLYU.cjs.map} +0 -0
  238. /package/dist/lib/node-esm/{ChatContainer-VR766C4M.mjs.map → ChatContainer-ZNN5CMVL.mjs.map} +0 -0
  239. /package/dist/lib/node-esm/{chunk-LBQGJE5T.mjs.map → chunk-J63VQFQO.mjs.map} +0 -0
  240. /package/dist/lib/node-esm/{settings-S7P5RWQI.mjs.map → settings-VHR5KT4J.mjs.map} +0 -0
@@ -2,11 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { contributes, type PluginsContext } from '@dxos/app-framework';
6
- import { AIServiceClientImpl } from '@dxos/assistant';
5
+ import { effect, signal } from '@preact/signals-core';
6
+
7
+ import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
8
+ import { type AIServiceClient, AIServiceEdgeClient, OllamaClient } from '@dxos/assistant';
7
9
  import { ClientCapabilities } from '@dxos/plugin-client';
8
10
 
9
11
  import { AssistantCapabilities } from './capabilities';
12
+ import { ASSISTANT_PLUGIN } from '../meta';
13
+ import { type AssistantSettingsProps } from '../types';
10
14
 
11
15
  // TODO(wittjosiah): Factor out.
12
16
  const DEFAULT_AI_SERVICE_URL = 'http://localhost:8788';
@@ -14,6 +18,21 @@ const DEFAULT_AI_SERVICE_URL = 'http://localhost:8788';
14
18
  export default (context: PluginsContext) => {
15
19
  const client = context.requestCapability(ClientCapabilities.Client);
16
20
  const endpoint = client.config.values.runtime?.services?.ai?.server ?? DEFAULT_AI_SERVICE_URL;
17
- const aiClient = new AIServiceClientImpl({ endpoint });
18
- return contributes(AssistantCapabilities.AiClient, aiClient);
21
+
22
+ const ai = signal<AIServiceClient>(new AIServiceEdgeClient({ endpoint }));
23
+
24
+ const unsubscribe = effect(() => {
25
+ // TODO(burdon): Could be undefined.
26
+ const settings = context
27
+ .requestCapability(Capabilities.SettingsStore)
28
+ .getStore<AssistantSettingsProps>(ASSISTANT_PLUGIN)?.value;
29
+
30
+ if (settings?.llmProvider === 'ollama') {
31
+ ai.value = new OllamaClient();
32
+ } else {
33
+ ai.value = new AIServiceEdgeClient({ endpoint });
34
+ }
35
+ });
36
+
37
+ return contributes(AssistantCapabilities.AiClient, ai, () => unsubscribe());
19
38
  };
@@ -11,14 +11,14 @@ import {
11
11
  type PluginsContext,
12
12
  } from '@dxos/app-framework';
13
13
  import { invariant } from '@dxos/invariant';
14
- import { log } from '@dxos/log';
15
14
  import { ClientCapabilities } from '@dxos/plugin-client';
16
15
  import { createExtension, type Node, ROOT_ID } from '@dxos/plugin-graph';
16
+ import { memoizeQuery } from '@dxos/plugin-space';
17
17
  import { SpaceAction } from '@dxos/plugin-space/types';
18
- import { type Space, Filter, getSpace } from '@dxos/react-client/echo';
18
+ import { type Space, Filter, fullyQualifiedId, getSpace, isSpace } from '@dxos/react-client/echo';
19
19
 
20
20
  import { ASSISTANT_DIALOG, ASSISTANT_PLUGIN } from '../meta';
21
- import { AIChatType, AssistantAction } from '../types';
21
+ import { AIChatType, AssistantAction, TemplateType } from '../types';
22
22
 
23
23
  export default (context: PluginsContext) =>
24
24
  contributes(Capabilities.AppGraphBuilder, [
@@ -51,7 +51,6 @@ export default (context: PluginsContext) =>
51
51
  }
52
52
 
53
53
  if (!chat) {
54
- log.warn('no chat found');
55
54
  return;
56
55
  }
57
56
 
@@ -82,6 +81,51 @@ export default (context: PluginsContext) =>
82
81
  },
83
82
  ],
84
83
  }),
84
+
85
+ createExtension({
86
+ id: `${ASSISTANT_PLUGIN}/root`,
87
+ filter: (node): node is Node<Space> => isSpace(node.data),
88
+ connector: ({ node }) => {
89
+ const templates = memoizeQuery(node.data, Filter.schema(TemplateType));
90
+ return templates.length > 0
91
+ ? [
92
+ {
93
+ id: `${ASSISTANT_PLUGIN}/templates`,
94
+ type: `${ASSISTANT_PLUGIN}/templates`,
95
+ data: null,
96
+ properties: {
97
+ label: ['templates label', { ns: ASSISTANT_PLUGIN }],
98
+ icon: 'ph--file-code--regular',
99
+ space: node.data,
100
+ },
101
+ },
102
+ ]
103
+ : [];
104
+ },
105
+ }),
106
+
107
+ createExtension({
108
+ id: `${ASSISTANT_PLUGIN}/templates`,
109
+ filter: (node): node is Node<null, { space: Space }> => node.id === `${ASSISTANT_PLUGIN}/templates`,
110
+ connector: ({ node }) => {
111
+ const templates = memoizeQuery(node.properties.space, Filter.schema(TemplateType));
112
+ return templates
113
+ .toSorted((a, b) => {
114
+ const nameA = a.name ?? '';
115
+ const nameB = b.name ?? '';
116
+ return nameA.localeCompare(nameB);
117
+ })
118
+ .map((template) => ({
119
+ id: fullyQualifiedId(template),
120
+ type: `${ASSISTANT_PLUGIN}/template`,
121
+ data: template,
122
+ properties: {
123
+ label: template.name ?? ['template title placeholder', { ns: ASSISTANT_PLUGIN }],
124
+ icon: 'ph--file-code--regular',
125
+ },
126
+ }));
127
+ },
128
+ }),
85
129
  ]);
86
130
 
87
131
  // TODO(burdon): Factor out.
@@ -2,11 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { type ReadonlySignal } from '@preact/signals-core';
6
+
5
7
  import { defineCapability } from '@dxos/app-framework';
6
- import { type AIServiceClientImpl } from '@dxos/assistant';
8
+ import { type AIServiceClient } from '@dxos/assistant';
7
9
 
8
10
  import { ASSISTANT_PLUGIN } from '../meta';
9
11
 
10
12
  export namespace AssistantCapabilities {
11
- export const AiClient = defineCapability<AIServiceClientImpl>(`${ASSISTANT_PLUGIN}/capability/ai-client`);
13
+ export const AiClient = defineCapability<ReadonlySignal<AIServiceClient>>(`${ASSISTANT_PLUGIN}/capability/ai-client`);
12
14
  }
@@ -30,7 +30,7 @@ export default () => [
30
30
  intent: AssistantAction.CreateTemplate,
31
31
  resolve: ({ name }) => ({
32
32
  data: {
33
- object: create(TemplateType, { name, source: '{{! Template }}' }),
33
+ object: create(TemplateType, { name, kind: { include: 'manual' }, source: '{{! Template }}' }),
34
34
  },
35
35
  }),
36
36
  }),
@@ -5,6 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
8
+ import { isInstanceOf } from '@dxos/echo-schema';
8
9
  import { SettingsStore } from '@dxos/local-storage';
9
10
  import { getSpace, isSpace } from '@dxos/react-client/echo';
10
11
 
@@ -30,13 +31,13 @@ export default () =>
30
31
  createSurface({
31
32
  id: `${ASSISTANT_PLUGIN}/chat`,
32
33
  role: 'article',
33
- filter: (data): data is { subject: AIChatType } => data.subject instanceof AIChatType,
34
+ filter: (data): data is { subject: AIChatType } => isInstanceOf(AIChatType, data.subject),
34
35
  component: ({ data, role }) => <ChatContainer role={role} chat={data.subject} />,
35
36
  }),
36
37
  createSurface({
37
38
  id: `${ASSISTANT_PLUGIN}/template`,
38
39
  role: 'article',
39
- filter: (data): data is { subject: TemplateType } => data.subject instanceof TemplateType,
40
+ filter: (data): data is { subject: TemplateType } => isInstanceOf(TemplateType, data.subject),
40
41
  component: ({ data, role }) => <TemplateContainer role={role} template={data.subject} />,
41
42
  }),
42
43
  createSurface({
@@ -12,21 +12,21 @@ const preventDefault = (event: Event) => event.preventDefault();
12
12
 
13
13
  const minSize = 5;
14
14
 
15
- // TODO(burdon): Factor out.
16
- export const AmbientDialog = ({
17
- children,
18
- open: _open,
19
- title,
20
- onOpenChange,
21
- }: PropsWithChildren<{ open?: boolean; onOpenChange?: (open: boolean) => void; title?: string }>) => {
15
+ export type AmbientDialogProps = PropsWithChildren<{
16
+ open?: boolean;
17
+ title?: string;
18
+ onOpenChange?: (open: boolean) => void;
19
+ }>;
20
+
21
+ export const AmbientDialog = ({ children, open: controlledOpen, title, onOpenChange }: AmbientDialogProps) => {
22
22
  const [resizeKey, setReizeKey] = useState(0);
23
23
  const [size, setSize] = useState<Size>('min-content');
24
- const [open, setOpen] = useState(_open);
24
+ const [open, setOpen] = useState(controlledOpen);
25
25
 
26
26
  // Update controlled value.
27
27
  useEffect(() => {
28
- setOpen(_open);
29
- }, [_open]);
28
+ setOpen(controlledOpen);
29
+ }, [controlledOpen]);
30
30
 
31
31
  // Update size and key.
32
32
  useEffect(() => {
@@ -52,7 +52,7 @@ export const AmbientDialog = ({
52
52
  {...resizeAttributes}
53
53
  style={{
54
54
  ...sizeStyle(size, 'vertical', true),
55
- maxBlockSize: 'calc(100dvh - env(safe-area-inset-bottom) - env(safe-area-inset-top) - 8rem)',
55
+ maxBlockSize: 'calc(100dvh - env(safe-area-inset-bottom) - env(safe-area-inset-top) - 9rem)',
56
56
  }}
57
57
  onInteractOutside={preventDefault}
58
58
  >
@@ -23,7 +23,13 @@ export const AssistantDialog: FC<{ chat?: AIChatType }> = ({ chat }) => {
23
23
 
24
24
  return (
25
25
  <AmbientDialog open={open} onOpenChange={setOpen} title={t('assistant dialog title')}>
26
- <ThreadContainer chat={chat} onOpenChange={setOpen} settings={settings} transcription={transcription} />
26
+ <ThreadContainer
27
+ chat={chat}
28
+ onOpenChange={setOpen}
29
+ settings={settings}
30
+ part={'dialog'}
31
+ transcription={transcription}
32
+ />
27
33
  </AmbientDialog>
28
34
  );
29
35
  };
@@ -4,13 +4,16 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { DEFAULT_LLM_MODELS } from '@dxos/assistant';
7
+ import { DEFAULT_EDGE_MODELS, DEFAULT_OLLAMA_MODELS } from '@dxos/assistant';
8
8
  import { Input, Select, useTranslation } from '@dxos/react-ui';
9
9
  import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
10
10
 
11
11
  import { ASSISTANT_PLUGIN } from '../../meta';
12
12
  import { type AssistantSettingsProps } from '../../types';
13
13
 
14
+ // TODO(burdon): Factor out.
15
+ const DEFAULT_VALUE = '__default';
16
+
14
17
  export const AssistantSettings = ({ settings }: { settings: AssistantSettingsProps }) => {
15
18
  const { t } = useTranslation(ASSISTANT_PLUGIN);
16
19
 
@@ -23,18 +26,49 @@ export const AssistantSettings = ({ settings }: { settings: AssistantSettingsPro
23
26
  />
24
27
  </DeprecatedFormInput>
25
28
 
26
- <DeprecatedFormInput label={t('settings llm model label')}>
29
+ <DeprecatedFormInput label={t('settings llm provider label')}>
30
+ <Input.Switch
31
+ checked={settings.llmProvider === 'ollama'}
32
+ onCheckedChange={(checked) => (settings.llmProvider = checked ? 'ollama' : 'edge')}
33
+ />
34
+ </DeprecatedFormInput>
35
+
36
+ <DeprecatedFormInput label={t('settings edge llm model label')}>
37
+ <Select.Root
38
+ value={settings.edgeModel ?? DEFAULT_VALUE}
39
+ onValueChange={(value) => {
40
+ settings.edgeModel = value === DEFAULT_VALUE ? undefined : value;
41
+ }}
42
+ >
43
+ <Select.TriggerButton placeholder={t('settings default llm model label')} />
44
+ <Select.Portal>
45
+ <Select.Content>
46
+ <Select.Viewport>
47
+ <Select.Option value={DEFAULT_VALUE}>{t('settings default label')}</Select.Option>
48
+ {DEFAULT_EDGE_MODELS.map((model) => (
49
+ <Select.Option key={model} value={model}>
50
+ {model}
51
+ </Select.Option>
52
+ ))}
53
+ </Select.Viewport>
54
+ </Select.Content>
55
+ </Select.Portal>
56
+ </Select.Root>
57
+ </DeprecatedFormInput>
58
+
59
+ <DeprecatedFormInput label={t('settings ollama llm model label')}>
27
60
  <Select.Root
28
- value={settings.llmModel ?? 'default'}
61
+ value={settings.ollamaModel ?? DEFAULT_VALUE}
29
62
  onValueChange={(value) => {
30
- settings.llmModel = value;
63
+ settings.ollamaModel = value === DEFAULT_VALUE ? undefined : value;
31
64
  }}
32
65
  >
33
66
  <Select.TriggerButton placeholder={t('settings default llm model label')} />
34
67
  <Select.Portal>
35
68
  <Select.Content>
36
69
  <Select.Viewport>
37
- {DEFAULT_LLM_MODELS.map((model) => (
70
+ <Select.Option value={DEFAULT_VALUE}>{t('settings default label')}</Select.Option>
71
+ {DEFAULT_OLLAMA_MODELS.map((model) => (
38
72
  <Select.Option key={model} value={model}>
39
73
  {model}
40
74
  </Select.Option>
@@ -11,6 +11,7 @@ import { withTheme, withLayout } from '@dxos/storybook-utils';
11
11
 
12
12
  import { Prompt } from './Prompt';
13
13
  import { PromptBar } from './PromptBar';
14
+ import type { ReferenceData } from './references';
14
15
  import translations from '../../translations';
15
16
 
16
17
  const meta: Meta<typeof Prompt> = {
@@ -77,3 +78,36 @@ export const Toolbar: Story = {
77
78
  );
78
79
  },
79
80
  };
81
+
82
+ export const Includes: Story = {
83
+ args: {
84
+ classNames: 'w-96 p-4 rounded outline outline-gray-200',
85
+ references: {
86
+ getReferences: async ({ query }) => {
87
+ const res = references.filter((i) => i.label.toLowerCase().startsWith(query.toLowerCase()));
88
+ console.log('getReferences', { query, res });
89
+ return res;
90
+ },
91
+ resolveReference: async ({ uri }) => {
92
+ const res = references.find((i) => i.uri === uri);
93
+ console.log('resolveReference', { uri, res });
94
+ return res ?? null;
95
+ },
96
+ },
97
+ },
98
+ };
99
+
100
+ const references: ReferenceData[] = [
101
+ {
102
+ uri: 'dxn:echo:@:AAAAAAAA',
103
+ label: 'Meeting Notes',
104
+ },
105
+ {
106
+ uri: 'dxn:echo:@:BBBBBBBB',
107
+ label: 'Project Plan',
108
+ },
109
+ {
110
+ uri: 'dxn:echo:@:CCCCCCCC',
111
+ label: 'Meeting Plan',
112
+ },
113
+ ];
@@ -2,6 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { Prec } from '@codemirror/state';
5
6
  import React, { forwardRef, useImperativeHandle } from 'react';
6
7
 
7
8
  import { type ThemedClassName, useThemeContext } from '@dxos/react-ui';
@@ -16,6 +17,7 @@ import {
16
17
  import { mx } from '@dxos/react-ui-theme';
17
18
 
18
19
  import { createAutocompleteExtension, type AutocompleteOptions } from './autocomplete';
20
+ import { promptReferences, type ReferencesProvider } from './references';
19
21
 
20
22
  // TODO(burdon): Handle object references.
21
23
 
@@ -27,16 +29,21 @@ export interface PromptController {
27
29
  export type PromptProps = ThemedClassName<
28
30
  {
29
31
  onOpenChange?: (open: boolean) => void;
32
+ references?: ReferencesProvider;
30
33
  } & AutocompleteOptions &
31
34
  Pick<UseTextEditorProps, 'autoFocus'> &
32
35
  Pick<BasicExtensionsOptions, 'lineWrapping' | 'placeholder'>
33
36
  >;
34
37
 
35
38
  export const Prompt = forwardRef<PromptController, PromptProps>(
36
- ({ classNames, autoFocus, lineWrapping = false, placeholder, onSubmit, onSuggest, onOpenChange }, forwardRef) => {
39
+ (
40
+ { classNames, autoFocus, lineWrapping = false, placeholder, onSubmit, onSuggest, onOpenChange, references },
41
+ forwardRef,
42
+ ) => {
37
43
  const { themeMode } = useThemeContext();
38
44
  const { parentRef, view } = useTextEditor(
39
45
  {
46
+ debug: true,
40
47
  autoFocus,
41
48
  extensions: [
42
49
  createBasicExtensions({
@@ -45,25 +52,28 @@ export const Prompt = forwardRef<PromptController, PromptProps>(
45
52
  placeholder,
46
53
  }),
47
54
  createThemeExtensions({ themeMode }),
55
+ references ? promptReferences({ provider: references }) : [],
48
56
  createAutocompleteExtension({ onSubmit, onSuggest }),
49
- keymap.of([
50
- {
51
- key: 'Alt-ArrowUp',
52
- preventDefault: true,
53
- run: (view) => {
54
- onOpenChange?.(true);
55
- return true;
57
+ Prec.highest(
58
+ keymap.of([
59
+ {
60
+ key: 'cmd-ArrowUp',
61
+ preventDefault: true,
62
+ run: (view) => {
63
+ onOpenChange?.(true);
64
+ return true;
65
+ },
56
66
  },
57
- },
58
- {
59
- key: 'Alt-ArrowDown',
60
- preventDefault: true,
61
- run: (view) => {
62
- onOpenChange?.(false);
63
- return true;
67
+ {
68
+ key: 'cmd-ArrowDown',
69
+ preventDefault: true,
70
+ run: (view) => {
71
+ onOpenChange?.(false);
72
+ return true;
73
+ },
64
74
  },
65
- },
66
- ]),
75
+ ]),
76
+ ),
67
77
  ],
68
78
  },
69
79
  [themeMode, onSubmit, onSuggest],
@@ -95,6 +105,6 @@ export const Prompt = forwardRef<PromptController, PromptProps>(
95
105
  [view, onSubmit],
96
106
  );
97
107
 
98
- return <div ref={parentRef} className={mx('w-full overflow-hidden', classNames)} />;
108
+ return <div ref={parentRef} className={mx('w-full', classNames)} />;
99
109
  },
100
110
  );
@@ -5,7 +5,7 @@
5
5
  import React, { useRef, useState } from 'react';
6
6
 
7
7
  import { useVoiceInput } from '@dxos/plugin-transcription';
8
- import { Icon, IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
+ import { Icon, IconButton, type ThemedClassName, Tooltip, useTranslation } from '@dxos/react-ui';
9
9
  import { Spinner } from '@dxos/react-ui-sfx';
10
10
  import { errorText, mx } from '@dxos/react-ui-theme';
11
11
 
@@ -13,7 +13,7 @@ import { Prompt, type PromptController, type PromptProps } from './Prompt';
13
13
  import { ASSISTANT_PLUGIN } from '../../meta';
14
14
 
15
15
  export type PromptBarProps = ThemedClassName<
16
- Pick<PromptProps, 'placeholder' | 'lineWrapping' | 'onSubmit' | 'onSuggest' | 'onOpenChange'> & {
16
+ Pick<PromptProps, 'placeholder' | 'lineWrapping' | 'onSubmit' | 'onSuggest' | 'onOpenChange' | 'references'> & {
17
17
  processing?: boolean;
18
18
  error?: Error;
19
19
  microphone?: boolean;
@@ -28,6 +28,7 @@ export const PromptBar = ({
28
28
  error,
29
29
  microphone,
30
30
  onCancel,
31
+ references,
31
32
  ...props
32
33
  }: PromptBarProps) => {
33
34
  const { t } = useTranslation(ASSISTANT_PLUGIN);
@@ -44,18 +45,27 @@ export const PromptBar = ({
44
45
  },
45
46
  });
46
47
 
47
- // TODO(burdon): Tooltip for error.
48
48
  return (
49
49
  <div
50
50
  className={mx(
51
- 'flex shrink-0 w-full grid grid-cols-[var(--rail-action)_1fr_var(--rail-action)] overflow-hidden',
51
+ 'shrink-0 w-full grid grid-cols-[var(--rail-action)_1fr_var(--rail-action)] overflow-hidden',
52
52
  classNames,
53
53
  )}
54
54
  >
55
55
  <div className='flex w-[--rail-action] h-[--rail-action] items-center justify-center'>
56
- {(error && <Icon icon='ph--warning-circle--regular' classNames={errorText} size={5} />) || (
57
- <Spinner active={processing} />
58
- )}
56
+ {(error && (
57
+ <Tooltip.Root delayDuration={0}>
58
+ <Tooltip.Trigger>
59
+ <Icon icon='ph--warning-circle--regular' classNames={errorText} size={5} />
60
+ </Tooltip.Trigger>
61
+ <Tooltip.Portal>
62
+ <Tooltip.Content>
63
+ <div className='text-sm text-error-500'>{error.message}</div>
64
+ <Tooltip.Arrow />
65
+ </Tooltip.Content>
66
+ </Tooltip.Portal>
67
+ </Tooltip.Root>
68
+ )) || <Spinner active={processing} />}
59
69
  </div>
60
70
  <Prompt
61
71
  ref={promptRef}
@@ -63,6 +73,7 @@ export const PromptBar = ({
63
73
  classNames='pbs-2'
64
74
  lineWrapping={true}
65
75
  placeholder={placeholder ?? t('prompt placeholder')}
76
+ references={references}
66
77
  {...props}
67
78
  />
68
79
  {(onCancel || microphone) && (
@@ -0,0 +1,180 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { autocompletion, completionKeymap, type CompletionResult } from '@codemirror/autocomplete';
6
+ import { type Extension, RangeSet } from '@codemirror/state';
7
+ import {
8
+ Decoration,
9
+ EditorView,
10
+ keymap,
11
+ ViewPlugin,
12
+ WidgetType,
13
+ type DecorationSet,
14
+ type ViewUpdate,
15
+ } from '@codemirror/view';
16
+
17
+ import { Mutex } from '@dxos/async';
18
+
19
+ export type ReferenceData = {
20
+ uri: string;
21
+ label: string;
22
+ // TODO(dmaretskyi): Consider adding details renderer for when you hover over the reference.
23
+ };
24
+
25
+ export interface ReferencesProvider {
26
+ getReferences({ query }: { query: string }): Promise<ReferenceData[]>;
27
+
28
+ resolveReference({ uri }: { uri: string }): Promise<ReferenceData | null>;
29
+ }
30
+
31
+ export type PromptReferencesOptions = {
32
+ provider: ReferencesProvider;
33
+ /**
34
+ * Will prevent the autocomplete from closing when the user blurs the editor.
35
+ * @default false
36
+ */
37
+ debug?: boolean;
38
+ /**
39
+ * @default '@'
40
+ */
41
+ triggerCharacter?: string;
42
+ };
43
+
44
+ /**
45
+ * Include references into text.
46
+ */
47
+ export const promptReferences = ({
48
+ provider,
49
+ debug = false,
50
+ triggerCharacter = '@',
51
+ }: PromptReferencesOptions): Extension => {
52
+ if (triggerCharacter.length !== 1) {
53
+ throw new Error('triggerCharacter must be a single character');
54
+ }
55
+
56
+ const decorationField = ViewPlugin.fromClass(
57
+ class ReferenceView {
58
+ private _mutex = new Mutex();
59
+
60
+ decorations: DecorationSet = Decoration.set([]);
61
+
62
+ constructor(view: EditorView) {
63
+ queueMicrotask(async () => {
64
+ const guard = await this._mutex.acquire();
65
+ try {
66
+ this.decorations = await this._computeDecorations(view);
67
+ } finally {
68
+ guard.release();
69
+ }
70
+ });
71
+ }
72
+
73
+ update(update: ViewUpdate) {
74
+ if (update.docChanged) {
75
+ queueMicrotask(async () => {
76
+ const guard = await this._mutex.acquire();
77
+ try {
78
+ this.decorations = await this._computeDecorations(update.view);
79
+ } finally {
80
+ guard.release();
81
+ }
82
+ });
83
+ }
84
+ }
85
+
86
+ private async _computeDecorations(view: EditorView): Promise<DecorationSet> {
87
+ const text = view.state.doc.toString();
88
+ const references = text.matchAll(new RegExp(`${triggerCharacter}[a-zA-Z0-9@:]+\\s`, 'g'));
89
+
90
+ const decorations = [];
91
+ for (const match of references) {
92
+ const reference = match[0];
93
+ const uri = reference.slice(1, -1);
94
+ const data = await provider.resolveReference({ uri });
95
+ if (data) {
96
+ decorations.push(
97
+ Decoration.replace({
98
+ widget: new ReferenceWidget(data),
99
+ }).range(match.index!, match.index! + reference.length),
100
+ );
101
+ }
102
+ }
103
+
104
+ return Decoration.set(decorations);
105
+ }
106
+ },
107
+ {
108
+ decorations: (v) => v.decorations,
109
+ provide: (plugin) => [
110
+ EditorView.atomicRanges.of(
111
+ (view): DecorationSet => view.plugin(decorationField)?.decorations ?? RangeSet.empty,
112
+ ),
113
+ ],
114
+ },
115
+ );
116
+
117
+ return [
118
+ decorationField,
119
+
120
+ EditorView.theme({
121
+ '.cm-reference-pill': {
122
+ borderRadius: '0.25rem',
123
+ borderWidth: '1px',
124
+ marginRight: '0.25rem',
125
+ marginLeft: '0.25rem',
126
+ },
127
+ }),
128
+
129
+ autocompletion({
130
+ activateOnTyping: true,
131
+ override: [
132
+ async (context): Promise<CompletionResult | null> => {
133
+ const match = context.matchBefore(new RegExp(`${triggerCharacter}[a-zA-Z0-9]+`));
134
+
135
+ if (!match || match?.to === match?.from) {
136
+ return null;
137
+ }
138
+
139
+ const query = match.text.slice(1);
140
+ const references = await provider.getReferences({ query });
141
+
142
+ return {
143
+ from: match.from,
144
+ filter: false,
145
+ options: references.map((reference) => ({
146
+ label: reference.label,
147
+ apply: `${triggerCharacter}${reference.uri} `,
148
+ })),
149
+ };
150
+ },
151
+ ],
152
+ closeOnBlur: !debug,
153
+ tooltipClass: () => 'shadow rounded',
154
+ aboveCursor: true,
155
+ }),
156
+
157
+ keymap.of(completionKeymap),
158
+ ];
159
+ };
160
+
161
+ class ReferenceWidget extends WidgetType {
162
+ constructor(private data: ReferenceData) {
163
+ super();
164
+ }
165
+
166
+ override toDOM() {
167
+ const span = document.createElement('span');
168
+ span.textContent = `@ ${this.data.label}`;
169
+ span.className = 'cm-reference-pill';
170
+ return span;
171
+ }
172
+
173
+ override eq(other: ReferenceWidget) {
174
+ return other.data.uri === this.data.uri;
175
+ }
176
+
177
+ override ignoreEvent() {
178
+ return true;
179
+ }
180
+ }