@dxos/assistant 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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