@dxos/assistant-toolkit 0.8.4-main.abd8ff62ef → 0.8.4-main.bc2380dfbc

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 (193) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/{add-artifact-BA5WQRDU.mjs → add-artifact-4IVGW6CI.mjs} +4 -4
  3. package/dist/lib/neutral/{add-artifact-BA5WQRDU.mjs.map → add-artifact-4IVGW6CI.mjs.map} +3 -3
  4. package/dist/lib/neutral/{agent-M2EW5M36.mjs → agent-F4L7UXME.mjs} +5 -5
  5. package/dist/lib/neutral/{agent-M2EW5M36.mjs.map → agent-F4L7UXME.mjs.map} +2 -2
  6. package/dist/lib/neutral/{chunk-CLHVRIYF.mjs → chunk-5GPL2WXU.mjs} +35 -36
  7. package/dist/lib/neutral/chunk-5GPL2WXU.mjs.map +7 -0
  8. package/dist/lib/neutral/{chunk-CVUA23QI.mjs → chunk-7UCYAP3T.mjs} +17 -17
  9. package/dist/lib/neutral/chunk-7UCYAP3T.mjs.map +7 -0
  10. package/dist/lib/neutral/{chunk-TO5IX24K.mjs → chunk-ANSF2BHN.mjs} +3 -3
  11. package/dist/lib/neutral/chunk-ANSF2BHN.mjs.map +7 -0
  12. package/dist/lib/neutral/{chunk-D5MG5OKX.mjs → chunk-BCT55UTL.mjs} +2 -2
  13. package/dist/lib/neutral/{chunk-J37DYY7A.mjs → chunk-COL54UJ3.mjs} +12 -3
  14. package/dist/lib/neutral/chunk-COL54UJ3.mjs.map +7 -0
  15. package/dist/lib/neutral/{chunk-E2XRNXWP.mjs → chunk-KS3IA6FQ.mjs} +11 -10
  16. package/dist/lib/neutral/chunk-KS3IA6FQ.mjs.map +7 -0
  17. package/dist/lib/neutral/{chunk-KY2TIPJ5.mjs → chunk-MMQ7HFL4.mjs} +4 -5
  18. package/dist/lib/neutral/chunk-MMQ7HFL4.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-PLGEBNTO.mjs +65 -0
  20. package/dist/lib/neutral/chunk-PLGEBNTO.mjs.map +7 -0
  21. package/dist/lib/neutral/{chunk-JCYLFOFK.mjs → chunk-W2722TC5.mjs} +5 -5
  22. package/dist/lib/neutral/{chunk-JCYLFOFK.mjs.map → chunk-W2722TC5.mjs.map} +3 -3
  23. package/dist/lib/neutral/{context-add-IIDPRRVB.mjs → context-add-S5MBW2NA.mjs} +4 -4
  24. package/dist/lib/neutral/context-add-S5MBW2NA.mjs.map +7 -0
  25. package/dist/lib/neutral/{context-remove-RDYV4PD4.mjs → context-remove-35O5T5N5.mjs} +4 -4
  26. package/dist/lib/neutral/context-remove-35O5T5N5.mjs.map +7 -0
  27. package/dist/lib/neutral/{create-project-GLDEAWTT.mjs → create-project-3AGXJ4TD.mjs} +5 -5
  28. package/dist/lib/neutral/{enable-blueprints-LBDZH2CY.mjs → enable-blueprints-IVKST3WH.mjs} +4 -4
  29. package/dist/lib/neutral/enable-blueprints-IVKST3WH.mjs.map +7 -0
  30. package/dist/lib/neutral/{fetch-messages-PWGUG5G3.mjs → fetch-messages-QOBBCTGC.mjs} +2 -2
  31. package/dist/lib/neutral/{get-context-B55SX5Y4.mjs → get-context-FBYWIP72.mjs} +4 -4
  32. package/dist/lib/neutral/{get-context-B55SX5Y4.mjs.map → get-context-FBYWIP72.mjs.map} +3 -3
  33. package/dist/lib/neutral/index.mjs +67 -57
  34. package/dist/lib/neutral/index.mjs.map +3 -3
  35. package/dist/lib/neutral/{load-LI7HHVD6.mjs → load-GAT3T2AD.mjs} +2 -2
  36. package/dist/lib/neutral/meta.json +1 -1
  37. package/dist/lib/neutral/{object-create-52Z7YKIA.mjs → object-create-PL3WRP74.mjs} +3 -3
  38. package/dist/lib/neutral/{object-delete-I266YAXI.mjs → object-delete-PZJQN5KW.mjs} +2 -2
  39. package/dist/lib/neutral/{object-update-HY4GI7LA.mjs → object-update-R43N3VJX.mjs} +2 -2
  40. package/dist/lib/neutral/{project-2YBPW5N7.mjs → project-VVXXUMAI.mjs} +4 -4
  41. package/dist/lib/neutral/{project-rules-XUBEPDP6.mjs → project-rules-KSVSOZJV.mjs} +3 -3
  42. package/dist/lib/neutral/{prompt-2WZQERT4.mjs → prompt-INL55Q2B.mjs} +10 -7
  43. package/dist/lib/neutral/{prompt-2WZQERT4.mjs.map → prompt-INL55Q2B.mjs.map} +3 -3
  44. package/dist/lib/neutral/{qualifier-2AC2ICOB.mjs → qualifier-DAF4H7V3.mjs} +11 -11
  45. package/dist/lib/neutral/qualifier-DAF4H7V3.mjs.map +7 -0
  46. package/dist/lib/neutral/{query-B3NOYFCK.mjs → query-MP5NSQKO.mjs} +3 -4
  47. package/dist/lib/neutral/query-MP5NSQKO.mjs.map +7 -0
  48. package/dist/lib/neutral/{query-blueprints-KXADGHSA.mjs → query-blueprints-PLWYVOI3.mjs} +2 -2
  49. package/dist/lib/neutral/{relation-create-Z3NGW4VU.mjs → relation-create-YAAAFTR2.mjs} +3 -3
  50. package/dist/lib/neutral/{relation-delete-LXY7W2YO.mjs → relation-delete-IEPKERFR.mjs} +2 -2
  51. package/dist/lib/neutral/{schema-add-4TXJO2V7.mjs → schema-add-5BNIINRS.mjs} +2 -2
  52. package/dist/lib/neutral/{schema-list-PJS5AFZ3.mjs → schema-list-54UK7S4R.mjs} +2 -2
  53. package/dist/lib/neutral/{sync-issues-LOLHZNFL.mjs → sync-issues-DWY76B3M.mjs} +6 -7
  54. package/dist/lib/neutral/sync-issues-DWY76B3M.mjs.map +7 -0
  55. package/dist/lib/neutral/{sync-triggers-EYJM4QWR.mjs → sync-triggers-NOIQLELD.mjs} +8 -9
  56. package/dist/lib/neutral/{sync-triggers-EYJM4QWR.mjs.map → sync-triggers-NOIQLELD.mjs.map} +3 -3
  57. package/dist/lib/neutral/{tag-add-5NOHUTIE.mjs → tag-add-NLVRGTC6.mjs} +2 -2
  58. package/dist/lib/neutral/{tag-remove-QTKYDJAW.mjs → tag-remove-N4HFBIA2.mjs} +2 -2
  59. package/dist/lib/neutral/testing/index.mjs +3 -3
  60. package/dist/lib/neutral/testing/index.mjs.map +3 -3
  61. package/dist/lib/neutral/{update-blueprints-N2AK2VUR.mjs → update-blueprints-2SNK6HLG.mjs} +2 -2
  62. package/dist/lib/neutral/update-tasks-QQUR53RN.mjs +13 -0
  63. package/dist/lib/neutral/update-tasks-QQUR53RN.mjs.map +7 -0
  64. package/dist/types/src/blueprints/blueprint-manager/functions/definitions.d.ts +10 -8
  65. package/dist/types/src/blueprints/blueprint-manager/functions/definitions.d.ts.map +1 -1
  66. package/dist/types/src/blueprints/blueprint-manager/functions/enable-blueprints.d.ts +6 -5
  67. package/dist/types/src/blueprints/blueprint-manager/functions/enable-blueprints.d.ts.map +1 -1
  68. package/dist/types/src/blueprints/blueprint-manager/functions/query-blueprints.d.ts +4 -3
  69. package/dist/types/src/blueprints/database/functions/context-add.d.ts +2 -2
  70. package/dist/types/src/blueprints/database/functions/context-add.d.ts.map +1 -1
  71. package/dist/types/src/blueprints/database/functions/context-remove.d.ts +2 -2
  72. package/dist/types/src/blueprints/database/functions/context-remove.d.ts.map +1 -1
  73. package/dist/types/src/blueprints/database/functions/definitions.d.ts +3 -3
  74. package/dist/types/src/blueprints/database/functions/definitions.d.ts.map +1 -1
  75. package/dist/types/src/blueprints/database/functions/query.d.ts +1 -2
  76. package/dist/types/src/blueprints/database/functions/query.d.ts.map +1 -1
  77. package/dist/types/src/blueprints/linear/functions/sync-issues.d.ts.map +1 -1
  78. package/dist/types/src/blueprints/planning/functions/index.d.ts +1 -1
  79. package/dist/types/src/blueprints/planning/functions/index.d.ts.map +1 -1
  80. package/dist/types/src/blueprints/planning/functions/update-tasks.d.ts +14 -1
  81. package/dist/types/src/blueprints/planning/functions/update-tasks.d.ts.map +1 -1
  82. package/dist/types/src/blueprints/planning/functions/update-tasks.test.d.ts +2 -0
  83. package/dist/types/src/blueprints/planning/functions/update-tasks.test.d.ts.map +1 -0
  84. package/dist/types/src/blueprints/project/functions/add-artifact.d.ts +1 -5
  85. package/dist/types/src/blueprints/project/functions/add-artifact.d.ts.map +1 -1
  86. package/dist/types/src/blueprints/project/functions/definitions.d.ts +16 -8
  87. package/dist/types/src/blueprints/project/functions/definitions.d.ts.map +1 -1
  88. package/dist/types/src/blueprints/project/functions/get-context.d.ts +1 -12
  89. package/dist/types/src/blueprints/project/functions/get-context.d.ts.map +1 -1
  90. package/dist/types/src/blueprints/project/functions/qualifier.d.ts +8 -4
  91. package/dist/types/src/blueprints/project/functions/qualifier.d.ts.map +1 -1
  92. package/dist/types/src/blueprints/project-wizard/functions/create-project.d.ts +6 -2
  93. package/dist/types/src/blueprints/project-wizard/functions/definitions.d.ts +12 -4
  94. package/dist/types/src/blueprints/project-wizard/functions/definitions.d.ts.map +1 -1
  95. package/dist/types/src/blueprints/project-wizard/functions/sync-triggers.d.ts +6 -2
  96. package/dist/types/src/blueprints/testing.d.ts +4 -4
  97. package/dist/types/src/blueprints/testing.d.ts.map +1 -1
  98. package/dist/types/src/crud/graph.d.ts +5 -7
  99. package/dist/types/src/crud/graph.d.ts.map +1 -1
  100. package/dist/types/src/functions/agent/definitions.d.ts +6 -5
  101. package/dist/types/src/functions/agent/definitions.d.ts.map +1 -1
  102. package/dist/types/src/sync/sync.d.ts +1 -2
  103. package/dist/types/src/sync/sync.d.ts.map +1 -1
  104. package/dist/types/src/types/Agent.d.ts +9 -7
  105. package/dist/types/src/types/Agent.d.ts.map +1 -1
  106. package/dist/types/src/types/McpServer.d.ts +4 -1
  107. package/dist/types/src/types/McpServer.d.ts.map +1 -1
  108. package/dist/types/src/types/Plan.d.ts.map +1 -1
  109. package/dist/types/tsconfig.tsbuildinfo +1 -1
  110. package/package.json +26 -26
  111. package/src/blueprints/automation/blueprint.ts +1 -1
  112. package/src/blueprints/blueprint-manager/blueprint.conversations.json +1 -1
  113. package/src/blueprints/blueprint-manager/blueprint.test.ts +21 -17
  114. package/src/blueprints/blueprint-manager/blueprint.ts +2 -2
  115. package/src/blueprints/blueprint-manager/functions/definitions.ts +2 -2
  116. package/src/blueprints/blueprint-manager/functions/enable-blueprints.ts +2 -2
  117. package/src/blueprints/browser/blueprint.test.ts +3 -3
  118. package/src/blueprints/browser/blueprint.ts +1 -1
  119. package/src/blueprints/database/blueprint.conversations.json +1 -1
  120. package/src/blueprints/database/blueprint.test.ts +6 -6
  121. package/src/blueprints/database/blueprint.ts +1 -1
  122. package/src/blueprints/database/functions/context-add.ts +2 -2
  123. package/src/blueprints/database/functions/context-remove.ts +2 -2
  124. package/src/blueprints/database/functions/definitions.ts +16 -16
  125. package/src/blueprints/database/functions/query.ts +2 -3
  126. package/src/blueprints/discord/blueprint.ts +1 -1
  127. package/src/blueprints/discord/functions/fetch-messages.test.ts +7 -2
  128. package/src/blueprints/linear/blueprint.ts +1 -1
  129. package/src/blueprints/linear/functions/linear.test.ts +1 -2
  130. package/src/blueprints/linear/functions/sync-issues.ts +1 -2
  131. package/src/blueprints/memory/blueprint.conversations.json +1 -1
  132. package/src/blueprints/memory/blueprint.ts +1 -1
  133. package/src/blueprints/planning/blueprint.ts +1 -1
  134. package/src/blueprints/planning/functions/index.ts +1 -1
  135. package/src/blueprints/planning/functions/{definitions.ts → update-tasks.md} +29 -50
  136. package/src/blueprints/planning/functions/update-tasks.test.ts +55 -0
  137. package/src/blueprints/planning/functions/update-tasks.ts +25 -3
  138. package/src/blueprints/project/blueprint.conversations.json +1 -1
  139. package/src/blueprints/project/blueprint.test.ts +15 -17
  140. package/src/blueprints/project/blueprint.ts +2 -2
  141. package/src/blueprints/project/functions/add-artifact.ts +1 -0
  142. package/src/blueprints/project/functions/agent.ts +1 -1
  143. package/src/blueprints/project/functions/definitions.ts +8 -8
  144. package/src/blueprints/project/functions/get-context.ts +1 -0
  145. package/src/blueprints/project/functions/qualifier.ts +5 -5
  146. package/src/blueprints/project-wizard/functions/sync-triggers.ts +4 -9
  147. package/src/blueprints/testing.ts +10 -4
  148. package/src/blueprints/websearch/blueprint.conversations.json +1 -1
  149. package/src/crud/graph.test.ts +1 -1
  150. package/src/crud/graph.ts +125 -127
  151. package/src/functions/agent/definitions.ts +8 -3
  152. package/src/functions/agent/prompt.conversations.json +1 -1
  153. package/src/functions/agent/prompt.test.ts +8 -11
  154. package/src/functions/agent/prompt.ts +5 -2
  155. package/src/sync/sync.ts +1 -2
  156. package/src/types/Agent.ts +28 -29
  157. package/src/types/McpServer.ts +5 -5
  158. package/src/types/Plan.ts +1 -0
  159. package/dist/lib/neutral/chunk-CLHVRIYF.mjs.map +0 -7
  160. package/dist/lib/neutral/chunk-CVUA23QI.mjs.map +0 -7
  161. package/dist/lib/neutral/chunk-E2XRNXWP.mjs.map +0 -7
  162. package/dist/lib/neutral/chunk-J37DYY7A.mjs.map +0 -7
  163. package/dist/lib/neutral/chunk-KY2TIPJ5.mjs.map +0 -7
  164. package/dist/lib/neutral/chunk-MMTKJBB5.mjs +0 -140
  165. package/dist/lib/neutral/chunk-MMTKJBB5.mjs.map +0 -7
  166. package/dist/lib/neutral/chunk-TO5IX24K.mjs.map +0 -7
  167. package/dist/lib/neutral/context-add-IIDPRRVB.mjs.map +0 -7
  168. package/dist/lib/neutral/context-remove-RDYV4PD4.mjs.map +0 -7
  169. package/dist/lib/neutral/enable-blueprints-LBDZH2CY.mjs.map +0 -7
  170. package/dist/lib/neutral/qualifier-2AC2ICOB.mjs.map +0 -7
  171. package/dist/lib/neutral/query-B3NOYFCK.mjs.map +0 -7
  172. package/dist/lib/neutral/sync-issues-LOLHZNFL.mjs.map +0 -7
  173. package/dist/lib/neutral/update-tasks-ML2FCYU5.mjs +0 -46
  174. package/dist/lib/neutral/update-tasks-ML2FCYU5.mjs.map +0 -7
  175. package/dist/types/src/blueprints/planning/functions/definitions.d.ts +0 -11
  176. package/dist/types/src/blueprints/planning/functions/definitions.d.ts.map +0 -1
  177. /package/dist/lib/neutral/{chunk-D5MG5OKX.mjs.map → chunk-BCT55UTL.mjs.map} +0 -0
  178. /package/dist/lib/neutral/{create-project-GLDEAWTT.mjs.map → create-project-3AGXJ4TD.mjs.map} +0 -0
  179. /package/dist/lib/neutral/{fetch-messages-PWGUG5G3.mjs.map → fetch-messages-QOBBCTGC.mjs.map} +0 -0
  180. /package/dist/lib/neutral/{load-LI7HHVD6.mjs.map → load-GAT3T2AD.mjs.map} +0 -0
  181. /package/dist/lib/neutral/{object-create-52Z7YKIA.mjs.map → object-create-PL3WRP74.mjs.map} +0 -0
  182. /package/dist/lib/neutral/{object-delete-I266YAXI.mjs.map → object-delete-PZJQN5KW.mjs.map} +0 -0
  183. /package/dist/lib/neutral/{object-update-HY4GI7LA.mjs.map → object-update-R43N3VJX.mjs.map} +0 -0
  184. /package/dist/lib/neutral/{project-2YBPW5N7.mjs.map → project-VVXXUMAI.mjs.map} +0 -0
  185. /package/dist/lib/neutral/{project-rules-XUBEPDP6.mjs.map → project-rules-KSVSOZJV.mjs.map} +0 -0
  186. /package/dist/lib/neutral/{query-blueprints-KXADGHSA.mjs.map → query-blueprints-PLWYVOI3.mjs.map} +0 -0
  187. /package/dist/lib/neutral/{relation-create-Z3NGW4VU.mjs.map → relation-create-YAAAFTR2.mjs.map} +0 -0
  188. /package/dist/lib/neutral/{relation-delete-LXY7W2YO.mjs.map → relation-delete-IEPKERFR.mjs.map} +0 -0
  189. /package/dist/lib/neutral/{schema-add-4TXJO2V7.mjs.map → schema-add-5BNIINRS.mjs.map} +0 -0
  190. /package/dist/lib/neutral/{schema-list-PJS5AFZ3.mjs.map → schema-list-54UK7S4R.mjs.map} +0 -0
  191. /package/dist/lib/neutral/{tag-add-5NOHUTIE.mjs.map → tag-add-NLVRGTC6.mjs.map} +0 -0
  192. /package/dist/lib/neutral/{tag-remove-QTKYDJAW.mjs.map → tag-remove-N4HFBIA2.mjs.map} +0 -0
  193. /package/dist/lib/neutral/{update-blueprints-N2AK2VUR.mjs.map → update-blueprints-2SNK6HLG.mjs.map} +0 -0
