@dxos/plugin-assistant 0.8.1-main.ba2dec9 → 0.8.1-staging.31c3ee1

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 (236) hide show
  1. package/dist/lib/browser/{AssistantDialog-AMON6O2T.mjs → AssistantDialog-YSHMAHW5.mjs} +15 -14
  2. package/dist/lib/browser/AssistantDialog-YSHMAHW5.mjs.map +7 -0
  3. package/dist/lib/browser/{ChatContainer-SPZK5ZHX.mjs → ChatContainer-V5GP7DYF.mjs} +11 -11
  4. package/dist/lib/browser/ChatContainer-V5GP7DYF.mjs.map +7 -0
  5. package/dist/lib/browser/TemplateContainer-K4EJNGIL.mjs +78 -0
  6. package/dist/lib/browser/TemplateContainer-K4EJNGIL.mjs.map +7 -0
  7. package/dist/lib/browser/ai-client-CDZLSNXE.mjs +35 -0
  8. package/dist/lib/browser/ai-client-CDZLSNXE.mjs.map +7 -0
  9. package/dist/lib/browser/app-graph-builder-MF5EVDWW.mjs +209 -0
  10. package/dist/lib/browser/app-graph-builder-MF5EVDWW.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-NV7SVHMV.mjs → chunk-3HCI5FIL.mjs} +2 -2
  12. package/dist/lib/browser/{chunk-NV7SVHMV.mjs.map → chunk-3HCI5FIL.mjs.map} +2 -2
  13. package/dist/lib/browser/{chunk-HI564NSX.mjs → chunk-FMB7RGMP.mjs} +379 -247
  14. package/dist/lib/browser/chunk-FMB7RGMP.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-IAMR2FAE.mjs +183 -0
  16. package/dist/lib/browser/chunk-IAMR2FAE.mjs.map +7 -0
  17. package/dist/lib/browser/{chunk-FR7IEJ7N.mjs → chunk-KYMKVE6M.mjs} +37 -15
  18. package/dist/lib/browser/chunk-KYMKVE6M.mjs.map +7 -0
  19. package/dist/lib/browser/{chunk-EUMPBC4T.mjs → chunk-NFUHCW2J.mjs} +3 -3
  20. package/dist/lib/browser/{chunk-NTLTGYYS.mjs → chunk-TXJWGWJ7.mjs} +3 -3
  21. package/dist/lib/browser/chunk-TXJWGWJ7.mjs.map +7 -0
  22. package/dist/lib/browser/index.mjs +37 -53
  23. package/dist/lib/browser/index.mjs.map +3 -3
  24. package/dist/lib/browser/{intent-resolver-FQRN6747.mjs → intent-resolver-WJGLKKVO.mjs} +8 -6
  25. package/dist/lib/browser/{intent-resolver-FQRN6747.mjs.map → intent-resolver-WJGLKKVO.mjs.map} +3 -3
  26. package/dist/lib/browser/meta.json +1 -1
  27. package/dist/lib/browser/{react-surface-GLNUJX7O.mjs → react-surface-57VRDOQT.mjs} +36 -15
  28. package/dist/lib/browser/react-surface-57VRDOQT.mjs.map +7 -0
  29. package/dist/lib/browser/{settings-VVQUGG56.mjs → settings-U6UFQX32.mjs} +4 -4
  30. package/dist/lib/browser/types/index.mjs +6 -2
  31. package/dist/lib/node/{AssistantDialog-DS7OCVMV.cjs → AssistantDialog-YI2BSGSX.cjs} +18 -17
  32. package/dist/lib/node/AssistantDialog-YI2BSGSX.cjs.map +7 -0
  33. package/dist/lib/node/{ChatContainer-7MNRJL6Q.cjs → ChatContainer-ZJ5JXF6A.cjs} +15 -15
  34. package/dist/lib/node/ChatContainer-ZJ5JXF6A.cjs.map +7 -0
  35. package/dist/lib/node/TemplateContainer-XWFYJB4T.cjs +104 -0
  36. package/dist/lib/node/TemplateContainer-XWFYJB4T.cjs.map +7 -0
  37. package/dist/lib/node/{ai-client-RBDOGK6W.cjs → ai-client-URCCYU6B.cjs} +19 -19
  38. package/dist/lib/node/ai-client-URCCYU6B.cjs.map +7 -0
  39. package/dist/lib/node/app-graph-builder-N5ZUUI2Z.cjs +220 -0
  40. package/dist/lib/node/app-graph-builder-N5ZUUI2Z.cjs.map +7 -0
  41. package/dist/lib/node/{chunk-34WE2FD2.cjs → chunk-APRU3QWK.cjs} +32 -9
  42. package/dist/lib/node/chunk-APRU3QWK.cjs.map +7 -0
  43. package/dist/lib/node/{chunk-3WXG6WA6.cjs → chunk-GBUNQ257.cjs} +6 -6
  44. package/dist/lib/node/chunk-GBUNQ257.cjs.map +7 -0
  45. package/dist/lib/node/{chunk-GNPXCHFT.cjs → chunk-Q5XWEMHB.cjs} +4 -4
  46. package/dist/lib/node/{chunk-GNPXCHFT.cjs.map → chunk-Q5XWEMHB.cjs.map} +2 -2
  47. package/dist/lib/node/{chunk-3HNLL6MY.cjs → chunk-RPBKMP2E.cjs} +350 -222
  48. package/dist/lib/node/chunk-RPBKMP2E.cjs.map +7 -0
  49. package/dist/lib/node/{chunk-NV4TQQSU.cjs → chunk-XI2ARIEO.cjs} +6 -6
  50. package/dist/lib/node/{chunk-PYTGHFKZ.cjs → chunk-ZKOC4ZFY.cjs} +40 -18
  51. package/dist/lib/node/chunk-ZKOC4ZFY.cjs.map +7 -0
  52. package/dist/lib/node/index.cjs +78 -94
  53. package/dist/lib/node/index.cjs.map +3 -3
  54. package/dist/lib/node/{intent-resolver-Z37RNNMC.cjs → intent-resolver-R3OSTIMH.cjs} +14 -12
  55. package/dist/lib/node/intent-resolver-R3OSTIMH.cjs.map +7 -0
  56. package/dist/lib/node/meta.json +1 -1
  57. package/dist/lib/node/{react-surface-PYGRBZY7.cjs → react-surface-NUQTM6MS.cjs} +47 -26
  58. package/dist/lib/node/react-surface-NUQTM6MS.cjs.map +7 -0
  59. package/dist/lib/node/{settings-TJHHVI6B.cjs → settings-TXGRCYAL.cjs} +8 -8
  60. package/dist/lib/node/types/index.cjs +15 -11
  61. package/dist/lib/node/types/index.cjs.map +2 -2
  62. package/dist/lib/node-esm/{AssistantDialog-TSVUYKUL.mjs → AssistantDialog-U2FQX5TD.mjs} +15 -14
  63. package/dist/lib/node-esm/AssistantDialog-U2FQX5TD.mjs.map +7 -0
  64. package/dist/lib/node-esm/{ChatContainer-H4X734PB.mjs → ChatContainer-QW3OOXTT.mjs} +11 -11
  65. package/dist/lib/node-esm/ChatContainer-QW3OOXTT.mjs.map +7 -0
  66. package/dist/lib/node-esm/TemplateContainer-EUM2X65J.mjs +79 -0
  67. package/dist/lib/node-esm/TemplateContainer-EUM2X65J.mjs.map +7 -0
  68. package/dist/lib/node-esm/ai-client-WMHS5EGV.mjs +36 -0
  69. package/dist/lib/node-esm/ai-client-WMHS5EGV.mjs.map +7 -0
  70. package/dist/lib/node-esm/app-graph-builder-DWBNIMHM.mjs +210 -0
  71. package/dist/lib/node-esm/app-graph-builder-DWBNIMHM.mjs.map +7 -0
  72. package/dist/lib/node-esm/{chunk-ICQN3TDS.mjs → chunk-6JK5HEUQ.mjs} +3 -3
  73. package/dist/lib/node-esm/chunk-6JK5HEUQ.mjs.map +7 -0
  74. package/dist/lib/node-esm/{chunk-7SV6X6XU.mjs → chunk-ECRK6TUQ.mjs} +2 -2
  75. package/dist/lib/node-esm/{chunk-7SV6X6XU.mjs.map → chunk-ECRK6TUQ.mjs.map} +2 -2
  76. package/dist/lib/node-esm/{chunk-JRP4BQT4.mjs → chunk-GBBXIW5F.mjs} +37 -15
  77. package/dist/lib/node-esm/chunk-GBBXIW5F.mjs.map +7 -0
  78. package/dist/lib/node-esm/{chunk-E44GXXNE.mjs → chunk-MVDAY3CZ.mjs} +379 -247
  79. package/dist/lib/node-esm/chunk-MVDAY3CZ.mjs.map +7 -0
  80. package/dist/lib/node-esm/chunk-MXK2EANZ.mjs +184 -0
  81. package/dist/lib/node-esm/chunk-MXK2EANZ.mjs.map +7 -0
  82. package/dist/lib/node-esm/{chunk-LBQGJE5T.mjs → chunk-PBZA7XJR.mjs} +3 -3
  83. package/dist/lib/node-esm/index.mjs +37 -53
  84. package/dist/lib/node-esm/index.mjs.map +3 -3
  85. package/dist/lib/node-esm/{intent-resolver-LOTXWV4J.mjs → intent-resolver-H32TL4X6.mjs} +8 -6
  86. package/dist/lib/node-esm/{intent-resolver-LOTXWV4J.mjs.map → intent-resolver-H32TL4X6.mjs.map} +3 -3
  87. package/dist/lib/node-esm/meta.json +1 -1
  88. package/dist/lib/node-esm/{react-surface-PEQD6IJS.mjs → react-surface-JBVZF6CP.mjs} +36 -15
  89. package/dist/lib/node-esm/react-surface-JBVZF6CP.mjs.map +7 -0
  90. package/dist/lib/node-esm/{settings-BVWR244C.mjs → settings-DZU5PNXM.mjs} +4 -4
  91. package/dist/lib/node-esm/types/index.mjs +6 -2
  92. package/dist/types/src/AssistantPlugin.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/ai-client.d.ts +2 -1
  94. package/dist/types/src/capabilities/ai-client.d.ts.map +1 -1
  95. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  96. package/dist/types/src/capabilities/capabilities.d.ts +2 -1
  97. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  98. package/dist/types/src/capabilities/index.d.ts +1 -1
  99. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  100. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  101. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  102. package/dist/types/src/components/AmbientDialog/AmbientDialog.d.ts +4 -3
  103. package/dist/types/src/components/AmbientDialog/AmbientDialog.d.ts.map +1 -1
  104. package/dist/types/src/components/AmbientDialog/AmbientDialog.stories.d.ts.map +1 -1
  105. package/dist/types/src/components/AssistantDialog.d.ts.map +1 -1
  106. package/dist/types/src/components/AssistantSettings/AssistantSettings.d.ts.map +1 -1
  107. package/dist/types/src/components/ChatContainer.d.ts +4 -2
  108. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  109. package/dist/types/src/components/Prompt/Prompt.d.ts +3 -0
  110. package/dist/types/src/components/Prompt/Prompt.d.ts.map +1 -1
  111. package/dist/types/src/components/Prompt/Prompt.stories.d.ts +1 -0
  112. package/dist/types/src/components/Prompt/Prompt.stories.d.ts.map +1 -1
  113. package/dist/types/src/components/Prompt/PromptBar.d.ts +2 -2
  114. package/dist/types/src/components/Prompt/PromptBar.d.ts.map +1 -1
  115. package/dist/types/src/components/Prompt/references.d.ts +30 -0
  116. package/dist/types/src/components/Prompt/references.d.ts.map +1 -0
  117. package/dist/types/src/components/TemplateContainer.d.ts.map +1 -1
  118. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts +3 -3
  119. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts.map +1 -1
  120. package/dist/types/src/components/Thread/Thread.d.ts +11 -1
  121. package/dist/types/src/components/Thread/Thread.d.ts.map +1 -1
  122. package/dist/types/src/components/Thread/ThreadContainer.d.ts +3 -0
  123. package/dist/types/src/components/Thread/ThreadContainer.d.ts.map +1 -1
  124. package/dist/types/src/components/Thread/ThreadContainer.stories.d.ts +3 -3
  125. package/dist/types/src/components/Thread/ThreadContainer.stories.d.ts.map +1 -1
  126. package/dist/types/src/components/Thread/ThreadMessage.d.ts.map +1 -1
  127. package/dist/types/src/components/index.d.ts +3 -2
  128. package/dist/types/src/components/index.d.ts.map +1 -1
  129. package/dist/types/src/hooks/index.d.ts +1 -0
  130. package/dist/types/src/hooks/index.d.ts.map +1 -1
  131. package/dist/types/src/hooks/processor.d.ts +7 -15
  132. package/dist/types/src/hooks/processor.d.ts.map +1 -1
  133. package/dist/types/src/hooks/useChatProcessor.d.ts +11 -2
  134. package/dist/types/src/hooks/useChatProcessor.d.ts.map +1 -1
  135. package/dist/types/src/hooks/useContextProvider.d.ts +17 -0
  136. package/dist/types/src/hooks/useContextProvider.d.ts.map +1 -0
  137. package/dist/types/src/hooks/useMessageQueue.d.ts +3 -3
  138. package/dist/types/src/hooks/useMessageQueue.d.ts.map +1 -1
  139. package/dist/types/src/meta.d.ts +2 -8
  140. package/dist/types/src/meta.d.ts.map +1 -1
  141. package/dist/types/src/testing/test-functions.d.ts.map +1 -1
  142. package/dist/types/src/translations.d.ts +26 -12
  143. package/dist/types/src/translations.d.ts.map +1 -1
  144. package/dist/types/src/types/chat.d.ts +4 -6
  145. package/dist/types/src/types/chat.d.ts.map +1 -1
  146. package/dist/types/src/types/template.d.ts +36 -0
  147. package/dist/types/src/types/template.d.ts.map +1 -1
  148. package/dist/types/src/types/types.d.ts +3 -1
  149. package/dist/types/src/types/types.d.ts.map +1 -1
  150. package/package.json +58 -55
  151. package/src/AssistantPlugin.tsx +19 -23
  152. package/src/capabilities/ai-client.ts +23 -7
  153. package/src/capabilities/app-graph-builder.ts +100 -5
  154. package/src/capabilities/capabilities.ts +3 -1
  155. package/src/capabilities/intent-resolver.ts +4 -3
  156. package/src/capabilities/react-surface.tsx +27 -9
  157. package/src/components/AmbientDialog/AmbientDialog.stories.tsx +3 -1
  158. package/src/components/AmbientDialog/AmbientDialog.tsx +11 -11
  159. package/src/components/AssistantDialog.tsx +8 -2
  160. package/src/components/AssistantSettings/AssistantSettings.tsx +39 -5
  161. package/src/components/ChatContainer.tsx +18 -4
  162. package/src/components/Prompt/Prompt.stories.tsx +34 -0
  163. package/src/components/Prompt/Prompt.tsx +28 -18
  164. package/src/components/Prompt/PromptBar.tsx +5 -3
  165. package/src/components/Prompt/references.ts +180 -0
  166. package/src/components/TemplateContainer.tsx +79 -4
  167. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +5 -5
  168. package/src/components/TemplateEditor/TemplateForm.stories.tsx +3 -3
  169. package/src/components/Thread/Thread.stories.tsx +3 -3
  170. package/src/components/Thread/Thread.tsx +21 -0
  171. package/src/components/Thread/ThreadContainer.stories.tsx +9 -14
  172. package/src/components/Thread/ThreadContainer.tsx +10 -4
  173. package/src/components/Thread/ThreadMessage.tsx +17 -9
  174. package/src/components/Toolbox/Toolbox.stories.tsx +2 -2
  175. package/src/components/index.ts +3 -0
  176. package/src/hooks/index.ts +1 -0
  177. package/src/hooks/processor.ts +57 -116
  178. package/src/hooks/useChatProcessor.tsx +35 -19
  179. package/src/hooks/useContextProvider.ts +55 -0
  180. package/src/hooks/useMessageQueue.ts +4 -6
  181. package/src/meta.ts +2 -2
  182. package/src/testing/test-functions.ts +2 -2
  183. package/src/translations.ts +11 -5
  184. package/src/types/chat.ts +2 -3
  185. package/src/types/template.ts +22 -0
  186. package/src/types/types.ts +3 -1
  187. package/dist/lib/browser/AssistantDialog-AMON6O2T.mjs.map +0 -7
  188. package/dist/lib/browser/ChatContainer-SPZK5ZHX.mjs.map +0 -7
  189. package/dist/lib/browser/TemplateContainer-B7MQNUPY.mjs +0 -23
  190. package/dist/lib/browser/TemplateContainer-B7MQNUPY.mjs.map +0 -7
  191. package/dist/lib/browser/ai-client-PORKRZXM.mjs +0 -33
  192. package/dist/lib/browser/ai-client-PORKRZXM.mjs.map +0 -7
  193. package/dist/lib/browser/app-graph-builder-36SKR7CX.mjs +0 -110
  194. package/dist/lib/browser/app-graph-builder-36SKR7CX.mjs.map +0 -7
  195. package/dist/lib/browser/chunk-FPXC3LKK.mjs +0 -162
  196. package/dist/lib/browser/chunk-FPXC3LKK.mjs.map +0 -7
  197. package/dist/lib/browser/chunk-FR7IEJ7N.mjs.map +0 -7
  198. package/dist/lib/browser/chunk-HI564NSX.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-NTLTGYYS.mjs.map +0 -7
  200. package/dist/lib/browser/react-surface-GLNUJX7O.mjs.map +0 -7
  201. package/dist/lib/node/AssistantDialog-DS7OCVMV.cjs.map +0 -7
  202. package/dist/lib/node/ChatContainer-7MNRJL6Q.cjs.map +0 -7
  203. package/dist/lib/node/TemplateContainer-R4BZZP3E.cjs +0 -53
  204. package/dist/lib/node/TemplateContainer-R4BZZP3E.cjs.map +0 -7
  205. package/dist/lib/node/ai-client-RBDOGK6W.cjs.map +0 -7
  206. package/dist/lib/node/app-graph-builder-V5JKKIY5.cjs +0 -122
  207. package/dist/lib/node/app-graph-builder-V5JKKIY5.cjs.map +0 -7
  208. package/dist/lib/node/chunk-34WE2FD2.cjs.map +0 -7
  209. package/dist/lib/node/chunk-3HNLL6MY.cjs.map +0 -7
  210. package/dist/lib/node/chunk-3WXG6WA6.cjs.map +0 -7
  211. package/dist/lib/node/chunk-PYTGHFKZ.cjs.map +0 -7
  212. package/dist/lib/node/intent-resolver-Z37RNNMC.cjs.map +0 -7
  213. package/dist/lib/node/react-surface-PYGRBZY7.cjs.map +0 -7
  214. package/dist/lib/node-esm/AssistantDialog-TSVUYKUL.mjs.map +0 -7
  215. package/dist/lib/node-esm/ChatContainer-H4X734PB.mjs.map +0 -7
  216. package/dist/lib/node-esm/TemplateContainer-WSHTZBB5.mjs +0 -24
  217. package/dist/lib/node-esm/TemplateContainer-WSHTZBB5.mjs.map +0 -7
  218. package/dist/lib/node-esm/ai-client-OTZVBDUH.mjs +0 -34
  219. package/dist/lib/node-esm/ai-client-OTZVBDUH.mjs.map +0 -7
  220. package/dist/lib/node-esm/app-graph-builder-DCAP6QAV.mjs +0 -111
  221. package/dist/lib/node-esm/app-graph-builder-DCAP6QAV.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-E44GXXNE.mjs.map +0 -7
  223. package/dist/lib/node-esm/chunk-ICQN3TDS.mjs.map +0 -7
  224. package/dist/lib/node-esm/chunk-JRP4BQT4.mjs.map +0 -7
  225. package/dist/lib/node-esm/chunk-LELXJPGJ.mjs +0 -163
  226. package/dist/lib/node-esm/chunk-LELXJPGJ.mjs.map +0 -7
  227. package/dist/lib/node-esm/react-surface-PEQD6IJS.mjs.map +0 -7
  228. package/dist/types/src/hooks/email.d.ts +0 -4
  229. package/dist/types/src/hooks/email.d.ts.map +0 -1
  230. package/src/hooks/email.ts +0 -49
  231. /package/dist/lib/browser/{chunk-EUMPBC4T.mjs.map → chunk-NFUHCW2J.mjs.map} +0 -0
  232. /package/dist/lib/browser/{settings-VVQUGG56.mjs.map → settings-U6UFQX32.mjs.map} +0 -0
  233. /package/dist/lib/node/{chunk-NV4TQQSU.cjs.map → chunk-XI2ARIEO.cjs.map} +0 -0
  234. /package/dist/lib/node/{settings-TJHHVI6B.cjs.map → settings-TXGRCYAL.cjs.map} +0 -0
  235. /package/dist/lib/node-esm/{chunk-LBQGJE5T.mjs.map → chunk-PBZA7XJR.mjs.map} +0 -0
  236. /package/dist/lib/node-esm/{settings-BVWR244C.mjs.map → settings-DZU5PNXM.mjs.map} +0 -0
