@dxos/assistant 0.14.0 → 0.16.0

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 (40) hide show
  1. package/dist/lib/ExecutionGraph.mjs.map +1 -1
  2. package/dist/lib/chunk-Agent.mjs +202 -0
  3. package/dist/lib/chunk-Agent.mjs.map +1 -0
  4. package/dist/lib/chunk-AiContext.mjs +462 -0
  5. package/dist/lib/chunk-AiContext.mjs.map +1 -0
  6. package/dist/lib/chunk-AiRequest.mjs.map +1 -1
  7. package/dist/lib/chunk-AiSession.mjs +2 -2
  8. package/dist/lib/chunk-AiSession.mjs.map +1 -1
  9. package/dist/lib/chunk-Alarm.mjs +37 -0
  10. package/dist/lib/chunk-Alarm.mjs.map +1 -0
  11. package/dist/lib/chunk-Chat.mjs +258 -0
  12. package/dist/lib/chunk-Chat.mjs.map +1 -0
  13. package/dist/lib/chunk-Harness.mjs +4 -4
  14. package/dist/lib/chunk-Harness.mjs.map +1 -1
  15. package/dist/lib/chunk-SessionLink.mjs +20 -0
  16. package/dist/lib/chunk-SessionLink.mjs.map +1 -0
  17. package/dist/lib/chunk-SkillHooks.mjs +47 -0
  18. package/dist/lib/chunk-SkillHooks.mjs.map +1 -0
  19. package/dist/lib/extraction.mjs.map +1 -1
  20. package/dist/lib/index.mjs +6 -6
  21. package/dist/lib/index.mjs.map +1 -1
  22. package/dist/lib/request/AiRequest.mjs +1 -2
  23. package/dist/lib/session/AiContext.mjs +1 -462
  24. package/dist/lib/session/AiSession.mjs +1 -2
  25. package/dist/lib/session/Alarm.mjs +1 -37
  26. package/dist/lib/session/Harness.mjs +1 -2
  27. package/dist/lib/session/SessionLink.mjs +1 -20
  28. package/dist/lib/session/SkillHooks.mjs +1 -47
  29. package/dist/lib/types/Agent.mjs +1 -202
  30. package/dist/lib/types/Chat.mjs +1 -258
  31. package/dist/types/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +23 -23
  33. package/src/request/AiRequest.test.ts +1 -1
  34. package/src/types/Agent.ts +1 -1
  35. package/dist/lib/session/AiContext.mjs.map +0 -1
  36. package/dist/lib/session/Alarm.mjs.map +0 -1
  37. package/dist/lib/session/SessionLink.mjs.map +0 -1
  38. package/dist/lib/session/SkillHooks.mjs.map +0 -1
  39. package/dist/lib/types/Agent.mjs.map +0 -1
  40. package/dist/lib/types/Chat.mjs.map +0 -1