package/src/crud/graph.ts CHANGED
@@ -11,9 +11,7 @@ import * as Option from 'effect/Option';
11
11
  import * as Schema from 'effect/Schema';
12
12
  import * as SchemaAST from 'effect/SchemaAST';
13
13
 
14
- import { Entity, Filter, Obj, Query, Type } from '@dxos/echo';
15
- import { Database } from '@dxos/echo';
16
- import { type Queue } from '@dxos/echo-db';
14
+ import { Database, Entity, Feed, Filter, Obj, Query, Type } from '@dxos/echo';
17
15
  import { isEncodedReference } from '@dxos/echo-protocol';
18
16
  import {
19
17
  ReferenceAnnotationId,
@@ -26,7 +24,6 @@ import {
26
24
  getTypeIdentifierAnnotation,
27
25
  } from '@dxos/echo/internal';
28
26
  import { mapAst } from '@dxos/effect';
29
- import { ContextQueueService } from '@dxos/functions';
30
27
  import { DXN, ObjectId } from '@dxos/keys';
31
28
  import { log } from '@dxos/log';
32
29
  import { deepMapValues, isNonNullable, trim } from '@dxos/util';
@@ -63,8 +60,8 @@ export const findRelatedSchema = async (db: Database.Database, anchor: Type.AnyE
63
60
  }
64
61
 
65
62
  return (
66
- isSchemaAddressableByDxn(anchor, DXN.parse(getTypeAnnotation(schema)!.sourceSchema!)) ||
67
- isSchemaAddressableByDxn(anchor, DXN.parse(getTypeAnnotation(schema)!.targetSchema!))
63
+ isSchemaAddressableByDXN(anchor, DXN.parse(getTypeAnnotation(schema)!.sourceSchema!)) ||
64
+ isSchemaAddressableByDXN(anchor, DXN.parse(getTypeAnnotation(schema)!.targetSchema!))
68
65
  );
69
66
  })