@@ -2,11 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import React, { useMemo } from 'react';
6
6
 
7
7
  import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
8
+ import { isInstanceOf } from '@dxos/echo-schema';
9
+ import { getTypename } from '@dxos/live-object';
8
10
  import { SettingsStore } from '@dxos/local-storage';
9
- import { getSpace, isSpace } from '@dxos/react-client/echo';
11
+ import { fullyQualifiedId, isReactiveObject, isSpace, type Space } from '@dxos/react-client/echo';
10
12
 
11
13
  import { AssistantDialog, AssistantSettings, ChatContainer, ServiceRegistry, TemplateContainer } from '../components';
12
14
  import { ASSISTANT_PLUGIN, ASSISTANT_DIALOG } from '../meta';
@@ -15,7 +17,7 @@ import { AIChatType, type AssistantSettingsProps, TemplateType } from '../types'
15
17
  export default () =>
16
18
  contributes(Capabilities.ReactSurface, [
17
19
  createSurface({
18
- id: `${ASSISTANT_PLUGIN}/settings`,
20
+ id: `${ASSISTANT_PLUGIN}/plugin-settings`,
19
21
  role: 'article',
20
22
  filter: (data): data is { subject: SettingsStore<AssistantSettingsProps> } =>
21
23
  data.subject instanceof SettingsStore && data.subject.prefix === ASSISTANT_PLUGIN,
@@ -30,20 +32,36 @@ export default () =>
30
32
  createSurface({
31
33
  id: `${ASSISTANT_PLUGIN}/chat`,
32
34
  role: 'article',
33
- filter: (data): data is { subject: AIChatType } => data.subject instanceof AIChatType,
35
+ filter: (data): data is { subject: AIChatType; variant: undefined } =>
36
+ isInstanceOf(AIChatType, data.subject) && data.variant !== 'assistant-chat',
34
37
  component: ({ data, role }) => <ChatContainer role={role} chat={data.subject} />,
35
38
  }),
39
+ createSurface({
40
+ id: `${ASSISTANT_PLUGIN}/object-chat`,
41
+ role: 'article',
42
+ filter: (data): data is { companionTo: AIChatType; subject: 'assistant-chat' } =>
43
+ isReactiveObject(data.companionTo) && data.companionTo.assistantChatQueue && data.subject === 'assistant-chat',
44
+ component: ({ data, role }) => {
45
+ const associatedArtifact = useMemo(
46
+ () => ({
47
+ id: fullyQualifiedId(data.companionTo),
48
+ typename: getTypename(data.companionTo) ?? 'unknown',
49
+ }),
50
+ [data.companionTo],
51
+ );
52
+ return <ChatContainer role={role} chat={data.companionTo} associatedArtifact={associatedArtifact} />;
53
+ },
54
+ }),
36
55
  createSurface({
37
56
  id: `${ASSISTANT_PLUGIN}/template`,
38
57
  role: 'article',
39
- filter: (data): data is { subject: TemplateType } => data.subject instanceof TemplateType,
58
+ filter: (data): data is { subject: TemplateType } => isInstanceOf(TemplateType, data.subject),
40
59
  component: ({ data, role }) => <TemplateContainer role={role} template={data.subject} />,
41
60
  }),
42
61
  createSurface({
43
62
  id: `${ASSISTANT_PLUGIN}/service-registry`,
44
- role: 'complementary--service-registry',
45
- component: ({ data }) => (
46
- <ServiceRegistry space={isSpace(data.subject) ? data.subject : getSpace(data.subject)!} />
47
- ),
63
+ role: 'deck-companion--service-registry',
64
+ filter: (data): data is { subject: Space } => isSpace(data.subject),
65
+ component: ({ data }) => <ServiceRegistry space={data.subject} />,
48
66
  }),
49
67
  ]);
@@ -65,7 +65,9 @@ const meta: Meta<typeof AmbientDialog> = {
65
65
  createIdentity: true,
66
66
  createSpace: true,
67
67
  }),
68
- withPluginManager({ plugins: [IntentPlugin()] }),
68
+ withPluginManager({
69
+ plugins: [IntentPlugin()],
70
+ }),
69
71
  withTheme,
70
72
  withLayout({ fullscreen: true, tooltips: true }),
71
73
  ],
