@dxos/assistant-toolkit 0.8.4-main.1068cf700f

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 (280) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +3 -0
  3. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  5. package/dist/lib/neutral/index.mjs +3708 -0
  6. package/dist/lib/neutral/index.mjs.map +7 -0
  7. package/dist/lib/neutral/meta.json +1 -0
  8. package/dist/lib/neutral/testing/index.mjs +44 -0
  9. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  10. package/dist/types/src/blueprints/design/design-blueprint.d.ts +18 -0
  11. package/dist/types/src/blueprints/design/design-blueprint.d.ts.map +1 -0
  12. package/dist/types/src/blueprints/design/design-blueprint.test.d.ts +2 -0
  13. package/dist/types/src/blueprints/design/design-blueprint.test.d.ts.map +1 -0
  14. package/dist/types/src/blueprints/design/index.d.ts +3 -0
  15. package/dist/types/src/blueprints/design/index.d.ts.map +1 -0
  16. package/dist/types/src/blueprints/discord/discord-blueprint.d.ts +18 -0
  17. package/dist/types/src/blueprints/discord/discord-blueprint.d.ts.map +1 -0
  18. package/dist/types/src/blueprints/discord/index.d.ts +3 -0
  19. package/dist/types/src/blueprints/discord/index.d.ts.map +1 -0
  20. package/dist/types/src/blueprints/index.d.ts +8 -0
  21. package/dist/types/src/blueprints/index.d.ts.map +1 -0
  22. package/dist/types/src/blueprints/linear/index.d.ts +3 -0
  23. package/dist/types/src/blueprints/linear/index.d.ts.map +1 -0
  24. package/dist/types/src/blueprints/linear/linear-blueprint.d.ts +18 -0
  25. package/dist/types/src/blueprints/linear/linear-blueprint.d.ts.map +1 -0
  26. package/dist/types/src/blueprints/markdown/index.d.ts +3 -0
  27. package/dist/types/src/blueprints/markdown/index.d.ts.map +1 -0
  28. package/dist/types/src/blueprints/markdown/markdown-blueprint.d.ts +18 -0
  29. package/dist/types/src/blueprints/markdown/markdown-blueprint.d.ts.map +1 -0
  30. package/dist/types/src/blueprints/planning/index.d.ts +3 -0
  31. package/dist/types/src/blueprints/planning/index.d.ts.map +1 -0
  32. package/dist/types/src/blueprints/planning/planning-blueprint.d.ts +18 -0
  33. package/dist/types/src/blueprints/planning/planning-blueprint.d.ts.map +1 -0
  34. package/dist/types/src/blueprints/planning/planning-blueprint.test.d.ts +2 -0
  35. package/dist/types/src/blueprints/planning/planning-blueprint.test.d.ts.map +1 -0
  36. package/dist/types/src/blueprints/research/index.d.ts +3 -0
  37. package/dist/types/src/blueprints/research/index.d.ts.map +1 -0
  38. package/dist/types/src/blueprints/research/research-blueprint.d.ts +18 -0
  39. package/dist/types/src/blueprints/research/research-blueprint.d.ts.map +1 -0
  40. package/dist/types/src/blueprints/research/research-blueprint.test.d.ts +2 -0
  41. package/dist/types/src/blueprints/research/research-blueprint.test.d.ts.map +1 -0
  42. package/dist/types/src/blueprints/testing.d.ts +10 -0
  43. package/dist/types/src/blueprints/testing.d.ts.map +1 -0
  44. package/dist/types/src/blueprints/websearch/index.d.ts +4 -0
  45. package/dist/types/src/blueprints/websearch/index.d.ts.map +1 -0
  46. package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts +18 -0
  47. package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts.map +1 -0
  48. package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts +27 -0
  49. package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts.map +1 -0
  50. package/dist/types/src/chat/Chat.d.ts +31 -0
  51. package/dist/types/src/chat/Chat.d.ts.map +1 -0
  52. package/dist/types/src/chat/index.d.ts +2 -0
  53. package/dist/types/src/chat/index.d.ts.map +1 -0
  54. package/dist/types/src/crud/graph.d.ts +67 -0
  55. package/dist/types/src/crud/graph.d.ts.map +1 -0
  56. package/dist/types/src/crud/graph.test.d.ts +2 -0
  57. package/dist/types/src/crud/graph.test.d.ts.map +1 -0
  58. package/dist/types/src/crud/index.d.ts +2 -0
  59. package/dist/types/src/crud/index.d.ts.map +1 -0
  60. package/dist/types/src/experimental/feed.test.d.ts +2 -0
  61. package/dist/types/src/experimental/feed.test.d.ts.map +1 -0
  62. package/dist/types/src/functions/agent/index.d.ts +5 -0
  63. package/dist/types/src/functions/agent/index.d.ts.map +1 -0
  64. package/dist/types/src/functions/agent/prompt.d.ts +76 -0
  65. package/dist/types/src/functions/agent/prompt.d.ts.map +1 -0
  66. package/dist/types/src/functions/discord/fetch-messages.d.ts +11 -0
  67. package/dist/types/src/functions/discord/fetch-messages.d.ts.map +1 -0
  68. package/dist/types/src/functions/discord/fetch-messages.test.d.ts +2 -0
  69. package/dist/types/src/functions/discord/fetch-messages.test.d.ts.map +1 -0
  70. package/dist/types/src/functions/discord/index.d.ts +12 -0
  71. package/dist/types/src/functions/discord/index.d.ts.map +1 -0
  72. package/dist/types/src/functions/document/create.d.ts +6 -0
  73. package/dist/types/src/functions/document/create.d.ts.map +1 -0
  74. package/dist/types/src/functions/document/index.d.ts +30 -0
  75. package/dist/types/src/functions/document/index.d.ts.map +1 -0
  76. package/dist/types/src/functions/document/read.d.ts +14 -0
  77. package/dist/types/src/functions/document/read.d.ts.map +1 -0
  78. package/dist/types/src/functions/document/update.d.ts +13 -0
  79. package/dist/types/src/functions/document/update.d.ts.map +1 -0
  80. package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts +174 -0
  81. package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts.map +1 -0
  82. package/dist/types/src/functions/entity-extraction/entity-extraction.test.d.ts +2 -0
  83. package/dist/types/src/functions/entity-extraction/entity-extraction.test.d.ts.map +1 -0
  84. package/dist/types/src/functions/entity-extraction/index.d.ts +175 -0
  85. package/dist/types/src/functions/entity-extraction/index.d.ts.map +1 -0
  86. package/dist/types/src/functions/exa/data/exa-search-1748337321991.d.ts +38 -0
  87. package/dist/types/src/functions/exa/data/exa-search-1748337321991.d.ts.map +1 -0
  88. package/dist/types/src/functions/exa/data/exa-search-1748337331526.d.ts +37 -0
  89. package/dist/types/src/functions/exa/data/exa-search-1748337331526.d.ts.map +1 -0
  90. package/dist/types/src/functions/exa/data/exa-search-1748337344119.d.ts +58 -0
  91. package/dist/types/src/functions/exa/data/exa-search-1748337344119.d.ts.map +1 -0
  92. package/dist/types/src/functions/exa/data/index.d.ts +3 -0
  93. package/dist/types/src/functions/exa/data/index.d.ts.map +1 -0
  94. package/dist/types/src/functions/exa/exa.d.ts +5 -0
  95. package/dist/types/src/functions/exa/exa.d.ts.map +1 -0
  96. package/dist/types/src/functions/exa/index.d.ts +3 -0
  97. package/dist/types/src/functions/exa/index.d.ts.map +1 -0
  98. package/dist/types/src/functions/exa/mock.d.ts +5 -0
  99. package/dist/types/src/functions/exa/mock.d.ts.map +1 -0
  100. package/dist/types/src/functions/github/fetch-prs.d.ts +6 -0
  101. package/dist/types/src/functions/github/fetch-prs.d.ts.map +1 -0
  102. package/dist/types/src/functions/index.d.ts +8 -0
  103. package/dist/types/src/functions/index.d.ts.map +1 -0
  104. package/dist/types/src/functions/linear/index.d.ts +9 -0
  105. package/dist/types/src/functions/linear/index.d.ts.map +1 -0
  106. package/dist/types/src/functions/linear/linear.test.d.ts +2 -0
  107. package/dist/types/src/functions/linear/linear.test.d.ts.map +1 -0
  108. package/dist/types/src/functions/linear/sync-issues.d.ts +12 -0
  109. package/dist/types/src/functions/linear/sync-issues.d.ts.map +1 -0
  110. package/dist/types/src/functions/research/document-create.d.ts +9 -0
  111. package/dist/types/src/functions/research/document-create.d.ts.map +1 -0
  112. package/dist/types/src/functions/research/index.d.ts +21 -0
  113. package/dist/types/src/functions/research/index.d.ts.map +1 -0
  114. package/dist/types/src/functions/research/research-graph.d.ts +19 -0
  115. package/dist/types/src/functions/research/research-graph.d.ts.map +1 -0
  116. package/dist/types/src/functions/research/research.d.ts +14 -0
  117. package/dist/types/src/functions/research/research.d.ts.map +1 -0
  118. package/dist/types/src/functions/research/research.test.d.ts +2 -0
  119. package/dist/types/src/functions/research/research.test.d.ts.map +1 -0
  120. package/dist/types/src/functions/research/types.d.ts +6 -0
  121. package/dist/types/src/functions/research/types.d.ts.map +1 -0
  122. package/dist/types/src/functions/tasks/index.d.ts +29 -0
  123. package/dist/types/src/functions/tasks/index.d.ts.map +1 -0
  124. package/dist/types/src/functions/tasks/read.d.ts +14 -0
  125. package/dist/types/src/functions/tasks/read.d.ts.map +1 -0
  126. package/dist/types/src/functions/tasks/task-list.d.ts +74 -0
  127. package/dist/types/src/functions/tasks/task-list.d.ts.map +1 -0
  128. package/dist/types/src/functions/tasks/task-list.test.d.ts +2 -0
  129. package/dist/types/src/functions/tasks/task-list.test.d.ts.map +1 -0
  130. package/dist/types/src/functions/tasks/update.d.ts +16 -0
  131. package/dist/types/src/functions/tasks/update.d.ts.map +1 -0
  132. package/dist/types/src/index.d.ts +9 -0
  133. package/dist/types/src/index.d.ts.map +1 -0
  134. package/dist/types/src/initiative/Initiative.d.ts +41 -0
  135. package/dist/types/src/initiative/Initiative.d.ts.map +1 -0
  136. package/dist/types/src/initiative/blueprint.d.ts +153 -0
  137. package/dist/types/src/initiative/blueprint.d.ts.map +1 -0
  138. package/dist/types/src/initiative/functions/addArtifact.d.ts +6 -0
  139. package/dist/types/src/initiative/functions/addArtifact.d.ts.map +1 -0
  140. package/dist/types/src/initiative/functions/agent.d.ts +62 -0
  141. package/dist/types/src/initiative/functions/agent.d.ts.map +1 -0
  142. package/dist/types/src/initiative/functions/getContext.d.ts +13 -0
  143. package/dist/types/src/initiative/functions/getContext.d.ts.map +1 -0
  144. package/dist/types/src/initiative/functions/index.d.ts +5 -0
  145. package/dist/types/src/initiative/functions/index.d.ts.map +1 -0
  146. package/dist/types/src/initiative/functions/qualifier.d.ts +60 -0
  147. package/dist/types/src/initiative/functions/qualifier.d.ts.map +1 -0
  148. package/dist/types/src/initiative/index.d.ts +6 -0
  149. package/dist/types/src/initiative/index.d.ts.map +1 -0
  150. package/dist/types/src/initiative/initiative.test.d.ts +2 -0
  151. package/dist/types/src/initiative/initiative.test.d.ts.map +1 -0
  152. package/dist/types/src/initiative/plan.d.ts +77 -0
  153. package/dist/types/src/initiative/plan.d.ts.map +1 -0
  154. package/dist/types/src/initiative/util.d.ts +29 -0
  155. package/dist/types/src/initiative/util.d.ts.map +1 -0
  156. package/dist/types/src/planning/blueprint.d.ts +18 -0
  157. package/dist/types/src/planning/blueprint.d.ts.map +1 -0
  158. package/dist/types/src/planning/functions/index.d.ts +2 -0
  159. package/dist/types/src/planning/functions/index.d.ts.map +1 -0
  160. package/dist/types/src/planning/functions/update-tasks.d.ts +9 -0
  161. package/dist/types/src/planning/functions/update-tasks.d.ts.map +1 -0
  162. package/dist/types/src/planning/index.d.ts +3 -0
  163. package/dist/types/src/planning/index.d.ts.map +1 -0
  164. package/dist/types/src/sync/index.d.ts +2 -0
  165. package/dist/types/src/sync/index.d.ts.map +1 -0
  166. package/dist/types/src/sync/sync.d.ts +15 -0
  167. package/dist/types/src/sync/sync.d.ts.map +1 -0
  168. package/dist/types/src/testing/index.d.ts +2 -0
  169. package/dist/types/src/testing/index.d.ts.map +1 -0
  170. package/dist/types/src/testing/plugins.d.ts +19 -0
  171. package/dist/types/src/testing/plugins.d.ts.map +1 -0
  172. package/dist/types/src/toolkits/AssistantToolkit.d.ts +43 -0
  173. package/dist/types/src/toolkits/AssistantToolkit.d.ts.map +1 -0
  174. package/dist/types/src/toolkits/AssistantToolkit.test.d.ts +2 -0
  175. package/dist/types/src/toolkits/AssistantToolkit.test.d.ts.map +1 -0
  176. package/dist/types/src/toolkits/SystemToolkit.d.ts +99 -0
  177. package/dist/types/src/toolkits/SystemToolkit.d.ts.map +1 -0
  178. package/dist/types/src/toolkits/WebToolkit.d.ts +38 -0
  179. package/dist/types/src/toolkits/WebToolkit.d.ts.map +1 -0
  180. package/dist/types/src/toolkits/index.d.ts +4 -0
  181. package/dist/types/src/toolkits/index.d.ts.map +1 -0
  182. package/dist/types/src/util/graphql.d.ts +22 -0
  183. package/dist/types/src/util/graphql.d.ts.map +1 -0
  184. package/dist/types/src/util/index.d.ts +2 -0
  185. package/dist/types/src/util/index.d.ts.map +1 -0
  186. package/dist/types/tsconfig.tsbuildinfo +1 -0
  187. package/package.json +74 -0
  188. package/src/blueprints/design/design-blueprint.test.ts +100 -0
  189. package/src/blueprints/design/design-blueprint.ts +31 -0
  190. package/src/blueprints/design/index.ts +7 -0
  191. package/src/blueprints/discord/discord-blueprint.ts +32 -0
  192. package/src/blueprints/discord/index.ts +7 -0
  193. package/src/blueprints/index.ts +11 -0
  194. package/src/blueprints/linear/index.ts +7 -0
  195. package/src/blueprints/linear/linear-blueprint.ts +33 -0
  196. package/src/blueprints/markdown/index.ts +7 -0
  197. package/src/blueprints/markdown/markdown-blueprint.ts +24 -0
  198. package/src/blueprints/planning/index.ts +7 -0
  199. package/src/blueprints/planning/planning-blueprint.test.ts +120 -0
  200. package/src/blueprints/planning/planning-blueprint.ts +96 -0
  201. package/src/blueprints/research/index.ts +7 -0
  202. package/src/blueprints/research/research-blueprint.test.ts +7 -0
  203. package/src/blueprints/research/research-blueprint.ts +51 -0
  204. package/src/blueprints/testing.ts +30 -0
  205. package/src/blueprints/websearch/index.ts +9 -0
  206. package/src/blueprints/websearch/websearch-blueprint.ts +18 -0
  207. package/src/blueprints/websearch/websearch-toolkit.ts +8 -0
  208. package/src/chat/Chat.ts +45 -0
  209. package/src/chat/index.ts +5 -0
  210. package/src/crud/graph.test.ts +46 -0
  211. package/src/crud/graph.ts +380 -0
  212. package/src/crud/index.ts +5 -0
  213. package/src/experimental/feed.test.ts +106 -0
  214. package/src/functions/agent/index.ts +11 -0
  215. package/src/functions/agent/prompt.ts +116 -0
  216. package/src/functions/discord/fetch-messages.test.ts +54 -0
  217. package/src/functions/discord/fetch-messages.ts +252 -0
  218. package/src/functions/discord/index.ts +9 -0
  219. package/src/functions/document/create.ts +29 -0
  220. package/src/functions/document/index.ts +13 -0
  221. package/src/functions/document/read.ts +32 -0
  222. package/src/functions/document/update.ts +32 -0
  223. package/src/functions/entity-extraction/entity-extraction.conversations.json +1 -0
  224. package/src/functions/entity-extraction/entity-extraction.test.ts +74 -0
  225. package/src/functions/entity-extraction/entity-extraction.ts +181 -0
  226. package/src/functions/entity-extraction/index.ts +9 -0
  227. package/src/functions/exa/data/exa-search-1748337321991.ts +131 -0
  228. package/src/functions/exa/data/exa-search-1748337331526.ts +144 -0
  229. package/src/functions/exa/data/exa-search-1748337344119.ts +133 -0
  230. package/src/functions/exa/data/index.ts +11 -0
  231. package/src/functions/exa/exa.ts +37 -0
  232. package/src/functions/exa/index.ts +6 -0
  233. package/src/functions/exa/mock.ts +71 -0
  234. package/src/functions/github/fetch-prs.ts +31 -0
  235. package/src/functions/index.ts +11 -0
  236. package/src/functions/linear/index.ts +9 -0
  237. package/src/functions/linear/linear.test.ts +58 -0
  238. package/src/functions/linear/sync-issues.ts +191 -0
  239. package/src/functions/research/document-create.ts +73 -0
  240. package/src/functions/research/index.ts +14 -0
  241. package/src/functions/research/research-graph.ts +49 -0
  242. package/src/functions/research/research-instructions.tpl +106 -0
  243. package/src/functions/research/research.conversations.json +1 -0
  244. package/src/functions/research/research.test.ts +144 -0
  245. package/src/functions/research/research.ts +182 -0
  246. package/src/functions/research/types.ts +26 -0
  247. package/src/functions/tasks/index.ts +11 -0
  248. package/src/functions/tasks/read.ts +34 -0
  249. package/src/functions/tasks/task-list.test.ts +99 -0
  250. package/src/functions/tasks/task-list.ts +165 -0
  251. package/src/functions/tasks/update.ts +52 -0
  252. package/src/index.ts +12 -0
  253. package/src/initiative/Initiative.ts +61 -0
  254. package/src/initiative/blueprint.ts +60 -0
  255. package/src/initiative/functions/addArtifact.ts +41 -0
  256. package/src/initiative/functions/agent.ts +77 -0
  257. package/src/initiative/functions/getContext.ts +54 -0
  258. package/src/initiative/functions/index.ts +8 -0
  259. package/src/initiative/functions/qualifier.ts +98 -0
  260. package/src/initiative/index.ts +9 -0
  261. package/src/initiative/initiative.test.ts +584 -0
  262. package/src/initiative/plan.ts +107 -0
  263. package/src/initiative/util.ts +137 -0
  264. package/src/planning/blueprint.ts +14 -0
  265. package/src/planning/functions/index.ts +5 -0
  266. package/src/planning/functions/update-tasks.ts +168 -0
  267. package/src/planning/index.ts +6 -0
  268. package/src/sync/index.ts +5 -0
  269. package/src/sync/sync.ts +95 -0
  270. package/src/testing/index.ts +5 -0
  271. package/src/testing/plugins.tsx +69 -0
  272. package/src/toolkits/AssistantToolkit.conversations.json +1 -0
  273. package/src/toolkits/AssistantToolkit.test.ts +72 -0
  274. package/src/toolkits/AssistantToolkit.ts +70 -0
  275. package/src/toolkits/SystemToolkit.ts +299 -0
  276. package/src/toolkits/WebToolkit.ts +34 -0
  277. package/src/toolkits/index.ts +7 -0
  278. package/src/typedefs.d.ts +8 -0
  279. package/src/util/graphql.ts +31 -0
  280. package/src/util/index.ts +5 -0
