@dxos/assistant-toolkit 0.8.4-main.21d9917

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 (249) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +3 -0
  3. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +2880 -0
  6. package/dist/lib/browser/index.mjs.map +7 -0
  7. package/dist/lib/browser/meta.json +1 -0
  8. package/dist/lib/browser/testing/index.mjs +43 -0
  9. package/dist/lib/browser/testing/index.mjs.map +7 -0
  10. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  11. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  12. package/dist/lib/node-esm/index.mjs +2881 -0
  13. package/dist/lib/node-esm/index.mjs.map +7 -0
  14. package/dist/lib/node-esm/meta.json +1 -0
  15. package/dist/lib/node-esm/testing/index.mjs +44 -0
  16. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  17. package/dist/types/src/blueprints/design/design-blueprint.d.ts +18 -0
  18. package/dist/types/src/blueprints/design/design-blueprint.d.ts.map +1 -0
  19. package/dist/types/src/blueprints/design/design-blueprint.test.d.ts +2 -0
  20. package/dist/types/src/blueprints/design/design-blueprint.test.d.ts.map +1 -0
  21. package/dist/types/src/blueprints/design/index.d.ts +3 -0
  22. package/dist/types/src/blueprints/design/index.d.ts.map +1 -0
  23. package/dist/types/src/blueprints/discord/discord-blueprint.d.ts +18 -0
  24. package/dist/types/src/blueprints/discord/discord-blueprint.d.ts.map +1 -0
  25. package/dist/types/src/blueprints/discord/index.d.ts +3 -0
  26. package/dist/types/src/blueprints/discord/index.d.ts.map +1 -0
  27. package/dist/types/src/blueprints/index.d.ts +7 -0
  28. package/dist/types/src/blueprints/index.d.ts.map +1 -0
  29. package/dist/types/src/blueprints/linear/index.d.ts +3 -0
  30. package/dist/types/src/blueprints/linear/index.d.ts.map +1 -0
  31. package/dist/types/src/blueprints/linear/linear-blueprint.d.ts +18 -0
  32. package/dist/types/src/blueprints/linear/linear-blueprint.d.ts.map +1 -0
  33. package/dist/types/src/blueprints/planning/index.d.ts +3 -0
  34. package/dist/types/src/blueprints/planning/index.d.ts.map +1 -0
  35. package/dist/types/src/blueprints/planning/planning-blueprint.d.ts +18 -0
  36. package/dist/types/src/blueprints/planning/planning-blueprint.d.ts.map +1 -0
  37. package/dist/types/src/blueprints/planning/planning-blueprint.test.d.ts +2 -0
  38. package/dist/types/src/blueprints/planning/planning-blueprint.test.d.ts.map +1 -0
  39. package/dist/types/src/blueprints/research/index.d.ts +3 -0
  40. package/dist/types/src/blueprints/research/index.d.ts.map +1 -0
  41. package/dist/types/src/blueprints/research/research-blueprint.d.ts +18 -0
  42. package/dist/types/src/blueprints/research/research-blueprint.d.ts.map +1 -0
  43. package/dist/types/src/blueprints/research/research-blueprint.test.d.ts +2 -0
  44. package/dist/types/src/blueprints/research/research-blueprint.test.d.ts.map +1 -0
  45. package/dist/types/src/blueprints/testing.d.ts +12 -0
  46. package/dist/types/src/blueprints/testing.d.ts.map +1 -0
  47. package/dist/types/src/blueprints/websearch/index.d.ts +4 -0
  48. package/dist/types/src/blueprints/websearch/index.d.ts.map +1 -0
  49. package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts +18 -0
  50. package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts.map +1 -0
  51. package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts +27 -0
  52. package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts.map +1 -0
  53. package/dist/types/src/crud/graph.d.ts +67 -0
  54. package/dist/types/src/crud/graph.d.ts.map +1 -0
  55. package/dist/types/src/crud/graph.test.d.ts +2 -0
  56. package/dist/types/src/crud/graph.test.d.ts.map +1 -0
  57. package/dist/types/src/crud/index.d.ts +2 -0
  58. package/dist/types/src/crud/index.d.ts.map +1 -0
  59. package/dist/types/src/experimental/feed.test.d.ts +2 -0
  60. package/dist/types/src/experimental/feed.test.d.ts.map +1 -0
  61. package/dist/types/src/functions/agent/index.d.ts +5 -0
  62. package/dist/types/src/functions/agent/index.d.ts.map +1 -0
  63. package/dist/types/src/functions/agent/prompt.d.ts +76 -0
  64. package/dist/types/src/functions/agent/prompt.d.ts.map +1 -0
  65. package/dist/types/src/functions/discord/fetch-messages.d.ts +11 -0
  66. package/dist/types/src/functions/discord/fetch-messages.d.ts.map +1 -0
  67. package/dist/types/src/functions/discord/fetch-messages.test.d.ts +2 -0
  68. package/dist/types/src/functions/discord/fetch-messages.test.d.ts.map +1 -0
  69. package/dist/types/src/functions/discord/index.d.ts +12 -0
  70. package/dist/types/src/functions/discord/index.d.ts.map +1 -0
  71. package/dist/types/src/functions/document/index.d.ts +13 -0
  72. package/dist/types/src/functions/document/index.d.ts.map +1 -0
  73. package/dist/types/src/functions/document/read.d.ts +7 -0
  74. package/dist/types/src/functions/document/read.d.ts.map +1 -0
  75. package/dist/types/src/functions/document/update.d.ts +6 -0
  76. package/dist/types/src/functions/document/update.d.ts.map +1 -0
  77. package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts +174 -0
  78. package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts.map +1 -0
  79. package/dist/types/src/functions/entity-extraction/entity-extraction.test.d.ts +2 -0
  80. package/dist/types/src/functions/entity-extraction/entity-extraction.test.d.ts.map +1 -0
  81. package/dist/types/src/functions/entity-extraction/index.d.ts +175 -0
  82. package/dist/types/src/functions/entity-extraction/index.d.ts.map +1 -0
  83. package/dist/types/src/functions/exa/data/exa-search-1748337321991.d.ts +38 -0
  84. package/dist/types/src/functions/exa/data/exa-search-1748337321991.d.ts.map +1 -0
  85. package/dist/types/src/functions/exa/data/exa-search-1748337331526.d.ts +37 -0
  86. package/dist/types/src/functions/exa/data/exa-search-1748337331526.d.ts.map +1 -0
  87. package/dist/types/src/functions/exa/data/exa-search-1748337344119.d.ts +58 -0
  88. package/dist/types/src/functions/exa/data/exa-search-1748337344119.d.ts.map +1 -0
  89. package/dist/types/src/functions/exa/data/index.d.ts +3 -0
  90. package/dist/types/src/functions/exa/data/index.d.ts.map +1 -0
  91. package/dist/types/src/functions/exa/exa.d.ts +5 -0
  92. package/dist/types/src/functions/exa/exa.d.ts.map +1 -0
  93. package/dist/types/src/functions/exa/index.d.ts +3 -0
  94. package/dist/types/src/functions/exa/index.d.ts.map +1 -0
  95. package/dist/types/src/functions/exa/mock.d.ts +5 -0
  96. package/dist/types/src/functions/exa/mock.d.ts.map +1 -0
  97. package/dist/types/src/functions/github/fetch-prs.d.ts +6 -0
  98. package/dist/types/src/functions/github/fetch-prs.d.ts.map +1 -0
  99. package/dist/types/src/functions/index.d.ts +8 -0
  100. package/dist/types/src/functions/index.d.ts.map +1 -0
  101. package/dist/types/src/functions/linear/index.d.ts +9 -0
  102. package/dist/types/src/functions/linear/index.d.ts.map +1 -0
  103. package/dist/types/src/functions/linear/linear.test.d.ts +2 -0
  104. package/dist/types/src/functions/linear/linear.test.d.ts.map +1 -0
  105. package/dist/types/src/functions/linear/sync-issues.d.ts +12 -0
  106. package/dist/types/src/functions/linear/sync-issues.d.ts.map +1 -0
  107. package/dist/types/src/functions/research/document-create.d.ts +9 -0
  108. package/dist/types/src/functions/research/document-create.d.ts.map +1 -0
  109. package/dist/types/src/functions/research/index.d.ts +21 -0
  110. package/dist/types/src/functions/research/index.d.ts.map +1 -0
  111. package/dist/types/src/functions/research/research-graph.d.ts +19 -0
  112. package/dist/types/src/functions/research/research-graph.d.ts.map +1 -0
  113. package/dist/types/src/functions/research/research.d.ts +14 -0
  114. package/dist/types/src/functions/research/research.d.ts.map +1 -0
  115. package/dist/types/src/functions/research/research.test.d.ts +2 -0
  116. package/dist/types/src/functions/research/research.test.d.ts.map +1 -0
  117. package/dist/types/src/functions/research/types.d.ts +6 -0
  118. package/dist/types/src/functions/research/types.d.ts.map +1 -0
  119. package/dist/types/src/functions/tasks/index.d.ts +15 -0
  120. package/dist/types/src/functions/tasks/index.d.ts.map +1 -0
  121. package/dist/types/src/functions/tasks/read.d.ts +7 -0
  122. package/dist/types/src/functions/tasks/read.d.ts.map +1 -0
  123. package/dist/types/src/functions/tasks/task-list.d.ts +74 -0
  124. package/dist/types/src/functions/tasks/task-list.d.ts.map +1 -0
  125. package/dist/types/src/functions/tasks/task-list.test.d.ts +2 -0
  126. package/dist/types/src/functions/tasks/task-list.test.d.ts.map +1 -0
  127. package/dist/types/src/functions/tasks/update.d.ts +9 -0
  128. package/dist/types/src/functions/tasks/update.d.ts.map +1 -0
  129. package/dist/types/src/index.d.ts +6 -0
  130. package/dist/types/src/index.d.ts.map +1 -0
  131. package/dist/types/src/initiative/Initiative.d.ts +84 -0
  132. package/dist/types/src/initiative/Initiative.d.ts.map +1 -0
  133. package/dist/types/src/initiative/InitiativeSchema.d.ts +19 -0
  134. package/dist/types/src/initiative/InitiativeSchema.d.ts.map +1 -0
  135. package/dist/types/src/initiative/functions/agent.d.ts +37 -0
  136. package/dist/types/src/initiative/functions/agent.d.ts.map +1 -0
  137. package/dist/types/src/initiative/functions/getContext.d.ts +17 -0
  138. package/dist/types/src/initiative/functions/getContext.d.ts.map +1 -0
  139. package/dist/types/src/initiative/functions/index.d.ts +4 -0
  140. package/dist/types/src/initiative/functions/index.d.ts.map +1 -0
  141. package/dist/types/src/initiative/functions/update.d.ts +7 -0
  142. package/dist/types/src/initiative/functions/update.d.ts.map +1 -0
  143. package/dist/types/src/initiative/index.d.ts +1 -0
  144. package/dist/types/src/initiative/index.d.ts.map +1 -0
  145. package/dist/types/src/initiative/initiative.test.d.ts +2 -0
  146. package/dist/types/src/initiative/initiative.test.d.ts.map +1 -0
  147. package/dist/types/src/sync/index.d.ts +2 -0
  148. package/dist/types/src/sync/index.d.ts.map +1 -0
  149. package/dist/types/src/sync/sync.d.ts +15 -0
  150. package/dist/types/src/sync/sync.d.ts.map +1 -0
  151. package/dist/types/src/testing/index.d.ts +2 -0
  152. package/dist/types/src/testing/index.d.ts.map +1 -0
  153. package/dist/types/src/testing/plugins.d.ts +19 -0
  154. package/dist/types/src/testing/plugins.d.ts.map +1 -0
  155. package/dist/types/src/toolkits/AssistantToolkit.d.ts +43 -0
  156. package/dist/types/src/toolkits/AssistantToolkit.d.ts.map +1 -0
  157. package/dist/types/src/toolkits/AssistantToolkit.test.d.ts +2 -0
  158. package/dist/types/src/toolkits/AssistantToolkit.test.d.ts.map +1 -0
  159. package/dist/types/src/toolkits/SystemToolkit.d.ts +99 -0
  160. package/dist/types/src/toolkits/SystemToolkit.d.ts.map +1 -0
  161. package/dist/types/src/toolkits/index.d.ts +3 -0
  162. package/dist/types/src/toolkits/index.d.ts.map +1 -0
  163. package/dist/types/src/util/graphql.d.ts +22 -0
  164. package/dist/types/src/util/graphql.d.ts.map +1 -0
  165. package/dist/types/src/util/index.d.ts +2 -0
  166. package/dist/types/src/util/index.d.ts.map +1 -0
  167. package/dist/types/tsconfig.tsbuildinfo +1 -0
  168. package/package.json +83 -0
  169. package/src/blueprints/design/design-blueprint.test.ts +105 -0
  170. package/src/blueprints/design/design-blueprint.ts +31 -0
  171. package/src/blueprints/design/index.ts +7 -0
  172. package/src/blueprints/discord/discord-blueprint.ts +32 -0
  173. package/src/blueprints/discord/index.ts +7 -0
  174. package/src/blueprints/index.ts +10 -0
  175. package/src/blueprints/linear/index.ts +7 -0
  176. package/src/blueprints/linear/linear-blueprint.ts +33 -0
  177. package/src/blueprints/planning/index.ts +7 -0
  178. package/src/blueprints/planning/planning-blueprint.test.ts +126 -0
  179. package/src/blueprints/planning/planning-blueprint.ts +96 -0
  180. package/src/blueprints/research/index.ts +7 -0
  181. package/src/blueprints/research/research-blueprint.test.ts +7 -0
  182. package/src/blueprints/research/research-blueprint.ts +51 -0
  183. package/src/blueprints/testing.ts +34 -0
  184. package/src/blueprints/websearch/index.ts +9 -0
  185. package/src/blueprints/websearch/websearch-blueprint.ts +18 -0
  186. package/src/blueprints/websearch/websearch-toolkit.ts +8 -0
  187. package/src/crud/graph.test.ts +46 -0
  188. package/src/crud/graph.ts +380 -0
  189. package/src/crud/index.ts +5 -0
  190. package/src/experimental/feed.test.ts +111 -0
  191. package/src/functions/agent/index.ts +11 -0
  192. package/src/functions/agent/prompt.ts +118 -0
  193. package/src/functions/discord/fetch-messages.test.ts +58 -0
  194. package/src/functions/discord/fetch-messages.ts +252 -0
  195. package/src/functions/discord/index.ts +9 -0
  196. package/src/functions/document/index.ts +12 -0
  197. package/src/functions/document/read.ts +30 -0
  198. package/src/functions/document/update.ts +33 -0
  199. package/src/functions/entity-extraction/entity-extraction.conversations.json +6597 -0
  200. package/src/functions/entity-extraction/entity-extraction.test.ts +93 -0
  201. package/src/functions/entity-extraction/entity-extraction.ts +183 -0
  202. package/src/functions/entity-extraction/index.ts +9 -0
  203. package/src/functions/exa/data/exa-search-1748337321991.ts +131 -0
  204. package/src/functions/exa/data/exa-search-1748337331526.ts +144 -0
  205. package/src/functions/exa/data/exa-search-1748337344119.ts +133 -0
  206. package/src/functions/exa/data/index.ts +11 -0
  207. package/src/functions/exa/exa.ts +37 -0
  208. package/src/functions/exa/index.ts +6 -0
  209. package/src/functions/exa/mock.ts +71 -0
  210. package/src/functions/github/fetch-prs.ts +31 -0
  211. package/src/functions/index.ts +11 -0
  212. package/src/functions/linear/index.ts +9 -0
  213. package/src/functions/linear/linear.test.ts +84 -0
  214. package/src/functions/linear/sync-issues.ts +191 -0
  215. package/src/functions/research/document-create.ts +76 -0
  216. package/src/functions/research/index.ts +14 -0
  217. package/src/functions/research/research-graph.ts +49 -0
  218. package/src/functions/research/research-instructions.tpl +106 -0
  219. package/src/functions/research/research.conversations.json +1 -0
  220. package/src/functions/research/research.test.ts +171 -0
  221. package/src/functions/research/research.ts +189 -0
  222. package/src/functions/research/types.ts +26 -0
  223. package/src/functions/tasks/index.ts +11 -0
  224. package/src/functions/tasks/read.ts +35 -0
  225. package/src/functions/tasks/task-list.test.ts +99 -0
  226. package/src/functions/tasks/task-list.ts +165 -0
  227. package/src/functions/tasks/update.ts +53 -0
  228. package/src/index.ts +9 -0
  229. package/src/initiative/Initiative.ts +99 -0
  230. package/src/initiative/InitiativeSchema.ts +37 -0
  231. package/src/initiative/functions/agent.ts +57 -0
  232. package/src/initiative/functions/getContext.ts +74 -0
  233. package/src/initiative/functions/index.ts +7 -0
  234. package/src/initiative/functions/update.ts +63 -0
  235. package/src/initiative/index.ts +3 -0
  236. package/src/initiative/initiative.conversations.json +1 -0
  237. package/src/initiative/initiative.test.ts +485 -0
  238. package/src/sync/index.ts +5 -0
  239. package/src/sync/sync.ts +95 -0
  240. package/src/testing/index.ts +5 -0
  241. package/src/testing/plugins.tsx +68 -0
  242. package/src/toolkits/AssistantToolkit.conversations.json +1 -0
  243. package/src/toolkits/AssistantToolkit.test.ts +94 -0
  244. package/src/toolkits/AssistantToolkit.ts +70 -0
  245. package/src/toolkits/SystemToolkit.ts +299 -0
  246. package/src/toolkits/index.ts +6 -0
  247. package/src/typedefs.d.ts +8 -0
  248. package/src/util/graphql.ts +31 -0
  249. package/src/util/index.ts +5 -0