@@ -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
  >
@@ -15,7 +15,7 @@ import { type AssistantSettingsProps, type AIChatType } from '../types';
15
15
 
16
16
  export const AssistantDialog: FC<{ chat?: AIChatType }> = ({ chat }) => {
17
17
  const { t } = useTranslation(ASSISTANT_PLUGIN);
18
- const transcription = useCapabilities(TranscriptionCapabilities.Transcription).length > 0;
18
+ const transcription = useCapabilities(TranscriptionCapabilities.Transcriber).length > 0;
19
19
  const settings = useCapability(Capabilities.SettingsStore).getStore<AssistantSettingsProps>(ASSISTANT_PLUGIN)?.value;
20
20
 
21
21
  // TODO(burdon): Refocus when open.
@@ -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>
@@ -5,6 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Capabilities, useCapabilities, useCapability } from '@dxos/app-framework';
8
+ import { type AssociatedArtifact } from '@dxos/artifact';
8
9
  import { TranscriptionCapabilities } from '@dxos/plugin-transcription';
9
10
  import { StackItem } from '@dxos/react-ui-stack';
10
11
 
@@ -13,13 +14,26 @@ import { ASSISTANT_PLUGIN } from '../meta';
13
14
  import { type AssistantSettingsProps, type AIChatType } from '../types';