70
67
  .map(
@@ -79,7 +76,7 @@ export const findRelatedSchema = async (db: Database.Database, anchor: Type.AnyE
79
76
  * Non-strict DXN comparison.
80
77
  * Returns true if the DXN could be resolved to the schema.
81
78
  */
82
- const isSchemaAddressableByDxn = (schema: Type.AnyEntity, dxn: DXN): boolean => {
79
+ const isSchemaAddressableByDXN = (schema: Type.AnyEntity, dxn: DXN): boolean => {
83
80
  if (getTypeIdentifierAnnotation(schema) === dxn.toString()) {
84
81
  return true;
85
82
  }
@@ -106,7 +103,7 @@ export const LocalSearchToolkit = Toolkit.make(
106
103
  },
107
104
  success: Schema.Unknown,
108
105
  failure: Schema.Never,
109
- dependencies: [Database.Service],
106
+ dependencies: [Database.Service, Feed.FeedService],
110
107
  }),
111
108
  );
112
109
 
@@ -115,11 +112,11 @@ export const LocalSearchHandler = LocalSearchToolkit.toLayer({
115
112
  const objects = yield* Database.runQuery(Query.select(Filter.text(query, { type: 'vector' })));
116
113
  const results = [...objects];
117
114
 
118
- const option = yield* Effect.serviceOption(ContextQueueService);
119
- if (Option.isSome(option)) {
120
- const queueObjects = yield* Effect.promise(() => option.value.queue.queryObjects());
121
- // TODO(dmaretskyi): Text search on the queue.
122
- results.push(...queueObjects);
115
+ const feedOption = yield* Effect.serviceOption(Feed.ContextFeedService);
116
+ if (Option.isSome(feedOption)) {
117
+ const feedObjects = yield* Feed.runQuery(feedOption.value.feed, Filter.everything());
118
+ // TODO(dmaretskyi): Text search on the feed.
119
+ results.push(...feedObjects);
123
120
  }
124
121
 
125
122
  return trim`
@@ -150,7 +147,7 @@ export const makeGraphWriterToolkit = ({ schema }: { schema: Type.AnyEntity[] })
150
147
  parameters: createExtractionSchema(schema).fields,
151
148
  success: Schema.Unknown,
152
149
  failure: Schema.Never,
153
- dependencies: [Database.Service, ContextQueueService],
150
+ dependencies: [Database.Service, Feed.ContextFeedService, Feed.FeedService],
154
151
  }).annotateContext(Context.make(GraphWriterSchema, { schema })),
155
152
  );
156
153
  };
@@ -171,9 +168,9 @@ export const makeGraphWriterHandler = (
171
168
  return toolkit.toLayer({
172
169
  graph_writer: Effect.fn(function* (input) {
173
170
  const { db } = yield* Database.Service;
174
- const { queue } = yield* ContextQueueService;
175
- const data = yield* Effect.promise(() => sanitizeObjects(schema, input as any, db, queue));
176
- yield* Effect.promise(() => queue.append(data as Obj.Unknown[]));
171
+ const { feed } = yield* Feed.ContextFeedService;
172
+ const data = yield* sanitizeObjects(schema, input as any, db, feed);
173
+ yield* Feed.append(feed, data as Obj.Unknown[]);
177
174
 
178
175
  const dxns = data.map((obj) => Obj.getDXN(obj));
179
176
  onAppend?.(dxns);
@@ -204,133 +201,134 @@ export const getSanitizedSchemaName = (schema: Type.AnyEntity) => {
204
201
  .type.replaceAll(/[^a-zA-Z0-9]+/g, '_');
205
202
  };
206
203
 
207
- export const sanitizeObjects = async (
204
+ export const sanitizeObjects = (
208
205
  types: Type.AnyEntity[],
209
206
  data: Record<string, readonly unknown[]>,
210
207
  db: Database.Database,
211
- queue?: Queue,
212
- ): Promise<Obj.Unknown[]> => {
213
- const entries = types
214
- .map(
215
- (type) =>
216
- data[`objects_${getSanitizedSchemaName(type)}`]?.map((object: any) => ({
217
- data: object,
218
- schema: type,
219
- })) ?? [],
220
- )
221
- .flat();
222
-
223
- const idMap = new Map<string, string>();
224
- const existingIds = new Set<ObjectId>();
225
- const enitties = new Map<ObjectId, Entity.Unknown>();
226
-
227
- const resolveId = (id: string): DXN | undefined => {
228
- if (ObjectId.isValid(id)) {
229
- existingIds.add(id);
230
- return DXN.fromLocalObjectId(id);
231
- }
208
+ feed?: Feed.Feed,
209
+ ): Effect.Effect<Obj.Unknown[], never, Feed.FeedService> =>
210
+ Effect.gen(function* () {
211
+ const entries = types
212
+ .map(
213
+ (type) =>
214
+ data[`objects_${getSanitizedSchemaName(type)}`]?.map((object: any) => ({
215
+ data: object,
216
+ schema: type,
217
+ })) ?? [],
218
+ )
219
+ .flat();
220
+
221
+ const idMap = new Map<string, string>();
222
+ const existingIds = new Set<ObjectId>();
223
+ const enitties = new Map<ObjectId, Entity.Unknown>();
224
+
225
+ const resolveId = (id: string): DXN | undefined => {
226
+ if (ObjectId.isValid(id)) {
227
+ existingIds.add(id);
228
+ return DXN.fromLocalObjectId(id);
229
+ }
232
230
 
233
- const mappedId = idMap.get(id);
234
- if (mappedId) {
235
- return DXN.fromLocalObjectId(mappedId);
236
- }
231
+ const mappedId = idMap.get(id);
232
+ if (mappedId) {
233
+ return DXN.fromLocalObjectId(mappedId);
234
+ }
237
235
 
238
- return undefined;
239
- };
236
+ return undefined;
237
+ };
240
238
 
241
- const res = entries
242
- .map((entry) => {
243
- // This entry mutates existing object.
244
- if (ObjectId.isValid(entry.data.id)) {
239
+ const res = entries
240
+ .map((entry) => {
241
+ // This entry mutates existing object.
242
+ if (ObjectId.isValid(entry.data.id)) {
243
+ return entry;
244
+ }
245
+
246
+ idMap.set(entry.data.id, ObjectId.random());
247
+ entry.data.id = idMap.get(entry.data.id);
245
248
  return entry;
246
- }
249
+ })
250
+ .map((entry) => {
251
+ const data = deepMapValues(entry.data, (value, recurse) => {
252
+ if (isEncodedReference(value)) {
253
+ const ref = value['/'];
254
+ const id = resolveId(ref);
255
+
256
+ if (id) {
257
+ // Link to an existing object.
258
+ return { '/': id.toString() };
259
+ } else {
260
+ // Search URIs?
261
+ return { '/': `search:?q=${encodeURIComponent(ref)}` };
262
+ }
263
+ }
247
264
 
248
- idMap.set(entry.data.id, ObjectId.random());
249
- entry.data.id = idMap.get(entry.data.id);
250
- return entry;
251
- })
252
- .map((entry) => {
253
- const data = deepMapValues(entry.data, (value, recurse) => {
254
- if (isEncodedReference(value)) {
255
- const ref = value['/'];
256
- const id = resolveId(ref);
257
-
258
- if (id) {
259
- // Link to an existing object.
260
- return { '/': id.toString() };
261
- } else {
262
- // Search URIs?
263
- return { '/': `search:?q=${encodeURIComponent(ref)}` };
265
+ return recurse(value);
266
+ });
267
+
268
+ if (Entity.getKind(entry.schema) === 'relation') {
269
+ const sourceDXN = resolveId(data.source);
270
+ if (!sourceDXN) {
271
+ log.warn('source not found', { source: data.source });
264
272
  }
273
+ const targetDXN = resolveId(data.target);
274
+ if (!targetDXN) {
275
+ log.warn('target not found', { target: data.target });
276
+ }
277
+ delete data.source;
278
+ delete data.target;
279
+ data[RelationSourceDXNId] = sourceDXN;
280
+ data[RelationTargetDXNId] = targetDXN;
265
281
  }
266
282
 
267
- return recurse(value);
268
- });
283
+ return {
284
+ data,
285
+ schema: entry.schema,
286
+ };
287
+ })
288
+ .filter((object) => !existingIds.has(object.data.id)); // TODO(dmaretskyi): This dissallows updating existing objects.
289
+
290
+ // TODO(dmaretskyi): Use ref resolver.
291
+ const dbObjects = yield* Effect.promise(() => db.query(Query.select(Filter.id(...existingIds))).run());
292
+ const feedObjects = feed && existingIds.size > 0 ? yield* Feed.runQuery(feed, Filter.id(...existingIds)) : [];
293
+ const objects = [...dbObjects, ...feedObjects].filter(isNonNullable);
294
+
295
+ // TODO(dmaretskyi): Returns everything if IDs are empty!
296
+ log.info('objects', { dbObjects, feedObjects, existingIds });
297
+ const missing = Array.from(existingIds).filter((id) => !objects.some((object) => object.id === id));
298
+ if (missing.length > 0) {
299
+ throw new Error(`Object IDs do not point to existing objects: ${missing.join(', ')}`);
300
+ }
269
301
 
270
- if (Entity.getKind(entry.schema) === 'relation') {
271
- const sourceDxn = resolveId(data.source);
272
- if (!sourceDxn) {
273
- log.warn('source not found', { source: data.source });
274
- }
275
- const targetDxn = resolveId(data.target);
276
- if (!targetDxn) {
277
- log.warn('target not found', { target: data.target });
302
+ return res.flatMap(({ data, schema }) => {
303
+ let skip = false;
304
+ if (RelationSourceDXNId in data) {
305
+ const id = (data[RelationSourceDXNId] as DXN).asEchoDXN()?.echoId;
306
+ const obj = objects.find((object) => object.id === id) ?? enitties.get(id!);
307
+ if (obj) {
308
+ delete data[RelationSourceDXNId];
309
+ data[RelationSourceId] = obj;
310
+ } else {
311
+ skip = true;
278
312
  }
279
- delete data.source;
280
- delete data.target;
281
- data[RelationSourceDXNId] = sourceDxn;
282
- data[RelationTargetDXNId] = targetDxn;
283
313
  }
284
-
285
- return {
286
- data,
287
- schema: entry.schema,
288
- };
289
- })
290
- .filter((object) => !existingIds.has(object.data.id)); // TODO(dmaretskyi): This dissallows updating existing objects.
291
-
292
- // TODO(dmaretskyi): Use ref resolver.
293
- const dbObjects = await db.query(Query.select(Filter.id(...existingIds))).run();
294
- const queueObjects = (await queue?.getObjectsById([...existingIds])) ?? [];
295
- const objects = [...dbObjects, ...queueObjects].filter(isNonNullable);
296
-
297
- // TODO(dmaretskyi): Returns everything if IDs are empty!
298
- log.info('objects', { dbObjects, queueObjects, existingIds });
299
- const missing = Array.from(existingIds).filter((id) => !objects.some((object) => object.id === id));
300
- if (missing.length > 0) {
301
- throw new Error(`Object IDs do not point to existing objects: ${missing.join(', ')}`);
302
- }
303
-
304
- return res.flatMap(({ data, schema }) => {
305
- let skip = false;
306
- if (RelationSourceDXNId in data) {
307
- const id = (data[RelationSourceDXNId] as DXN).asEchoDXN()?.echoId;
308
- const obj = objects.find((object) => object.id === id) ?? enitties.get(id!);
309
- if (obj) {
310
- delete data[RelationSourceDXNId];
311
- data[RelationSourceId] = obj;
312
- } else {
313
- skip = true;
314
+ if (RelationTargetDXNId in data) {
315
+ const id = (data[RelationTargetDXNId] as DXN).asEchoDXN()?.echoId;
316
+ const obj = objects.find((object) => object.id === id) ?? enitties.get(id!);
317
+ if (obj) {
318
+ delete data[RelationTargetDXNId];
319
+ data[RelationTargetId] = obj;
320
+ } else {
321
+ skip = true;
322
+ }
314
323
  }
315
- }
316
- if (RelationTargetDXNId in data) {
317
- const id = (data[RelationTargetDXNId] as DXN).asEchoDXN()?.echoId;
318
- const obj = objects.find((object) => object.id === id) ?? enitties.get(id!);
319
- if (obj) {
320
- delete data[RelationTargetDXNId];
321
- data[RelationTargetId] = obj;
322
- } else {
323
- skip = true;
324
+ if (!skip) {
325
+ const obj = createObject(schema, data);
326
+ enitties.set(obj.id, obj);
327
+ return [obj];
324
328
  }
325
- }
326
- if (!skip) {
327
- const obj = createObject(schema, data);
328
- enitties.set(obj.id, obj);
329
- return [obj];
330
- }
331
- return [];
329
+ return [];
330
+ });
332
331
  });
333
- };
334
332
 
335
333
  const SoftRef = Schema.Struct({
336
334
  '/': Schema.String,
@@ -7,13 +7,15 @@ import * as Schema from 'effect/Schema';
7
7
  import { AiService, OpaqueToolkit, ModelName } from '@dxos/ai';
8
8
  import { Routine, Trace, Operation, OperationRegistry } from '@dxos/compute';
9
9
  import { Database, Feed, Ref } from '@dxos/echo';
10
+ import { Text } from '@dxos/schema';
10
11
 
11
12
  import * as Chat from '../../types/Chat';
12
13
 
14
+ // TODO(dmaretskyi): Rename to RunRoutine.
13
15
  export const AgentPrompt = Operation.make({
14
16
  meta: {
15
17
  key: 'org.dxos.function.prompt',
16
- name: 'Agent',
18
+ name: 'Run Routine',
17
19
  description: 'Agentic worker that executes a provided prompt using blueprints and tools.',
18
20
  },
19
21
  input: Schema.Struct({
@@ -27,8 +29,8 @@ export const AgentPrompt = Operation.make({
27
29
  /**
28
30
  * @default @anthropic/claude-opus-4-6
29
31
  */
30
-
31
32
  model: Schema.optional(ModelName),
33
+
32
34
  /**
33
35
  * Input object or data.
34
36
  * References get auto-resolved.
@@ -40,6 +42,9 @@ export const AgentPrompt = Operation.make({
40
42
  }),
41
43
  }),
42
44
  output: Schema.Any,
45
+ // ECHO types that the handler loads via Database.load(). Declaring them here ensures the
46
+ // runtime registers their schema before remote invocation (e.g. via the EDGE function service).
47
+ types: [Routine.Routine, Text.Text, Feed.Feed, Chat.Chat],
43
48
  services: [
44
49
  AiService.AiService,
45
50
  Database.Service,
@@ -48,4 +53,4 @@ export const AgentPrompt = Operation.make({
48
53
  OperationRegistry.Service,
49
54
  Trace.TraceService,
50
55
  ],
51
- });
56
+ }).pipe(Operation.intrinsic);
@@ -1 +1 @@
1
- {"conversations":[{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"$id":"/schemas/any","title":"any"},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].","options":{}},{"role":"user","content":"Reply with a single word: ack.\n<input>{}</input>","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01BJnJPY3oMFLFRKBzfm18k4","modelId":"claude-opus-4-6","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user wants me to reply with a single word: \"ack\".","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EvABClkIDRgCKkDoETBa+lesagv7ixB9LGrYHpBYfS/DCnRnegAetRGGWDl0kkFyqVQI7oDc+ZWbyk9tB+4ePqoqNXQXwE3240/HMg9jbGF1ZGUtb3B1cy00LTY4ABIMZ4jEaKNKFseHE6SGGgxDCMKKPXa0JrDQ52ciMG+cUvHgNQwSWMWlYEBfsVvvwZnDif1WmjybXm26QJIGtpnF/4kQQkk8Re1W0OPoYCpFYVSQgk56gj+oWRLRn8FgcWrdoxhpuw6BVArd0/EEeXi78h9AJPLa7BN30HyfNmAOQ5LiuW8fznNPRzCv1yHLrjw4IE+GGAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"tool-params-start","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","name":"completeJob","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","delta":"{\"success\": ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","delta":"\"ack\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":757,"outputTokens":85,"totalTokens":842},"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":757,"output_tokens":60,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"$id":"/schemas/any","title":"any"},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].","options":{}},{"role":"user","content":"Reply with a single word: ack.\n<input>{}</input>","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user wants me to reply with a single word: \"ack\".","options":{}},{"type":"tool-call","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","name":"completeJob","params":{"success":"ack"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01N1FCMswXa62WFdsMrbu4Kv","name":"completeJob","isFailure":false,"result":{},"providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01XmKNsc4F8Re8N5UEDdxcjp","modelId":"claude-opus-4-6","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":824,"outputTokens":2,"totalTokens":826},"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":824,"output_tokens":2,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
1
+ {"conversations":[{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"$id":"/schemas/any","title":"any"},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].","options":{}},{"role":"user","content":"Reply with a single word: ack.\n<input>{}</input>","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_014de59sT4sHe36njza5yiBZ","modelId":"claude-opus-4-6","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" user wants me to reply with a single word \"ack\" and complete the job.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EoQCClkIDRgCKkDmvWuElJmvgQqKv/OM8h45Qm9vFiau8OtHTiKeFGzABfFt5k5Oc9XiWXg1jeCrSXFmAcI3XEaKXp6jF8PCj/O0Mg9jbGF1ZGUtb3B1cy00LTY4ABIM63lszYQjMtcgEi3WGgzpeUSSrp9JhxxUoGsiMFJjapYnuh9y/rE9xW660c0B5Av77wj/bAOfx2vMXoXlHzL0C9O7TlzfgR+zqrw6cipZeF169zGXzr1tdCpD4N9lF1/HvBBieF/jOP7lhN5GXbuxFHatNfix4ocm9beWxWqOQ+WcOXQWJB8lQu+B/mW1y1MXgwTiQi1rf9OhDxtxXoBiIKCSp0aZPBMYAQ=="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"tool-params-start","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","name":"completeJob","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","delta":"{\"success\": ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","delta":"\"a","metadata":{}},{"type":"tool-params-delta","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","delta":"ck\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":757,"outputTokens":89,"totalTokens":846},"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":757,"output_tokens":9,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-6","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"$id":"/schemas/any","title":"any"},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].","options":{}},{"role":"user","content":"Reply with a single word: ack.\n<input>{}</input>","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user wants me to reply with a single word \"ack\" and complete the job.","options":{}},{"type":"tool-call","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","name":"completeJob","params":{"success":"ack"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01Bn2cwnUQYvUCJ4RsL2SSuY","name":"completeJob","isFailure":false,"result":{},"providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01R5VQTdGZLcaSFeVhzNYn6K","modelId":"claude-opus-4-6","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":824,"outputTokens":2,"totalTokens":826},"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":824,"output_tokens":2,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
@@ -5,11 +5,10 @@
5
5
  import { describe, expect, it } from '@effect/vitest';
6
6
  import * as Effect from 'effect/Effect';
7
7
 
8
- import { ContextBinding } from '@dxos/assistant';
8
+ import { AiContext } from '@dxos/assistant';
9
9
  import { Routine, Operation, OperationHandlerSet } from '@dxos/compute';
10
- import { Database, Feed, Obj, Ref } from '@dxos/echo';
10
+ import { Database, Feed, Filter, Obj, Ref } from '@dxos/echo';
11
11
  import { TestHelpers } from '@dxos/effect/testing';
12
- import { QueueService } from '@dxos/functions';
13
12
  import { AssistantTestLayer } from '@dxos/functions-runtime/testing';
14
13
  import { ObjectId } from '@dxos/keys';
15
14
  import { Text } from '@dxos/schema';
@@ -25,13 +24,13 @@ const operationHandlerSet = OperationHandlerSet.make(defaultAgentPrompt);
25
24
 
26
25
  const TestLayer = AssistantTestLayer({
27
26
  operationHandlers: operationHandlerSet,
28
- types: [Chat.Chat, Message.Message, ContextBinding, Text.Text],
27
+ types: [Chat.Chat, Message.Message, AiContext.Binding, Text.Text],
29
28
  aiServicePreset: 'edge-remote',
30
29
  });
31
30
 
32
- const countQueueMessages = (queue: { queryObjects: () => Promise<Obj.Unknown[]> }) =>
33
- Effect.promise(async () => {
34
- const items = await queue.queryObjects();
31
+ const countFeedMessages = (feed: Feed.Feed) =>
32
+ Effect.gen(function* () {
33
+ const items = yield* Feed.runQuery(feed, Filter.everything());
35
34
  return items.filter(Obj.instanceOf(Message.Message)).length;
36
35
  });
37
36
 
@@ -41,9 +40,7 @@ describe('Agent prompt', () => {
41
40
  Effect.fnUntraced(
42
41
  function* (_) {
43
42
  const feed = yield* Database.add(Feed.make());
44
- const queueDxn = Feed.getQueueDxn(feed)!;
45
- const queue = yield* QueueService.getQueue<Message.Message | ContextBinding>(queueDxn);
46
- const messageCountBefore = yield* countQueueMessages(queue);
43
+ const messageCountBefore = yield* countFeedMessages(feed);
47
44
 
48
45
  const chat = yield* Database.add(
49
46
  Chat.make({
@@ -68,7 +65,7 @@ describe('Agent prompt', () => {
68
65
  chat: Ref.make(chat),
69
66
  });
70
67
 
71
- const messageCountAfter = yield* countQueueMessages(queue);
68
+ const messageCountAfter = yield* countFeedMessages(feed);
72
69
 
73
70
  expect(messageCountAfter).toBeGreaterThan(messageCountBefore);
74
71
  expect(result).toBe('ack');
@@ -100,7 +100,7 @@ export default AgentPrompt.pipe(
100
100
  });
101
101
 
102
102
  const runtime = yield* Effect.runtime<Feed.FeedService>();
103
- const session = yield* acquireReleaseResource(() => new AiSession({ feed, runtime }));
103
+ const session = yield* acquireReleaseResource(() => new AiSession.Session({ feed, runtime }));
104
104
 
105
105
  yield* Effect.promise(() =>
106
106
  session.context.bind({
@@ -149,8 +149,11 @@ export default AgentPrompt.pipe(
149
149
  ),
150
150
  );
151
151
  },
152
+ Effect.tapBoth({
153
+ onSuccess: () => Database.flush(),
154
+ onFailure: () => Database.flush(),
155
+ }),
152
156
  Effect.scoped,
153
- Effect.provide(Trace.writerLayerNoop),
154
157
  ),
155
158
  ),
156
159
  Operation.opaqueHandler,
package/src/sync/sync.ts CHANGED
@@ -4,8 +4,7 @@
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
- import { Filter, Obj, Query, Ref } from '@dxos/echo';
8
- import { Database } from '@dxos/echo';
7
+ import { Database, Filter, Obj, Query, Ref } from '@dxos/echo';
9
8
  import { failedInvariant } from '@dxos/invariant';
10
9
  import { log } from '@dxos/log';
11
10
 
@@ -8,16 +8,14 @@ import * as Effect from 'effect/Effect';
8
8
  import * as Function from 'effect/Function';
9
9
  import * as Schema from 'effect/Schema';
10
10
 
11
- import { AiContextBinder, AiContextService } from '@dxos/assistant';
11
+ import { AiContext } from '@dxos/assistant';
12
12
  import { type Blueprint } from '@dxos/compute';
13
13
  import { Annotation, Database, Feed, Format, Obj, Ref, Relation, Type } from '@dxos/echo';
14
- import { Queue } from '@dxos/echo-db';
15
14
  import { type ObjectNotFoundError } from '@dxos/echo/Err';
16
- import { FormInputAnnotation, LabelAnnotation } from '@dxos/echo/internal';
15
+ import { FormInputAnnotation } from '@dxos/echo/internal';
17
16
  import { acquireReleaseResource } from '@dxos/effect';
18
- import { QueueService } from '@dxos/functions';
19
17
  import { invariant } from '@dxos/invariant';
20
- import { QueueAnnotation, Text } from '@dxos/schema';
18
+ import { Text } from '@dxos/schema';
21
19
 
22
20
  import * as Chat from './Chat';
23
21
  import * as Plan from './Plan';
@@ -64,24 +62,29 @@ export const Agent = Schema.Struct({
64
62
  }),
65
63
  ).pipe(FormInputAnnotation.set(false)),
66
64
 
67
- /**
68
- * Input feed for subscriptions.
69
- */
70
- // TODO(burdon): Rename to Feed?
71
- // NOTE: Named `queue` to conform to subscribable schema (see QueueAnnotation).
72
- queue: Schema.optional(Ref.Ref(Queue).pipe(FormInputAnnotation.set(false))),
73
-
74
65
  /**
75
66
  * References to objects with a canonical queue property.
76
67
  * Schema must have the QueueAnnotation.
77
68
  */
69
+ // Change to trigger.
78
70
  // TODO(dmaretskyi): Turn into an array of objects when form-data
79
71
  subscriptions: Schema.Array(Ref.Ref(Obj.Unknown)).pipe(FormInputAnnotation.set(false)),
80
72
 
73
+ /**
74
+ * Cron expression for a timer trigger that invokes the agent worker on a schedule.
75
+ * The timer trigger bypasses the qualifier and goes straight to the agent worker.
76
+ */
77
+ // Change to trigger.
78
+ cron: Schema.optional(Schema.String).annotations({
79
+ title: 'Cron',
80
+ description: 'Cron expression for a timer trigger that invokes the agent on a schedule.',
81
+ }),
82
+
81
83
  /**
82
84
  * Allow the agent to filter events.
83
85
  * Related events will be added to the input queue of the agent.
84
86
  * It is recommended to enable this.
87
+ * @deprecated
85
88
  */
86
89
  filterEvents: Schema.optional(Schema.Boolean).annotations({
87
90
  title: 'Filter events',
@@ -89,20 +92,16 @@ export const Agent = Schema.Struct({
89
92
  }),
90
93
 
91
94
  /**
92
- * Cron expression for a timer trigger that invokes the agent worker on a schedule.
93
- * The timer trigger bypasses the qualifier and goes straight to the agent worker.
95
+ * Input feed for subscriptions.
96
+ * @deprecated Subscriptions will write directly to the agent.
94
97
  */
95
- cron: Schema.optional(Schema.String).annotations({
96
- title: 'Cron',
97
- description: 'Cron expression for a timer trigger that invokes the agent on a schedule.',
98
- }),
98
+ feed: Schema.optional(Ref.Ref(Feed.Feed).pipe(FormInputAnnotation.set(false))),
99
99
  }).pipe(
100
100
  Type.object({
101
101
  typename: 'org.dxos.type.agent',
102
102
  version: '0.1.0',
103
103
  }),
104
- LabelAnnotation.set(['name']),
105
- QueueAnnotation.set(true),
104
+ Annotation.LabelAnnotation.set(['name']),
106
105
  Annotation.IconAnnotation.set({
107
106
  icon: 'ph--drone--regular',
108
107
  hue: 'sky',
@@ -126,11 +125,11 @@ export const makeInitialized = (
126
125
  contextObjects?: Ref.Ref<Obj.Any>[];
127
126
  },
128
127
  blueprint: Blueprint.Blueprint,
129
- ): Effect.Effect<Agent, never, QueueService | Feed.FeedService | Database.Service> =>
128
+ ): Effect.Effect<Agent, never, Feed.FeedService | Database.Service> =>
130
129
  Effect.gen(function* () {
131
130
  const agent = Obj.make(Agent, {
132
131
  ...props,
133
- instructions: Ref.make(Text.make(props.instructions)),
132
+ instructions: Ref.make(Text.make({ content: props.instructions })),
134
133
  plan: Ref.make(Plan.makePlan({ tasks: [] })),
135
134
  artifacts: props.artifacts ?? [],
136
135
  subscriptions: props.subscriptions ?? [],
@@ -140,7 +139,7 @@ export const makeInitialized = (
140
139
  yield* Database.add(agent);
141
140
  const feed = yield* Database.add(Feed.make());
142
141
  const runtime = yield* Effect.runtime<Feed.FeedService>();
143
- const contextBinder = new AiContextBinder({ feed, runtime });
142
+ const contextBinder = new AiContext.Binder({ feed, runtime });
144
143
  // TODO(dmaretskyi): Blueprint registry.
145
144
  const agentBlueprint = yield* Database.add(Obj.clone(blueprint, { deep: true }));
146
145
  yield* Effect.promise(() =>
@@ -163,11 +162,11 @@ export const makeInitialized = (
163
162
  }),
164
163
  );
165
164
 
166
- const inputQueue = yield* QueueService.createQueue();
165
+ const inputFeed = yield* Database.add(Feed.make());
167
166
 
168
167
  Obj.update(agent, (agent) => {
169
168
  agent.chat = Ref.make(chat);
170
- agent.queue = Ref.fromDXN(inputQueue.dxn);
169
+ agent.feed = Ref.make(inputFeed);
171
170
  });
172
171
 
173
172
  return agent;
@@ -193,7 +192,7 @@ export const resetChatHistory = (
193
192
  const runtime = yield* Effect.runtime<Feed.FeedService>();
194
193
  const existingContextBinder = yield* acquireReleaseResource(
195
194
  () =>
196
- new AiContextBinder({
195
+ new AiContext.Binder({
197
196
  feed: existingFeed,
198
197
  runtime,
199
198
  }),
@@ -202,7 +201,7 @@ export const resetChatHistory = (
202
201
  const objects = existingContextBinder.getObjects().map((object) => Ref.make(object));
203
202
 
204
203
  const feed = yield* Database.add(Feed.make());
205
- const contextBinder = new AiContextBinder({ feed, runtime });
204
+ const contextBinder = new AiContext.Binder({ feed, runtime });
206
205
  yield* Effect.promise(() =>
207
206
  contextBinder.bind({
208
207
  blueprints,
@@ -228,8 +227,8 @@ export const resetChatHistory = (
228
227
  );
229
228
  }).pipe(Effect.scoped);
230
229
 
231
- export const getFromChatContext: Effect.Effect<Agent, Error, AiContextService> = Effect.gen(function* () {
232
- const agents = yield* Function.pipe(AiContextService.findObjects(Agent));
230
+ export const getFromChatContext: Effect.Effect<Agent, Error, AiContext.Service> = Effect.gen(function* () {
231
+ const agents = yield* Function.pipe(AiContext.Service.findObjects(Agent));
233
232
  if (agents.length !== 1) {
234
233
  return yield* Effect.fail(new Error(`There should be exactly one agent in context. Got: ${agents.length}`));
235
234
  }