@@ -0,0 +1,137 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Function from 'effect/Function';
7
+
8
+ import { AiContextBinder, AiContextService, type ContextBinding } from '@dxos/assistant';
9
+ import { type Blueprint } from '@dxos/blueprints';
10
+ import { Database, Obj, Ref, Relation } from '@dxos/echo';
11
+ import { type ObjectNotFoundError } from '@dxos/echo/Err';
12
+ import { acquireReleaseResource } from '@dxos/effect';
13
+ import { QueueService } from '@dxos/functions';
14
+ import { invariant } from '@dxos/invariant';
15
+ import { Text } from '@dxos/schema';
16
+ import type { Message } from '@dxos/types';
17
+
18
+ import * as Chat from '../chat/Chat';
19
+
20
+ import { Initiative } from './Initiative';
21
+ import { makePlan } from './plan';
22
+
23
+ /**
24
+ * Creates a fully initialized Initiative with chat, queue, and context bindings.
25
+ *
26
+ * @param props - Initiative properties including spec, plan, blueprints, and context objects.
27
+ * @param blueprint - The blueprint to use for the initiative context.
28
+ * @returns An Effect that yields the initialized Initiative.
29
+ */
30
+ export const makeInitialized = (
31
+ props: Omit<Obj.MakeProps<typeof Initiative>, 'spec' | 'plan' | 'artifacts' | 'subscriptions' | 'chat'> &
32
+ Partial<Pick<Obj.MakeProps<typeof Initiative>, 'artifacts' | 'subscriptions'>> & {
33
+ spec: string;
34
+ blueprints?: Ref.Ref<Blueprint.Blueprint>[];
35
+ contextObjects?: Ref.Ref<Obj.Any>[];
36
+ },
37
+ blueprint: Blueprint.Blueprint,
38
+ ): Effect.Effect<Initiative, never, QueueService | Database.Service> =>
39
+ Effect.gen(function* () {
40
+ const initiative = Obj.make(Initiative, {
41
+ ...props,
42
+ spec: Ref.make(Text.make(props.spec)),
43
+ plan: Ref.make(makePlan({ tasks: [] })),
44
+ artifacts: props.artifacts ?? [],
45
+ subscriptions: props.subscriptions ?? [],
46
+ });
47
+ yield* Database.add(initiative);
48
+ const queue = yield* QueueService.createQueue<Message.Message | ContextBinding>();
49
+ const contextBinder = new AiContextBinder({ queue });
50
+ // TODO(dmaretskyi): Blueprint registry.
51
+ const initiativeBlueprint = yield* Database.add(Obj.clone(blueprint, { deep: true }));
52
+ yield* Effect.promise(() =>
53
+ contextBinder.bind({
54
+ blueprints: [Ref.make(initiativeBlueprint), ...(props.blueprints ?? [])],
55
+ objects: [Ref.make(initiative), ...(props.contextObjects ?? [])],
56
+ }),
57
+ );
58
+ const chat = yield* Database.add(
59
+ Chat.make({
60
+ queue: Ref.fromDXN(queue.dxn),
61
+ }),
62
+ );
63
+ yield* Database.add(
64
+ Relation.make(Chat.CompanionTo, {
65
+ [Relation.Source]: chat,
66
+ [Relation.Target]: initiative,
67
+ }),
68
+ );
69
+
70
+ const inputQueue = yield* QueueService.createQueue();
71
+
72
+ Obj.change(initiative, (initiative) => {
73
+ initiative.chat = Ref.make(chat);
74
+ initiative.queue = Ref.fromDXN(inputQueue.dxn);
75
+ });
76
+
77
+ return initiative;
78
+ });
79
+
80
+ /**
81
+ * Resets the initiative chat history by rebuilding the chat context.
82
+ * Preserves the existing blueprints and objects from the current chat context.
83
+ *
84
+ * @param initiative - The initiative whose chat history should be reset. Must have an existing chat.
85
+ * @returns An Effect that resets the chat history.
86
+ */
87
+ export const resetChatHistory = (
88
+ initiative: Initiative,
89
+ ): Effect.Effect<void, ObjectNotFoundError, QueueService | Database.Service> =>
90
+ Effect.gen(function* () {
91
+ invariant(initiative.chat, 'Initiative must have an existing chat to reset.');
92
+
93
+ const existingQueue = yield* initiative.chat.pipe(Database.load).pipe(
94
+ Effect.map((_) => _.queue),
95
+ Effect.flatMap(Database.load),
96
+ );
97
+ const existingContextBinder = yield* acquireReleaseResource(
98
+ () =>
99
+ new AiContextBinder({
100
+ queue: existingQueue,
101
+ }),
102
+ );
103
+ const blueprints = existingContextBinder.getBlueprints().map((blueprint) => Ref.make(blueprint));
104
+ const objects = existingContextBinder.getObjects().map((object) => Ref.make(object));
105
+
106
+ const queue = yield* QueueService.createQueue();
107
+ const contextBinder = new AiContextBinder({ queue });
108
+ yield* Effect.promise(() =>
109
+ contextBinder.bind({
110
+ blueprints,
111
+ objects,
112
+ }),
113
+ );
114
+ const chat = yield* Database.add(
115
+ Chat.make({
116
+ queue: Ref.fromDXN(queue.dxn),
117
+ }),
118
+ );
119
+ Obj.change(initiative, (initiative) => {
120
+ initiative.chat = Ref.make(chat);
121
+ });
122
+ yield* Database.add(
123
+ Relation.make(Chat.CompanionTo, {
124
+ [Relation.Source]: chat,
125
+ [Relation.Target]: initiative,
126
+ }),
127
+ );
128
+ }).pipe(Effect.scoped);
129
+
130
+ export const getFromChatContext: Effect.Effect<Initiative, never, AiContextService> = Effect.gen(function* () {
131
+ const initiatives = yield* Function.pipe(AiContextService.findObjects(Initiative));
132
+ if (initiatives.length !== 1) {
133
+ throw new Error('There should be exactly one initiative in context. Got: ' + initiatives.length);
134
+ }
135
+ const initiative = initiatives[0];
136
+ return initiative;
137
+ });
@@ -0,0 +1,14 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Blueprint } from '@dxos/blueprints';
6
+
7
+ import { updateTasks } from './functions';
8
+
9
+ export const PlanningBlueprint = Blueprint.make({
10
+ key: 'dxos.org/blueprint/planning',
11
+ name: 'Planning',
12
+ description: 'Plans and tracks complex tasks with artifact management.',
13
+ tools: Blueprint.toolDefinitions({ functions: [updateTasks] }),
14
+ });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { default as updateTasks } from './update-tasks';
@@ -0,0 +1,168 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Schema from 'effect/Schema';
7
+
8
+ import { AiContextService } from '@dxos/assistant';
9
+ import { Database, Obj } from '@dxos/echo';
10
+ import { defineFunction } from '@dxos/functions';
11
+ import { trim } from '@dxos/util';
12
+
13
+ import * as Initiative from '../../initiative';
14
+
15
+ const INSTRUCTIONS = trim`
16
+ TASK MANAGEMENT TOOL - USAGE GUIDELINES
17
+
18
+ This tool maintains an organized task list during work sessions to track progress, break down objectives, and ensure thoroughness. After creating initial tasks, update them silently without announcing changes to the user.
19
+
20
+ === CORE USAGE PRINCIPLES ===
21
+
22
+ Create and manage tasks for: multi-step objectives requiring 3+ distinct actions, complex projects needing careful sequencing, user requests for task organization, multiple deliverables provided together, new instructions (capture as tasks immediately with new IDs), completed work (mark done and add follow-ups), and active work (mark as 'in-progress', limit one at a time).
23
+
24
+ Skip task management for: single straightforward actions, simple requests achievable in 1-2 steps, informational queries, quick lookups or clarifications, and avoid creating verification tasks unless requested.
25
+
26
+ === TOOL SPECIFICATION ===
27
+
28
+ update-tasks requires an array of task objects. Each task object contains:
29
+ - id (string, required): unique identifier like "task_1" or "research_sources"
30
+ - title (string, optional): update to clarify or refine task description
31
+ - status (string, optional): 'todo' | 'in-progress' | 'done'
32
+
33
+ Task status meanings: 'todo' means not yet started, 'in-progress' means currently being worked on, 'done' means completed successfully.
34
+
35
+ === OPERATIONAL GUIDELINES ===
36
+
37
+ Update tasks in real-time as work progresses. Mark tasks 'done' immediately upon completion. Maintain only ONE task with 'in-progress' status at a time. Complete current tasks before starting new ones. Use specific, actionable task titles. Break complex work into manageable logical pieces. Batch task updates with other actions when possible for efficiency.
38
+
39
+ === USAGE EXAMPLES ===
40
+
41
+ <example type="research_project">
42
+ <user_message>I need to research sustainable packaging options and write a report comparing costs and environmental impact.</user_message>
43
+ <assistant_action>
44
+ Creates tasks:
45
+ 1. {id: "research_materials", title: "Research sustainable packaging materials", status: "in-progress"}
46
+ 2. {id: "compare_costs", title: "Compile cost comparison data", status: "todo"}
47
+ 3. {id: "assess_impact", title: "Evaluate environmental impact metrics", status: "todo"}
48
+ 4. {id: "draft_report", title: "Write comparative analysis report", status: "todo"}
49
+
50
+ Begins research work immediately in same response.
51
+ </assistant_action>
52
+ <reasoning>Multi-phase project requiring systematic tracking across research, analysis, and writing stages.</reasoning>
53
+ </example>
54
+
55
+ <example type="event_planning">
56
+ <user_message>Help me plan a team retreat - venue, agenda, catering, and send invitations.</user_message>
57
+ <assistant_action>
58
+ Creates tasks:
59
+ 1. {id: "venue_options", title: "Research and recommend venues", status: "in-progress"}
60
+ 2. {id: "draft_agenda", title: "Create retreat agenda", status: "todo"}
61
+ 3. {id: "arrange_catering", title: "Coordinate catering options", status: "todo"}
62
+ 4. {id: "send_invites", title: "Draft and send invitations", status: "todo"}
63
+ </assistant_action>
64
+ <reasoning>Multiple distinct deliverables with dependencies requiring organized tracking.</reasoning>
65
+ </example>
66
+
67
+ <example type="document_analysis">
68
+ <user_message>Review this 30-page contract for key terms, risks, and negotiation points.</user_message>
69
+ <assistant_action>
70
+ Creates tasks:
71
+ 1. {id: "extract_key_terms", title: "Identify key contractual terms", status: "in-progress"}
72
+ 2. {id: "flag_risks", title: "Flag potential risks and liabilities", status: "todo"}
73
+ 3. {id: "negotiation_points", title: "Compile negotiation recommendations", status: "todo"}
74
+ 4. {id: "summary_doc", title: "Prepare executive summary", status: "todo"}
75
+ </assistant_action>
76
+ <reasoning>Substantial analysis work requiring methodical breakdown and systematic review.</reasoning>
77
+ </example>
78
+
79
+ <example type="multiple_deliverables">
80
+ <user_message>I need: 1) competitor analysis for three companies, 2) SWOT analysis, 3) market positioning recommendations.</user_message>
81
+ <assistant_action>
82
+ Creates tasks:
83
+ 1. {id: "competitor_research", title: "Research three competitor companies", status: "in-progress"}
84
+ 2. {id: "swot_analysis", title: "Develop SWOT analysis", status: "todo"}
85
+ 3. {id: "positioning_recs", title: "Create market positioning recommendations", status: "todo"}
86
+ </assistant_action>
87
+ <reasoning>User provided numbered list of distinct deliverables requiring separate effort.</reasoning>
88
+ </example>
89
+
90
+ <example type="skip_simple_question">
91
+ <user_message>What's the difference between renewable and sustainable energy?</user_message>
92
+ <assistant_action>Provides explanation directly without creating tasks.</assistant_action>
93
+ <reasoning>Informational request with no actionable work to complete or track.</reasoning>
94
+ </example>
95
+
96
+ <example type="skip_quick_lookup">
97
+ <user_message>Find the population of Tokyo.</user_message>
98
+ <assistant_action>Searches and provides answer without task tracking.</assistant_action>
99
+ <reasoning>Single straightforward lookup completable immediately.</reasoning>
100
+ </example>
101
+
102
+ <example type="skip_trivial_task">
103
+ <user_message>Summarize this 2-paragraph email.</user_message>
104
+ <assistant_action>Provides summary directly without creating tasks.</assistant_action>
105
+ <reasoning>Single simple action requiring no breakdown or progress tracking.</reasoning>
106
+ </example>
107
+
108
+ <example type="skip_single_action">
109
+ <user_message>Check if my flight is on time.</user_message>
110
+ <assistant_action>Performs lookup and reports status without task management.</assistant_action>
111
+ <reasoning>One-step action with immediate completion, no organizational benefit from tasks.</reasoning>
112
+ </example>
113
+
114
+ === BEST PRACTICES ===
115
+
116
+ For task creation: use descriptive unique IDs reflecting the work, start first task as 'in-progress', batch initial creation with beginning work. For progress tracking: update status immediately upon completion, keep only one 'in-progress' task unless parallel work is natural, add follow-up tasks as they emerge. For task breakdown: aim for reasonably-scoped tasks, group related small actions into logical units, split tasks requiring different approaches.
117
+
118
+ When uncertain whether to use task management, err on the side of creating tasks. Proactive organization demonstrates thoroughness and ensures comprehensive work completion.
119
+ `;
120
+
121
+ const TaskProps = Schema.Struct({
122
+ id: Initiative.TaskId,
123
+ title: Schema.String,
124
+ status: Schema.Literal('todo', 'in-progress', 'done'),
125
+ });
126
+
127
+ export default defineFunction({
128
+ key: 'dxos.org/function/planning/update-tasks',
129
+ name: 'Update tasks',
130
+ description: INSTRUCTIONS,
131
+ inputSchema: Schema.Struct({
132
+ tasks: Schema.Array(TaskProps),
133
+ }),
134
+ handler: Effect.fn(function* ({ data: { tasks: newTasks } }) {
135
+ const initiative = yield* Initiative.getFromChatContext;
136
+ const plan = yield* Database.load(initiative.plan);
137
+
138
+ Obj.change(plan, (plan) => {
139
+ for (const task of newTasks) {
140
+ const existingTask = plan.tasks.find((t) => t.id === task.id);
141
+ if (existingTask) {
142
+ existingTask.title = task.title;
143
+ existingTask.status = task.status;
144
+ } else {
145
+ plan.tasks.push({
146
+ id: task.id,
147
+ title: task.title,
148
+ status: task.status,
149
+ });
150
+ }
151
+ }
152
+ });
153
+
154
+ // console.log('\n====== TASKS ======\n');
155
+ // for (const task of tasks) {
156
+ // console.log(`- **${task.status?.toLocaleUpperCase()}**: ${task.title ?? 'No title'} (id: ${task.id})`);
157
+ // }
158
+ // console.log('\n====== END TASKS ======\n');
159
+
160
+ return `
161
+ Tasks updated. Don't forget to mark tasks as done when you're done with them or update their status to 'in-progress' when you start working on them.
162
+ Current plan:
163
+ <plan>
164
+ ${Initiative.formatPlan(plan)}
165
+ </plan>
166
+ `;
167
+ }, AiContextService.fixFunctionHandlerType),
168
+ });
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { PlanningBlueprint } from './blueprint';
6
+ export * as PlanningFunctions from './functions';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './sync';
@@ -0,0 +1,95 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Filter, Obj, Query, Ref } from '@dxos/echo';
8
+ import { Database } from '@dxos/echo';
9
+ import { failedInvariant } from '@dxos/invariant';
10
+ import { log } from '@dxos/log';
11
+
12
+ /**
13
+ * Syncs objects to the database.
14
+ * If there's an object with a matching foreign key in the database, it will be updated.
15
+ * Otherwise, a new object will be added.
16
+ * Recursively syncs top-level refs.
17
+ *
18
+ * @param opts.foreignKeyId - The key to use for matching objects.
19
+ */
20
+ export const syncObjects: (
21
+ objs: Obj.Unknown[],
22
+ opts: { foreignKeyId: string },
23
+ ) => Effect.Effect<Obj.Unknown[], never, Database.Service> = Effect.fn('syncObjects')(function* (
24
+ objs,
25
+ { foreignKeyId },
26
+ ) {
27
+ return yield* Effect.forEach(
28
+ objs,
29
+ Effect.fnUntraced(function* (obj) {
30
+ // Sync referenced objects.
31
+ for (const key of Object.keys(obj)) {
32
+ if (typeof key !== 'string' || key === 'id') continue;
33
+ if (!Ref.isRef((obj as any)[key])) continue;
34
+ const ref: Ref.Unknown = (obj as any)[key];
35
+ if (!ref.target) continue;
36
+ if (Obj.getDXN(ref.target).isLocalObjectId()) {
37
+ // obj not persisted to db.
38
+ const [target] = yield* syncObjects([ref.target], { foreignKeyId });
39
+ (obj as any)[key] = Ref.make(target);
40
+ }
41
+ }
42
+
43
+ const schema = Obj.getSchema(obj) ?? failedInvariant('No schema.');
44
+ const foreignId = Obj.getKeys(obj, foreignKeyId)[0]?.id ?? failedInvariant('No foreign key.');
45
+ const [existing] = yield* Database.runQuery(
46
+ Query.select(Filter.foreignKeys(schema, [{ source: foreignKeyId, id: foreignId }])),
47
+ );
48
+ log('sync object', {
49
+ type: Obj.getTypename(obj),
50
+ foreignId,
51
+ existing: existing ? Obj.getDXN(existing) : undefined,
52
+ });
53
+ if (!existing) {
54
+ yield* Database.add(obj);
55
+ return obj;
56
+ } else {
57
+ copyObjectData(existing, obj);
58
+ return existing;
59
+ }
60
+ }),
61
+ { concurrency: 1 },
62
+ );
63
+ });
64
+
65
+ const copyObjectData = (existing: Obj.Unknown, newObj: Obj.Unknown) => {
66
+ Obj.change(existing, (obj) => {
67
+ // Copy properties from newObj to existing.
68
+ for (const key of Object.keys(newObj)) {
69
+ if (typeof key !== 'string' || key === 'id') continue;
70
+ if (
71
+ typeof (newObj as any)[key] !== 'string' &&
72
+ typeof (newObj as any)[key] !== 'number' &&
73
+ typeof (newObj as any)[key] !== 'boolean' &&
74
+ !Ref.isRef((newObj as any)[key])
75
+ )
76
+ continue;
77
+ (obj as any)[key] = (newObj as any)[key];
78
+ }
79
+
80
+ // Delete properties that don't exist in newObj.
81
+ for (const key of Object.keys(obj)) {
82
+ if (typeof key !== 'string' || key === 'id') continue;
83
+ if (!(key in newObj)) {
84
+ delete (obj as any)[key];
85
+ }
86
+ }
87
+
88
+ // Update foreign keys.
89
+ for (const foreignKey of Obj.getMeta(newObj).keys) {
90
+ Obj.deleteKeys(obj, foreignKey.source);
91
+ // TODO(dmaretskyi): Doesn't work: `Obj.getMeta(existing).keys.push(foreignKey);`
92
+ Obj.getMeta(obj).keys.push({ ...foreignKey });
93
+ }
94
+ });
95
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './plugins';
@@ -0,0 +1,69 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import React from 'react';
7
+
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { Format, type Obj, Type } from '@dxos/echo';
11
+ import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
12
+
13
+ export const MapSchema = Schema.Struct({
14
+ coordinates: Format.GeoPoint,
15
+ }).pipe(
16
+ Type.object({
17
+ typename: 'example.com/type/Map',
18
+ version: '0.1.0',
19
+ }),
20
+ );
21
+
22
+ export type MapSchema = Schema.Schema.Type<typeof MapSchema>;
23
+
24
+ // TODO(burdon): Move to ECHO def.
25
+ export type ArtifactsContext = {
26
+ items: Obj.Unknown[];
27
+ getArtifacts: () => Obj.Unknown[];
28
+ addArtifact: (artifact: Obj.Unknown) => void;
29
+ };
30
+
31
+ declare global {
32
+ interface ToolContextExtensions {
33
+ artifacts?: ArtifactsContext;
34
+ }
35
+ }
36
+
37
+ // TODO(dmaretskyi): Removed images from conductor GPT implementation.
38
+ const isImage = (data: any): data is any => false;
39
+
40
+ export const capabilities: Capability.Any[] = [
41
+ Capability.contributes(
42
+ Capabilities.ReactSurface,
43
+ Surface.create({
44
+ id: 'plugin-image',
45
+ role: 'card--extrinsic',
46
+ filter: (data: any): data is any => isImage(data.value),
47
+ component: ({ data }) => (
48
+ <img
49
+ className='grow object-cover'
50
+ src={`data:image/jpeg;base64,${data.value.source.data}`}
51
+ alt={data.value.prompt ?? `Generated image [id=${data.value.id}]`}
52
+ />
53
+ ),
54
+ }),
55
+ ),
56
+
57
+ //
58
+ // Default
59
+ //
60
+ Capability.contributes(
61
+ Capabilities.ReactSurface,
62
+ Surface.create({
63
+ id: 'plugin-default',
64
+ role: 'card--extrinsic',
65
+ position: 'fallback',
66
+ component: ({ data }) => <JsonFilter data={data} />,
67
+ }),
68
+ ),
69
+ ];
@@ -0,0 +1 @@
1
+ {"conversations":[{"parameters":{"model":"@anthropic/claude-opus-4-0","stream":true,"tools":[]},"prompt":{"content":[{"role":"system","content":"## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"Add to context: {\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8D\",\"@type\":\"dxn:type:dxos.org/type/Organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01ESZ2RnTWWshCN6AuVjhxBW","modelId":"claude-opus-4-20250514","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user is adding","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" an","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" Organization","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" object","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" to the context.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" This","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" appears","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" to be a DXOS object","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" with:","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- An","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" ID","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- A type designation","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" (@","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"type)","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" indicating","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" it's an Organization type version","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" 0.1.0\n-","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" Metadata with","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" an","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" empty keys array\n- A name:","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" \"Cyberdyne Systems\"","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- A website: \"https://cyb","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"erdyne.com\"\n\nI shoul","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"d acknowledge that","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" this","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" has","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" been added to the context and be","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" ready to reference","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" or work","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" with this organization data","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" as","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" needed.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EswECkYICxgCKkAKoUuFWE5zJ6soltEFAuI6miLz75XAO+fhBFkck5nOV8Zgw+xtXu+lcLNKF9T+nYU005q7jufvyi6dUAL4VAbDEgxQiKz084T8/HxIiC0aDGHf4286rPMhEleyDyIwW+6ZQtEfTq8gYiaaOpyqPRwa3cPy26HMeKj/1BXdMW9MJDcjxj02kjji0a4BV8AzKrMD6vSRsoAjP6ql8CxTqD91VvFiLqs4rqhHOVwlmmKVygRMogk5RvvRG/T4QzEGZSd7Xcl8yB19i03q3kpErfJu6b8+mFhndVcgBbFeFoGAA9aAJleUTdyLKvx/hSexzF0Th7xEdP1VTM4//JVq3lXB2LqqJzih7wTbqTn92vq5leNtGDoKJwnFdNvoxixY+HgB1JKSfsSGkZolby5yOp6kG52/2okeJfokgYpIjAxny8KjVq7SHsD9o9fLrKuA3VtzwG9eBBtK5t11bJoGQF+vGEmIwha35riPZIvzpa+SAbY4bU9QtMOnqn21fwYyhur/5WPXMZl3AsvJSi8yDcUrCbjsYcIxcn8lbCdbKA4sLMtQimREj7NU8onkj9ymivbG5CgluFohwpTFKyX4SNKd9MYdtE31Acmop2Zi2iHJQ+d/jH7tn503qoCeHV6LkMEEd0oFN5qHqRA5N0SBdKWrHzmlbBT4IHM4TvEwMINkzqf3J4TkCCwj727G4g7qepboMHiqtVYt5+HsQIZ3g8vR6hMTBoJn7qVUCWb67PImJNNQDzXoumvVEpHi9ZUI/rzJf+a8GAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"I've added the Cyb","metadata":{}},{"type":"text-delta","id":"1","delta":"erdyne Systems organization object","metadata":{}},{"type":"text-delta","id":"1","delta":" to the","metadata":{}},{"type":"text-delta","id":"1","delta":" context. This","metadata":{}},{"type":"text-delta","id":"1","delta":" organization","metadata":{}},{"type":"text-delta","id":"1","delta":" has","metadata":{}},{"type":"text-delta","id":"1","delta":":","metadata":{}},{"type":"text-delta","id":"1","delta":"\n- Name","metadata":{}},{"type":"text-delta","id":"1","delta":": Cyberdyne Systems\n-","metadata":{}},{"type":"text-delta","id":"1","delta":" Website: https://cyberdyne.","metadata":{}},{"type":"text-delta","id":"1","delta":"com\n- Type: dxos","metadata":{}},{"type":"text-delta","id":"1","delta":".org/type/Organization:0","metadata":{}},{"type":"text-delta","id":"1","delta":".1.0","metadata":{}},{"type":"text-delta","id":"1","delta":"\n- ID: 01JG","metadata":{}},{"type":"text-delta","id":"1","delta":"FJJZ00G0W","metadata":{}},{"type":"text-delta","id":"1","delta":"KQSJGMAKCNT8","metadata":{}},{"type":"text-delta","id":"1","delta":"D\n\nI","metadata":{}},{"type":"text-delta","id":"1","delta":" can now reference this organization data","metadata":{}},{"type":"text-delta","id":"1","delta":" in","metadata":{}},{"type":"text-delta","id":"1","delta":" any","metadata":{}},{"type":"text-delta","id":"1","delta":" subsequent","metadata":{}},{"type":"text-delta","id":"1","delta":" operations","metadata":{}},{"type":"text-delta","id":"1","delta":" or queries","metadata":{}},{"type":"text-delta","id":"1","delta":" you","metadata":{}},{"type":"text-delta","id":"1","delta":"'","metadata":{}},{"type":"text-delta","id":"1","delta":"d like to perform","metadata":{}},{"type":"text-delta","id":"1","delta":".","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":135,"outputTokens":224,"totalTokens":359},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":135,"output_tokens":4,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-0","stream":true,"tools":[{"name":"context-add","description":"Adds the object to the chat context.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The ID of the document to add.","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}},{"name":"context-remove","description":"Removes the object from the chat context.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The ID of the document to remove.","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"Add to context: {\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8D\",\"@type\":\"dxn:type:dxos.org/type/Organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01PwdqJ4KYGWGo88Bpgkcb1b","modelId":"claude-opus-4-20250514","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user wants to add an object to","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" the context. The","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" object has:","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- id: \"01J","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"GFJJZ00G0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"WKQSJGMAKCNT","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"8D\"\n- It","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"'s an","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" Organization type object","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- name","metadata":{}},{"type":"reasoning-delta","id":"0","delta":": \"Cyberdyne Systems\"","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n- website: \"https://cyb","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"erdyne.com\"\n\nI nee","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"d to use the context-add function with","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" the","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" id parameter.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EqkDCkYICxgCKkDRhGEp8nE9S2hhdiFom4JqAoWxdW/nKv7jjNB9Uybh5aeqVE13x2HhOoQJMWph3asUEzzt5B15yGTfoKc9lHSCEgytP588WsRipnT22dIaDFQPA72QE/XIbvEA+CIwxPckN1BzzMGgibUZmFKXxBdos3WMVBf2RpenWMQSppU+Ese4HQmltoQmp9zf7lj0KpAC1ZJP/lOSBxUTXS8BZWa7nOPclHVSohW2Ug8mul/NfMEDawimCvkkVYRRrdZQp1IeG/+kvJG7rQbgYsDU6SXN4zdPKcYtjv9wfIpRT6f200g1iBqRr1qKiMhLKpFNcAsOUaNQDXhKhr/A6ZhH4gaovEw65v10fyeUoHGzUHrDAEpy8cYDvzF/3TPEJhe3zIBw60cepyLaEZy+Z/1qmY2lsEqrkh95rv9WFASlB30nm762InotIIkAsMlxXY1xI0n+AZgh/ypPqyqaGiMVZ8aHKVLiCkBE1uTZszZBh7L2raEXK6znKVNSA4SiN33Mwzw7kEBBFrsuhrQnKqg8l5GaNqaE77knShQAXkzQYmgy8FMYAQ=="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"I'll add this Organization","metadata":{}},{"type":"text-delta","id":"1","delta":" object to the context for you.","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"tool-params-start","id":"toolu_01P7myKvWntosLM6RtWwKZGA","name":"context-add","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01P7myKvWntosLM6RtWwKZGA","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01P7myKvWntosLM6RtWwKZGA","delta":"{\"id\": \"01JG","metadata":{}},{"type":"tool-params-delta","id":"toolu_01P7myKvWntosLM6RtWwKZGA","delta":"FJJZ00G0WKQ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01P7myKvWntosLM6RtWwKZGA","delta":"SJGMAK","metadata":{}},{"type":"tool-params-delta","id":"toolu_01P7myKvWntosLM6RtWwKZGA","delta":"CNT8D\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01P7myKvWntosLM6RtWwKZGA","metadata":{}},{"type":"tool-call","id":"toolu_01P7myKvWntosLM6RtWwKZGA","name":"context-add","params":{"id":"01JGFJJZ00G0WKQSJGMAKCNT8D"},"providerExecuted":false,"metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":911,"outputTokens":183,"totalTokens":1094},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":911,"output_tokens":8,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-0","stream":true,"tools":[{"name":"context-add","description":"Adds the object to the chat context.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The ID of the document to add.","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}},{"name":"context-remove","description":"Removes the object from the chat context.","inputSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The ID of the document to remove.","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"## Blueprints Definitions\n\n<blueprint>\n \n</blueprint>","options":{}},{"role":"user","content":"Add to context: {\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8D\",\"@type\":\"dxn:type:dxos.org/type/Organization:0.1.0\",\"@meta\":{\"keys\":[]},\"name\":\"Cyberdyne Systems\",\"website\":\"https://cyberdyne.com\"}","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user wants to add an object to the context. The object has:\n- id: \"01JGFJJZ00G0WKQSJGMAKCNT8D\"\n- It's an Organization type object\n- name: \"Cyberdyne Systems\"\n- website: \"https://cyberdyne.com\"\n\nI need to use the context-add function with the id parameter.","options":{}},{"type":"text","text":"I'll add this Organization object to the context for you.","options":{}},{"type":"tool-call","id":"toolu_01P7myKvWntosLM6RtWwKZGA","name":"context-add","params":{"id":"01JGFJJZ00G0WKQSJGMAKCNT8D"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01P7myKvWntosLM6RtWwKZGA","name":"context-add","isFailure":false,"result":{},"providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01Rq8MMkzbb7kQcbuSf2pFcN","modelId":"claude-opus-4-20250514","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I","metadata":{}},{"type":"text-delta","id":"0","delta":"'ve successfully added the","metadata":{}},{"type":"text-delta","id":"0","delta":" Cyberdyne Systems organization to the context","metadata":{}},{"type":"text-delta","id":"0","delta":". This","metadata":{}},{"type":"text-delta","id":"0","delta":" organization object includes:","metadata":{}},{"type":"text-delta","id":"0","delta":"\n- Name","metadata":{}},{"type":"text-delta","id":"0","delta":": Cyberdyne Systems\n-","metadata":{}},{"type":"text-delta","id":"0","delta":" Website: https://cyberdyne.","metadata":{}},{"type":"text-delta","id":"0","delta":"com\n- Type: Organization","metadata":{}},{"type":"text-delta","id":"0","delta":" (version","metadata":{}},{"type":"text-delta","id":"0","delta":" 0.1.0)","metadata":{}},{"type":"text-delta","id":"0","delta":"\n\nThe object is","metadata":{}},{"type":"text-delta","id":"0","delta":" now available","metadata":{}},{"type":"text-delta","id":"0","delta":" in the chat","metadata":{}},{"type":"text-delta","id":"0","delta":" context for","metadata":{}},{"type":"text-delta","id":"0","delta":" reference","metadata":{}},{"type":"text-delta","id":"0","delta":" and can","metadata":{}},{"type":"text-delta","id":"0","delta":" be used in our","metadata":{}},{"type":"text-delta","id":"0","delta":" conversation.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":979,"outputTokens":77,"totalTokens":1056},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":979,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
@@ -0,0 +1,72 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, expect, it } from '@effect/vitest';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Layer from 'effect/Layer';
8
+
9
+ import { MemoizedAiService } from '@dxos/ai/testing';
10
+ import { AiContextService, AiConversationService, GenericToolkit } from '@dxos/assistant';
11
+ import { AssistantTestLayer } from '@dxos/assistant/testing';
12
+ import { waitForCondition } from '@dxos/async';
13
+ import { Blueprint, Template } from '@dxos/blueprints';
14
+ import { Database, Obj, Ref } from '@dxos/echo';
15
+ import { TestHelpers } from '@dxos/effect/testing';
16
+ import { ObjectId } from '@dxos/keys';
17
+ import { Message, Organization, Person } from '@dxos/types';
18
+
19
+ import * as AssistantToolkit from './AssistantToolkit';
20
+
21
+ ObjectId.dangerouslyDisableRandomness();
22
+
23
+ const TestLayer = AssistantTestLayer({
24
+ types: [Blueprint.Blueprint, Message.Message, Person.Person, Organization.Organization],
25
+ toolkits: [GenericToolkit.make(AssistantToolkit.AssistantToolkit, AssistantToolkit.layer())],
26
+ tracing: 'pretty',
27
+ });
28
+
29
+ const blueprint = Blueprint.make({
30
+ key: 'dxos.org/blueprint/assistant',
31
+ name: 'Assistant',
32
+ tools: Blueprint.toolDefinitions({ tools: AssistantToolkit.tools }),
33
+ instructions: Template.make(),
34
+ });
35
+
36
+ describe('AssistantToolkit', () => {
37
+ it.scoped(
38
+ 'can add to context',
39
+ Effect.fnUntraced(
40
+ function* (_) {
41
+ yield* AiContextService.bindContext({
42
+ blueprints: [Ref.make(yield* Database.add(blueprint))],
43
+ });
44
+
45
+ const organization = yield* Database.add(
46
+ Obj.make(Organization.Organization, {
47
+ name: 'Cyberdyne Systems',
48
+ website: 'https://cyberdyne.com',
49
+ }),
50
+ );
51
+
52
+ yield* AiConversationService.run({
53
+ prompt: `Add to context: ${JSON.stringify(organization)}`,
54
+ });
55
+
56
+ const { binder } = yield* AiContextService;
57
+ yield* Effect.promise(() =>
58
+ waitForCondition({
59
+ condition: () => binder.getBlueprints().length > 0 && binder.getObjects().length > 0,
60
+ timeout: 10_000,
61
+ }),
62
+ );
63
+
64
+ expect(binder.getBlueprints()).toEqual([blueprint]);
65
+ expect(binder.getObjects()).toEqual([organization]);
66
+ },
67
+ Effect.provide(AiConversationService.layerNewQueue().pipe(Layer.provideMerge(TestLayer))),
68
+ TestHelpers.provideTestContext,
69
+ ),
70
+ MemoizedAiService.isGenerationEnabled() ? 60_000 : undefined,
71
+ );
72
+ });