14
15
 
15
16
  // TODO(burdon): Attention.
16
- export const ChatContainer = ({ chat, role }: { chat: AIChatType; role: string }) => {
17
- const transcription = useCapabilities(TranscriptionCapabilities.Transcription).length > 0;
17
+ export const ChatContainer = ({
18
+ role,
19
+ chat,
20
+ associatedArtifact,
21
+ }: {
22
+ role: string;
23
+ chat: AIChatType;
24
+ associatedArtifact?: AssociatedArtifact;
25
+ }) => {
26
+ const transcription = useCapabilities(TranscriptionCapabilities.Transcriber).length > 0;
18
27
  const settings = useCapability(Capabilities.SettingsStore).getStore<AssistantSettingsProps>(ASSISTANT_PLUGIN)?.value;
19
28
 
20
29
  return (
21
- <StackItem.Content toolbar={false} role={role} classNames='mli-auto w-full max-w-[50rem]'>
22
- <ThreadContainer chat={chat} settings={settings} transcription={transcription} />
30
+ <StackItem.Content role={role} classNames='container-max-width'>
31
+ <ThreadContainer
32
+ chat={chat}
33
+ settings={settings}
34
+ transcription={transcription}
35
+ associatedArtifact={associatedArtifact}
36
+ />
23
37
  </StackItem.Content>
24
38
  );
25
39
  };
@@ -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
  );
