@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,584 @@
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 Exit from 'effect/Exit';
8
+ import * as Record from 'effect/Record';
9
+
10
+ import { MemoizedAiService } from '@dxos/ai/testing';
11
+ import { AiConversation } from '@dxos/assistant';
12
+ import { AssistantTestLayerWithTriggers } from '@dxos/assistant/testing';
13
+ import { Blueprint } from '@dxos/blueprints';
14
+ import { SpaceProperties } from '@dxos/client-protocol';
15
+ import { Database, Obj, Ref } from '@dxos/echo';
16
+ import { acquireReleaseResource } from '@dxos/effect';
17
+ import { TestHelpers } from '@dxos/effect/testing';
18
+ import { FunctionDefinition, QueueService, Trigger } from '@dxos/functions';
19
+ import { TriggerDispatcher } from '@dxos/functions-runtime';
20
+ import { invariant } from '@dxos/invariant';
21
+ import { ObjectId } from '@dxos/keys';
22
+ import { MarkdownBlueprint } from '@dxos/plugin-markdown/blueprints';
23
+ import { WithProperties } from '@dxos/plugin-markdown/testing';
24
+ import { Markdown } from '@dxos/plugin-markdown/types';
25
+ import { Collection, Text } from '@dxos/schema';
26
+ import { Message } from '@dxos/types';
27
+ import { trim } from '@dxos/util';
28
+
29
+ import { Planning } from '..';
30
+ import { Chat } from '../chat';
31
+
32
+ import { agent } from './functions';
33
+
34
+ import * as Initiative from '.';
35
+
36
+ ObjectId.dangerouslyDisableRandomness();
37
+
38
+ const TestLayer = AssistantTestLayerWithTriggers({
39
+ aiServicePreset: 'edge-remote',
40
+ functions: [
41
+ ...Initiative.getFunctions(),
42
+ ...MarkdownBlueprint.functions,
43
+ ...Record.values(Planning.PlanningFunctions),
44
+ ],
45
+ types: [
46
+ Initiative.Initiative,
47
+ Initiative.Plan,
48
+ Chat.CompanionTo,
49
+ Chat.Chat,
50
+ SpaceProperties,
51
+ Blueprint.Blueprint,
52
+ Trigger.Trigger,
53
+ Text.Text,
54
+ Markdown.Document,
55
+ Collection.Collection,
56
+ ],
57
+ tracing: 'pretty',
58
+ });
59
+
60
+ const SYSTEM = trim`
61
+ You are a helpful assistant that can help with tasks in the outside world.
62
+ Be transparent about what you are doing and what you are not doing.
63
+ If you do not have tools to complete the task, inform the user.
64
+ DO NOT PRETEND TO DO SOMETHING YOU CAN'T DO.
65
+ `;
66
+
67
+ describe.runIf(TestHelpers.tagEnabled('flaky'))('Initiative', () => {
68
+ it.scoped(
69
+ 'shopping list',
70
+ Effect.fnUntraced(
71
+ function* (_) {
72
+ const initiative = yield* Database.add(
73
+ yield* Initiative.makeInitialized(
74
+ {
75
+ name: 'Shopping list',
76
+ spec: 'Keep a shopping list of items to buy.',
77
+ blueprints: [Ref.make(MarkdownBlueprint.make())],
78
+ },
79
+ Initiative.makeBlueprint(),
80
+ ),
81
+ );
82
+ const chatQueue = initiative.chat?.target?.queue?.target as any;
83
+ invariant(chatQueue, 'Initiative chat queue not found.');
84
+ yield* Database.flush({ indexes: true });
85
+ const conversation = yield* acquireReleaseResource(() => new AiConversation({ queue: chatQueue }));
86
+ yield* Effect.promise(() => conversation.context.open());
87
+
88
+ yield* conversation.createRequest({
89
+ system: SYSTEM,
90
+ prompt: `List ingredients for a scrambled eggs on a toast breakfast.`,
91
+ });
92
+
93
+ console.log(yield* Effect.promise(() => dumpInitiative(initiative)));
94
+ },
95
+ Effect.provide(TestLayer),
96
+ TestHelpers.provideTestContext,
97
+ ),
98
+ MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
99
+ );
100
+
101
+ it.scoped(
102
+ 'expense tracking list',
103
+ Effect.fnUntraced(
104
+ function* (_) {
105
+ const initiative = yield* Database.add(
106
+ yield* Initiative.makeInitialized(
107
+ {
108
+ name: 'Expense tracking',
109
+ spec: trim`
110
+ Keep a list of expenses in a markdown document (create artifact "Expenses").
111
+ Process incoming emails, add the relevant ones to the list.
112
+
113
+ Format:
114
+
115
+ ## Expences
116
+
117
+ - Flight to London (2026-02-01): £100
118
+ - Hotel in London (2026-02-01): £100
119
+ `,
120
+ blueprints: [Ref.make(MarkdownBlueprint.make())],
121
+ },
122
+ Initiative.makeBlueprint(),
123
+ ),
124
+ );
125
+ yield* Database.flush({ indexes: true });
126
+
127
+ const inboxQueue = yield* QueueService.createQueue();
128
+ yield* Database.add(
129
+ Trigger.make({
130
+ enabled: true,
131
+ spec: {
132
+ kind: 'queue',
133
+ queue: inboxQueue.dxn.toString(),
134
+ },
135
+ function: Ref.make(FunctionDefinition.serialize(agent)),
136
+ input: {
137
+ initiative: Ref.make(initiative),
138
+ event: '{{event}}',
139
+ },
140
+ }),
141
+ );
142
+
143
+ yield* QueueService.append(
144
+ inboxQueue,
145
+ TEST_MESSAGES.map((message) => Obj.clone(message)),
146
+ );
147
+
148
+ const dispatcher = yield* TriggerDispatcher;
149
+ const invocations = yield* dispatcher.invokeScheduledTriggers({ kinds: ['queue'], untilExhausted: true });
150
+ expect(invocations.every((invocation) => Exit.isSuccess(invocation.result))).toBe(true);
151
+
152
+ console.log(yield* Effect.promise(() => dumpInitiative(initiative)));
153
+ },
154
+ WithProperties,
155
+ Effect.provide(TestLayer),
156
+ TestHelpers.provideTestContext,
157
+ ),
158
+ MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
159
+ );
160
+
161
+ it.scoped(
162
+ 'planning',
163
+ Effect.fnUntraced(
164
+ function* (_) {
165
+ const initiative = yield* Database.add(
166
+ yield* Initiative.makeInitialized(
167
+ {
168
+ name: 'Egg making',
169
+ spec: trim`
170
+ I'm testing how planning (task management) works.
171
+ Create tasks to make scrambled eggs.
172
+
173
+ Then simulate this plan execution in a markdown document.
174
+ The document should reflect the state of all objects involved in the cooking process.
175
+ The document should also have the log of actions taken.
176
+
177
+ Important: simualte actions one by one, in the order they are listed.
178
+ Simlate by updating the local document.
179
+
180
+ <example>
181
+ # State
182
+
183
+ - 2 raw eggs
184
+ - 1 frying pan
185
+
186
+ # Action log
187
+
188
+ - Taken 2 raw eggs out of the fridge.
189
+ </example>
190
+ `,
191
+ blueprints: [Ref.make(MarkdownBlueprint.make()), Ref.make(Obj.clone(Planning.PlanningBlueprint))],
192
+ },
193
+ Initiative.makeBlueprint(),
194
+ ),
195
+ );
196
+ yield* Database.flush({ indexes: true });
197
+
198
+ const chatQueue = initiative.chat?.target?.queue?.target as any;
199
+ invariant(chatQueue, 'Initiative chat queue not found.');
200
+ yield* Database.flush({ indexes: true });
201
+ const conversation = yield* acquireReleaseResource(() => new AiConversation({ queue: chatQueue }));
202
+ yield* Effect.promise(() => conversation.context.open());
203
+
204
+ yield* conversation.createRequest({
205
+ system: SYSTEM,
206
+ prompt: `Go`,
207
+ });
208
+
209
+ console.log(yield* Effect.promise(() => dumpInitiative(initiative)));
210
+ },
211
+ WithProperties,
212
+ Effect.provide(TestLayer),
213
+ TestHelpers.provideTestContext,
214
+ ),
215
+ MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
216
+ );
217
+ });
218
+
219
+ const dumpInitiative = async (initiative: Initiative.Initiative) => {
220
+ let text = '';
221
+ text += `============== Initiative: ${initiative.name} ==============\n\n`;
222
+ text += `============== Spec ==============\n\n`;
223
+ text += `${await initiative.spec.load().then((_) => _.content)}\n`;
224
+ text += `============== Plan ==============\n\n`;
225
+ text += `${await initiative.plan?.load().then((_) => Initiative.formatPlan(_))}\n`;
226
+ text += `============== Artifacts ==============\n\n`;
227
+ for (const artifact of initiative.artifacts) {
228
+ const data = await artifact.data.load();
229
+ text += `============== ${artifact.name} (${Obj.getTypename(data)}) ==============\n`;
230
+ if (Obj.instanceOf(Markdown.Document, data)) {
231
+ text += `# ${Obj.getLabel(data)}\n\n${await data.content.load().then((_) => _.content)}\n`;
232
+ } else {
233
+ text += ` ${JSON.stringify(data, null, 2)}\n`;
234
+ }
235
+ text += '\n';
236
+ }
237
+ return text;
238
+ };
239
+
240
+ const TEST_MESSAGES = [
241
+ // Expense-related emails
242
+ Obj.make(Message.Message, {
243
+ created: new Date('2026-01-28T10:15:00Z').toISOString(),
244
+ sender: { email: 'receipts@britishairways.com' },
245
+ blocks: [
246
+ {
247
+ _tag: 'text',
248
+ text: trim`
249
+ From: receipts@britishairways.com
250
+ Subject: Your British Airways booking confirmation - BA287
251
+
252
+ Dear Mr. Smith,
253
+
254
+ Thank you for booking with British Airways. Your flight reservation is confirmed.
255
+
256
+ BOOKING REFERENCE: XK7M2P
257
+
258
+ FLIGHT DETAILS
259
+ ─────────────────────────────────────
260
+ Flight: BA287
261
+ Date: 15 February 2026
262
+ Route: San Francisco (SFO) → London Heathrow (LHR)
263
+ Departure: 17:45 PST
264
+ Arrival: 12:15 GMT (+1 day)
265
+ Class: Economy
266
+
267
+ PASSENGER
268
+ ─────────────────────────────────────
269
+ John Smith
270
+
271
+ PAYMENT SUMMARY
272
+ ─────────────────────────────────────
273
+ Base fare: £485.00
274
+ Taxes and fees: £127.50
275
+ ─────────────────────────────────────
276
+ TOTAL PAID: £612.50
277
+
278
+ Payment method: Visa ending in 4521
279
+ Transaction date: 28 January 2026
280
+
281
+ Please keep this email for your records.
282
+
283
+ Kind regards,
284
+ British Airways
285
+ `,
286
+ },
287
+ ],
288
+ }),
289
+ Obj.make(Message.Message, {
290
+ created: new Date('2026-01-29T14:30:00Z').toISOString(),
291
+ sender: { email: 'noreply@booking.com' },
292
+ blocks: [
293
+ {
294
+ _tag: 'text',
295
+ text: trim`
296
+ From: noreply@booking.com
297
+ Subject: Booking Confirmation - The Savoy London
298
+
299
+ Booking Confirmation
300
+
301
+ Dear John Smith,
302
+
303
+ Your booking is confirmed!
304
+
305
+ Hotel: The Savoy London
306
+ Address: Strand, London WC2R 0EU, United Kingdom
307
+ Check-in: 15 February 2026, 15:00
308
+ Check-out: 18 February 2026, 11:00
309
+ Guests: 1 adult
310
+ Room: Deluxe King Room
311
+
312
+ Total amount: £450.00
313
+ Payment: Paid via credit card ending in 4521
314
+ Booking reference: BK-789456123
315
+
316
+ We look forward to welcoming you!
317
+
318
+ Best regards,
319
+ Booking.com
320
+ `,
321
+ },
322
+ ],
323
+ }),
324
+ Obj.make(Message.Message, {
325
+ created: new Date('2026-02-15T19:45:00Z').toISOString(),
326
+ sender: { email: 'receipt@uber.com' },
327
+ blocks: [
328
+ {
329
+ _tag: 'text',
330
+ text: trim`
331
+ From: receipt@uber.com
332
+ Subject: Your trip receipt
333
+
334
+ Trip Receipt
335
+
336
+ Trip Date: February 15, 2026 at 7:30 PM
337
+ Trip ID: 1A2B3C4D5E
338
+
339
+ Route: London Heathrow Airport → The Savoy London
340
+ Distance: 18.2 miles
341
+ Duration: 45 minutes
342
+
343
+ Fare breakdown:
344
+ Base fare: £12.50
345
+ Distance: £18.20
346
+ Time: £11.25
347
+ Booking fee: £2.50
348
+ ─────────────────────────────────────
349
+ Subtotal: £44.45
350
+ VAT (20%): £8.89
351
+ ─────────────────────────────────────
352
+ Total: £53.34
353
+
354
+ Payment method: Visa •••• 4521
355
+
356
+ Thank you for riding with Uber!
357
+ `,
358
+ },
359
+ ],
360
+ }),
361
+ Obj.make(Message.Message, {
362
+ created: new Date('2026-02-16T20:15:00Z').toISOString(),
363
+ sender: { email: 'receipts@opentable.com' },
364
+ blocks: [
365
+ {
366
+ _tag: 'text',
367
+ text: trim`
368
+ From: receipts@opentable.com
369
+ Subject: Your receipt from The Ivy
370
+
371
+ Receipt
372
+
373
+ Restaurant: The Ivy
374
+ Address: 1-5 West Street, London WC2H 9NQ
375
+ Date: February 16, 2026
376
+ Time: 8:00 PM
377
+ Table: 12
378
+ Guests: 2
379
+
380
+ Order Summary:
381
+ ─────────────────────────────────────
382
+ Starter - Scallops £18.00
383
+ Main - Ribeye Steak £32.00
384
+ Main - Sea Bass £28.00
385
+ Side - Truffle Fries £8.50
386
+ Wine - Chardonnay (bottle) £45.00
387
+ Dessert - Chocolate Soufflé £12.00
388
+ ─────────────────────────────────────
389
+ Subtotal: £143.50
390
+ Service charge (12.5%): £17.94
391
+ ─────────────────────────────────────
392
+ Total: £161.44
393
+
394
+ Payment: Card ending in 4521
395
+ Reservation ID: OT-987654321
396
+
397
+ Thank you for dining with us!
398
+ `,
399
+ },
400
+ ],
401
+ }),
402
+ Obj.make(Message.Message, {
403
+ created: new Date('2026-02-17T09:00:00Z').toISOString(),
404
+ sender: { email: 'receipts@amazon.co.uk' },
405
+ blocks: [
406
+ {
407
+ _tag: 'text',
408
+ text: trim`
409
+ From: receipts@amazon.co.uk
410
+ Subject: Your Amazon.co.uk order #123-4567890-1234567
411
+
412
+ Order Confirmation
413
+
414
+ Hello John Smith,
415
+
416
+ We've received your order and will send a confirmation when it ships.
417
+
418
+ Order #123-4567890-1234567
419
+ Order Date: February 17, 2026
420
+
421
+ Items Ordered:
422
+ ─────────────────────────────────────
423
+ 1x London Travel Guide 2026 £12.99
424
+ 1x Universal Travel Adapter £8.50
425
+ ─────────────────────────────────────
426
+ Items: £21.49
427
+ Shipping & Handling: £4.99
428
+ ─────────────────────────────────────
429
+ Order Total: £26.48
430
+
431
+ Payment method: Visa ending in 4521
432
+ Shipping to: The Savoy London, Strand, London WC2R 0EU
433
+
434
+ Estimated delivery: February 18, 2026
435
+
436
+ Thank you for your order!
437
+ `,
438
+ },
439
+ ],
440
+ }),
441
+ // Unrelated emails
442
+ Obj.make(Message.Message, {
443
+ created: new Date('2026-01-30T08:00:00Z').toISOString(),
444
+ sender: { email: 'newsletter@techcrunch.com' },
445
+ blocks: [
446
+ {
447
+ _tag: 'text',
448
+ text: trim`
449
+ From: newsletter@techcrunch.com
450
+ Subject: Weekly Tech Roundup - AI Breakthroughs & Startup News
451
+
452
+ TechCrunch Weekly Newsletter
453
+
454
+ This week in tech:
455
+
456
+ • OpenAI announces GPT-5 with enhanced reasoning capabilities
457
+ • New quantum computing milestone achieved by IBM
458
+ • 5 startups that raised over $100M this week
459
+ • The future of autonomous vehicles: what's next?
460
+
461
+ Read the full stories: https://techcrunch.com/weekly
462
+
463
+ Unsubscribe | Manage preferences
464
+ `,
465
+ },
466
+ ],
467
+ }),
468
+ Obj.make(Message.Message, {
469
+ created: new Date('2026-02-01T12:00:00Z').toISOString(),
470
+ sender: { email: 'sarah.johnson@gmail.com' },
471
+ blocks: [
472
+ {
473
+ _tag: 'text',
474
+ text: trim`
475
+ From: sarah.johnson@gmail.com
476
+ Subject: Re: Coffee next week?
477
+
478
+ Hey John,
479
+
480
+ Sounds great! How about Tuesday at 2pm? The usual place?
481
+
482
+ Let me know if that works for you.
483
+
484
+ Cheers,
485
+ Sarah
486
+ `,
487
+ },
488
+ ],
489
+ }),
490
+ Obj.make(Message.Message, {
491
+ created: new Date('2026-02-10T10:30:00Z').toISOString(),
492
+ sender: { email: 'promotions@nike.com' },
493
+ blocks: [
494
+ {
495
+ _tag: 'text',
496
+ text: trim`
497
+ From: promotions@nike.com
498
+ Subject: 🏃‍♂️ 30% Off Running Shoes - Limited Time!
499
+
500
+ Don't miss out!
501
+
502
+ Get 30% off all running shoes this week only. Use code RUN30 at checkout.
503
+
504
+ Shop now: https://nike.com/sale
505
+
506
+ Valid until February 17, 2026.
507
+
508
+ Unsubscribe | View in browser
509
+ `,
510
+ },
511
+ ],
512
+ }),
513
+ Obj.make(Message.Message, {
514
+ created: new Date('2026-02-14T16:20:00Z').toISOString(),
515
+ sender: { email: 'notifications@github.com' },
516
+ blocks: [
517
+ {
518
+ _tag: 'text',
519
+ text: trim`
520
+ From: notifications@github.com
521
+ Subject: [dxos/dxos] New pull request: feat: add expense tracking
522
+
523
+ johnsmith opened a pull request in dxos/dxos
524
+
525
+ Title: feat: add expense tracking
526
+ Branch: feature/expense-tracking → main
527
+
528
+ This PR adds a new expense tracking feature to the assistant toolkit.
529
+
530
+ Review it here: https://github.com/dxos/dxos/pull/1234
531
+
532
+ You're receiving this because you're watching this repository.
533
+ `,
534
+ },
535
+ ],
536
+ }),
537
+ Obj.make(Message.Message, {
538
+ created: new Date('2026-02-18T11:00:00Z').toISOString(),
539
+ sender: { email: 'receipts@britishairways.com' },
540
+ blocks: [
541
+ {
542
+ _tag: 'text',
543
+ text: trim`
544
+ From: receipts@britishairways.com
545
+ Subject: Your British Airways booking confirmation - BA288
546
+
547
+ Dear Mr. Smith,
548
+
549
+ Thank you for booking with British Airways. Your return flight reservation is confirmed.
550
+
551
+ BOOKING REFERENCE: YK8N3Q
552
+
553
+ FLIGHT DETAILS
554
+ ─────────────────────────────────────
555
+ Flight: BA288
556
+ Date: 20 February 2026
557
+ Route: London Heathrow (LHR) → San Francisco (SFO)
558
+ Departure: 10:30 GMT
559
+ Arrival: 13:15 PST
560
+ Class: Economy
561
+
562
+ PASSENGER
563
+ ─────────────────────────────────────
564
+ John Smith
565
+
566
+ PAYMENT SUMMARY
567
+ ─────────────────────────────────────
568
+ Base fare: £520.00
569
+ Taxes and fees: £135.00
570
+ ─────────────────────────────────────
571
+ TOTAL PAID: £655.00
572
+
573
+ Payment method: Visa ending in 4521
574
+ Transaction date: 18 February 2026
575
+
576
+ Please keep this email for your records.
577
+
578
+ Kind regards,
579
+ British Airways
580
+ `,
581
+ },
582
+ ],
583
+ }),
584
+ ];
@@ -0,0 +1,107 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { Obj, Type } from '@dxos/echo';
8
+
9
+ import * as Chat from '../chat/Chat';
10
+
11
+ export const TaskId = Schema.String.pipe(Schema.brand('@dxos/assistant-toolkit/TaskId'));
12
+ export type TaskId = Schema.Schema.Type<typeof TaskId>;
13
+
14
+ export const Task = Schema.Struct({
15
+ /**
16
+ * Short task ID unique within the plan.
17
+ */
18
+ id: TaskId,
19
+
20
+ title: Schema.String.annotations({
21
+ description: 'Task title and description.',
22
+ }),
23
+
24
+ status: Schema.Literal('todo', 'in-progress', 'done'),
25
+
26
+ /**
27
+ * Parent task ID.
28
+ */
29
+ parent: Schema.optional(TaskId).annotations({
30
+ description: 'Parent task ID.',
31
+ }),
32
+
33
+ /**
34
+ * Chat object that this task is associated with.
35
+ */
36
+ chat: Schema.optional(Type.Ref(Chat.Chat)),
37
+ });
38
+ export interface Task extends Schema.Schema.Type<typeof Task> {}
39
+
40
+ /**
41
+ * Hierarchical collection of tasks for humans and agents to track progress.
42
+ */
43
+ export const Plan = Schema.Struct({
44
+ tasks: Schema.Array(Task),
45
+ }).pipe(
46
+ Type.object({
47
+ typename: 'dxos.org/type/Plan',
48
+ version: '0.1.0',
49
+ }),
50
+ );
51
+ export interface Plan extends Schema.Schema.Type<typeof Plan> {}
52
+
53
+ export const generateTaskId = (plan: Plan): TaskId => {
54
+ const existingIds = plan.tasks
55
+ .map((task) => {
56
+ const [num, letter] = task.id.split('-');
57
+ return parseInt(num);
58
+ })
59
+ .filter((_) => !isNaN(_));
60
+ let newId;
61
+ if (existingIds.length === 0) {
62
+ newId = 1;
63
+ } else {
64
+ newId = Math.max(...existingIds) + 1;
65
+ }
66
+ // Add random suffix to avoid collisions.
67
+ return TaskId.make(`${newId}-${crypto.randomUUID().slice(0, 2)}`);
68
+ };
69
+
70
+ /**
71
+ * Add new tasks to a plan, generating IDs for new tasks.
72
+ * Use inside an `Obj.change` callback.
73
+ */
74
+ export const addTasks = (
75
+ plan: Obj.Mutable<Plan>,
76
+ tasks: (Pick<Task, 'title'> & Partial<Pick<Task, 'status' | 'parent' | 'chat'>>)[],
77
+ ) => {
78
+ for (const task of tasks) {
79
+ const taskId = generateTaskId(plan);
80
+ plan.tasks.push({ id: taskId, ...task, status: task.status ?? 'todo' });
81
+ }
82
+ return plan;
83
+ };
84
+
85
+ interface MakePlanProps {
86
+ tasks: {
87
+ title: string;
88
+ status?: 'todo' | 'in-progress' | 'done';
89
+ }[];
90
+ }
91
+
92
+ export const makePlan = (props: MakePlanProps): Plan => {
93
+ const plan = Obj.make(Plan, { tasks: [] });
94
+ Obj.change(plan, (plan) => {
95
+ addTasks(plan, props.tasks);
96
+ });
97
+ return plan;
98
+ };
99
+
100
+ /**
101
+ * Formats plan to markdown format.
102
+ */
103
+ export const formatPlan = (plan: Plan): string => {
104
+ return plan.tasks
105
+ .map((task) => `- **${task.status?.toLocaleUpperCase()}**: ${task.title ?? 'No title'} <!-- id=${task.id} -->`)
106
+ .join('\n');
107
+ };