@dxos/assistant 0.8.4-main.b97322e → 0.8.4-main.bcb3aa67d6

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