@dxos/assistant 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0

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 (142) hide show
  1. package/README.md +1 -0
  2. package/dist/lib/neutral/chunk-UAWIXKF6.mjs +1875 -0
  3. package/dist/lib/neutral/chunk-UAWIXKF6.mjs.map +7 -0
  4. package/dist/lib/{browser → neutral}/extraction/index.mjs +29 -35
  5. package/dist/lib/neutral/extraction/index.mjs.map +7 -0
  6. package/dist/lib/neutral/index.mjs +551 -0
  7. package/dist/lib/neutral/index.mjs.map +7 -0
  8. package/dist/lib/neutral/meta.json +1 -0
  9. package/dist/lib/neutral/testing/index.mjs +114 -0
  10. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  11. package/dist/types/src/conversation/context.d.ts +116 -64
  12. package/dist/types/src/conversation/context.d.ts.map +1 -1
  13. package/dist/types/src/conversation/context.test.d.ts +2 -0
  14. package/dist/types/src/conversation/context.test.d.ts.map +1 -0
  15. package/dist/types/src/conversation/conversation.d.ts +45 -18
  16. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  17. package/dist/types/src/conversation/conversation.test.d.ts +2 -0
  18. package/dist/types/src/conversation/conversation.test.d.ts.map +1 -0
  19. package/dist/types/src/diff.d.ts +3 -1
  20. package/dist/types/src/diff.d.ts.map +1 -1
  21. package/dist/types/src/errors.d.ts +12 -16
  22. package/dist/types/src/errors.d.ts.map +1 -1
  23. package/dist/types/src/execution-graph.d.ts +2 -2
  24. package/dist/types/src/execution-graph.d.ts.map +1 -1
  25. package/dist/types/src/extraction/extraction-ner-function/index.d.ts +0 -1
  26. package/dist/types/src/extraction/extraction-ner-function/index.d.ts.map +1 -1
  27. package/dist/types/src/extraction/extraction.d.ts +1059 -313
  28. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  29. package/dist/types/src/extraction/index.d.ts +0 -1
  30. package/dist/types/src/extraction/index.d.ts.map +1 -1
  31. package/dist/types/src/extraction/quotes.d.ts +2 -2
  32. package/dist/types/src/extraction/quotes.d.ts.map +1 -1
  33. package/dist/types/src/functions/services.d.ts +28 -9
  34. package/dist/types/src/functions/services.d.ts.map +1 -1
  35. package/dist/types/src/functions.test.d.ts +2 -0
  36. package/dist/types/src/functions.test.d.ts.map +1 -0
  37. package/dist/types/src/index.d.ts +2 -0
  38. package/dist/types/src/index.d.ts.map +1 -1
  39. package/dist/types/src/service/AgentService.d.ts +61 -0
  40. package/dist/types/src/service/AgentService.d.ts.map +1 -0
  41. package/dist/types/src/service/AgentService.test.d.ts +2 -0
  42. package/dist/types/src/service/AgentService.test.d.ts.map +1 -0
  43. package/dist/types/src/service/agent-process.d.ts +17 -0
  44. package/dist/types/src/service/agent-process.d.ts.map +1 -0
  45. package/dist/types/src/service/index.d.ts +3 -0
  46. package/dist/types/src/service/index.d.ts.map +1 -0
  47. package/dist/types/src/session/artifact-diff.d.ts +1 -1
  48. package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
  49. package/dist/types/src/session/format.d.ts +3 -3
  50. package/dist/types/src/session/format.d.ts.map +1 -1
  51. package/dist/types/src/session/index.d.ts +1 -1
  52. package/dist/types/src/session/index.d.ts.map +1 -1
  53. package/dist/types/src/session/observer.d.ts +4 -3
  54. package/dist/types/src/session/observer.d.ts.map +1 -1
  55. package/dist/types/src/session/session.d.ts +72 -11
  56. package/dist/types/src/session/session.d.ts.map +1 -1
  57. package/dist/types/src/session/toolkit.d.ts +9 -6
  58. package/dist/types/src/session/toolkit.d.ts.map +1 -1
  59. package/dist/types/src/session/version-pin.d.ts +2 -2
  60. package/dist/types/src/session/version-pin.d.ts.map +1 -1
  61. package/dist/types/src/templates/system.d.ts +0 -1
  62. package/dist/types/src/templates/system.d.ts.map +1 -1
  63. package/dist/types/src/testing/index.d.ts +2 -0
  64. package/dist/types/src/testing/index.d.ts.map +1 -0
  65. package/dist/types/src/testing/layer.d.ts +35 -0
  66. package/dist/types/src/testing/layer.d.ts.map +1 -0
  67. package/dist/types/src/tracing.d.ts +264 -0
  68. package/dist/types/src/tracing.d.ts.map +1 -0
  69. package/dist/types/src/types/artifact.d.ts +13 -5
  70. package/dist/types/src/types/artifact.d.ts.map +1 -1
  71. package/dist/types/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +42 -33
  73. package/src/conversation/context.test.ts +52 -0
  74. package/src/conversation/context.ts +307 -90
  75. package/src/conversation/conversation.test.ts +58 -0
  76. package/src/conversation/conversation.ts +209 -62
  77. package/src/diff.test.ts +36 -5
  78. package/src/diff.ts +13 -4
  79. package/src/errors.ts +2 -2
  80. package/src/execution-graph.test.ts +3 -3
  81. package/src/execution-graph.ts +6 -6
  82. package/src/extraction/extraction-ner-function/index.ts +0 -1
  83. package/src/extraction/extraction.ts +40 -12
  84. package/src/extraction/index.ts +0 -1
  85. package/src/extraction/quotes.ts +4 -5
  86. package/src/functions/services.ts +217 -50
  87. package/src/functions.conversations.json +1 -0
  88. package/src/functions.test.ts +82 -0
  89. package/src/index.ts +2 -0
  90. package/src/service/AgentService.conversations.json +1 -0
  91. package/src/service/AgentService.test.ts +169 -0
  92. package/src/service/AgentService.ts +165 -0
  93. package/src/service/agent-process.ts +359 -0
  94. package/src/service/index.ts +6 -0
  95. package/src/session/artifact-diff.ts +1 -1
  96. package/src/session/format.test.ts +110 -39
  97. package/src/session/format.ts +12 -14
  98. package/src/session/index.ts +1 -2
  99. package/src/session/observer.ts +4 -1
  100. package/src/session/session.conversations.json +1 -1
  101. package/src/session/session.test.ts +58 -17
  102. package/src/session/session.ts +249 -113
  103. package/src/session/toolkit.ts +21 -25
  104. package/src/session/version-pin.ts +4 -3
  105. package/src/templates/instructions/format.tpl +0 -4
  106. package/src/templates/instructions/system.tpl +11 -2
  107. package/src/templates/system.ts +6 -5
  108. package/src/testing/index.ts +5 -0
  109. package/src/testing/layer.ts +258 -0
  110. package/src/tracing.ts +113 -0
  111. package/src/types/artifact.ts +31 -13
  112. package/dist/lib/browser/extraction/index.mjs.map +0 -7
  113. package/dist/lib/browser/index.mjs +0 -1290
  114. package/dist/lib/browser/index.mjs.map +0 -7
  115. package/dist/lib/browser/meta.json +0 -1
  116. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  117. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  118. package/dist/lib/node-esm/extraction/index.mjs +0 -226
  119. package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
  120. package/dist/lib/node-esm/index.mjs +0 -1291
  121. package/dist/lib/node-esm/index.mjs.map +0 -7
  122. package/dist/lib/node-esm/meta.json +0 -1
  123. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +0 -4
  124. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +0 -1
  125. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +0 -2
  126. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +0 -1
  127. package/dist/types/src/extraction/extraction-llm-function/index.d.ts +0 -2
  128. package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +0 -1
  129. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +0 -345
  130. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +0 -1
  131. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +0 -2
  132. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +0 -1
  133. package/dist/types/src/session/GenericToolkit.d.ts +0 -84
  134. package/dist/types/src/session/GenericToolkit.d.ts.map +0 -1
  135. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +0 -84
  136. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +0 -62
  137. package/src/extraction/extraction-llm-function/index.ts +0 -5
  138. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +0 -116
  139. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +0 -56
  140. package/src/session/GenericToolkit.ts +0 -130
  141. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  142. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