@@ -0,0 +1,485 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, it } from '@effect/vitest';
6
+ import * as Effect from 'effect/Effect';
7
+
8
+ import { MemoizedAiService } from '@dxos/ai/testing';
9
+ import { AiConversation } from '@dxos/assistant';
10
+ import { AssistantTestLayerWithTriggers } from '@dxos/assistant/testing';
11
+ import { Blueprint } from '@dxos/blueprints';
12
+ import { Database, Obj, Ref } from '@dxos/echo';
13
+ import { acquireReleaseResource } from '@dxos/effect';
14
+ import { TestHelpers } from '@dxos/effect/testing';
15
+ import { FunctionDefinition, QueueService, Trigger } from '@dxos/functions';
16
+ import { TriggerDispatcher } from '@dxos/functions-runtime';
17
+ import { invariant } from '@dxos/invariant';
18
+ import { ObjectId } from '@dxos/keys';
19
+ import { Text } from '@dxos/schema';
20
+ import { Message } from '@dxos/types';
21
+ import { trim } from '@dxos/util';
22
+
23
+ import { agent } from './functions';
24
+ import * as Initiative from './Initiative';
25
+
26
+ ObjectId.dangerouslyDisableRandomness();
27
+
28
+ const TestLayer = AssistantTestLayerWithTriggers({
29
+ aiServicePreset: 'edge-remote',
30
+ functions: [...Initiative.functions],
31
+ types: [Initiative.Initiative, Blueprint.Blueprint, Trigger.Trigger, Text.Text],
32
+ tracing: 'pretty',
33
+ });
34
+
35
+ const SYSTEM = trim`
36
+ If you do not have tools to complete the task, inform the user. DO NOT PRETEND TO DO SOMETHING YOU CAN'T DO.
37
+ `;
38
+
39
+ describe('Initiative', () => {
40
+ it.scoped(
41
+ 'shopping list',
42
+ Effect.fnUntraced(
43
+ function* (_) {
44
+ const initiative = yield* Database.Service.add(
45
+ yield* Initiative.make({
46
+ name: 'Shopping list',
47
+ spec: 'Keep a shopping list of items to buy.',
48
+ }),
49
+ );
50
+ invariant(initiative.chat?.target, 'Initiative chat queue not found.');
51
+ yield* Database.Service.flush({ indexes: true });
52
+ const conversation = yield* acquireReleaseResource(
53
+ () => new AiConversation({ queue: initiative.chat?.target as any }),
54
+ );
55
+ yield* Effect.promise(() => conversation.context.open());
56
+
57
+ yield* conversation.createRequest({
58
+ system: SYSTEM,
59
+ prompt: `List ingredients for a scrambled eggs on a toast breakfast.`,
60
+ });
61
+
62
+ console.log(yield* Effect.promise(() => dumpInitiative(initiative)));
63
+ },
64
+ Effect.provide(TestLayer),
65
+ TestHelpers.provideTestContext,
66
+ ),
67
+ MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
68
+ );
69
+
70
+ it.scoped(
71
+ 'expense tracking list',
72
+ Effect.fnUntraced(
73
+ function* (_) {
74
+ const initiative = yield* Database.Service.add(
75
+ yield* Initiative.make({
76
+ name: 'Expense tracking',
77
+ spec: trim`
78
+ Keep a list of expenses in a markdown document (create artifact "Expenses").
79
+ Process incoming emails, add the relevant ones to the list.
80
+
81
+ Format:
82
+
83
+ ## Expences
84
+
85
+ - Flight to London (2026-02-01): £100
86
+ - Hotel in London (2026-02-01): £100
87
+ `,
88
+ }),
89
+ );
90
+ yield* Database.Service.flush({ indexes: true });
91
+
92
+ const inboxQueue = yield* QueueService.createQueue();
93
+ yield* Database.Service.add(
94
+ Trigger.make({
95
+ enabled: true,
96
+ spec: {
97
+ kind: 'queue',
98
+ queue: inboxQueue.dxn.toString(),
99
+ },
100
+ function: Ref.make(FunctionDefinition.serialize(agent)),
101
+ input: {
102
+ initiative: Ref.make(initiative),
103
+ event: '{{event}}',
104
+ },
105
+ }),
106
+ );
107
+
108
+ yield* QueueService.append(
109
+ inboxQueue,
110
+ TEST_MESSAGES.map((message) => Obj.clone(message)),
111
+ );
112
+
113
+ const dispatcher = yield* TriggerDispatcher;
114
+ yield* dispatcher.invokeScheduledTriggers({ kinds: ['queue'], untilExhausted: true });
115
+
116
+ console.log(yield* Effect.promise(() => dumpInitiative(initiative)));
117
+ },
118
+ Effect.provide(TestLayer),
119
+ TestHelpers.provideTestContext,
120
+ ),
121
+ MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
122
+ );
123
+ });
124
+
125
+ const dumpInitiative = async (initiative: Initiative.Initiative) => {
126
+ let text = '';
127
+ text += `============== Initiative: ${initiative.name} ==============\n\n`;
128
+ for (const artifact of initiative.artifacts) {
129
+ const data = await artifact.data.load();
130
+ text += `============== ${artifact.name} (${Obj.getTypename(data)}) ==============\n`;
131
+ if (Obj.instanceOf(Text.Text, data)) {
132
+ text += ` ${data.content}\n`;
133
+ } else {
134
+ text += ` ${JSON.stringify(data, null, 2)}\n`;
135
+ }
136
+ text += '\n';
137
+ }
138
+ return text;
139
+ };
140
+
141
+ const TEST_MESSAGES = [
142
+ // Expense-related emails
143
+ Obj.make(Message.Message, {
144
+ created: new Date('2026-01-28T10:15:00Z').toISOString(),
145
+ sender: { email: 'receipts@britishairways.com' },
146
+ blocks: [
147
+ {
148
+ _tag: 'text',
149
+ text: trim`
150
+ From: receipts@britishairways.com
151
+ Subject: Your British Airways booking confirmation - BA287
152
+
153
+ Dear Mr. Smith,
154
+
155
+ Thank you for booking with British Airways. Your flight reservation is confirmed.
156
+
157
+ BOOKING REFERENCE: XK7M2P
158
+
159
+ FLIGHT DETAILS
160
+ ─────────────────────────────────────
161
+ Flight: BA287
162
+ Date: 15 February 2026
163
+ Route: San Francisco (SFO) → London Heathrow (LHR)
164
+ Departure: 17:45 PST
165
+ Arrival: 12:15 GMT (+1 day)
166
+ Class: Economy
167
+
168
+ PASSENGER
169
+ ─────────────────────────────────────
170
+ John Smith
171
+
172
+ PAYMENT SUMMARY
173
+ ─────────────────────────────────────
174
+ Base fare: £485.00
175
+ Taxes and fees: £127.50
176
+ ─────────────────────────────────────
177
+ TOTAL PAID: £612.50
178
+
179
+ Payment method: Visa ending in 4521
180
+ Transaction date: 28 January 2026
181
+
182
+ Please keep this email for your records.
183
+
184
+ Kind regards,
185
+ British Airways
186
+ `,
187
+ },
188
+ ],
189
+ }),
190
+ Obj.make(Message.Message, {
191
+ created: new Date('2026-01-29T14:30:00Z').toISOString(),
192
+ sender: { email: 'noreply@booking.com' },
193
+ blocks: [
194
+ {
195
+ _tag: 'text',
196
+ text: trim`
197
+ From: noreply@booking.com
198
+ Subject: Booking Confirmation - The Savoy London
199
+
200
+ Booking Confirmation
201
+
202
+ Dear John Smith,
203
+
204
+ Your booking is confirmed!
205
+
206
+ Hotel: The Savoy London
207
+ Address: Strand, London WC2R 0EU, United Kingdom
208
+ Check-in: 15 February 2026, 15:00
209
+ Check-out: 18 February 2026, 11:00
210
+ Guests: 1 adult
211
+ Room: Deluxe King Room
212
+
213
+ Total amount: £450.00
214
+ Payment: Paid via credit card ending in 4521
215
+ Booking reference: BK-789456123
216
+
217
+ We look forward to welcoming you!
218
+
219
+ Best regards,
220
+ Booking.com
221
+ `,
222
+ },
223
+ ],
224
+ }),
225
+ Obj.make(Message.Message, {
226
+ created: new Date('2026-02-15T19:45:00Z').toISOString(),
227
+ sender: { email: 'receipt@uber.com' },
228
+ blocks: [
229
+ {
230
+ _tag: 'text',
231
+ text: trim`
232
+ From: receipt@uber.com
233
+ Subject: Your trip receipt
234
+
235
+ Trip Receipt
236
+
237
+ Trip Date: February 15, 2026 at 7:30 PM
238
+ Trip ID: 1A2B3C4D5E
239
+
240
+ Route: London Heathrow Airport → The Savoy London
241
+ Distance: 18.2 miles
242
+ Duration: 45 minutes
243
+
244
+ Fare breakdown:
245
+ Base fare: £12.50
246
+ Distance: £18.20
247
+ Time: £11.25
248
+ Booking fee: £2.50
249
+ ─────────────────────────────────────
250
+ Subtotal: £44.45
251
+ VAT (20%): £8.89
252
+ ─────────────────────────────────────
253
+ Total: £53.34
254
+
255
+ Payment method: Visa •••• 4521
256
+
257
+ Thank you for riding with Uber!
258
+ `,
259
+ },
260
+ ],
261
+ }),
262
+ Obj.make(Message.Message, {
263
+ created: new Date('2026-02-16T20:15:00Z').toISOString(),
264
+ sender: { email: 'receipts@opentable.com' },
265
+ blocks: [
266
+ {
267
+ _tag: 'text',
268
+ text: trim`
269
+ From: receipts@opentable.com
270
+ Subject: Your receipt from The Ivy
271
+
272
+ Receipt
273
+
274
+ Restaurant: The Ivy
275
+ Address: 1-5 West Street, London WC2H 9NQ
276
+ Date: February 16, 2026
277
+ Time: 8:00 PM
278
+ Table: 12
279
+ Guests: 2
280
+
281
+ Order Summary:
282
+ ─────────────────────────────────────
283
+ Starter - Scallops £18.00
284
+ Main - Ribeye Steak £32.00
285
+ Main - Sea Bass £28.00
286
+ Side - Truffle Fries £8.50
287
+ Wine - Chardonnay (bottle) £45.00
288
+ Dessert - Chocolate Soufflé £12.00
289
+ ─────────────────────────────────────
290
+ Subtotal: £143.50
291
+ Service charge (12.5%): £17.94
292
+ ─────────────────────────────────────
293
+ Total: £161.44
294
+
295
+ Payment: Card ending in 4521
296
+ Reservation ID: OT-987654321
297
+
298
+ Thank you for dining with us!
299
+ `,
300
+ },
301
+ ],
302
+ }),
303
+ Obj.make(Message.Message, {
304
+ created: new Date('2026-02-17T09:00:00Z').toISOString(),
305
+ sender: { email: 'receipts@amazon.co.uk' },
306
+ blocks: [
307
+ {
308
+ _tag: 'text',
309
+ text: trim`
310
+ From: receipts@amazon.co.uk
311
+ Subject: Your Amazon.co.uk order #123-4567890-1234567
312
+
313
+ Order Confirmation
314
+
315
+ Hello John Smith,
316
+
317
+ We've received your order and will send a confirmation when it ships.
318
+
319
+ Order #123-4567890-1234567
320
+ Order Date: February 17, 2026
321
+
322
+ Items Ordered:
323
+ ─────────────────────────────────────
324
+ 1x London Travel Guide 2026 £12.99
325
+ 1x Universal Travel Adapter £8.50
326
+ ─────────────────────────────────────
327
+ Items: £21.49
328
+ Shipping & Handling: £4.99
329
+ ─────────────────────────────────────
330
+ Order Total: £26.48
331
+
332
+ Payment method: Visa ending in 4521
333
+ Shipping to: The Savoy London, Strand, London WC2R 0EU
334
+
335
+ Estimated delivery: February 18, 2026
336
+
337
+ Thank you for your order!
338
+ `,
339
+ },
340
+ ],
341
+ }),
342
+ // Unrelated emails
343
+ Obj.make(Message.Message, {
344
+ created: new Date('2026-01-30T08:00:00Z').toISOString(),
345
+ sender: { email: 'newsletter@techcrunch.com' },
346
+ blocks: [
347
+ {
348
+ _tag: 'text',
349
+ text: trim`
350
+ From: newsletter@techcrunch.com
351
+ Subject: Weekly Tech Roundup - AI Breakthroughs & Startup News
352
+
353
+ TechCrunch Weekly Newsletter
354
+
355
+ This week in tech:
356
+
357
+ • OpenAI announces GPT-5 with enhanced reasoning capabilities
358
+ • New quantum computing milestone achieved by IBM
359
+ • 5 startups that raised over $100M this week
360
+ • The future of autonomous vehicles: what's next?
361
+
362
+ Read the full stories: https://techcrunch.com/weekly
363
+
364
+ Unsubscribe | Manage preferences
365
+ `,
366
+ },
367
+ ],
368
+ }),
369
+ Obj.make(Message.Message, {
370
+ created: new Date('2026-02-01T12:00:00Z').toISOString(),
371
+ sender: { email: 'sarah.johnson@gmail.com' },
372
+ blocks: [
373
+ {
374
+ _tag: 'text',
375
+ text: trim`
376
+ From: sarah.johnson@gmail.com
377
+ Subject: Re: Coffee next week?
378
+
379
+ Hey John,
380
+
381
+ Sounds great! How about Tuesday at 2pm? The usual place?
382
+
383
+ Let me know if that works for you.
384
+
385
+ Cheers,
386
+ Sarah
387
+ `,
388
+ },
389
+ ],
390
+ }),
391
+ Obj.make(Message.Message, {
392
+ created: new Date('2026-02-10T10:30:00Z').toISOString(),
393
+ sender: { email: 'promotions@nike.com' },
394
+ blocks: [
395
+ {
396
+ _tag: 'text',
397
+ text: trim`
398
+ From: promotions@nike.com
399
+ Subject: 🏃‍♂️ 30% Off Running Shoes - Limited Time!
400
+
401
+ Don't miss out!
402
+
403
+ Get 30% off all running shoes this week only. Use code RUN30 at checkout.
404
+
405
+ Shop now: https://nike.com/sale
406
+
407
+ Valid until February 17, 2026.
408
+
409
+ Unsubscribe | View in browser
410
+ `,
411
+ },
412
+ ],
413
+ }),
414
+ Obj.make(Message.Message, {
415
+ created: new Date('2026-02-14T16:20:00Z').toISOString(),
416
+ sender: { email: 'notifications@github.com' },
417
+ blocks: [
418
+ {
419
+ _tag: 'text',
420
+ text: trim`
421
+ From: notifications@github.com
422
+ Subject: [dxos/dxos] New pull request: feat: add expense tracking
423
+
424
+ johnsmith opened a pull request in dxos/dxos
425
+
426
+ Title: feat: add expense tracking
427
+ Branch: feature/expense-tracking → main
428
+
429
+ This PR adds a new expense tracking feature to the assistant toolkit.
430
+
431
+ Review it here: https://github.com/dxos/dxos/pull/1234
432
+
433
+ You're receiving this because you're watching this repository.
434
+ `,
435
+ },
436
+ ],
437
+ }),
438
+ Obj.make(Message.Message, {
439
+ created: new Date('2026-02-18T11:00:00Z').toISOString(),
440
+ sender: { email: 'receipts@britishairways.com' },
441
+ blocks: [
442
+ {
443
+ _tag: 'text',
444
+ text: trim`
445
+ From: receipts@britishairways.com
446
+ Subject: Your British Airways booking confirmation - BA288
447
+
448
+ Dear Mr. Smith,
449
+
450
+ Thank you for booking with British Airways. Your return flight reservation is confirmed.
451
+
452
+ BOOKING REFERENCE: YK8N3Q
453
+
454
+ FLIGHT DETAILS
455
+ ─────────────────────────────────────
456
+ Flight: BA288
457
+ Date: 20 February 2026
458
+ Route: London Heathrow (LHR) → San Francisco (SFO)
459
+ Departure: 10:30 GMT
460
+ Arrival: 13:15 PST
461
+ Class: Economy
462
+
463
+ PASSENGER
464
+ ─────────────────────────────────────
465
+ John Smith
466
+
467
+ PAYMENT SUMMARY
468
+ ─────────────────────────────────────
469
+ Base fare: £520.00
470
+ Taxes and fees: £135.00
471
+ ─────────────────────────────────────
472
+ TOTAL PAID: £655.00
473
+
474
+ Payment method: Visa ending in 4521
475
+ Transaction date: 18 February 2026
476
+
477
+ Please keep this email for your records.
478
+
479
+ Kind regards,
480
+ British Airways
481
+ `,
482
+ },
483
+ ],
484
+ }),
485
+ ];
@@ -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.Service.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.Service.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,68 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import React from 'react';
7
+
8
+ import { Capability, Common } from '@dxos/app-framework';
9
+ import { Format, type Obj, Type } from '@dxos/echo';
10
+ import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
11
+
12
+ export const MapSchema = Schema.Struct({
13
+ coordinates: Format.GeoPoint,
14
+ }).pipe(
15
+ Type.object({
16
+ typename: 'example.com/type/Map',
17
+ version: '0.1.0',
18
+ }),
19
+ );
20
+
21
+ export type MapSchema = Schema.Schema.Type<typeof MapSchema>;
22
+
23
+ // TODO(burdon): Move to ECHO def.
24
+ export type ArtifactsContext = {
25
+ items: Obj.Unknown[];
26
+ getArtifacts: () => Obj.Unknown[];
27
+ addArtifact: (artifact: Obj.Unknown) => void;
28
+ };
29
+
30
+ declare global {
31
+ interface ToolContextExtensions {
32
+ artifacts?: ArtifactsContext;
33
+ }
34
+ }
35
+
36
+ // TODO(dmaretskyi): Removed images from conductor GPT implementation.
37
+ const isImage = (data: any): data is any => false;
38
+
39
+ export const capabilities: Capability.Any[] = [
40
+ Capability.contributes(
41
+ Common.Capability.ReactSurface,
42
+ Common.createSurface({
43
+ id: 'plugin-image',
44
+ role: 'card--extrinsic',
45
+ filter: (data: any): data is any => isImage(data.value),
46
+ component: ({ data }) => (
47
+ <img
48
+ className='grow object-cover'
49
+ src={`data:image/jpeg;base64,${data.value.source.data}`}
50
+ alt={data.value.prompt ?? `Generated image [id=${data.value.id}]`}
51
+ />
52
+ ),
53
+ }),
54
+ ),
55
+
56
+ //
57
+ // Default
58
+ //
59
+ Capability.contributes(
60
+ Common.Capability.ReactSurface,
61
+ Common.createSurface({
62
+ id: 'plugin-default',
63
+ role: 'card--extrinsic',
64
+ position: 'fallback',
65
+ component: ({ data }) => <JsonFilter data={data} />,
66
+ }),
67
+ ),
68
+ ];