@@ -7,13 +7,13 @@ import React, { useRef, useState } from 'react';
7
7
  import { useVoiceInput } from '@dxos/plugin-transcription';
8
8
  import { Icon, IconButton, type ThemedClassName, Tooltip, useTranslation } from '@dxos/react-ui';
9
9
  import { Spinner } from '@dxos/react-ui-sfx';
10
- import { errorText, mx } from '@dxos/react-ui-theme';
10
+ import { errorMessageColors, errorText, mx } from '@dxos/react-ui-theme';
11
11
 
12
12
  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);
@@ -59,7 +60,7 @@ export const PromptBar = ({
59
60
  </Tooltip.Trigger>
60
61
  <Tooltip.Portal>
61
62
  <Tooltip.Content>
62
- <div className='text-sm text-error-500'>{error.message}</div>
63
+ <div className={mx('text-sm', errorMessageColors)}>{error.message}</div>
63
64
  <Tooltip.Arrow />
64
65
  </Tooltip.Content>
65
66
  </Tooltip.Portal>
@@ -72,6 +73,7 @@ export const PromptBar = ({
72
73
  classNames='pbs-2'
73
74
  lineWrapping={true}
74
75
  placeholder={placeholder ?? t('prompt placeholder')}
76
+ references={references}
75
77
  {...props}
76
78
  />
77
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
+ }