@@ -0,0 +1,1875 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-J5LGTIGS.mjs";
4
+
5
+ // src/conversation/context.ts
6
+ import { Atom, Registry } from "@effect-atom/atom-react";
7
+ import * as EArray from "effect/Array";
8
+ import * as Context from "effect/Context";
9
+ import * as Effect from "effect/Effect";
10
+ import * as Function from "effect/Function";
11
+ import * as Runtime from "effect/Runtime";
12
+ import * as Schema from "effect/Schema";
13
+ import { Blueprint } from "@dxos/blueprints";
14
+ import { Resource } from "@dxos/context";
15
+ import { DXN, Feed, Obj, Query, Ref, Type } from "@dxos/echo";
16
+ import { assertArgument } from "@dxos/invariant";
17
+ import { log } from "@dxos/log";
18
+ import { ComplexSet, isNonNullable } from "@dxos/util";
19
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/assistant/src/conversation/context.ts";
20
+ var ContextBinding = Schema.Struct({
21
+ blueprints: Schema.Struct({
22
+ added: Schema.Array(Ref.Ref(Blueprint.Blueprint)),
23
+ removed: Schema.Array(Ref.Ref(Blueprint.Blueprint))
24
+ }),
25
+ objects: Schema.Struct({
26
+ added: Schema.Array(Ref.Ref(Obj.Unknown)),
27
+ removed: Schema.Array(Ref.Ref(Obj.Unknown))
28
+ })
29
+ }).pipe(Type.object({
30
+ typename: "org.dxos.type.contextBinding",
31
+ version: "0.1.0"
32
+ }));
33
+ var Bindings = class {
34
+ blueprints = new ComplexSet((ref) => ref.dxn.toString());
35
+ // TODO(burdon): Some DXNs have the Space prefix so only compare the object ID.
36
+ objects = new ComplexSet((ref) => ref.dxn.asEchoDXN()?.echoId);
37
+ toJSON() {
38
+ return {
39
+ blueprints: EArray.fromIterable(this.blueprints).map((ref) => ref.dxn.toString()),
40
+ objects: EArray.fromIterable(this.objects).map((ref) => ref.dxn.toString())
41
+ };
42
+ }
43
+ };
44
+ var AiContextBinder = class extends Resource {
45
+ _blueprints = Atom.make([]).pipe(Atom.keepAlive);
46
+ _objects = Atom.make([]).pipe(Atom.keepAlive);
47
+ _registry;
48
+ _feed;
49
+ _runtime;
50
+ #bindingsQuery;
51
+ constructor(options) {
52
+ super();
53
+ assertArgument(options.feed, "options.feed", "Feed is required");
54
+ assertArgument(options.runtime, "options.runtime", "Feed runtime is required");
55
+ this._feed = options.feed;
56
+ this._runtime = options.runtime;
57
+ this._registry = options.registry ?? Registry.make();
58
+ }
59
+ /**
60
+ * Returns the blueprints atom for subscription.
61
+ */
62
+ get blueprints() {
63
+ return this._blueprints;
64
+ }
65
+ /**
66
+ * Returns the objects atom for subscription.
67
+ */
68
+ get objects() {
69
+ return this._objects;
70
+ }
71
+ /**
72
+ * Gets the current blueprints value.
73
+ */
74
+ getBlueprints() {
75
+ return this._registry.get(this._blueprints);
76
+ }
77
+ /**
78
+ * Gets the current objects value.
79
+ */
80
+ getObjects() {
81
+ return this._registry.get(this._objects);
82
+ }
83
+ /**
84
+ * Subscribe to changes in blueprints.
85
+ */
86
+ subscribeBlueprints(cb) {
87
+ return this._registry.subscribe(this._blueprints, () => cb(this._registry.get(this._blueprints)));
88
+ }
89
+ /**
90
+ * Subscribe to changes in objects.
91
+ */
92
+ subscribeObjects(cb) {
93
+ return this._registry.subscribe(this._objects, () => cb(this._registry.get(this._objects)));
94
+ }
95
+ async _open() {
96
+ this.#bindingsQuery = await Runtime.runPromise(this._runtime)(Feed.query(this._feed, Query.type(ContextBinding)));
97
+ const initialResults = await this.#bindingsQuery.run();
98
+ await this._updateBindings(initialResults);
99
+ this._ctx.onDispose(this.#bindingsQuery.subscribe(async () => {
100
+ await this._updateBindings(this.#bindingsQuery.results);
101
+ }));
102
+ }
103
+ /**
104
+ * Re-reads bindings from the feed to pick up changes made by other processes.
105
+ */
106
+ async sync() {
107
+ if (this.#bindingsQuery) {
108
+ const results = await this.#bindingsQuery.run();
109
+ log("sync", {
110
+ bindingItems: results.length
111
+ }, {
112
+ F: __dxlog_file,
113
+ L: 152,
114
+ S: this,
115
+ C: (f, a) => f(...a)
116
+ });
117
+ await this._updateBindings(results);
118
+ log("sync complete", {
119
+ blueprints: this._registry.get(this._blueprints).length,
120
+ blueprintKeys: this._registry.get(this._blueprints).map((bp) => bp.key)
121
+ }, {
122
+ F: __dxlog_file,
123
+ L: 154,
124
+ S: this,
125
+ C: (f, a) => f(...a)
126
+ });
127
+ }
128
+ }
129
+ async _updateBindings(items) {
130
+ if (items.length === 0) {
131
+ return;
132
+ }
133
+ const bindings = this._reduce(items);
134
+ log("_updateBindings", {
135
+ items: items.length,
136
+ blueprintRefs: [
137
+ ...bindings.blueprints
138
+ ].map((ref) => ({
139
+ dxn: ref.dxn.toString(),
140
+ available: ref.isAvailable
141
+ }))
142
+ }, {
143
+ F: __dxlog_file,
144
+ L: 169,
145
+ S: this,
146
+ C: (f, a) => f(...a)
147
+ });
148
+ const currentBlueprints = this._registry.get(this._blueprints);
149
+ const currentObjects = this._registry.get(this._objects);
150
+ const resolvedBlueprints = await this._resolve(bindings.blueprints, currentBlueprints);
151
+ const resolvedObjects = await this._resolve(bindings.objects, currentObjects);
152
+ log("_updateBindings resolved", {
153
+ resolvedBlueprints: resolvedBlueprints.length,
154
+ resolvedBlueprintKeys: resolvedBlueprints.map((bp) => bp.key)
155
+ }, {
156
+ F: __dxlog_file,
157
+ L: 180,
158
+ S: this,
159
+ C: (f, a) => f(...a)
160
+ });
161
+ const reducedBlueprintDxns = new ComplexSet(DXN.hash, [
162
+ ...bindings.blueprints
163
+ ].map((ref) => ref.dxn));
164
+ const reducedObjectDxns = new ComplexSet(DXN.hash, [
165
+ ...bindings.objects
166
+ ].map((ref) => ref.dxn));
167
+ const filteredBlueprints = currentBlueprints.filter((obj) => reducedBlueprintDxns.has(Obj.getDXN(obj)));
168
+ const filteredObjects = currentObjects.filter((obj) => reducedObjectDxns.has(Obj.getDXN(obj)));
169
+ const mergedBlueprints = this._mergeInto(filteredBlueprints, resolvedBlueprints);
170
+ const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);
171
+ this._registry.set(this._blueprints, mergedBlueprints);
172
+ this._registry.set(this._objects, mergedObjects);
173
+ log("updated bindings", {
174
+ blueprints: mergedBlueprints.length,
175
+ objects: mergedObjects.length
176
+ }, {
177
+ F: __dxlog_file,
178
+ L: 203,
179
+ S: this,
180
+ C: (f, a) => f(...a)
181
+ });
182
+ }
183
+ async _close() {
184
+ this._registry.set(this._blueprints, []);
185
+ this._registry.set(this._objects, []);
186
+ }
187
+ async bind({ blueprints, objects }) {
188
+ const currentBlueprints = this._registry.get(this._blueprints);
189
+ const currentObjects = this._registry.get(this._objects);
190
+ const { added: addedBlueprints, next: nextBlueprints } = this._processBindings(blueprints, currentBlueprints);
191
+ const { added: addedObjects, next: nextObjects } = this._processBindings(objects, currentObjects);
192
+ if (!addedBlueprints.length && !addedObjects.length) {
193
+ return;
194
+ }
195
+ this._registry.set(this._blueprints, nextBlueprints);
196
+ this._registry.set(this._objects, nextObjects);
197
+ log("bind", {
198
+ blueprints: addedBlueprints.length,
199
+ objects: addedObjects.length
200
+ }, {
201
+ F: __dxlog_file,
202
+ L: 229,
203
+ S: this,
204
+ C: (f, a) => f(...a)
205
+ });
206
+ await Runtime.runPromise(this._runtime)(Feed.append(this._feed, [
207
+ Obj.make(ContextBinding, {
208
+ blueprints: {
209
+ added: addedBlueprints,
210
+ removed: []
211
+ },
212
+ objects: {
213
+ added: addedObjects,
214
+ removed: []
215
+ }
216
+ })
217
+ ]));
218
+ }
219
+ async unbind({ blueprints, objects }) {
220
+ if (!blueprints?.length && !objects?.length) {
221
+ return;
222
+ }
223
+ const removedBlueprintDxns = (blueprints ?? []).map((ref) => ref.dxn);
224
+ const removedObjectDxns = (objects ?? []).map((ref) => ref.dxn);
225
+ if (removedBlueprintDxns.length > 0) {
226
+ const current = this._registry.get(this._blueprints);
227
+ this._registry.set(this._blueprints, current.filter((obj) => !removedBlueprintDxns.some((dxn) => DXN.equalsEchoId(Obj.getDXN(obj), dxn))));
228
+ }
229
+ if (removedObjectDxns.length > 0) {
230
+ const current = this._registry.get(this._objects);
231
+ this._registry.set(this._objects, current.filter((obj) => !removedObjectDxns.some((dxn) => DXN.equalsEchoId(Obj.getDXN(obj), dxn))));
232
+ }
233
+ log("unbind", {
234
+ blueprints: blueprints?.length,
235
+ objects: objects?.length
236
+ }, {
237
+ F: __dxlog_file,
238
+ L: 269,
239
+ S: this,
240
+ C: (f, a) => f(...a)
241
+ });
242
+ await Runtime.runPromise(this._runtime)(Feed.append(this._feed, [
243
+ Obj.make(ContextBinding, {
244
+ blueprints: {
245
+ added: [],
246
+ removed: blueprints ?? []
247
+ },
248
+ objects: {
249
+ added: [],
250
+ removed: objects ?? []
251
+ }
252
+ })
253
+ ]));
254
+ }
255
+ /**
256
+ * Process bindings to filter duplicates and determine next state.
257
+ */
258
+ _processBindings(refs, current) {
259
+ const next = [
260
+ ...current
261
+ ];
262
+ const added = [];
263
+ if (!refs?.length) {
264
+ return {
265
+ added,
266
+ next
267
+ };
268
+ }
269
+ const seen = new Set(current.map((obj) => Obj.getDXN(obj).toString()));
270
+ for (const ref of refs) {
271
+ const dxn = ref.dxn.toString();
272
+ if (!seen.has(dxn)) {
273
+ seen.add(dxn);
274
+ added.push(ref);
275
+ if (ref.isAvailable) {
276
+ const target = ref.target;
277
+ if (target) {
278
+ next.push(target);
279
+ }
280
+ }
281
+ }
282
+ }
283
+ return {
284
+ added,
285
+ next
286
+ };
287
+ }
288
+ /**
289
+ * Reduce results into sets of blueprints and objects.
290
+ */
291
+ _reduce(items) {
292
+ return Function.pipe(items, EArray.reduce(new Bindings(), (context, { blueprints, objects }) => {
293
+ blueprints.added.forEach((ref) => context.blueprints.add(ref));
294
+ blueprints.removed.forEach((ref) => context.blueprints.delete(ref));
295
+ objects.added.forEach((ref) => context.objects.add(ref));
296
+ objects.removed.forEach((ref) => {
297
+ for (const obj of context.objects) {
298
+ if (DXN.equalsEchoId(obj.dxn, ref.dxn)) {
299
+ context.objects.delete(obj);
300
+ }
301
+ }
302
+ });
303
+ return context;
304
+ }));
305
+ }
306
+ /**
307
+ * Merge resolved items into the current set, adding only items not already present (by DXN).
308
+ */
309
+ _mergeInto(current, resolved) {
310
+ const seen = new Set(current.map((obj) => Obj.getDXN(obj).toString()));
311
+ const merged = [
312
+ ...current
313
+ ];
314
+ for (const obj of resolved) {
315
+ const dxn = Obj.getDXN(obj).toString();
316
+ if (!seen.has(dxn)) {
317
+ seen.add(dxn);
318
+ merged.push(obj);
319
+ }
320
+ }
321
+ return merged;
322
+ }
323
+ /**
324
+ * Resolve references to objects, loading them first if needed and falling back to existing objects.
325
+ */
326
+ async _resolve(refs, current) {
327
+ const refArray = [
328
+ ...refs
329
+ ];
330
+ await Promise.all(refArray.map((ref) => ref.tryLoad()));
331
+ return refArray.map((ref) => {
332
+ let target;
333
+ if (ref.isAvailable) {
334
+ target = ref.target;
335
+ }
336
+ return target ?? current.find((obj) => Obj.getDXN(obj).toString() === ref.dxn.toString());
337
+ }).filter(isNonNullable);
338
+ }
339
+ };
340
+ var AiContextService = class _AiContextService extends Context.Tag("@dxos/assistant/AiContextService")() {
341
+ static bindContext = ({ blueprints, objects }) => Effect.gen(function* () {
342
+ const { binder } = yield* _AiContextService;
343
+ yield* Effect.promise(() => binder.bind({
344
+ blueprints,
345
+ objects
346
+ }));
347
+ });
348
+ static findObjects = (type) => {
349
+ return Effect.gen(function* () {
350
+ const { binder } = yield* _AiContextService;
351
+ return binder.getObjects().filter(Obj.instanceOf(type));
352
+ });
353
+ };
354
+ };
355
+
356
+ // src/session/artifact-diff.ts
357
+ import * as Context2 from "effect/Context";
358
+ var ArtifactDiffResolver = class extends Context2.Tag("@dxos/assistant/ArtifactDiffResolver")() {
359
+ };
360
+
361
+ // src/session/observer.ts
362
+ import * as Effect2 from "effect/Effect";
363
+ import * as Function2 from "effect/Function";
364
+ var GenerationObserver = Object.freeze({
365
+ make: ({ onBegin = Function2.constant(Effect2.void), onPart = Function2.constant(Effect2.void), onBlock = Function2.constant(Effect2.void), onEnd = Function2.constant(Effect2.void), onMessage = Function2.constant(Effect2.void) } = {}) => ({
366
+ onBegin,
367
+ onPart,
368
+ onBlock,
369
+ onEnd,
370
+ onMessage
371
+ }),
372
+ noop: () => GenerationObserver.make(),
373
+ /**
374
+ * Debug printer to be used in unit-tests and browser devtools.
375
+ */
376
+ fromPrinter: (printer) => GenerationObserver.make({
377
+ onBlock: (block) => Effect2.sync(() => {
378
+ if (block.pending) {
379
+ return;
380
+ }
381
+ printer.printContentBlock(block);
382
+ }),
383
+ onMessage: (message) => Effect2.sync(() => {
384
+ if (message.sender.role === "assistant") {
385
+ return;
386
+ }
387
+ printer.printMessage(message);
388
+ })
389
+ })
390
+ });
391
+
392
+ // src/tracing.ts
393
+ import * as Schema2 from "effect/Schema";
394
+ import { Obj as Obj2 } from "@dxos/echo";
395
+ import { Trace } from "@dxos/functions";
396
+ import { ContentBlock, Actor } from "@dxos/types";
397
+ var PartialBlock = Trace.EventType("assistant.partialBlock", {
398
+ schema: Schema2.Struct({
399
+ messageId: Obj2.ID,
400
+ role: Actor.Role,
401
+ block: ContentBlock.Any
402
+ }),
403
+ isEphemeral: true
404
+ });
405
+ var CompleteBlock = Trace.EventType("assistant.completeBlock", {
406
+ schema: Schema2.Struct({
407
+ messageId: Obj2.ID,
408
+ role: Actor.Role,
409
+ block: ContentBlock.Any
410
+ }),
411
+ isEphemeral: false
412
+ });
413
+ var AgentTurnStarted = Trace.EventType("assistant.agentTurnStarted", {
414
+ schema: Schema2.Struct({
415
+ /** Number of history messages. */
416
+ historyLength: Schema2.Number,
417
+ /** Number of pending messages. */
418
+ pendingLength: Schema2.Number,
419
+ /** System prompt length in characters. */
420
+ systemPromptLength: Schema2.Number
421
+ }),
422
+ isEphemeral: false
423
+ });
424
+ var AgentTurnCompleted = Trace.EventType("assistant.agentTurnCompleted", {
425
+ schema: Schema2.Struct({
426
+ /** Number of messages produced in this turn. */
427
+ messageCount: Schema2.Number,
428
+ /** Whether the agent is done (no more tool calls). */
429
+ done: Schema2.Boolean
430
+ }),
431
+ isEphemeral: false
432
+ });
433
+ var ToolCallStarted = Trace.EventType("assistant.toolCallStarted", {
434
+ schema: Schema2.Struct({
435
+ /** Tool name. */
436
+ name: Schema2.String,
437
+ /** Tool call ID. */
438
+ toolCallId: Schema2.String
439
+ }),
440
+ isEphemeral: false
441
+ });
442
+ var ToolCallCompleted = Trace.EventType("assistant.toolCallCompleted", {
443
+ schema: Schema2.Struct({
444
+ /** Tool name. */
445
+ name: Schema2.String,
446
+ /** Tool call ID. */
447
+ toolCallId: Schema2.String,
448
+ /** Whether the tool call resulted in an error. */
449
+ isError: Schema2.Boolean
450
+ }),
451
+ isEphemeral: false
452
+ });
453
+ var AgentInputReceived = Trace.EventType("assistant.agentInputReceived", {
454
+ schema: Schema2.Struct({
455
+ /** Type of input: 'prompt' or 'tool_result'. */
456
+ inputType: Schema2.String,
457
+ /** Length of input content. */
458
+ contentLength: Schema2.Number
459
+ }),
460
+ isEphemeral: false
461
+ });
462
+ var AgentRequestCompleted = Trace.EventType("assistant.agentRequestCompleted", {
463
+ schema: Schema2.Struct({
464
+ /** Number of pending items remaining in queue. */
465
+ pendingItems: Schema2.Number
466
+ }),
467
+ isEphemeral: false
468
+ });
469
+
470
+ // src/errors.ts
471
+ import { BaseError } from "@dxos/errors";
472
+ var AiModelError = class extends BaseError.extend("AiModelError", "AI model error") {
473
+ };
474
+ var AiAssistantError = class extends BaseError.extend("AiAssistantError", "AI assistant error") {
475
+ };
476
+
477
+ // src/session/format.ts
478
+ import * as Effect3 from "effect/Effect";
479
+ import * as Function3 from "effect/Function";
480
+ import * as Option from "effect/Option";
481
+ import { Template } from "@dxos/blueprints";
482
+ import { Obj as Obj3 } from "@dxos/echo";
483
+ import { ObjectVersion } from "@dxos/echo-db";
484
+ import { log as log2 } from "@dxos/log";
485
+ import { Message } from "@dxos/types";
486
+ import { trim } from "@dxos/util";
487
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/assistant/src/session/format.ts";
488
+ var formatSystemPrompt = ({ system, blueprints = [], objects = [] }) => Effect3.gen(function* () {
489
+ const blueprintDefs = yield* Function3.pipe(blueprints, Effect3.forEach((blueprint) => Effect3.succeed(blueprint.instructions)), Effect3.flatMap(Effect3.forEach((template) => Effect3.gen(function* () {
490
+ return trim`
491
+ <blueprint>
492
+ ${yield* Template.processTemplate(template)}
493
+ </blueprint>
494
+ `;
495
+ }))), Effect3.map((blueprints2) => blueprints2.length > 0 ? [
496
+ "## Blueprints Definitions",
497
+ ...blueprints2
498
+ ].join("\n\n") : void 0));
499
+ const objectDefs = yield* Function3.pipe(objects, Effect3.forEach((object) => Effect3.succeed(trim`
500
+ <object>
501
+ <dxn>${Obj3.getDXN(object)}</dxn>
502
+ <typename>${Obj3.getTypename(object)}</typename>
503
+ </object>
504
+ `)), Effect3.map((objects2) => objects2.length > 0 ? [
505
+ "## Context Objects",
506
+ ...objects2
507
+ ].join("\n\n") : void 0));
508
+ return yield* Function3.pipe(Effect3.succeed([
509
+ system,
510
+ blueprintDefs,
511
+ objectDefs
512
+ ].filter((def) => def !== void 0)), Effect3.map((parts) => parts.join("\n\n")));
513
+ });
514
+ var formatUserPrompt = ({ prompt, history = [] }) => Effect3.gen(function* () {
515
+ const blocks = [];
516
+ const artifactDiffResolver = yield* Effect3.serviceOption(ArtifactDiffResolver);
517
+ if (Option.isSome(artifactDiffResolver)) {
518
+ const versions = gatherObjectVersions(history);
519
+ const artifactDiff = yield* Effect3.tryPromise({
520
+ try: () => artifactDiffResolver.value.resolve([
521
+ ...versions.entries()
522
+ ].map(([id, version]) => ({
523
+ id,
524
+ lastVersion: version
525
+ }))),
526
+ catch: AiAssistantError.wrap({
527
+ message: "Artifact diff resolution error"
528
+ })
529
+ });
530
+ log2("version", {
531
+ artifactDiff,
532
+ versions
533
+ }, {
534
+ F: __dxlog_file2,
535
+ L: 93,
536
+ S: this,
537
+ C: (f, a) => f(...a)
538
+ });
539
+ for (const [id, { version }] of [
540
+ ...artifactDiff.entries()
541
+ ]) {
542
+ if (ObjectVersion.equals(version, versions.get(id))) {
543
+ artifactDiff.delete(id);
544
+ continue;
545
+ }
546
+ blocks.push({
547
+ _tag: "anchor",
548
+ objectId: id,
549
+ version
550
+ });
551
+ }
552
+ if (artifactDiff.size > 0) {
553
+ blocks.push(createArtifactUpdateBlock(artifactDiff));
554
+ }
555
+ }
556
+ return Obj3.make(Message.Message, {
557
+ created: (/* @__PURE__ */ new Date()).toISOString(),
558
+ sender: {
559
+ role: "user"
560
+ },
561
+ blocks: [
562
+ ...blocks,
563
+ {
564
+ _tag: "text",
565
+ text: prompt
566
+ }
567
+ ]
568
+ });
569
+ });
570
+ var gatherObjectVersions = (messages) => {
571
+ const artifactIds = /* @__PURE__ */ new Map();
572
+ for (const message of messages) {
573
+ for (const block of message.blocks) {
574
+ if (block._tag === "anchor") {
575
+ artifactIds.set(block.objectId, block.version);
576
+ }
577
+ }
578
+ }
579
+ return artifactIds;
580
+ };
581
+ var createArtifactUpdateBlock = (artifactDiff) => {
582
+ return {
583
+ _tag: "text",
584
+ // TODO(dmaretskyi): Does this need to be a special content-block?
585
+ disposition: "artifact-update",
586
+ text: trim`
587
+ The following artifacts have been updated since the last message:
588
+ ${[
589
+ ...artifactDiff.entries()
590
+ ].map(([id, { diff }]) => `<changed-artifact id="${id}">${diff ? `
591
+ ${diff}` : ""}</changed-artifact>`).join("\n")}
592
+ `
593
+ };
594
+ };
595
+
596
+ // src/session/session.ts
597
+ import * as LanguageModel from "@effect/ai/LanguageModel";
598
+ import * as Array2 from "effect/Array";
599
+ import * as Chunk from "effect/Chunk";
600
+ import * as Effect4 from "effect/Effect";
601
+ import { pipe as pipe3 } from "effect/Function";
602
+ import * as Option2 from "effect/Option";
603
+ import * as Stream from "effect/Stream";
604
+ import { AiParser, AiPreprocessor, AiSummarizer, callTool, withoutToolCallParising } from "@dxos/ai";
605
+ import { Obj as Obj4 } from "@dxos/echo";
606
+ import { Trace as Trace2, TracingService } from "@dxos/functions";
607
+ import { log as log3 } from "@dxos/log";
608
+ import { ContentBlock as ContentBlock2, Message as Message2 } from "@dxos/types";
609
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/assistant/src/session/session.ts";
610
+ var AiSession = class {
611
+ _options;
612
+ /** Prevents concurrent execution of session. */
613
+ _semaphore = Effect4.runSync(Effect4.makeSemaphore(1));
614
+ _observer;
615
+ _onOutput;
616
+ /** Message history from queue. */
617
+ // TODO(burdon): Evolve into supporting a git-like graph of messages.
618
+ _history = [];
619
+ /** Pending messages for this session (incl. the current prompt). */
620
+ _pending = [];
621
+ _started = 0;
622
+ _ended = 0;
623
+ _toolCalls = 0;
624
+ constructor(_options = {}) {
625
+ this._options = _options;
626
+ this._observer = _options.observer ?? GenerationObserver.noop();
627
+ this._onOutput = _options.onOutput ?? (() => Effect4.void);
628
+ }
629
+ get duration() {
630
+ return this._ended - this._started;
631
+ }
632
+ get toolCalls() {
633
+ return this._toolCalls;
634
+ }
635
+ get pending() {
636
+ return this._pending;
637
+ }
638
+ _submitMessage = (message) => Effect4.gen(this, function* () {
639
+ this._pending.push(message);
640
+ yield* this._observer.onMessage(message);
641
+ for (const block of message.blocks) {
642
+ yield* Trace2.write(CompleteBlock, {
643
+ messageId: message.id,
644
+ role: message.sender.role,
645
+ block
646
+ });
647
+ }
648
+ yield* this._onOutput(message);
649
+ return message;
650
+ });
651
+ getToolCalls = () => pipe3([
652
+ ...this._history,
653
+ ...this._pending
654
+ ], Array2.reverse, Array2.takeWhile((_) => _.sender.role === "assistant"), Array2.flatMap((_) => _.blocks.filter(ContentBlock2.is("toolCall")).map((block) => ({
655
+ block,
656
+ message: _
657
+ }))), Array2.filter((_) => !_.block.providerExecuted));
658
+ /**
659
+ * Initialize a session: set up history, perform summarization if needed, and submit the user prompt.
660
+ * Must be called before `runTurn()`.
661
+ */
662
+ begin = ({ prompt, system, history = [], blueprints = [], objects = [] }) => Effect4.gen(this, function* () {
663
+ this._started = Date.now();
664
+ this._history = [
665
+ ...history
666
+ ];
667
+ this._pending = [];
668
+ const systemPrompt = yield* formatSystemPrompt({
669
+ system,
670
+ blueprints,
671
+ objects
672
+ }).pipe(Effect4.orDie);
673
+ if (this._options.summarizationThreshold !== void 0) {
674
+ const tokenCount = yield* AiPreprocessor.estimateTokens(yield* AiPreprocessor.preprocessPrompt([
675
+ ...this._history
676
+ ], {
677
+ system: systemPrompt
678
+ }));
679
+ if (tokenCount > this._options.summarizationThreshold) {
680
+ const summary = yield* AiSummarizer.summarize([
681
+ ...this._history
682
+ ]);
683
+ yield* this._submitMessage(summary);
684
+ }
685
+ }
686
+ yield* this._submitMessage(yield* formatUserPrompt({
687
+ prompt,
688
+ history
689
+ }));
690
+ });
691
+ /**
692
+ * Execute a single turn: one LLM generation followed by tool execution.
693
+ * The toolkit and system prompt can be updated between turns to reflect context changes (e.g. dynamically enabled blueprints).
694
+ */
695
+ runAgentTurn = ({ system, toolkit }) => Effect4.gen(this, function* () {
696
+ log3("request", {
697
+ system: {
698
+ snippet: createSnippet(system),
699
+ length: system.length
700
+ },
701
+ pending: this._pending.length,
702
+ history: this._history.length
703
+ }, {
704
+ F: __dxlog_file3,
705
+ L: 207,
706
+ S: this,
707
+ C: (f, a) => f(...a)
708
+ });
709
+ const prompt = yield* AiPreprocessor.preprocessPrompt([
710
+ ...this._history,
711
+ ...this._pending
712
+ ], {
713
+ system,
714
+ cacheControl: "ephemeral"
715
+ });
716
+ const observer = this._observer;
717
+ let currentMessageId = null;
718
+ const messages = yield* LanguageModel.streamText({
719
+ prompt,
720
+ toolkit,
721
+ disableToolCallResolution: true
722
+ }).pipe(withoutToolCallParising, AiParser.parseResponse({
723
+ emitPartial: true,
724
+ onBegin: () => observer.onBegin(),
725
+ onBlock: (block) => observer.onBlock(block),
726
+ onPart: (part) => observer.onPart(part),
727
+ onEnd: (summary) => observer.onEnd(summary)
728
+ }), Stream.mapEffect((block) => Effect4.gen(this, function* () {
729
+ if (block.pending) {
730
+ currentMessageId ??= Obj4.ID.random();
731
+ log3("emit ephemeral message", {
732
+ id: currentMessageId,
733
+ type: block._tag
734
+ }, {
735
+ F: __dxlog_file3,
736
+ L: 239,
737
+ S: this,
738
+ C: (f, a) => f(...a)
739
+ });
740
+ yield* Trace2.write(PartialBlock, {
741
+ messageId: currentMessageId,
742
+ role: "assistant",
743
+ block
744
+ });
745
+ return Option2.none();
746
+ } else {
747
+ currentMessageId ??= Obj4.ID.random();
748
+ const id = currentMessageId;
749
+ currentMessageId = null;
750
+ log3("emit complete message", {
751
+ id,
752
+ type: block._tag
753
+ }, {
754
+ F: __dxlog_file3,
755
+ L: 250,
756
+ S: this,
757
+ C: (f, a) => f(...a)
758
+ });
759
+ const message = Obj4.make(Message2.Message, {
760
+ id,
761
+ created: (/* @__PURE__ */ new Date()).toISOString(),
762
+ sender: {
763
+ role: "assistant"
764
+ },
765
+ blocks: [
766
+ block
767
+ ]
768
+ });
769
+ return Option2.some(yield* this._submitMessage(message));
770
+ }
771
+ }), {
772
+ concurrency: 1,
773
+ unordered: false
774
+ }), Stream.filterMap((_) => _), Stream.runCollect, Effect4.map(Chunk.toArray));
775
+ const toolCalls = this.getToolCalls();
776
+ if (toolCalls.length === 0) {
777
+ this._ended = Date.now();
778
+ return {
779
+ messages,
780
+ done: true
781
+ };
782
+ } else if (!toolkit) {
783
+ throw new Error("No toolkit provided");
784
+ }
785
+ return {
786
+ messages,
787
+ done: false
788
+ };
789
+ });
790
+ runTools = ({ toolkit }) => Effect4.gen(this, function* () {
791
+ const toolCalls = this.getToolCalls();
792
+ const toolResults = yield* Effect4.forEach(toolCalls, ({ block, message }) => {
793
+ if (!toolkit) {
794
+ throw new Error("No toolkit provided");
795
+ }
796
+ return callTool(toolkit, block).pipe(Effect4.provide(TracingService.layerSubframe((context) => ({
797
+ ...context,
798
+ parentMessage: message.id,
799
+ toolCallId: block.toolCallId
800
+ }))));
801
+ });
802
+ yield* this._submitMessage(Obj4.make(Message2.Message, {
803
+ created: (/* @__PURE__ */ new Date()).toISOString(),
804
+ sender: {
805
+ role: "tool"
806
+ },
807
+ blocks: toolResults
808
+ }));
809
+ this._toolCalls += toolResults.length;
810
+ });
811
+ /**
812
+ * Run a full conversation turn loop. Equivalent to calling `begin()` then `runTurn()` in a loop.
813
+ */
814
+ run = ({ prompt, system: systemTemplate, history = [], objects = [], blueprints = [], toolkit }) => Effect4.gen(this, function* () {
815
+ yield* this.begin({
816
+ prompt,
817
+ system: systemTemplate,
818
+ history,
819
+ objects,
820
+ blueprints
821
+ });
822
+ const system = yield* formatSystemPrompt({
823
+ system: systemTemplate,
824
+ blueprints,
825
+ objects
826
+ }).pipe(Effect4.orDie);
827
+ do {
828
+ const { done } = yield* this.runAgentTurn({
829
+ system,
830
+ toolkit
831
+ });
832
+ if (done) {
833
+ break;
834
+ }
835
+ yield* this.runTools({
836
+ toolkit
837
+ });
838
+ } while (true);
839
+ log3("done", {
840
+ pending: this._pending.length,
841
+ duration: this.duration,
842
+ tools: this._toolCalls
843
+ }, {
844
+ F: __dxlog_file3,
845
+ L: 334,
846
+ S: this,
847
+ C: (f, a) => f(...a)
848
+ });
849
+ return this._pending;
850
+ }).pipe(this._semaphore.withPermits(1), Effect4.withSpan("AiSession.run"));
851
+ };
852
+ var createSnippet = (text, len = 32) => text.length <= len * 2 ? text : [
853
+ text.slice(0, len),
854
+ "...",
855
+ text.slice(-len)
856
+ ].join("");
857
+
858
+ // src/session/toolkit.ts
859
+ import * as Toolkit from "@effect/ai/Toolkit";
860
+ import * as Effect5 from "effect/Effect";
861
+ import { GenericToolkit, ToolExecutionService, ToolResolverService } from "@dxos/ai";
862
+ import { isTruthy } from "@dxos/util";
863
+ var createToolkit = ({ toolkit: toolkitProp, blueprints = [], genericToolkits = [] }) => Effect5.gen(function* () {
864
+ const blueprintToolkit = yield* ToolResolverService.resolveToolkit(blueprints.flatMap(({ tools }) => tools));
865
+ const blueprintToolHandler = yield* blueprintToolkit.toContext(ToolExecutionService.handlersFor(blueprintToolkit));
866
+ const genericToolkit = GenericToolkit.merge(...genericToolkits);
867
+ const toolkit = Toolkit.merge(...[
868
+ toolkitProp,
869
+ blueprintToolkit,
870
+ genericToolkit.toolkit
871
+ ].filter(isTruthy));
872
+ return yield* toolkit.pipe(Effect5.provide(blueprintToolHandler), Effect5.provide(genericToolkit.layer));
873
+ });
874
+
875
+ // src/session/version-pin.ts
876
+ import * as Schema3 from "effect/Schema";
877
+ import { getVersion } from "@dxos/echo-db";
878
+ import { ObjectId } from "@dxos/keys";
879
+ var ObjectVersionSchema = Schema3.Unknown;
880
+ var VersionPinSchema = Schema3.Struct({
881
+ // TODO(dmaretskyi): Use Ref when those support encoding.
882
+ objectId: ObjectId,
883
+ // TODO(dmaretskyi): Could be opaque.
884
+ version: ObjectVersionSchema
885
+ });
886
+ var VersionPin = class extends VersionPinSchema {
887
+ static DISPOSITION = "version-pin";
888
+ static fromObject(object) {
889
+ return VersionPin.make({
890
+ objectId: object.id,
891
+ version: getVersion(object)
892
+ });
893
+ }
894
+ static createBlock(pin) {
895
+ return {
896
+ _tag: "json",
897
+ disposition: VersionPin.DISPOSITION,
898
+ data: JSON.stringify(pin)
899
+ };
900
+ }
901
+ };
902
+
903
+ // src/conversation/conversation.ts
904
+ import * as Array3 from "effect/Array";
905
+ import * as Context3 from "effect/Context";
906
+ import * as Effect6 from "effect/Effect";
907
+ import * as Either from "effect/Either";
908
+ import { pipe as pipe4 } from "effect/Function";
909
+ import * as Layer from "effect/Layer";
910
+ import * as Record from "effect/Record";
911
+ import * as Runtime2 from "effect/Runtime";
912
+ import { Resource as Resource2 } from "@dxos/context";
913
+ import { Database, Feed as Feed2, Filter, Obj as Obj5 } from "@dxos/echo";
914
+ import { acquireReleaseResource } from "@dxos/effect";
915
+ import { invariant } from "@dxos/invariant";
916
+ import { log as log4 } from "@dxos/log";
917
+ import { McpToolkit } from "@dxos/mcp-client";
918
+ import { Message as Message3 } from "@dxos/types";
919
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/core/assistant/src/conversation/conversation.ts";
920
+ var SUMMARY_THRESHOLD = 8e4;
921
+ var AiConversation = class extends Resource2 {
922
+ /**
923
+ * Blueprints and objects bound to the conversation.
924
+ */
925
+ _binder;
926
+ _feed;
927
+ _runtime;
928
+ _toolkit;
929
+ constructor(options) {
930
+ super();
931
+ this._feed = options.feed;
932
+ this._runtime = options.runtime;
933
+ invariant(this._feed, void 0, {
934
+ F: __dxlog_file4,
935
+ L: 74,
936
+ S: this,
937
+ A: [
938
+ "this._feed",
939
+ ""
940
+ ]
941
+ });
942
+ invariant(this._runtime, void 0, {
943
+ F: __dxlog_file4,
944
+ L: 75,
945
+ S: this,
946
+ A: [
947
+ "this._runtime",
948
+ ""
949
+ ]
950
+ });
951
+ this._binder = new AiContextBinder({
952
+ feed: this._feed,
953
+ runtime: this._runtime,
954
+ registry: options.registry
955
+ });
956
+ }
957
+ async _open() {
958
+ await this._binder.open(this._ctx);
959
+ }
960
+ get feed() {
961
+ return this._feed;
962
+ }
963
+ get context() {
964
+ return this._binder;
965
+ }
966
+ get toolkit() {
967
+ return this._toolkit;
968
+ }
969
+ async getHistory() {
970
+ const queryResult = await Runtime2.runPromise(this._runtime)(Feed2.query(this._feed, Filter.type(Message3.Message)));
971
+ const items = await queryResult.run();
972
+ return items.filter(Obj5.instanceOf(Message3.Message));
973
+ }
974
+ getTools() {
975
+ return Effect6.gen(this, function* () {
976
+ const blueprints = this.context.getBlueprints();
977
+ const tookit = yield* createToolkit({
978
+ toolkit: this._toolkit,
979
+ blueprints
980
+ });
981
+ return tookit.tools;
982
+ }).pipe(Effect6.orDie);
983
+ }
984
+ /**
985
+ * Creates a new cancelable request effect.
986
+ */
987
+ createRequest(params) {
988
+ return Effect6.gen(this, function* () {
989
+ const history = yield* Effect6.promise(() => this.getHistory());
990
+ const blueprints = this.context.getBlueprints();
991
+ const objects = this.context.getObjects();
992
+ log4("run", {
993
+ history: history.length,
994
+ blueprints: blueprints.length,
995
+ objects: objects.length
996
+ }, {
997
+ F: __dxlog_file4,
998
+ L: 120,
999
+ S: this,
1000
+ C: (f, a) => f(...a)
1001
+ });
1002
+ const session = new AiSession({
1003
+ summarizationThreshold: SUMMARY_THRESHOLD,
1004
+ observer: params.observer,
1005
+ onOutput: (message) => Effect6.promise(() => Runtime2.runPromise(this._runtime)(Feed2.append(this._feed, [
1006
+ message
1007
+ ])))
1008
+ });
1009
+ yield* session.begin({
1010
+ history,
1011
+ blueprints,
1012
+ objects,
1013
+ prompt: params.prompt,
1014
+ system: params.system
1015
+ });
1016
+ do {
1017
+ yield* Effect6.promise(() => this.context.sync());
1018
+ const currentBlueprints = this.context.getBlueprints();
1019
+ const mcps = yield* connectMcpServers(currentBlueprints);
1020
+ const toolkit = yield* createToolkit({
1021
+ toolkit: params.toolkit,
1022
+ blueprints: currentBlueprints,
1023
+ genericToolkits: mcps
1024
+ });
1025
+ log4("toolkit", {
1026
+ tools: Record.keys(toolkit.tools)
1027
+ }, {
1028
+ F: __dxlog_file4,
1029
+ L: 151,
1030
+ S: this,
1031
+ C: (f, a) => f(...a)
1032
+ });
1033
+ const system = yield* formatSystemPrompt({
1034
+ system: params.system,
1035
+ blueprints: currentBlueprints,
1036
+ objects: this.context.getObjects()
1037
+ }).pipe(Effect6.orDie);
1038
+ const { done } = yield* session.runAgentTurn({
1039
+ system,
1040
+ toolkit
1041
+ });
1042
+ if (done) {
1043
+ break;
1044
+ }
1045
+ yield* session.runTools({
1046
+ toolkit
1047
+ });
1048
+ } while (true);
1049
+ log4("result", {
1050
+ messages: session.pending.length,
1051
+ duration: session.duration,
1052
+ toolCalls: session.toolCalls
1053
+ }, {
1054
+ F: __dxlog_file4,
1055
+ L: 170,
1056
+ S: this,
1057
+ C: (f, a) => f(...a)
1058
+ });
1059
+ return [
1060
+ ...session.pending
1061
+ ];
1062
+ }).pipe(Effect6.provide(Layer.mergeAll(Layer.succeed(AiContextService, {
1063
+ binder: this.context
1064
+ }), Layer.succeed(AiConversationService, this))));
1065
+ }
1066
+ };
1067
+ var AiConversationService = class _AiConversationService extends Context3.Tag("@dxos/assistant/AiConversationService")() {
1068
+ /**
1069
+ * Create a new conversation layer from options.
1070
+ */
1071
+ static layer = (options) => aiContextFromConversation.pipe(Layer.provideMerge(Layer.scoped(_AiConversationService, Effect6.gen(function* () {
1072
+ const conversation = yield* acquireReleaseResource(() => new AiConversation(options));
1073
+ return conversation;
1074
+ }))));
1075
+ /**
1076
+ * Create a new conversation with a new feed.
1077
+ */
1078
+ static layerNewFeed = (options) => Layer.unwrapScoped(Effect6.gen(function* () {
1079
+ const feed = Feed2.make();
1080
+ yield* Database.add(feed);
1081
+ const runtime4 = yield* Effect6.runtime();
1082
+ return _AiConversationService.layer({
1083
+ ...options,
1084
+ feed,
1085
+ runtime: runtime4
1086
+ });
1087
+ }));
1088
+ /**
1089
+ * Run a prompt in the current conversation.
1090
+ */
1091
+ static run = (params) => Effect6.gen(function* () {
1092
+ const conversation = yield* _AiConversationService;
1093
+ return yield* conversation.createRequest(params);
1094
+ });
1095
+ };
1096
+ var aiContextFromConversation = Layer.effect(AiContextService, Effect6.gen(function* () {
1097
+ const conversation = yield* AiConversationService;
1098
+ return {
1099
+ binder: conversation.context
1100
+ };
1101
+ }));
1102
+ var connectMcpServers = (blueprints) => pipe4(blueprints, Array3.flatMap((_) => _.mcpServers ?? []), Effect6.forEach(({ url, protocol }) => McpToolkit.make({
1103
+ url,
1104
+ kind: protocol
1105
+ }).pipe(
1106
+ // NOTE: Type-inference fails here without explicit void return.
1107
+ Effect6.tap((toolkit) => log4.info("Connected to MCP server", {
1108
+ url,
1109
+ tools: Object.keys(toolkit.toolkit.tools).length
1110
+ }, {
1111
+ F: __dxlog_file4,
1112
+ L: 268,
1113
+ S: void 0,
1114
+ C: (f, a) => f(...a)
1115
+ })),
1116
+ Effect6.tapDefect((error) => Effect6.sync(() => log4.warn("Failed to connect to MCP server", {
1117
+ error
1118
+ }, {
1119
+ F: __dxlog_file4,
1120
+ L: 270,
1121
+ S: void 0,
1122
+ C: (f, a) => f(...a)
1123
+ }))),
1124
+ Effect6.either
1125
+ )), Effect6.map(Array3.filterMap((_) => Either.getRight(_))));
1126
+
1127
+ // src/types/artifact.ts
1128
+ import * as Schema4 from "effect/Schema";
1129
+ import { Obj as Obj6, Ref as Ref2 } from "@dxos/echo";
1130
+ import { Database as Database2 } from "@dxos/echo";
1131
+ import { EncodedReference } from "@dxos/echo-protocol";
1132
+ import { DXN as DXN2, LOCAL_SPACE_TAG } from "@dxos/keys";
1133
+ import { trim as trim2 } from "@dxos/util";
1134
+ var createArtifactElement = (id) => `<artifact id=${id} />`;
1135
+ var ArtifactId = class extends Schema4.String.annotations({
1136
+ // TODO(dmaretskyi): This section gets overriden.
1137
+ description: trim2`
1138
+ The ID of the referenced object. Formats accepted:
1139
+ - DXN (dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4). DXNs can be prepended with an @ symbol for compatibility with in-text references.
1140
+ - space ID, object ID tuple (spaceID:objectID)
1141
+ - Only object ID that is assumed to be in the current space (01KG7R1ZXWFMWQ4DA1Q6TN1DG4)
1142
+ `,
1143
+ examples: [
1144
+ "dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4",
1145
+ "@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4",
1146
+ "BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4",
1147
+ "01KG7R1ZXWFMWQ4DA1Q6TN1DG4"
1148
+ ]
1149
+ }) {
1150
+ static toDXN(reference, owningSpaceId) {
1151
+ if (reference.startsWith("@dxn:")) {
1152
+ return DXN2.parse(reference.slice(1));
1153
+ } else if (reference.startsWith("dxn:")) {
1154
+ return DXN2.parse(reference);
1155
+ } else if (/^[A-Z0-9]+:[A-Z0-9]+$/.test(reference)) {
1156
+ const [spaceId, objectId] = reference.split(":");
1157
+ return new DXN2(DXN2.kind.ECHO, [
1158
+ spaceId === owningSpaceId ? LOCAL_SPACE_TAG : spaceId,
1159
+ objectId
1160
+ ]);
1161
+ } else if (/^[A-Z0-9]+$/.test(reference)) {
1162
+ return DXN2.fromLocalObjectId(reference);
1163
+ } else {
1164
+ throw new Error(`Unable to parse object reference: ${reference}`);
1165
+ }
1166
+ }
1167
+ /**
1168
+ * Resolves an artifact ID to an object.
1169
+ */
1170
+ static resolve(schema, ref) {
1171
+ const dxn = ArtifactId.toDXN(ref);
1172
+ return Database2.resolve(dxn, schema);
1173
+ }
1174
+ };
1175
+ var RefFromLLM = Schema4.transform(ArtifactId, Ref2.Ref(Obj6.Unknown), {
1176
+ decode: (fromA, fromI) => EncodedReference.fromDXN(ArtifactId.toDXN(fromA)),
1177
+ encode: (toI, toA) => EncodedReference.toDXN(toI).toString(),
1178
+ strict: false
1179
+ }).annotations({
1180
+ description: ArtifactId.ast.annotations.description
1181
+ });
1182
+
1183
+ // src/functions/services.ts
1184
+ import * as Tool from "@effect/ai/Tool";
1185
+ import * as Context4 from "effect/Context";
1186
+ import * as Effect7 from "effect/Effect";
1187
+ import * as Layer2 from "effect/Layer";
1188
+ import * as Option3 from "effect/Option";
1189
+ import * as Record2 from "effect/Record";
1190
+ import * as Schema5 from "effect/Schema";
1191
+ import * as SchemaAST from "effect/SchemaAST";
1192
+ import { AiToolNotFoundError, ToolExecutionService as ToolExecutionService2, ToolResolverService as ToolResolverService2 } from "@dxos/ai";
1193
+ import { GenericToolkit as GenericToolkit2 } from "@dxos/ai";
1194
+ import { todo } from "@dxos/debug";
1195
+ import { Ref as Ref3 } from "@dxos/echo";
1196
+ import { FunctionInvocationService, FunctionNotFoundError } from "@dxos/functions";
1197
+ import { invariant as invariant2 } from "@dxos/invariant";
1198
+ import { Operation, OperationRegistry } from "@dxos/operation";
1199
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/core/assistant/src/functions/services.ts";
1200
+ var makeToolResolverFromFunctions = () => {
1201
+ return Layer2.effect(ToolResolverService2, Effect7.gen(function* () {
1202
+ const toolkitProvider = yield* GenericToolkit2.GenericToolkitProvider;
1203
+ const functionInvocationService = yield* FunctionInvocationService;
1204
+ return {
1205
+ resolve: (id) => Effect7.gen(function* () {
1206
+ const toolkit = toolkitProvider.getToolkit();
1207
+ const tool = toolkit.toolkit.tools[id];
1208
+ if (tool) {
1209
+ return tool;
1210
+ }
1211
+ return yield* functionInvocationService.resolveFunction(id).pipe(Effect7.map(projectFunctionToTool), Effect7.catchTag("FunctionNotFound", () => Effect7.fail(new AiToolNotFoundError(id))));
1212
+ })
1213
+ };
1214
+ }));
1215
+ };
1216
+ var makeToolExecutionServiceFromFunctions = () => {
1217
+ return Layer2.effect(ToolExecutionService2, Effect7.gen(function* () {
1218
+ const toolkitProvider = yield* GenericToolkit2.GenericToolkitProvider;
1219
+ const toolkit = toolkitProvider.getToolkit();
1220
+ const toolkitHandler = yield* toolkit.toolkit.pipe(Effect7.provide(toolkit.layer));
1221
+ invariant2(isHandlerLike(toolkitHandler), void 0, {
1222
+ F: __dxlog_file5,
1223
+ L: 82,
1224
+ S: this,
1225
+ A: [
1226
+ "isHandlerLike(toolkitHandler)",
1227
+ ""
1228
+ ]
1229
+ });
1230
+ const functionInvocationService = yield* FunctionInvocationService;
1231
+ return {
1232
+ handlersFor: (toolkit2) => {
1233
+ const makeHandler = (tool) => {
1234
+ return Effect7.fn(`toolFunctionHandler ${tool.name}`)(function* (input) {
1235
+ if (toolkitHandler.tools[tool.name]) {
1236
+ if (Tool.isProviderDefined(tool)) {
1237
+ throw new Error("Attempted to call a provider-defined tool");
1238
+ }
1239
+ const { result } = yield* toolkitHandler.handle(tool.name, input);
1240
+ return result;
1241
+ }
1242
+ const functionDef = getOperationFromTool(tool).pipe(Option3.getOrThrow);
1243
+ return yield* functionInvocationService.invokeFunction(functionDef, input).pipe(Effect7.catchAllDefect((defect) => Effect7.fail(defect)));
1244
+ });
1245
+ };
1246
+ return toolkit2.of(Record2.map(toolkit2.tools, (tool, _name) => Tool.isUserDefined(tool) ? makeHandler(tool) : null));
1247
+ }
1248
+ };
1249
+ }));
1250
+ };
1251
+ var makeToolResolverFromOperations = ({ toolkit: extraToolkit = GenericToolkit2.empty } = {}) => {
1252
+ return Layer2.effect(ToolResolverService2, Effect7.gen(function* () {
1253
+ const toolkitProvider = yield* GenericToolkit2.GenericToolkitProvider;
1254
+ const operationRegistry = yield* OperationRegistry.Service;
1255
+ return {
1256
+ resolve: (id) => Effect7.gen(function* () {
1257
+ const toolkit = GenericToolkit2.merge(extraToolkit, toolkitProvider.getToolkit());
1258
+ const tool = toolkit.toolkit.tools[id];
1259
+ if (tool) {
1260
+ return tool;
1261
+ }
1262
+ return yield* operationRegistry.resolve(id).pipe(Effect7.flatMap(Option3.match({
1263
+ onSome: (_) => Effect7.succeed(projectFunctionToTool(_)),
1264
+ onNone: () => Effect7.fail(new AiToolNotFoundError(id))
1265
+ })));
1266
+ })
1267
+ };
1268
+ }));
1269
+ };
1270
+ var makeToolExecutionService = (opts) => Layer2.effect(ToolExecutionService2, Effect7.gen(function* () {
1271
+ const toolkitProvider = yield* GenericToolkit2.GenericToolkitProvider;
1272
+ const toolkit = toolkitProvider.getToolkit();
1273
+ const toolkitHandler = yield* toolkit.toolkit.pipe(Effect7.provide(toolkit.layer));
1274
+ invariant2(isHandlerLike(toolkitHandler), void 0, {
1275
+ F: __dxlog_file5,
1276
+ L: 162,
1277
+ S: this,
1278
+ A: [
1279
+ "isHandlerLike(toolkitHandler)",
1280
+ ""
1281
+ ]
1282
+ });
1283
+ return {
1284
+ handlersFor: (toolkit2) => {
1285
+ const makeHandler = (tool) => {
1286
+ return Effect7.fn(`toolFunctionHandler ${tool.name}`)(function* (input) {
1287
+ if (toolkitHandler.tools[tool.name]) {
1288
+ if (Tool.isProviderDefined(tool)) {
1289
+ throw new Error("Attempted to call a provider-defined tool");
1290
+ }
1291
+ const { result } = yield* toolkitHandler.handle(tool.name, input);
1292
+ return result;
1293
+ }
1294
+ return yield* opts.invoke(tool, input).pipe(Effect7.catchAllDefect((defect) => Effect7.fail(defect)));
1295
+ });
1296
+ };
1297
+ return toolkit2.of(Record2.map(toolkit2.tools, (tool, _name) => Tool.isUserDefined(tool) ? makeHandler(tool) : null));
1298
+ }
1299
+ };
1300
+ }));
1301
+ var makeToolExecutionServiceFromOperationInvoker = () => {
1302
+ return Layer2.unwrapEffect(Effect7.gen(function* () {
1303
+ const operationInvoker = yield* Operation.Service;
1304
+ return makeToolExecutionService({
1305
+ invoke: (tool, input) => Effect7.gen(function* () {
1306
+ const operationDef = getOperationFromTool(tool).pipe(Option3.getOrThrow);
1307
+ return yield* operationInvoker.invoke(operationDef, input).pipe(Effect7.orDie);
1308
+ })
1309
+ });
1310
+ }));
1311
+ };
1312
+ var functionInvocationServiceFromOperations = Layer2.effect(FunctionInvocationService, Effect7.gen(function* () {
1313
+ const operationRegistry = yield* OperationRegistry.Service;
1314
+ const operationInvoker = yield* Operation.Service;
1315
+ return {
1316
+ invokeFunction: (operationDef, input) => operationInvoker.invoke(operationDef, input).pipe(Effect7.orDie),
1317
+ resolveFunction: (key) => operationRegistry.resolve(key).pipe(Effect7.flatten, Effect7.catchTag("NoSuchElementException", () => Effect7.fail(new FunctionNotFoundError(key))))
1318
+ };
1319
+ }));
1320
+ var ToolExecutionServices = Layer2.mergeAll(makeToolResolverFromFunctions(), makeToolExecutionServiceFromFunctions());
1321
+ var FunctionToolAnnotation = class extends Context4.Tag("@dxos/assistant/FunctionToolAnnotation")() {
1322
+ };
1323
+ var getOperationFromTool = (tool) => {
1324
+ return Context4.getOption(FunctionToolAnnotation)(tool.annotations).pipe(Option3.map(({ definition }) => definition));
1325
+ };
1326
+ var toolCache = /* @__PURE__ */ new WeakMap();
1327
+ var projectFunctionToTool = (fn3) => {
1328
+ if (toolCache.has(fn3)) {
1329
+ return toolCache.get(fn3);
1330
+ }
1331
+ const tool = Tool.make(makeToolName(fn3.meta.name ?? fn3.meta.key), {
1332
+ description: fn3.meta.description,
1333
+ parameters: createStructFieldsFromSchema(fn3.input),
1334
+ failure: Schema5.Any
1335
+ }).annotate(FunctionToolAnnotation, {
1336
+ definition: fn3
1337
+ });
1338
+ toolCache.set(fn3, tool);
1339
+ return tool;
1340
+ };
1341
+ var makeToolName = (name) => {
1342
+ const toolName = name.toLowerCase().replace(/[^a-zA-Z0-9]/g, "-");
1343
+ invariant2(toolName.match(/^[a-z_][a-z0-9-_]*$/), void 0, {
1344
+ F: __dxlog_file5,
1345
+ L: 272,
1346
+ S: void 0,
1347
+ A: [
1348
+ "toolName.match(/^[a-z_][a-z0-9-_]*$/)",
1349
+ ""
1350
+ ]
1351
+ });
1352
+ return toolName;
1353
+ };
1354
+ var createStructFieldsFromSchema = (schema) => {
1355
+ switch (schema.ast._tag) {
1356
+ case "TypeLiteral":
1357
+ return Object.fromEntries(schema.ast.propertySignatures.map((prop) => [
1358
+ prop.name,
1359
+ Schema5.make(mapSchemaTypeForLLM(prop.type))
1360
+ ]));
1361
+ case "VoidKeyword":
1362
+ return {};
1363
+ default:
1364
+ return todo(`Unsupported schema AST: ${schema.ast._tag}`);
1365
+ }
1366
+ };
1367
+ var mapSchemaTypeForLLM = (ast) => {
1368
+ if (Ref3.isRefType(ast)) {
1369
+ const description = ast.annotations.description ? ast.annotations.description + "\n" + RefFromLLM.ast.annotations.description : RefFromLLM.ast.annotations.description;
1370
+ return RefFromLLM.annotations({
1371
+ description
1372
+ }).ast;
1373
+ } else if (SchemaAST.isTupleType(ast)) {
1374
+ return new SchemaAST.TupleType(ast.elements.map((t) => new SchemaAST.OptionalType(mapSchemaTypeForLLM(t.type), t.isOptional, t.annotations)), ast.rest.map((t) => new SchemaAST.Type(mapSchemaTypeForLLM(t.type), t.annotations)), ast.isReadonly, ast.annotations);
1375
+ } else if (SchemaAST.isTypeLiteral(ast)) {
1376
+ return new SchemaAST.TypeLiteral(ast.propertySignatures.map((p) => new SchemaAST.PropertySignature(p.name, mapSchemaTypeForLLM(p.type), p.isOptional, p.isReadonly, p.annotations)), ast.indexSignatures, ast.annotations);
1377
+ }
1378
+ return ast;
1379
+ };
1380
+ var isHandlerLike = (value2) => {
1381
+ return typeof value2.tools === "object" && typeof value2.handle === "function";
1382
+ };
1383
+
1384
+ // src/service/agent-process.ts
1385
+ import * as Tool2 from "@effect/ai/Tool";
1386
+ import * as Toolkit2 from "@effect/ai/Toolkit";
1387
+ import * as Cause from "effect/Cause";
1388
+ import * as Duration from "effect/Duration";
1389
+ import * as Effect8 from "effect/Effect";
1390
+ import * as Exit from "effect/Exit";
1391
+ import * as Layer3 from "effect/Layer";
1392
+ import * as Match from "effect/Match";
1393
+ import * as Option4 from "effect/Option";
1394
+ import * as Schema6 from "effect/Schema";
1395
+ import { AiService, GenericToolkit as GenericToolkit3 } from "@dxos/ai";
1396
+ import { Database as Database3, DXN as DXN3, Feed as Feed3, Obj as Obj7 } from "@dxos/echo";
1397
+ import { acquireReleaseResource as acquireReleaseResource2 } from "@dxos/effect";
1398
+ import { TracingService as TracingService2 } from "@dxos/functions";
1399
+ import { Process, ProcessManager, StorageService } from "@dxos/functions-runtime";
1400
+ import { log as log5 } from "@dxos/log";
1401
+ import { Operation as Operation2, OperationRegistry as OperationRegistry2 } from "@dxos/operation";
1402
+ import { trim as trim3 } from "@dxos/util";
1403
+ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/assistant/src/service/agent-process.ts";
1404
+ var AGENT_PROCESS_KEY = "org.dxos.testing.process.agent";
1405
+ var AgentProcess = (options) => Process.make({
1406
+ key: AGENT_PROCESS_KEY,
1407
+ input: Schema6.String,
1408
+ output: Schema6.Void,
1409
+ services: [
1410
+ Database3.Service,
1411
+ GenericToolkit3.GenericToolkitProvider,
1412
+ Operation2.Service,
1413
+ OperationRegistry2.Service,
1414
+ StorageService.StorageService,
1415
+ Feed3.FeedService,
1416
+ ProcessManager.ProcessOperationInvoker.Service,
1417
+ AiService.AiService,
1418
+ // @deprecated Required by AiSessionRunRequirements for backward compat with tool handlers.
1419
+ TracingService2
1420
+ ]
1421
+ }, (ctx) => Effect8.gen(function* () {
1422
+ const feedDxn = ctx.params.target;
1423
+ if (feedDxn == null) {
1424
+ return yield* Effect8.die(new Error("Agent executable requires spawn options.target set to a queue DXN."));
1425
+ }
1426
+ const feed = yield* Database3.resolve(DXN3.parse(feedDxn), Feed3.Feed).pipe(Effect8.orDie);
1427
+ const runtime4 = yield* Effect8.runtime();
1428
+ const conversation = yield* acquireReleaseResource2(() => new AiConversation({
1429
+ feed,
1430
+ runtime: runtime4
1431
+ }));
1432
+ let inputQueue = [
1433
+ ...yield* AgentEventsKey.get
1434
+ ];
1435
+ const storageService = yield* StorageService.StorageService;
1436
+ const toolCallManager = new ToolCallManager(storageService);
1437
+ yield* toolCallManager.load();
1438
+ return {
1439
+ onInput: Effect8.fnUntraced(function* (prompt) {
1440
+ log5("agent onInput received", {
1441
+ promptLength: prompt.length,
1442
+ backlog: inputQueue.length
1443
+ }, {
1444
+ F: __dxlog_file6,
1445
+ L: 79,
1446
+ S: this,
1447
+ C: (f, a) => f(...a)
1448
+ });
1449
+ inputQueue.push({
1450
+ _tag: "prompt",
1451
+ content: prompt
1452
+ });
1453
+ log5("agent onInput persisting queue", {
1454
+ depth: inputQueue.length
1455
+ }, {
1456
+ F: __dxlog_file6,
1457
+ L: 81,
1458
+ S: this,
1459
+ C: (f, a) => f(...a)
1460
+ });
1461
+ yield* AgentEventsKey.set(inputQueue);
1462
+ log5("agent onInput persisted", {
1463
+ depth: inputQueue.length
1464
+ }, {
1465
+ F: __dxlog_file6,
1466
+ L: 83,
1467
+ S: this,
1468
+ C: (f, a) => f(...a)
1469
+ });
1470
+ ctx.setAlarm();
1471
+ log5("agent onInput alarm scheduled", void 0, {
1472
+ F: __dxlog_file6,
1473
+ L: 85,
1474
+ S: this,
1475
+ C: (f, a) => f(...a)
1476
+ });
1477
+ }),
1478
+ onAlarm: Effect8.fnUntraced(function* () {
1479
+ log5("agent onAlarm fired", {
1480
+ pending: inputQueue.length
1481
+ }, {
1482
+ F: __dxlog_file6,
1483
+ L: 89,
1484
+ S: this,
1485
+ C: (f, a) => f(...a)
1486
+ });
1487
+ const item = inputQueue.shift();
1488
+ if (!item) {
1489
+ log5("agent onAlarm empty queue", {}, {
1490
+ F: __dxlog_file6,
1491
+ L: 92,
1492
+ S: this,
1493
+ C: (f, a) => f(...a)
1494
+ });
1495
+ return;
1496
+ }
1497
+ if (item._tag === "tool_result" && toolCallManager.isReported(item.pid)) {
1498
+ log5.info("skip tool result that was reported synchronously", {
1499
+ pid: item.pid
1500
+ }, {
1501
+ F: __dxlog_file6,
1502
+ L: 97,
1503
+ S: this,
1504
+ C: (f, a) => f(...a)
1505
+ });
1506
+ return;
1507
+ }
1508
+ log5("agent onAlarm handling", {
1509
+ tag: item._tag
1510
+ }, {
1511
+ F: __dxlog_file6,
1512
+ L: 102,
1513
+ S: this,
1514
+ C: (f, a) => f(...a)
1515
+ });
1516
+ const prompt = Match.value(item).pipe(Match.tag("prompt", (item2) => item2.content), Match.tag("tool_result", (item2) => item2.isError ? toolErrorResponse(item2.pid, item2.result) : toolResultResponse(item2.pid, item2.result)), Match.exhaustive);
1517
+ log5("begin request", {
1518
+ prompt
1519
+ }, {
1520
+ F: __dxlog_file6,
1521
+ L: 114,
1522
+ S: this,
1523
+ C: (f, a) => f(...a)
1524
+ });
1525
+ yield* conversation.createRequest({
1526
+ prompt,
1527
+ // TODO(dmaretskyi): Polling currently broken, agent relies on completion notifications being delivered.
1528
+ // toolkit: AsynchronousExectionToolkit,
1529
+ system: options.systemPrompt
1530
+ });
1531
+ log5("end request", void 0, {
1532
+ F: __dxlog_file6,
1533
+ L: 121,
1534
+ S: this,
1535
+ C: (f, a) => f(...a)
1536
+ });
1537
+ yield* AgentEventsKey.set(inputQueue);
1538
+ if (inputQueue.length > 0) {
1539
+ ctx.setAlarm();
1540
+ }
1541
+ }, Effect8.orDie, Effect8.provide(Layer3.mergeAll(makeToolResolverFromOperations(), ToolExecutionService3({
1542
+ toolCallManager,
1543
+ feed
1544
+ }), functionInvocationServiceFromOperations, AsynchronousExectionToolkitLayer, AiService.model(options.model ?? "@anthropic/claude-opus-4-6")).pipe(Layer3.orDie))),
1545
+ onChildEvent: Effect8.fnUntraced(function* (event) {
1546
+ log5.info("childEvent", {
1547
+ event
1548
+ }, {
1549
+ F: __dxlog_file6,
1550
+ L: 142,
1551
+ S: this,
1552
+ C: (f, a) => f(...a)
1553
+ });
1554
+ if (event._tag === "exited") {
1555
+ if (!toolCallManager.isToolCall(event.pid)) {
1556
+ log5.verbose("childEvent ignored non-tool call", {
1557
+ pid: event.pid
1558
+ }, {
1559
+ F: __dxlog_file6,
1560
+ L: 145,
1561
+ S: this,
1562
+ C: (f, a) => f(...a)
1563
+ });
1564
+ return;
1565
+ }
1566
+ const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
1567
+ const fiber = yield* operationInvoker.attachFiber(event.pid).pipe(Effect8.orDie);
1568
+ const result = yield* fiber.await.pipe(Effect8.orDie).pipe(Effect8.map(Exit.match({
1569
+ onSuccess: (value2) => ({
1570
+ _tag: "tool_result",
1571
+ pid: event.pid,
1572
+ result: value2,
1573
+ isError: false
1574
+ }),
1575
+ onFailure: (cause) => ({
1576
+ _tag: "tool_result",
1577
+ pid: event.pid,
1578
+ result: Cause.pretty(cause),
1579
+ isError: true
1580
+ })
1581
+ })));
1582
+ inputQueue.push(result);
1583
+ log5("agent onChildEvent persisted tool result", {
1584
+ depth: inputQueue.length,
1585
+ childPid: event.pid
1586
+ }, {
1587
+ F: __dxlog_file6,
1588
+ L: 170,
1589
+ S: this,
1590
+ C: (f, a) => f(...a)
1591
+ });
1592
+ yield* AgentEventsKey.set(inputQueue);
1593
+ ctx.setAlarm();
1594
+ log5("agent onChildEvent alarm scheduled", {
1595
+ depth: inputQueue.length
1596
+ }, {
1597
+ F: __dxlog_file6,
1598
+ L: 173,
1599
+ S: this,
1600
+ C: (f, a) => f(...a)
1601
+ });
1602
+ }
1603
+ })
1604
+ };
1605
+ }));
1606
+ var AgentEvent = Schema6.Union(Schema6.TaggedStruct("prompt", {
1607
+ content: Schema6.String
1608
+ }), Schema6.TaggedStruct("tool_result", {
1609
+ pid: Process.ID,
1610
+ result: Schema6.Unknown,
1611
+ isError: Schema6.Boolean
1612
+ }));
1613
+ var AgentEventsKey = StorageService.key(Schema6.parseJson(Schema6.Array(AgentEvent).pipe(Schema6.mutable)), "inputQueue").pipe(StorageService.withDefault(() => []));
1614
+ var ToolCallState = Schema6.Struct({
1615
+ activeCalls: Schema6.Array(Schema6.Struct({
1616
+ pid: Process.ID,
1617
+ // Whether the result was reported to the agent.
1618
+ reported: Schema6.Boolean
1619
+ }).pipe(Schema6.mutable)).pipe(Schema6.mutable)
1620
+ });
1621
+ var ToolCallStateKey = StorageService.key(Schema6.parseJson(ToolCallState.pipe(Schema6.mutable)), "toolCallState").pipe(StorageService.withDefault(() => ({
1622
+ activeCalls: []
1623
+ })));
1624
+ var ToolCallManager = class {
1625
+ #storageService;
1626
+ #state = {
1627
+ activeCalls: []
1628
+ };
1629
+ constructor(storageService) {
1630
+ this.#storageService = storageService;
1631
+ }
1632
+ load() {
1633
+ return Effect8.gen(this, function* () {
1634
+ this.#state = yield* ToolCallStateKey.get;
1635
+ }).pipe(Effect8.provideService(StorageService.StorageService, this.#storageService));
1636
+ }
1637
+ beginCall(pid) {
1638
+ return Effect8.gen(this, function* () {
1639
+ this.#state.activeCalls.push({
1640
+ pid,
1641
+ reported: false
1642
+ });
1643
+ yield* ToolCallStateKey.set(this.#state);
1644
+ }).pipe(Effect8.provideService(StorageService.StorageService, this.#storageService));
1645
+ }
1646
+ markAsReported(pid) {
1647
+ return Effect8.gen(this, function* () {
1648
+ const call = this.#state.activeCalls.find((call2) => call2.pid === pid);
1649
+ if (!call) {
1650
+ return;
1651
+ }
1652
+ call.reported = true;
1653
+ yield* ToolCallStateKey.set(this.#state);
1654
+ }).pipe(Effect8.provideService(StorageService.StorageService, this.#storageService));
1655
+ }
1656
+ isToolCall(pid) {
1657
+ return this.#state.activeCalls.some((call) => call.pid === pid);
1658
+ }
1659
+ isReported(pid) {
1660
+ return this.#state.activeCalls.some((call) => call.pid === pid && call.reported);
1661
+ }
1662
+ };
1663
+ var ToolExecutionService3 = ({ backgroundThreshold = Duration.seconds(1), toolCallManager, feed }) => Layer3.unwrapEffect(Effect8.gen(function* () {
1664
+ const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
1665
+ return makeToolExecutionService({
1666
+ invoke: (tool, input) => Effect8.gen(function* () {
1667
+ const operationDef = getOperationFromTool(tool).pipe(Option4.getOrThrow);
1668
+ log5("invoking operation", {
1669
+ operationDef,
1670
+ input
1671
+ }, {
1672
+ F: __dxlog_file6,
1673
+ L: 277,
1674
+ S: this,
1675
+ C: (f, a) => f(...a)
1676
+ });
1677
+ const fiber = yield* operationInvoker.invokeFiber(operationDef, input, {
1678
+ environment: {
1679
+ conversation: Obj7.getDXN(feed).toString()
1680
+ }
1681
+ });
1682
+ toolCallManager.beginCall(fiber.pid);
1683
+ log5("invoked operation", {
1684
+ operationDef,
1685
+ input,
1686
+ fiber
1687
+ }, {
1688
+ F: __dxlog_file6,
1689
+ L: 284,
1690
+ S: this,
1691
+ C: (f, a) => f(...a)
1692
+ });
1693
+ const result = yield* fiber.await.pipe(Effect8.tap(() => toolCallManager.markAsReported(fiber.pid)), Effect8.timeout(backgroundThreshold), Effect8.catchTag("TimeoutException", () => Effect8.succeed(toolIsRunningInBackgroundResponse(fiber.pid))));
1694
+ log5("result", {
1695
+ result
1696
+ }, {
1697
+ F: __dxlog_file6,
1698
+ L: 291,
1699
+ S: this,
1700
+ C: (f, a) => f(...a)
1701
+ });
1702
+ return result;
1703
+ })
1704
+ });
1705
+ }));
1706
+ var AsynchronousExectionToolkit = class extends Toolkit2.make(Tool2.make("poll-tools", {
1707
+ description: trim3`
1708
+ Poll tool calls running in the background.
1709
+ Set wait to true to wait for the tool call to complete before returning.
1710
+ Only set wait to true if you dont have other tasks to perform in parallel.
1711
+ Set an appropriate timeout to avoid waiting forever.
1712
+ You will also be notified about the job completion separatelly, so you do not always need to inspect the job if you dont need the result right now.
1713
+ `,
1714
+ parameters: {
1715
+ ids: Schema6.Array(Schema6.String).annotations({
1716
+ description: "The IDs of the jobs to inspect."
1717
+ }),
1718
+ wait: Schema6.optional(Schema6.Boolean).annotations({
1719
+ description: "Whether to wait for the job to complete before returning.",
1720
+ default: false
1721
+ }),
1722
+ timeout: Schema6.optional(Schema6.Number).annotations({
1723
+ description: "Maximum time to wait for the job to complete. If the job does not complete within the timeout, the current state is returned.",
1724
+ default: 1e4
1725
+ })
1726
+ }
1727
+ })) {
1728
+ };
1729
+ var AsynchronousExectionToolkitLayer = AsynchronousExectionToolkit.toLayer(Effect8.gen(function* () {
1730
+ const invoker = yield* ProcessManager.ProcessOperationInvoker.Service;
1731
+ return {
1732
+ "poll-tools": ({ ids, wait, timeout: timeout2 = 1e4 }) => Effect8.gen(function* () {
1733
+ return yield* Effect8.forEach(ids, (pid) => invoker.attachFiber(Process.ID.make(pid)).pipe(Effect8.flatMap((_) => _.await), Effect8.timeout(Duration.millis(timeout2)), Effect8.flatMap(Exit.match({
1734
+ onSuccess: (value2) => Effect8.succeed(toolResultResponse(pid, value2)),
1735
+ onFailure: (cause) => Effect8.succeed(toolErrorResponse(pid, Cause.pretty(cause)))
1736
+ })), Effect8.catchTag("ProcessNotFoundError", () => Effect8.succeed(`Process not found: ${pid}`)), Effect8.catchTag("TimeoutException", () => Effect8.succeed(`Process still running: ${pid}`))));
1737
+ })
1738
+ };
1739
+ }));
1740
+ var toolIsRunningInBackgroundResponse = (pid) => `Tool is running in the background id=${pid}; wait for the completion notification to get the result.`;
1741
+ var toolResultResponse = (pid, value2) => `<result pid=${pid}>${JSON.stringify(value2)}</result>`;
1742
+ var toolErrorResponse = (pid, cause) => `<error pid=${pid}>${cause}</error>`;
1743
+
1744
+ // src/service/AgentService.ts
1745
+ var AgentService_exports = {};
1746
+ __export(AgentService_exports, {
1747
+ AgentService: () => AgentService,
1748
+ createSession: () => createSession,
1749
+ getSession: () => getSession,
1750
+ layer: () => layer
1751
+ });
1752
+ import * as Context5 from "effect/Context";
1753
+ import * as Effect9 from "effect/Effect";
1754
+ import * as Layer4 from "effect/Layer";
1755
+ import { Blueprint as Blueprint2 } from "@dxos/blueprints";
1756
+ import { Database as Database4, Feed as Feed4, Obj as Obj8, Ref as Ref4 } from "@dxos/echo";
1757
+ import { acquireReleaseResource as acquireReleaseResource3 } from "@dxos/effect";
1758
+ import { ProcessManager as ProcessManager2 } from "@dxos/functions-runtime";
1759
+ var AgentService = class extends Context5.Tag("@dxos/assistant/AgentService")() {
1760
+ };
1761
+ var getSession = Effect9.serviceFunctionEffect(AgentService, (service) => service.getSession);
1762
+ var createSession = Effect9.fn("createSession")(function* (opts) {
1763
+ const blueprints = yield* Effect9.forEach(opts?.blueprints ?? [], (blueprint) => Blueprint2.upsert(blueprint.key).pipe(Effect9.map(Ref4.make)));
1764
+ const feed = yield* Database4.add(Feed4.make());
1765
+ const runtime4 = yield* Effect9.runtime();
1766
+ const binder = yield* acquireReleaseResource3(() => new AiContextBinder({
1767
+ feed,
1768
+ runtime: runtime4
1769
+ }));
1770
+ yield* Effect9.promise(() => binder.bind({
1771
+ blueprints,
1772
+ objects: opts?.context ?? []
1773
+ }));
1774
+ return yield* getSession(feed);
1775
+ }, Effect9.scoped);
1776
+ var layer = (opts) => Layer4.effect(AgentService, Effect9.gen(function* () {
1777
+ const processManager = yield* ProcessManager2.ProcessManagerService;
1778
+ const sessionCache = /* @__PURE__ */ new Map();
1779
+ return {
1780
+ getSession: (feed) => Effect9.gen(function* () {
1781
+ const cached = sessionCache.get(feed.id);
1782
+ if (cached) {
1783
+ return cached;
1784
+ }
1785
+ const target = Obj8.getDXN(feed).toString();
1786
+ const executable = AgentProcess({
1787
+ systemPrompt: opts?.systemPrompt
1788
+ });
1789
+ const processes = yield* processManager.list({
1790
+ target,
1791
+ key: executable.key
1792
+ });
1793
+ let handle;
1794
+ if (processes.length > 0) {
1795
+ handle = processes[0];
1796
+ } else {
1797
+ handle = yield* processManager.spawn(executable, {
1798
+ name: "agent",
1799
+ target,
1800
+ traceMeta: {
1801
+ conversationId: feed.id
1802
+ }
1803
+ });
1804
+ }
1805
+ const session = makeSession(handle, feed);
1806
+ sessionCache.set(feed.id, session);
1807
+ return session;
1808
+ })
1809
+ };
1810
+ }));
1811
+ var makeSession = (process, feed) => ({
1812
+ feed,
1813
+ submitPrompt: (prompt) => process.submitInput(prompt),
1814
+ waitForCompletion: () => process.runToCompletion(),
1815
+ subscribeEphemeral: () => process.subscribeEphemeral(),
1816
+ addContext: (context) => Effect9.gen(function* () {
1817
+ const runtime4 = yield* Effect9.runtime();
1818
+ const binder = yield* acquireReleaseResource3(() => new AiContextBinder({
1819
+ feed,
1820
+ runtime: runtime4
1821
+ }));
1822
+ yield* Effect9.promise(() => binder.bind({
1823
+ blueprints: [],
1824
+ objects: context
1825
+ }));
1826
+ }).pipe(Effect9.scoped),
1827
+ getContext: () => Effect9.gen(function* () {
1828
+ const runtime4 = yield* Effect9.runtime();
1829
+ const binder = yield* acquireReleaseResource3(() => new AiContextBinder({
1830
+ feed,
1831
+ runtime: runtime4
1832
+ }));
1833
+ return binder.getObjects().map((object) => Ref4.make(object));
1834
+ }).pipe(Effect9.scoped)
1835
+ });
1836
+
1837
+ export {
1838
+ ContextBinding,
1839
+ Bindings,
1840
+ AiContextBinder,
1841
+ AiContextService,
1842
+ ArtifactDiffResolver,
1843
+ GenerationObserver,
1844
+ PartialBlock,
1845
+ CompleteBlock,
1846
+ AgentTurnStarted,
1847
+ AgentTurnCompleted,
1848
+ ToolCallStarted,
1849
+ ToolCallCompleted,
1850
+ AgentInputReceived,
1851
+ AgentRequestCompleted,
1852
+ AiModelError,
1853
+ AiAssistantError,
1854
+ formatSystemPrompt,
1855
+ formatUserPrompt,
1856
+ AiSession,
1857
+ createToolkit,
1858
+ VersionPin,
1859
+ AiConversation,
1860
+ AiConversationService,
1861
+ createArtifactElement,
1862
+ ArtifactId,
1863
+ RefFromLLM,
1864
+ makeToolResolverFromFunctions,
1865
+ makeToolExecutionServiceFromFunctions,
1866
+ makeToolResolverFromOperations,
1867
+ makeToolExecutionService,
1868
+ makeToolExecutionServiceFromOperationInvoker,
1869
+ functionInvocationServiceFromOperations,
1870
+ ToolExecutionServices,
1871
+ getOperationFromTool,
1872
+ AGENT_PROCESS_KEY,
1873
+ AgentService_exports
1874
+ };
1875
+ //# sourceMappingURL=chunk-UAWIXKF6.mjs.map