@@ -0,0 +1,462 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import * as Context from "effect/Context";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Schema from "effect/Schema";
5
+ import { DXN, Database, Feed, Obj, Query, Ref, Type } from "@dxos/echo";
6
+ import { assertArgument, invariant } from "@dxos/invariant";
7
+ import { log } from "@dxos/log";
8
+ import { EID as EID$1 } from "@dxos/keys";
9
+ import { ComplexSet, isNonNullable } from "@dxos/util";
10
+ import * as Function from "effect/Function";
11
+ import * as EArray from "effect/Array";
12
+ import * as Order from "effect/Order";
13
+ import * as Atom from "effect/reactivity/Atom";
14
+ import * as Skill from "@dxos/compute/Skill";
15
+ import { Resource } from "@dxos/context";
16
+ import * as AtomEx from "@dxos/effect/AtomEx";
17
+ import * as RuntimeProvider from "@dxos/effect/RuntimeProvider";
18
+ //#region src/session/AiContext.ts
19
+ var AiContext_exports = /* @__PURE__ */ __exportAll({
20
+ Binder: () => Binder,
21
+ Binding: () => Binding,
22
+ Bindings: () => Bindings
23
+ });
24
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/compute/assistant/src/session/AiContext.ts";
25
+ /**
26
+ * Thread message that binds or unbinds contextual objects to a conversation.
27
+ */
28
+ var Binding = class extends Type.makeObject(DXN.make("org.dxos.type.contextBinding", "0.1.0"))(Schema.Struct({
29
+ skills: Schema.Struct({
30
+ added: Schema.Array(Ref.Ref(Skill.Skill)),
31
+ removed: Schema.Array(Ref.Ref(Skill.Skill))
32
+ }),
33
+ objects: Schema.Struct({
34
+ added: Schema.Array(Ref.Ref(Obj.Unknown)),
35
+ removed: Schema.Array(Ref.Ref(Obj.Unknown))
36
+ })
37
+ })) {};
38
+ var Bindings = class {
39
+ skills = new ComplexSet((ref) => ref.uri);
40
+ objects = new ComplexSet((ref) => {
41
+ const echoUri = EID$1.tryParse(ref.uri);
42
+ return echoUri ? EID$1.getEntityId(echoUri) : void 0;
43
+ });
44
+ toJSON() {
45
+ return {
46
+ skills: EArray.fromIterable(this.skills).map((ref) => ref.uri),
47
+ objects: EArray.fromIterable(this.objects).map((ref) => ref.uri)
48
+ };
49
+ }
50
+ };
51
+ /**
52
+ * Bindings appended in this realm, per feed id (stable whether or not the feed is persisted yet).
53
+ *
54
+ * Lets {@link Binder.sync} skip its re-read when nothing here could have changed the bindings: the
55
+ * re-read is a feed-scoped query, which waits for an index pass over every pending write, and it
56
+ * exists only for read-your-writes — a binding written elsewhere arrives through the live query.
57
+ */
58
+ var bindingWrites = /* @__PURE__ */ new Map();
59
+ var bindingWriteCount = (feed) => bindingWrites.get(feed.id) ?? 0;
60
+ var countBindingWrite = (feed) => {
61
+ bindingWrites.set(feed.id, (bindingWrites.get(feed.id) ?? 0) + 1);
62
+ };
63
+ /**
64
+ * Manages bindings of skills and objects to a conversation.
65
+ */
66
+ var Binder = class extends Resource {
67
+ _skills = Atom.make([]).pipe(Atom.keepAlive);
68
+ _objects = Atom.make([]).pipe(Atom.keepAlive);
69
+ _registry;
70
+ _feed;
71
+ _runtime;
72
+ _hold;
73
+ #bindingsQuery;
74
+ /** {@link bindingWriteCount} at the last read of the bindings query. */
75
+ #readWrites = 0;
76
+ /**
77
+ * Keys of the refs the feed already binds, whether or not their targets resolve here: a registry
78
+ * skill bound by URI never matches its resolved target's URI, so the atoms alone cannot tell it is bound.
79
+ */
80
+ #bound = {
81
+ skills: /* @__PURE__ */ new Set(),
82
+ objects: /* @__PURE__ */ new Set()
83
+ };
84
+ #pending;
85
+ /** Bumped by each held write, so only the latest resolution of the held bindings lands. */
86
+ #heldGeneration = 0;
87
+ constructor(options) {
88
+ super();
89
+ assertArgument(options.feed, "options.feed", "Feed is required");
90
+ assertArgument(options.runtime, "options.runtime", "Feed runtime is required");
91
+ this._feed = options.feed;
92
+ this._runtime = options.runtime;
93
+ this._registry = options.registry ?? AtomEx.makeRegistry();
94
+ this._hold = options.hold ?? false;
95
+ }
96
+ /**
97
+ * Returns the skills atom for subscription.
98
+ */
99
+ get skills() {
100
+ return this._skills;
101
+ }
102
+ /**
103
+ * Returns the objects atom for subscription.
104
+ */
105
+ get objects() {
106
+ return this._objects;
107
+ }
108
+ /**
109
+ * Gets the current skills value.
110
+ */
111
+ getSkills() {
112
+ return this._registry.get(this._skills);
113
+ }
114
+ /**
115
+ * Gets the current objects value.
116
+ */
117
+ getObjects() {
118
+ return this._registry.get(this._objects);
119
+ }
120
+ /**
121
+ * Subscribe to changes in skills.
122
+ */
123
+ subscribeSkills(cb) {
124
+ return this._registry.subscribe(this._skills, () => cb(this._registry.get(this._skills)));
125
+ }
126
+ /**
127
+ * Subscribe to changes in objects.
128
+ */
129
+ subscribeObjects(cb) {
130
+ return this._registry.subscribe(this._objects, () => cb(this._registry.get(this._objects)));
131
+ }
132
+ async _open() {
133
+ if (this._hold) {
134
+ this.#pending = [];
135
+ return;
136
+ }
137
+ await this._follow();
138
+ }
139
+ /**
140
+ * Writes a holding binder's bindings to its feed, which the caller has stored, as one binding. Later
141
+ * writes go straight to the feed, which the binder does not follow.
142
+ */
143
+ async flush() {
144
+ const held = this.#pending;
145
+ if (!held) return;
146
+ invariant(Obj.getDatabase(this._feed), "The feed must be stored before its bindings are flushed.", {
147
+ "~LogMeta": "~LogMeta",
148
+ F: __dxlog_file,
149
+ L: 184,
150
+ S: this,
151
+ A: ["Obj.getDatabase(this._feed)", "'The feed must be stored before its bindings are flushed.'"]
152
+ });
153
+ this.#pending = void 0;
154
+ const { skills, objects } = this._reduce(held);
155
+ if (skills.size > 0 || objects.size > 0) await this._append(Obj.make(Binding, {
156
+ skills: {
157
+ added: [...skills],
158
+ removed: []
159
+ },
160
+ objects: {
161
+ added: [...objects],
162
+ removed: []
163
+ }
164
+ }));
165
+ }
166
+ async _follow() {
167
+ const bindingsQuery = await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.query(this._feed, Query.type(Binding)));
168
+ this.#bindingsQuery = bindingsQuery;
169
+ this.#readWrites = bindingWriteCount(this._feed);
170
+ const initialResults = await bindingsQuery.run();
171
+ await this._updateBindings(initialResults);
172
+ this._ctx.onDispose(bindingsQuery.subscribe(async () => {
173
+ await this._updateBindings(bindingsQuery.results);
174
+ }));
175
+ }
176
+ /**
177
+ * Re-reads bindings from the feed to pick up changes made by other processes in this realm, such
178
+ * as a tool that bound a skill. A no-op when none has been written since the last read.
179
+ */
180
+ async sync() {
181
+ const writes = bindingWriteCount(this._feed);
182
+ if (this.#bindingsQuery && writes !== this.#readWrites) {
183
+ let results;
184
+ try {
185
+ results = await this.#bindingsQuery.run();
186
+ } catch (error) {
187
+ log.warn("bindings sync failed; keeping the current bindings", { error }, {
188
+ "~LogMeta": "~LogMeta",
189
+ F: __dxlog_file,
190
+ L: 230,
191
+ S: this
192
+ });
193
+ return;
194
+ }
195
+ log("sync", { bindingItems: results.length }, {
196
+ "~LogMeta": "~LogMeta",
197
+ F: __dxlog_file,
198
+ L: 233,
199
+ S: this
200
+ });
201
+ await this._updateBindings(results);
202
+ this.#readWrites = writes;
203
+ log("sync complete", {
204
+ skills: this._registry.get(this._skills).length,
205
+ skillKeys: this._registry.get(this._skills).map((skill) => Obj.getMeta(skill).key)
206
+ }, {
207
+ "~LogMeta": "~LogMeta",
208
+ F: __dxlog_file,
209
+ L: 237,
210
+ S: this
211
+ });
212
+ }
213
+ }
214
+ async _updateBindings(items) {
215
+ if (items.length === 0) return;
216
+ const bindings = this._reduce(inAppendOrder(items));
217
+ this.#bound = {
218
+ skills: new Set([...bindings.skills].map((ref) => refKey(ref.uri))),
219
+ objects: new Set([...bindings.objects].map((ref) => refKey(ref.uri)))
220
+ };
221
+ log("_updateBindings", {
222
+ items: items.length,
223
+ skillRefs: [...bindings.skills].map((ref) => ({
224
+ uri: ref.uri,
225
+ available: ref.isAvailable
226
+ }))
227
+ }, {
228
+ "~LogMeta": "~LogMeta",
229
+ F: __dxlog_file,
230
+ L: 258,
231
+ S: this
232
+ });
233
+ const currentSkills = this._registry.get(this._skills);
234
+ const currentObjects = this._registry.get(this._objects);
235
+ const resolvedSkills = await this._resolve(bindings.skills, currentSkills);
236
+ const resolvedObjects = await this._resolve(bindings.objects, currentObjects);
237
+ log("_updateBindings resolved", {
238
+ resolvedSkills: resolvedSkills.length,
239
+ resolvedSkillKeys: resolvedSkills.map((bp) => Obj.getMeta(bp).key ?? "<missing>")
240
+ }, {
241
+ "~LogMeta": "~LogMeta",
242
+ F: __dxlog_file,
243
+ L: 269,
244
+ S: this
245
+ });
246
+ const reducedSkillDxns = new Set([...bindings.skills].map((ref) => ref.uri));
247
+ const reducedObjectDxns = new Set([...bindings.objects].map((ref) => ref.uri));
248
+ const filteredSkills = currentSkills.filter((obj) => {
249
+ const uri = Obj.getURI(obj);
250
+ return uri != null && reducedSkillDxns.has(uri);
251
+ });
252
+ const filteredObjects = currentObjects.filter((obj) => {
253
+ const uri = Obj.getURI(obj);
254
+ return uri != null && reducedObjectDxns.has(uri);
255
+ });
256
+ const mergedSkills = this._mergeInto(filteredSkills, resolvedSkills);
257
+ const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);
258
+ this._registry.set(this._skills, mergedSkills);
259
+ this._registry.set(this._objects, mergedObjects);
260
+ log("updated bindings", {
261
+ skills: mergedSkills.length,
262
+ objects: mergedObjects.length
263
+ }, {
264
+ "~LogMeta": "~LogMeta",
265
+ F: __dxlog_file,
266
+ L: 292,
267
+ S: this
268
+ });
269
+ }
270
+ async _close() {
271
+ this._registry.set(this._skills, []);
272
+ this._registry.set(this._objects, []);
273
+ }
274
+ async bind({ skills, objects }) {
275
+ const currentSkills = this._registry.get(this._skills);
276
+ const currentObjects = this._registry.get(this._objects);
277
+ const { added: addedSkills, next: nextSkills } = this._processBindings(skills, currentSkills, this.#bound.skills);
278
+ const { added: addedObjects, next: nextObjects } = this._processBindings(objects, currentObjects, this.#bound.objects);
279
+ if (!addedSkills.length && !addedObjects.length) return;
280
+ addedSkills.forEach((ref) => this.#bound.skills.add(refKey(ref.uri)));
281
+ addedObjects.forEach((ref) => this.#bound.objects.add(refKey(ref.uri)));
282
+ this._registry.set(this._skills, nextSkills);
283
+ this._registry.set(this._objects, nextObjects);
284
+ log("bind", {
285
+ skills: addedSkills.length,
286
+ objects: addedObjects.length
287
+ }, {
288
+ "~LogMeta": "~LogMeta",
289
+ F: __dxlog_file,
290
+ L: 324,
291
+ S: this
292
+ });
293
+ await this._write(Obj.make(Binding, {
294
+ skills: {
295
+ added: addedSkills,
296
+ removed: []
297
+ },
298
+ objects: {
299
+ added: addedObjects,
300
+ removed: []
301
+ }
302
+ }));
303
+ }
304
+ async unbind({ skills, objects }) {
305
+ if (!skills?.length && !objects?.length) return;
306
+ (skills ?? []).forEach((ref) => this.#bound.skills.delete(refKey(ref.uri)));
307
+ (objects ?? []).forEach((ref) => this.#bound.objects.delete(refKey(ref.uri)));
308
+ const removedSkillKeys = new Set((skills ?? []).map((ref) => refKey(ref.uri)));
309
+ const removedObjectKeys = new Set((objects ?? []).map((ref) => refKey(ref.uri)));
310
+ if (removedSkillKeys.size > 0) {
311
+ const current = this._registry.get(this._skills);
312
+ this._registry.set(this._skills, current.filter((obj) => !removedSkillKeys.has(refKey(Obj.getURI(obj)))));
313
+ }
314
+ if (removedObjectKeys.size > 0) {
315
+ const current = this._registry.get(this._objects);
316
+ this._registry.set(this._objects, current.filter((obj) => !removedObjectKeys.has(refKey(Obj.getURI(obj)))));
317
+ }
318
+ log("unbind", {
319
+ skills: skills?.length,
320
+ objects: objects?.length
321
+ }, {
322
+ "~LogMeta": "~LogMeta",
323
+ F: __dxlog_file,
324
+ L: 365,
325
+ S: this
326
+ });
327
+ await this._write(Obj.make(Binding, {
328
+ skills: {
329
+ added: [],
330
+ removed: skills ?? []
331
+ },
332
+ objects: {
333
+ added: [],
334
+ removed: objects ?? []
335
+ }
336
+ }));
337
+ }
338
+ async _write(binding) {
339
+ if (this.#pending) {
340
+ this.#pending.push(binding);
341
+ await this._resolveHeld(this.#pending);
342
+ return;
343
+ }
344
+ await this._append(binding);
345
+ }
346
+ /**
347
+ * Sets the atoms from the held bindings. Their refs have no feed query to hydrate them, so each is
348
+ * resolved against the database, which also spans the registry.
349
+ */
350
+ async _resolveHeld(held) {
351
+ const generation = ++this.#heldGeneration;
352
+ const { db } = Context.get(this._runtime, Database.Service);
353
+ const { skills, objects } = this._reduce(held);
354
+ const hydrate = (refs) => [...refs].map((ref) => ref.isAvailable ? ref : db.makeRef(ref.uri));
355
+ const [resolvedSkills, resolvedObjects] = await Promise.all([this._resolve(hydrate(skills), this._registry.get(this._skills)), this._resolve(hydrate(objects), this._registry.get(this._objects))]);
356
+ if (generation !== this.#heldGeneration) return;
357
+ this._registry.set(this._skills, resolvedSkills);
358
+ this._registry.set(this._objects, resolvedObjects);
359
+ }
360
+ async _append(binding) {
361
+ await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.append(this._feed, [binding]));
362
+ countBindingWrite(this._feed);
363
+ }
364
+ /**
365
+ * Process bindings to filter duplicates (against the resolved targets and the refs already bound) and
366
+ * determine next state.
367
+ */
368
+ _processBindings(refs, current, bound) {
369
+ const next = [...current];
370
+ const added = [];
371
+ if (!refs?.length) return {
372
+ added,
373
+ next
374
+ };
375
+ const seen = /* @__PURE__ */ new Set([...bound, ...current.map((obj) => refKey(Obj.getURI(obj)))]);
376
+ for (const ref of refs) {
377
+ const key = refKey(ref.uri);
378
+ if (seen.has(key)) continue;
379
+ seen.add(key);
380
+ added.push(ref);
381
+ if (ref.isAvailable) {
382
+ const target = ref.target;
383
+ if (target) next.push(target);
384
+ }
385
+ }
386
+ return {
387
+ added,
388
+ next
389
+ };
390
+ }
391
+ /**
392
+ * Reduce results into sets of skills and objects.
393
+ *
394
+ * Order-sensitive: a later removal must fold after the addition it undoes, so callers pass items
395
+ * in append order (see {@link inAppendOrder}).
396
+ */
397
+ _reduce(items) {
398
+ return Function.pipe(items, EArray.reduce(new Bindings(), (context, { skills, objects }) => {
399
+ skills.added.forEach((ref) => context.skills.add(ref));
400
+ skills.removed.forEach((ref) => context.skills.delete(ref));
401
+ objects.added.forEach((ref) => context.objects.add(ref));
402
+ objects.removed.forEach((ref) => {
403
+ for (const obj of context.objects) if (obj.uri === ref.uri || EID$1.tryParse(obj.uri) && EID$1.tryParse(ref.uri) && EID$1.getEntityId(EID$1.tryParse(obj.uri)) === EID$1.getEntityId(EID$1.tryParse(ref.uri))) context.objects.delete(obj);
404
+ });
405
+ return context;
406
+ }));
407
+ }
408
+ /**
409
+ * Merge resolved items into the current set, adding only items not already present (by DXN).
410
+ */
411
+ _mergeInto(current, resolved) {
412
+ const seen = new Set(current.map((obj) => Obj.getURI(obj)));
413
+ const merged = [...current];
414
+ for (const obj of resolved) {
415
+ const uri = Obj.getURI(obj);
416
+ if (!seen.has(uri)) {
417
+ seen.add(uri);
418
+ merged.push(obj);
419
+ }
420
+ }
421
+ return merged;
422
+ }
423
+ /**
424
+ * Resolve references to objects, loading them first if needed and falling back to existing objects.
425
+ * DXN refs (e.g. `dxn:org.dxos.skill.database`) resolve via the wired-up ECHO ref resolver
426
+ * which already spans both the space DB and the hypergraph registry.
427
+ */
428
+ async _resolve(refs, current) {
429
+ const refArray = [...refs];
430
+ await Promise.all(refArray.map((ref) => ref.tryLoad()));
431
+ return refArray.map((ref) => {
432
+ let target;
433
+ if (ref.isAvailable) target = ref.target;
434
+ const resolved = target ?? current.find((obj) => Obj.getURI(obj) === ref.uri);
435
+ if (!resolved) log.warn("unresolved context binding", { uri: ref.uri }, {
436
+ "~LogMeta": "~LogMeta",
437
+ F: __dxlog_file,
438
+ L: 523,
439
+ S: this
440
+ });
441
+ return resolved;
442
+ }).filter(isNonNullable);
443
+ }
444
+ };
445
+ /**
446
+ * Identity of a bound ref: an ECHO URI compares in its local form, since some carry the space and some do not.
447
+ */
448
+ var refKey = (uri) => {
449
+ const echoUri = EID$1.tryParse(uri);
450
+ return echoUri ? EID$1.toLocal(echoUri) : uri;
451
+ };
452
+ /**
453
+ * Bindings in the order they were appended, which is the order the fold has to see them: a query
454
+ * returns an unordered set, so an unsorted fold can apply a removal before the addition it undoes
455
+ * and silently keep the object bound. Server-assigned position is authoritative; a locally-written
456
+ * block has none yet and sorts last, which is correct — it is the newest.
457
+ */
458
+ var inAppendOrder = (items) => EArray.sort(items, Order.mapInput(Order.Number, Feed.getPosition));
459
+ //#endregion
460
+ export { Bindings as i, Binder as n, Binding as r, AiContext_exports as t };
461
+
462
+ //# sourceMappingURL=chunk-AiContext.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-AiContext.mjs","names":["EID"],"sources":["../../src/session/AiContext.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as EArray from 'effect/Array';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Order from 'effect/Order';\nimport * as Atom from 'effect/reactivity/Atom';\nimport * as AtomRegistry from 'effect/reactivity/AtomRegistry';\nimport * as Schema from 'effect/Schema';\n\nimport * as Skill from '@dxos/compute/Skill';\nimport { Resource } from '@dxos/context';\nimport { Database, DXN, Feed, Obj, Query, type QueryResult, Ref, Type } from '@dxos/echo';\nimport * as AtomEx from '@dxos/effect/AtomEx';\nimport * as RuntimeProvider from '@dxos/effect/RuntimeProvider';\nimport { assertArgument, invariant } from '@dxos/invariant';\nimport { EID, type URI } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { ComplexSet, isNonNullable } from '@dxos/util';\n\n/**\n * Thread message that binds or unbinds contextual objects to a conversation.\n */\nexport class Binding extends Type.makeObject<Binding>(DXN.make('org.dxos.type.contextBinding', '0.1.0'))(\n Schema.Struct({\n skills: Schema.Struct({\n added: Schema.Array(Ref.Ref(Skill.Skill)),\n removed: Schema.Array(Ref.Ref(Skill.Skill)),\n }),\n\n objects: Schema.Struct({\n added: Schema.Array(Ref.Ref(Obj.Unknown)),\n removed: Schema.Array(Ref.Ref(Obj.Unknown)),\n }),\n }),\n) {}\nexport type BindingProps = Partial<{\n skills: Ref.Ref<Skill.Skill>[];\n objects: Ref.Ref<Obj.Unknown>[];\n}>;\n\nexport class Bindings {\n readonly skills = new ComplexSet<Ref.Ref<Skill.Skill>>((ref) => ref.uri);\n\n // TODO(burdon): Some DXNs have the Space prefix so only compare the object ID.\n readonly objects = new ComplexSet<Ref.Ref<Obj.Unknown>>((ref) => {\n const echoUri = EID.tryParse(ref.uri);\n return echoUri ? EID.getEntityId(echoUri) : undefined;\n });\n\n toJSON(): { skills: URI.URI[]; objects: URI.URI[] } {\n return {\n skills: EArray.fromIterable(this.skills).map((ref) => ref.uri),\n objects: EArray.fromIterable(this.objects).map((ref) => ref.uri),\n };\n }\n}\n\n/**\n * Bindings appended in this realm, per feed id (stable whether or not the feed is persisted yet).\n *\n * Lets {@link Binder.sync} skip its re-read when nothing here could have changed the bindings: the\n * re-read is a feed-scoped query, which waits for an index pass over every pending write, and it\n * exists only for read-your-writes — a binding written elsewhere arrives through the live query.\n */\nconst bindingWrites = new Map<string, number>();\n\nconst bindingWriteCount = (feed: Feed.Feed): number => bindingWrites.get(feed.id) ?? 0;\n\nconst countBindingWrite = (feed: Feed.Feed): void => {\n bindingWrites.set(feed.id, (bindingWrites.get(feed.id) ?? 0) + 1);\n};\n\nexport type BinderOptions = {\n feed: Feed.Feed;\n runtime: Context.Context<Database.Service>;\n /** @effect/atom-react Registry for reactive state management. */\n registry?: AtomRegistry.AtomRegistry;\n /** Holds bindings in memory until {@link Binder.flush}, so the feed need not be stored yet (a draft conversation). */\n hold?: boolean;\n};\n\n/**\n * Manages bindings of skills and objects to a conversation.\n */\nexport class Binder extends Resource {\n private readonly _skills = Atom.make<Skill.Skill[]>([]).pipe(Atom.keepAlive);\n private readonly _objects = Atom.make<Obj.Unknown[]>([]).pipe(Atom.keepAlive);\n private readonly _registry: AtomRegistry.AtomRegistry;\n private readonly _feed: Feed.Feed;\n private readonly _runtime: Context.Context<Database.Service>;\n private readonly _hold: boolean;\n\n #bindingsQuery: QueryResult.QueryResult<Binding> | undefined;\n\n /** {@link bindingWriteCount} at the last read of the bindings query. */\n #readWrites = 0;\n\n /**\n * Keys of the refs the feed already binds, whether or not their targets resolve here: a registry\n * skill bound by URI never matches its resolved target's URI, so the atoms alone cannot tell it is bound.\n */\n #bound = { skills: new Set<URI.URI>(), objects: new Set<URI.URI>() };\n\n #pending?: Binding[];\n\n /** Bumped by each held write, so only the latest resolution of the held bindings lands. */\n #heldGeneration = 0;\n\n constructor(options: BinderOptions) {\n super();\n assertArgument(options.feed, 'options.feed', 'Feed is required');\n assertArgument(options.runtime, 'options.runtime', 'Feed runtime is required');\n this._feed = options.feed;\n this._runtime = options.runtime;\n this._registry = options.registry ?? AtomEx.makeRegistry();\n this._hold = options.hold ?? false;\n }\n\n /**\n * Returns the skills atom for subscription.\n */\n get skills(): Atom.Atom<Skill.Skill[]> {\n return this._skills;\n }\n\n /**\n * Returns the objects atom for subscription.\n */\n get objects(): Atom.Atom<Obj.Unknown[]> {\n return this._objects;\n }\n\n /**\n * Gets the current skills value.\n */\n getSkills(): Skill.Skill[] {\n return this._registry.get(this._skills);\n }\n\n /**\n * Gets the current objects value.\n */\n getObjects(): Obj.Unknown[] {\n return this._registry.get(this._objects);\n }\n\n /**\n * Subscribe to changes in skills.\n */\n subscribeSkills(cb: (skills: Skill.Skill[]) => void): () => void {\n return this._registry.subscribe(this._skills, () => cb(this._registry.get(this._skills)));\n }\n\n /**\n * Subscribe to changes in objects.\n */\n subscribeObjects(cb: (objects: Obj.Unknown[]) => void): () => void {\n return this._registry.subscribe(this._objects, () => cb(this._registry.get(this._objects)));\n }\n\n protected override async _open(): Promise<void> {\n if (this._hold) {\n this.#pending = [];\n return;\n }\n await this._follow();\n }\n\n /**\n * Writes a holding binder's bindings to its feed, which the caller has stored, as one binding. Later\n * writes go straight to the feed, which the binder does not follow.\n */\n async flush(): Promise<void> {\n const held = this.#pending;\n if (!held) {\n return;\n }\n invariant(Obj.getDatabase(this._feed), 'The feed must be stored before its bindings are flushed.');\n this.#pending = undefined;\n const { skills, objects } = this._reduce(held);\n if (skills.size > 0 || objects.size > 0) {\n await this._append(\n Obj.make(Binding, {\n skills: { added: [...skills], removed: [] },\n objects: { added: [...objects], removed: [] },\n }),\n );\n }\n }\n\n private async _follow(): Promise<void> {\n const bindingsQuery = await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(\n Feed.query(this._feed, Query.type(Binding)),\n );\n this.#bindingsQuery = bindingsQuery;\n\n // Process initial state before returning.\n this.#readWrites = bindingWriteCount(this._feed);\n const initialResults = await bindingsQuery.run();\n await this._updateBindings(initialResults);\n\n // Subscribe to future changes.\n this._ctx.onDispose(\n bindingsQuery.subscribe(async () => {\n await this._updateBindings(bindingsQuery.results);\n }),\n );\n }\n\n /**\n * Re-reads bindings from the feed to pick up changes made by other processes in this realm, such\n * as a tool that bound a skill. A no-op when none has been written since the last read.\n */\n async sync(): Promise<void> {\n const writes = bindingWriteCount(this._feed);\n if (this.#bindingsQuery && writes !== this.#readWrites) {\n let results: Binding[];\n try {\n results = await this.#bindingsQuery.run();\n } catch (error) {\n // The query's live subscription already keeps the bindings current, so a re-read that fails\n // (an index query timing out under load) costs freshness, not correctness — and a caller\n // running this between agent turns would otherwise fail the whole agent process on it.\n log.warn('bindings sync failed; keeping the current bindings', { error });\n return;\n }\n log('sync', { bindingItems: results.length });\n await this._updateBindings(results);\n // Only after the update lands, so one that fails is retried by the next sync.\n this.#readWrites = writes;\n log('sync complete', {\n skills: this._registry.get(this._skills).length,\n // Read the meta key directly: `Skill.getKey` throws on a space-authored skill, which would\n // make a diagnostic log the thing that breaks the sync.\n skillKeys: this._registry.get(this._skills).map((skill) => Obj.getMeta(skill).key),\n });\n }\n }\n\n private async _updateBindings(items: Binding[]): Promise<void> {\n // Skip update if no items - preserve existing state set by bind().\n if (items.length === 0) {\n return;\n }\n\n const bindings = this._reduce(inAppendOrder(items));\n this.#bound = {\n skills: new Set([...bindings.skills].map((ref) => refKey(ref.uri))),\n objects: new Set([...bindings.objects].map((ref) => refKey(ref.uri))),\n };\n\n log('_updateBindings', {\n items: items.length,\n skillRefs: [...bindings.skills].map((ref) => ({ uri: ref.uri, available: ref.isAvailable })),\n });\n\n // Resolve references (loading them first if needed).\n const currentSkills = this._registry.get(this._skills);\n const currentObjects = this._registry.get(this._objects);\n const resolvedSkills = await this._resolve(bindings.skills, currentSkills);\n const resolvedObjects = await this._resolve(bindings.objects, currentObjects);\n\n log('_updateBindings resolved', {\n resolvedSkills: resolvedSkills.length,\n resolvedSkillKeys: resolvedSkills.map((bp) => Obj.getMeta(bp).key ?? '<missing>'),\n });\n\n // Filter current state to only items still in the reduced binding set,\n // then merge in newly resolved items. This ensures unbind events are respected.\n const reducedSkillDxns = new Set<URI.URI>([...bindings.skills].map((ref) => ref.uri));\n const reducedObjectDxns = new Set<URI.URI>([...bindings.objects].map((ref) => ref.uri));\n const filteredSkills = currentSkills.filter((obj) => {\n const uri = Obj.getURI(obj);\n return uri != null && reducedSkillDxns.has(uri);\n });\n const filteredObjects = currentObjects.filter((obj) => {\n const uri = Obj.getURI(obj);\n return uri != null && reducedObjectDxns.has(uri);\n });\n const mergedSkills = this._mergeInto(filteredSkills, resolvedSkills);\n const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);\n\n this._registry.set(this._skills, mergedSkills);\n this._registry.set(this._objects, mergedObjects);\n\n log('updated bindings', {\n skills: mergedSkills.length,\n objects: mergedObjects.length,\n });\n }\n\n protected override async _close(): Promise<void> {\n // Reset atoms to empty state.\n this._registry.set(this._skills, []);\n this._registry.set(this._objects, []);\n }\n\n async bind({ skills, objects }: BindingProps): Promise<void> {\n const currentSkills = this._registry.get(this._skills);\n const currentObjects = this._registry.get(this._objects);\n\n const { added: addedSkills, next: nextSkills } = this._processBindings(skills, currentSkills, this.#bound.skills);\n const { added: addedObjects, next: nextObjects } = this._processBindings(\n objects,\n currentObjects,\n this.#bound.objects,\n );\n if (!addedSkills.length && !addedObjects.length) {\n return;\n }\n addedSkills.forEach((ref) => this.#bound.skills.add(refKey(ref.uri)));\n addedObjects.forEach((ref) => this.#bound.objects.add(refKey(ref.uri)));\n\n // Atomic updates - subscribers notified automatically.\n this._registry.set(this._skills, nextSkills);\n this._registry.set(this._objects, nextObjects);\n\n log('bind', { skills: addedSkills.length, objects: addedObjects.length });\n await this._write(\n Obj.make(Binding, {\n skills: {\n added: addedSkills,\n removed: [],\n },\n objects: {\n added: addedObjects,\n removed: [],\n },\n }),\n );\n }\n\n async unbind({ skills, objects }: BindingProps): Promise<void> {\n if (!skills?.length && !objects?.length) {\n return;\n }\n\n (skills ?? []).forEach((ref) => this.#bound.skills.delete(refKey(ref.uri)));\n (objects ?? []).forEach((ref) => this.#bound.objects.delete(refKey(ref.uri)));\n\n // Immediately update atom state so removals are reflected before the queue round-trips.\n const removedSkillKeys = new Set((skills ?? []).map((ref) => refKey(ref.uri)));\n const removedObjectKeys = new Set((objects ?? []).map((ref) => refKey(ref.uri)));\n if (removedSkillKeys.size > 0) {\n const current = this._registry.get(this._skills);\n this._registry.set(\n this._skills,\n current.filter((obj) => !removedSkillKeys.has(refKey(Obj.getURI(obj)))),\n );\n }\n if (removedObjectKeys.size > 0) {\n const current = this._registry.get(this._objects);\n this._registry.set(\n this._objects,\n current.filter((obj) => !removedObjectKeys.has(refKey(Obj.getURI(obj)))),\n );\n }\n\n log('unbind', { skills: skills?.length, objects: objects?.length });\n await this._write(\n Obj.make(Binding, {\n skills: {\n added: [],\n removed: skills ?? [],\n },\n objects: {\n added: [],\n removed: objects ?? [],\n },\n }),\n );\n }\n\n private async _write(binding: Binding): Promise<void> {\n if (this.#pending) {\n this.#pending.push(binding);\n await this._resolveHeld(this.#pending);\n return;\n }\n await this._append(binding);\n }\n\n /**\n * Sets the atoms from the held bindings. Their refs have no feed query to hydrate them, so each is\n * resolved against the database, which also spans the registry.\n */\n private async _resolveHeld(held: Binding[]): Promise<void> {\n const generation = ++this.#heldGeneration;\n const { db } = Context.get(this._runtime, Database.Service);\n const { skills, objects } = this._reduce(held);\n const hydrate = <T extends Obj.Unknown>(refs: Iterable<Ref.Ref<T>>): Ref.Ref<T>[] =>\n [...refs].map((ref) => (ref.isAvailable ? ref : db.makeRef<T>(ref.uri)));\n const [resolvedSkills, resolvedObjects] = await Promise.all([\n this._resolve(hydrate(skills), this._registry.get(this._skills)),\n this._resolve(hydrate(objects), this._registry.get(this._objects)),\n ]);\n if (generation !== this.#heldGeneration) {\n return;\n }\n this._registry.set(this._skills, resolvedSkills);\n this._registry.set(this._objects, resolvedObjects);\n }\n\n private async _append(binding: Binding): Promise<void> {\n await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.append(this._feed, [binding]));\n countBindingWrite(this._feed);\n }\n\n /**\n * Process bindings to filter duplicates (against the resolved targets and the refs already bound) and\n * determine next state.\n */\n private _processBindings<T extends Obj.Unknown>(\n refs: Ref.Ref<T>[] | undefined,\n current: T[],\n bound: ReadonlySet<URI.URI>,\n ): { added: Ref.Ref<T>[]; next: T[] } {\n const next = [...current];\n const added: Ref.Ref<T>[] = [];\n if (!refs?.length) {\n return { added, next };\n }\n\n const seen = new Set<URI.URI>([...bound, ...current.map((obj) => refKey(Obj.getURI(obj)))]);\n for (const ref of refs) {\n const key = refKey(ref.uri);\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n added.push(ref);\n\n // Only resolve target if available (has target or resolver).\n if (ref.isAvailable) {\n const target = ref.target;\n if (target) {\n next.push(target);\n }\n }\n }\n\n return { added, next };\n }\n\n /**\n * Reduce results into sets of skills and objects.\n *\n * Order-sensitive: a later removal must fold after the addition it undoes, so callers pass items\n * in append order (see {@link inAppendOrder}).\n */\n private _reduce(items: Binding[]): Bindings {\n return Function.pipe(\n items,\n EArray.reduce(new Bindings(), (context, { skills, objects }) => {\n skills.added.forEach((ref) => context.skills.add(ref));\n skills.removed.forEach((ref) => context.skills.delete(ref));\n\n objects.added.forEach((ref) => context.objects.add(ref));\n objects.removed.forEach((ref) => {\n for (const obj of context.objects) {\n if (\n obj.uri === ref.uri ||\n (EID.tryParse(obj.uri) &&\n EID.tryParse(ref.uri) &&\n EID.getEntityId(EID.tryParse(obj.uri)!) === EID.getEntityId(EID.tryParse(ref.uri)!))\n ) {\n context.objects.delete(obj);\n }\n }\n });\n\n return context;\n }),\n );\n }\n\n /**\n * Merge resolved items into the current set, adding only items not already present (by DXN).\n */\n private _mergeInto<T extends Obj.Unknown>(current: T[], resolved: T[]): T[] {\n const seen = new Set(current.map((obj) => Obj.getURI(obj)));\n const merged = [...current];\n for (const obj of resolved) {\n const uri = Obj.getURI(obj);\n if (!seen.has(uri)) {\n seen.add(uri);\n merged.push(obj);\n }\n }\n return merged;\n }\n\n /**\n * Resolve references to objects, loading them first if needed and falling back to existing objects.\n * DXN refs (e.g. `dxn:org.dxos.skill.database`) resolve via the wired-up ECHO ref resolver\n * which already spans both the space DB and the hypergraph registry.\n */\n private async _resolve<T extends Obj.Unknown>(refs: Iterable<Ref.Ref<T>>, current: T[]): Promise<T[]> {\n const refArray = [...refs];\n\n // Load all refs that need loading.\n await Promise.all(refArray.map((ref) => ref.tryLoad()));\n\n return refArray\n .map((ref) => {\n let target: T | undefined;\n // Only resolve target if available (has target or resolver).\n if (ref.isAvailable) {\n target = ref.target;\n }\n\n // Fallback to existing object.\n const resolved = target ?? current.find((obj) => Obj.getURI(obj) === ref.uri);\n if (!resolved) {\n // A binding that cannot load (e.g. a registry skill the host never registered) would otherwise\n // vanish from the session without trace.\n log.warn('unresolved context binding', { uri: ref.uri });\n }\n return resolved;\n })\n .filter(isNonNullable);\n }\n}\n\n/**\n * Identity of a bound ref: an ECHO URI compares in its local form, since some carry the space and some do not.\n */\nconst refKey = (uri: URI.URI): URI.URI => {\n const echoUri = EID.tryParse(uri);\n return echoUri ? EID.toLocal(echoUri) : uri;\n};\n\n/**\n * Bindings in the order they were appended, which is the order the fold has to see them: a query\n * returns an unordered set, so an unsorted fold can apply a removal before the addition it undoes\n * and silently keep the object bound. Server-assigned position is authoritative; a locally-written\n * block has none yet and sorts last, which is correct — it is the newest.\n */\nconst inAppendOrder = (items: readonly Binding[]): Binding[] =>\n EArray.sort(items, Order.mapInput(Order.Number, Feed.getPosition));\n"],"mappings":"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"}