@dxos/assistant 0.9.0 → 0.9.1-staging.ee54ba693a
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.
- package/dist/lib/neutral/extraction/index.mjs +108 -119
- package/dist/lib/neutral/extraction/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +395 -234
- package/dist/lib/neutral/index.mjs.map +4 -4
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts +2 -0
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts +26 -0
- package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts.map +1 -0
- package/dist/types/src/extraction/index.d.ts +1 -1
- package/dist/types/src/extraction/index.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +8 -1
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/request/AiRequest.d.ts +19 -208
- package/dist/types/src/request/AiRequest.d.ts.map +1 -1
- package/dist/types/src/request/format.d.ts +1 -1
- package/dist/types/src/request/format.d.ts.map +1 -1
- package/dist/types/src/session/AiContext.d.ts +27 -105
- package/dist/types/src/session/AiContext.d.ts.map +1 -1
- package/dist/types/src/session/AiSession.d.ts +11 -29
- package/dist/types/src/session/AiSession.d.ts.map +1 -1
- package/dist/types/src/session/Harness.d.ts +122 -0
- package/dist/types/src/session/Harness.d.ts.map +1 -0
- package/dist/types/src/session/SessionLink.d.ts +8 -11
- package/dist/types/src/session/SessionLink.d.ts.map +1 -1
- package/dist/types/src/session/SessionLoader.d.ts +2 -2
- package/dist/types/src/session/SessionLoader.d.ts.map +1 -1
- package/dist/types/src/session/SkillHooks.d.ts +28 -0
- package/dist/types/src/session/SkillHooks.d.ts.map +1 -0
- package/dist/types/src/session/harness-control.d.ts +177 -0
- package/dist/types/src/session/harness-control.d.ts.map +1 -0
- package/dist/types/src/session/index.d.ts +3 -0
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +4 -4
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/templates/system.d.ts +4 -6
- package/dist/types/src/templates/system.d.ts.map +1 -1
- package/dist/types/src/tool-runtime/index.d.ts.map +1 -0
- package/dist/types/src/tool-runtime/services.d.ts.map +1 -0
- package/dist/types/src/util/artifact.d.ts.map +1 -1
- package/dist/types/src/util/diff.d.ts +9 -3
- package/dist/types/src/util/diff.d.ts.map +1 -1
- package/dist/types/src/util/tracing.d.ts +40 -0
- package/dist/types/src/util/tracing.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -25
- package/src/extraction/extraction-llm-function/index.ts +5 -0
- package/src/extraction/extraction-llm-function/proper-noun-extraction.ts +78 -0
- package/src/extraction/index.ts +1 -1
- package/src/extraction/quotes.test.ts +67 -2
- package/src/extraction/quotes.ts +47 -13
- package/src/index.ts +1 -1
- package/src/request/AiRequest.ts +45 -14
- package/src/request/format.ts +9 -11
- package/src/session/AiContext.test.ts +52 -32
- package/src/session/AiContext.ts +73 -95
- package/src/session/AiSession.test.ts +4 -4
- package/src/session/AiSession.ts +51 -83
- package/src/session/Harness.ts +241 -0
- package/src/session/SessionLink.ts +8 -8
- package/src/session/SessionLoader.ts +4 -4
- package/src/session/SkillHooks.ts +71 -0
- package/src/session/harness-control.ts +30 -0
- package/src/session/index.ts +3 -0
- package/src/session/toolkit.ts +8 -8
- package/src/templates/instructions/format.tpl +3 -3
- package/src/templates/instructions/system.tpl +10 -12
- package/src/templates/system.ts +6 -2
- package/src/util/artifact.ts +9 -2
- package/src/util/diff.test.ts +4 -4
- package/src/util/diff.ts +15 -8
- package/src/util/tracing.ts +1 -1
- package/dist/types/src/extraction/extraction.d.ts +0 -1677
- package/dist/types/src/extraction/extraction.d.ts.map +0 -1
- package/dist/types/src/functions/index.d.ts.map +0 -1
- package/dist/types/src/functions/services.d.ts.map +0 -1
- package/src/extraction/extraction-llm-function/transcription-instructions.tpl +0 -28
- package/src/extraction/extraction.ts +0 -105
- /package/dist/types/src/{functions → tool-runtime}/index.d.ts +0 -0
- /package/dist/types/src/{functions → tool-runtime}/services.d.ts +0 -0
- /package/src/{functions → tool-runtime}/index.ts +0 -0
- /package/src/{functions → tool-runtime}/services.ts +0 -0
|
@@ -2,48 +2,68 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as Context from 'effect/Context';
|
|
6
5
|
import * as Effect from 'effect/Effect';
|
|
7
|
-
import * as Layer from 'effect/Layer';
|
|
8
|
-
import * as Runtime from 'effect/Runtime';
|
|
9
6
|
import * as Schema from 'effect/Schema';
|
|
10
|
-
import { describe,
|
|
7
|
+
import { describe, test } from 'vitest';
|
|
11
8
|
|
|
12
|
-
import { DXN, Feed, Obj, Ref, Type } from '@dxos/echo';
|
|
9
|
+
import { Database, DXN, Feed, Obj, Ref, Type } from '@dxos/echo';
|
|
10
|
+
import { TestDatabaseLayer } from '@dxos/echo-client/testing';
|
|
13
11
|
|
|
14
12
|
import * as AiContext from './AiContext';
|
|
15
13
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
append: async () => {},
|
|
19
|
-
remove: async () => {},
|
|
20
|
-
query: () =>
|
|
21
|
-
({
|
|
22
|
-
subscribe: () => () => {},
|
|
23
|
-
results: [],
|
|
24
|
-
run: async () => [],
|
|
25
|
-
}) as any,
|
|
26
|
-
sync: async () => {},
|
|
27
|
-
getSyncState: async () => ({ blocksToPull: 0, blocksToPush: 0, totalBlocks: 0 }),
|
|
28
|
-
};
|
|
29
|
-
const layer = Layer.succeed(Feed.FeedService, mockFeedService);
|
|
30
|
-
return Effect.runSync(Effect.runtime<Feed.FeedService>().pipe(Effect.provide(layer)));
|
|
31
|
-
};
|
|
14
|
+
const TypeA = Type.makeObject(DXN.make('org.dxos.type.a', '0.1.0'))(Schema.Struct({}));
|
|
15
|
+
const TypeB = Type.makeObject(DXN.make('org.dxos.type.b', '0.1.0'))(Schema.Struct({}));
|
|
32
16
|
|
|
33
17
|
describe('AiContext.Binder', () => {
|
|
34
|
-
|
|
35
|
-
const feed = Feed.make();
|
|
36
|
-
const runtime = createMockFeedRuntime();
|
|
37
|
-
const binder = new AiContext.Binder({ feed, runtime });
|
|
18
|
+
const TestLayer = TestDatabaseLayer({ types: [Feed.Feed, TypeA, TypeB] });
|
|
38
19
|
|
|
39
|
-
|
|
20
|
+
test('reopened binder resolves all distinct bound objects', async ({ expect }) => {
|
|
21
|
+
await Effect.gen(function* () {
|
|
22
|
+
const feed = yield* Database.add(Feed.make());
|
|
23
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
const a = yield* Database.add(Obj.make(TypeA, {}));
|
|
26
|
+
const b = yield* Database.add(Obj.make(TypeB, {}));
|
|
43
27
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
28
|
+
// Bind two distinct objects across two separate bindings (as the chat + companion do).
|
|
29
|
+
const writer = new AiContext.Binder({ feed, runtime });
|
|
30
|
+
yield* Effect.promise(() => writer.open());
|
|
31
|
+
yield* Effect.promise(() => writer.bind({ objects: [Ref.make(a)] }));
|
|
32
|
+
yield* Effect.promise(() => writer.bind({ objects: [Ref.make(b)] }));
|
|
33
|
+
yield* Effect.promise(() => writer.close());
|
|
34
|
+
|
|
35
|
+
// Reopen over the same feed (the path ContextModule takes): bindings are re-read via _reduce.
|
|
36
|
+
const reader = new AiContext.Binder({ feed, runtime });
|
|
37
|
+
yield* Effect.promise(() => reader.open());
|
|
38
|
+
const objects = reader.getObjects();
|
|
39
|
+
yield* Effect.promise(() => reader.close());
|
|
40
|
+
|
|
41
|
+
expect(objects.map((obj) => Obj.getURI(obj)).sort()).toEqual([Obj.getURI(a), Obj.getURI(b)].sort());
|
|
42
|
+
})
|
|
43
|
+
.pipe(Effect.provide(TestLayer))
|
|
44
|
+
.pipe(Effect.runPromise);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should handle bind with Ref', async () => {
|
|
48
|
+
await Effect.gen(function* () {
|
|
49
|
+
const feed = yield* Database.add(Feed.make());
|
|
50
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
51
|
+
|
|
52
|
+
const TestSchema = Type.makeObject(DXN.make('org.dxos.type.example', '0.1.0'))(Schema.Struct({}));
|
|
53
|
+
|
|
54
|
+
const obj = Obj.make(TestSchema, {});
|
|
55
|
+
const ref = Ref.make(obj);
|
|
56
|
+
|
|
57
|
+
const binder = new AiContext.Binder({ feed, runtime });
|
|
58
|
+
|
|
59
|
+
yield* Effect.promise(() =>
|
|
60
|
+
binder.bind({
|
|
61
|
+
skills: [],
|
|
62
|
+
objects: [ref],
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
})
|
|
66
|
+
.pipe(Effect.provide(TestLayer))
|
|
67
|
+
.pipe(Effect.runPromise);
|
|
48
68
|
});
|
|
49
69
|
});
|
package/src/session/AiContext.ts
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
import { Atom, Registry as AtomRegistry } from '@effect-atom/atom-react';
|
|
8
8
|
import * as EArray from 'effect/Array';
|
|
9
|
-
import * as Context from 'effect/Context';
|
|
10
|
-
import * as Effect from 'effect/Effect';
|
|
11
9
|
import * as Function from 'effect/Function';
|
|
12
10
|
import * as Runtime from 'effect/Runtime';
|
|
13
11
|
import * as Schema from 'effect/Schema';
|
|
14
12
|
|
|
15
|
-
import {
|
|
13
|
+
import { Skill } from '@dxos/compute';
|
|
16
14
|
import { Resource } from '@dxos/context';
|
|
17
|
-
import { Annotation, DXN, Feed, Obj, type QueryResult,
|
|
15
|
+
import { Annotation, Database, DXN, Feed, Obj, Query, type QueryResult, Ref, Type } from '@dxos/echo';
|
|
18
16
|
import { assertArgument } from '@dxos/invariant';
|
|
19
17
|
import { EID, type URI } from '@dxos/keys';
|
|
20
18
|
import { log } from '@dxos/log';
|
|
@@ -23,26 +21,26 @@ import { ComplexSet, isNonNullable } from '@dxos/util';
|
|
|
23
21
|
/**
|
|
24
22
|
* Thread message that binds or unbinds contextual objects to a conversation.
|
|
25
23
|
*/
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
export class Binding extends Type.makeObject<Binding>(DXN.make('org.dxos.type.contextBinding', '0.1.0'))(
|
|
25
|
+
Schema.Struct({
|
|
26
|
+
skills: Schema.Struct({
|
|
27
|
+
added: Schema.Array(Ref.Ref(Skill.Skill)),
|
|
28
|
+
removed: Schema.Array(Ref.Ref(Skill.Skill)),
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
objects: Schema.Struct({
|
|
32
|
+
added: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
33
|
+
removed: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
34
|
+
}),
|
|
35
|
+
}).pipe(Annotation.HiddenAnnotation.set(true)),
|
|
36
|
+
) {}
|
|
39
37
|
export type BindingProps = Partial<{
|
|
40
|
-
|
|
38
|
+
skills: Ref.Ref<Skill.Skill>[];
|
|
41
39
|
objects: Ref.Ref<Obj.Unknown>[];
|
|
42
40
|
}>;
|
|
43
41
|
|
|
44
42
|
export class Bindings {
|
|
45
|
-
readonly
|
|
43
|
+
readonly skills = new ComplexSet<Ref.Ref<Skill.Skill>>((ref) => ref.uri);
|
|
46
44
|
|
|
47
45
|
// TODO(burdon): Some DXNs have the Space prefix so only compare the object ID.
|
|
48
46
|
readonly objects = new ComplexSet<Ref.Ref<Obj.Unknown>>((ref) => {
|
|
@@ -50,9 +48,9 @@ export class Bindings {
|
|
|
50
48
|
return echoUri ? EID.getEntityId(echoUri) : undefined;
|
|
51
49
|
});
|
|
52
50
|
|
|
53
|
-
toJSON(): {
|
|
51
|
+
toJSON(): { skills: URI.URI[]; objects: URI.URI[] } {
|
|
54
52
|
return {
|
|
55
|
-
|
|
53
|
+
skills: EArray.fromIterable(this.skills).map((ref) => ref.uri),
|
|
56
54
|
objects: EArray.fromIterable(this.objects).map((ref) => ref.uri),
|
|
57
55
|
};
|
|
58
56
|
}
|
|
@@ -60,21 +58,21 @@ export class Bindings {
|
|
|
60
58
|
|
|
61
59
|
export type BinderOptions = {
|
|
62
60
|
feed: Feed.Feed;
|
|
63
|
-
runtime: Runtime.Runtime<
|
|
61
|
+
runtime: Runtime.Runtime<Database.Service>;
|
|
64
62
|
/** @effect-atom/atom-react Registry for reactive state management. */
|
|
65
63
|
registry?: AtomRegistry.Registry;
|
|
66
64
|
};
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
|
-
* Manages bindings of
|
|
67
|
+
* Manages bindings of skills and objects to a conversation.
|
|
70
68
|
*/
|
|
71
69
|
// TODO(burdon): Context should manage ephemeral state of bindings until prompt is issued?
|
|
72
70
|
export class Binder extends Resource {
|
|
73
|
-
private readonly
|
|
71
|
+
private readonly _skills = Atom.make<Skill.Skill[]>([]).pipe(Atom.keepAlive);
|
|
74
72
|
private readonly _objects = Atom.make<Obj.Unknown[]>([]).pipe(Atom.keepAlive);
|
|
75
73
|
private readonly _registry: AtomRegistry.Registry;
|
|
76
74
|
private readonly _feed: Feed.Feed;
|
|
77
|
-
private readonly _runtime: Runtime.Runtime<
|
|
75
|
+
private readonly _runtime: Runtime.Runtime<Database.Service>;
|
|
78
76
|
|
|
79
77
|
#bindingsQuery: QueryResult.QueryResult<Binding> | undefined;
|
|
80
78
|
|
|
@@ -88,10 +86,10 @@ export class Binder extends Resource {
|
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
/**
|
|
91
|
-
* Returns the
|
|
89
|
+
* Returns the skills atom for subscription.
|
|
92
90
|
*/
|
|
93
|
-
get
|
|
94
|
-
return this.
|
|
91
|
+
get skills(): Atom.Atom<Skill.Skill[]> {
|
|
92
|
+
return this._skills;
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
/**
|
|
@@ -102,10 +100,10 @@ export class Binder extends Resource {
|
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
/**
|
|
105
|
-
* Gets the current
|
|
103
|
+
* Gets the current skills value.
|
|
106
104
|
*/
|
|
107
|
-
|
|
108
|
-
return this._registry.get(this.
|
|
105
|
+
getSkills(): Skill.Skill[] {
|
|
106
|
+
return this._registry.get(this._skills);
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
/**
|
|
@@ -116,10 +114,10 @@ export class Binder extends Resource {
|
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
/**
|
|
119
|
-
* Subscribe to changes in
|
|
117
|
+
* Subscribe to changes in skills.
|
|
120
118
|
*/
|
|
121
|
-
|
|
122
|
-
return this._registry.subscribe(this.
|
|
119
|
+
subscribeSkills(cb: (skills: Skill.Skill[]) => void): () => void {
|
|
120
|
+
return this._registry.subscribe(this._skills, () => cb(this._registry.get(this._skills)));
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
/**
|
|
@@ -153,8 +151,8 @@ export class Binder extends Resource {
|
|
|
153
151
|
log('sync', { bindingItems: results.length });
|
|
154
152
|
await this._updateBindings(results);
|
|
155
153
|
log('sync complete', {
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
skills: this._registry.get(this._skills).length,
|
|
155
|
+
skillKeys: this._registry.get(this._skills).map((bp) => Skill.getKey(bp)),
|
|
158
156
|
});
|
|
159
157
|
}
|
|
160
158
|
}
|
|
@@ -169,25 +167,25 @@ export class Binder extends Resource {
|
|
|
169
167
|
|
|
170
168
|
log('_updateBindings', {
|
|
171
169
|
items: items.length,
|
|
172
|
-
|
|
170
|
+
skillRefs: [...bindings.skills].map((ref) => ({ uri: ref.uri, available: ref.isAvailable })),
|
|
173
171
|
});
|
|
174
172
|
|
|
175
173
|
// Resolve references (loading them first if needed).
|
|
176
|
-
const
|
|
174
|
+
const currentSkills = this._registry.get(this._skills);
|
|
177
175
|
const currentObjects = this._registry.get(this._objects);
|
|
178
|
-
const
|
|
176
|
+
const resolvedSkills = await this._resolve(bindings.skills, currentSkills);
|
|
179
177
|
const resolvedObjects = await this._resolve(bindings.objects, currentObjects);
|
|
180
178
|
|
|
181
179
|
log('_updateBindings resolved', {
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
resolvedSkills: resolvedSkills.length,
|
|
181
|
+
resolvedSkillKeys: resolvedSkills.map((bp) => Obj.getMeta(bp).key ?? '<missing>'),
|
|
184
182
|
});
|
|
185
183
|
|
|
186
|
-
// Drop
|
|
187
|
-
// (e.g. tool/operation registration calls
|
|
188
|
-
const
|
|
184
|
+
// Drop skills that have no registry key — they cannot be used downstream
|
|
185
|
+
// (e.g. tool/operation registration calls Skill.getKey which throws).
|
|
186
|
+
const keyedSkills = resolvedSkills.filter((bp) => {
|
|
189
187
|
if (Obj.getMeta(bp).key === undefined) {
|
|
190
|
-
log.warn('dropping
|
|
188
|
+
log.warn('dropping skill with no meta key', { uri: Obj.getURI(bp) });
|
|
191
189
|
return false;
|
|
192
190
|
}
|
|
193
191
|
return true;
|
|
@@ -195,54 +193,54 @@ export class Binder extends Resource {
|
|
|
195
193
|
|
|
196
194
|
// Filter current state to only items still in the reduced binding set,
|
|
197
195
|
// then merge in newly resolved items. This ensures unbind events are respected.
|
|
198
|
-
const
|
|
196
|
+
const reducedSkillDxns = new Set<URI.URI>([...bindings.skills].map((ref) => ref.uri));
|
|
199
197
|
const reducedObjectDxns = new Set<URI.URI>([...bindings.objects].map((ref) => ref.uri));
|
|
200
|
-
const
|
|
198
|
+
const filteredSkills = currentSkills.filter((obj) => {
|
|
201
199
|
const uri = Obj.getURI(obj);
|
|
202
|
-
return uri != null &&
|
|
200
|
+
return uri != null && reducedSkillDxns.has(uri) && Obj.getMeta(obj).key !== undefined;
|
|
203
201
|
});
|
|
204
202
|
const filteredObjects = currentObjects.filter((obj) => {
|
|
205
203
|
const uri = Obj.getURI(obj);
|
|
206
204
|
return uri != null && reducedObjectDxns.has(uri);
|
|
207
205
|
});
|
|
208
|
-
const
|
|
206
|
+
const mergedSkills = this._mergeInto(filteredSkills, keyedSkills);
|
|
209
207
|
const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);
|
|
210
208
|
|
|
211
|
-
this._registry.set(this.
|
|
209
|
+
this._registry.set(this._skills, mergedSkills);
|
|
212
210
|
this._registry.set(this._objects, mergedObjects);
|
|
213
211
|
|
|
214
212
|
log('updated bindings', {
|
|
215
|
-
|
|
213
|
+
skills: mergedSkills.length,
|
|
216
214
|
objects: mergedObjects.length,
|
|
217
215
|
});
|
|
218
216
|
}
|
|
219
217
|
|
|
220
218
|
protected override async _close(): Promise<void> {
|
|
221
219
|
// Reset atoms to empty state.
|
|
222
|
-
this._registry.set(this.
|
|
220
|
+
this._registry.set(this._skills, []);
|
|
223
221
|
this._registry.set(this._objects, []);
|
|
224
222
|
}
|
|
225
223
|
|
|
226
|
-
async bind({
|
|
227
|
-
const
|
|
224
|
+
async bind({ skills, objects }: BindingProps): Promise<void> {
|
|
225
|
+
const currentSkills = this._registry.get(this._skills);
|
|
228
226
|
const currentObjects = this._registry.get(this._objects);
|
|
229
227
|
|
|
230
|
-
const { added:
|
|
228
|
+
const { added: addedSkills, next: nextSkills } = this._processBindings(skills, currentSkills);
|
|
231
229
|
const { added: addedObjects, next: nextObjects } = this._processBindings(objects, currentObjects);
|
|
232
|
-
if (!
|
|
230
|
+
if (!addedSkills.length && !addedObjects.length) {
|
|
233
231
|
return;
|
|
234
232
|
}
|
|
235
233
|
|
|
236
234
|
// Atomic updates - subscribers notified automatically.
|
|
237
|
-
this._registry.set(this.
|
|
235
|
+
this._registry.set(this._skills, nextSkills);
|
|
238
236
|
this._registry.set(this._objects, nextObjects);
|
|
239
237
|
|
|
240
|
-
log('bind', {
|
|
238
|
+
log('bind', { skills: addedSkills.length, objects: addedObjects.length });
|
|
241
239
|
await Runtime.runPromise(this._runtime)(
|
|
242
240
|
Feed.append(this._feed, [
|
|
243
241
|
Obj.make(Binding, {
|
|
244
|
-
|
|
245
|
-
added:
|
|
242
|
+
skills: {
|
|
243
|
+
added: addedSkills,
|
|
246
244
|
removed: [],
|
|
247
245
|
},
|
|
248
246
|
objects: {
|
|
@@ -254,19 +252,19 @@ export class Binder extends Resource {
|
|
|
254
252
|
);
|
|
255
253
|
}
|
|
256
254
|
|
|
257
|
-
async unbind({
|
|
258
|
-
if (!
|
|
255
|
+
async unbind({ skills, objects }: BindingProps): Promise<void> {
|
|
256
|
+
if (!skills?.length && !objects?.length) {
|
|
259
257
|
return;
|
|
260
258
|
}
|
|
261
259
|
|
|
262
260
|
// Immediately update atom state so removals are reflected before the queue round-trips.
|
|
263
|
-
const
|
|
261
|
+
const removedSkillDxns = (skills ?? []).map((ref) => ref.uri);
|
|
264
262
|
const removedObjectDxns = (objects ?? []).map((ref) => ref.uri);
|
|
265
|
-
if (
|
|
266
|
-
const current = this._registry.get(this.
|
|
263
|
+
if (removedSkillDxns.length > 0) {
|
|
264
|
+
const current = this._registry.get(this._skills);
|
|
267
265
|
this._registry.set(
|
|
268
|
-
this.
|
|
269
|
-
current.filter((obj) => !
|
|
266
|
+
this._skills,
|
|
267
|
+
current.filter((obj) => !removedSkillDxns.some((uri) => Obj.getURI(obj) === uri)),
|
|
270
268
|
);
|
|
271
269
|
}
|
|
272
270
|
if (removedObjectDxns.length > 0) {
|
|
@@ -277,13 +275,13 @@ export class Binder extends Resource {
|
|
|
277
275
|
);
|
|
278
276
|
}
|
|
279
277
|
|
|
280
|
-
log('unbind', {
|
|
278
|
+
log('unbind', { skills: skills?.length, objects: objects?.length });
|
|
281
279
|
await Runtime.runPromise(this._runtime)(
|
|
282
280
|
Feed.append(this._feed, [
|
|
283
281
|
Obj.make(Binding, {
|
|
284
|
-
|
|
282
|
+
skills: {
|
|
285
283
|
added: [],
|
|
286
|
-
removed:
|
|
284
|
+
removed: skills ?? [],
|
|
287
285
|
},
|
|
288
286
|
objects: {
|
|
289
287
|
added: [],
|
|
@@ -329,14 +327,14 @@ export class Binder extends Resource {
|
|
|
329
327
|
}
|
|
330
328
|
|
|
331
329
|
/**
|
|
332
|
-
* Reduce results into sets of
|
|
330
|
+
* Reduce results into sets of skills and objects.
|
|
333
331
|
*/
|
|
334
332
|
private _reduce(items: Binding[]): Bindings {
|
|
335
333
|
return Function.pipe(
|
|
336
334
|
items,
|
|
337
|
-
EArray.reduce(new Bindings(), (context, {
|
|
338
|
-
|
|
339
|
-
|
|
335
|
+
EArray.reduce(new Bindings(), (context, { skills, objects }) => {
|
|
336
|
+
skills.added.forEach((ref) => context.skills.add(ref));
|
|
337
|
+
skills.removed.forEach((ref) => context.skills.delete(ref));
|
|
340
338
|
|
|
341
339
|
objects.added.forEach((ref) => context.objects.add(ref));
|
|
342
340
|
objects.removed.forEach((ref) => {
|
|
@@ -375,7 +373,7 @@ export class Binder extends Resource {
|
|
|
375
373
|
|
|
376
374
|
/**
|
|
377
375
|
* Resolve references to objects, loading them first if needed and falling back to existing objects.
|
|
378
|
-
* DXN refs (e.g. `dxn:org.dxos.
|
|
376
|
+
* DXN refs (e.g. `dxn:org.dxos.skill.database`) resolve via the wired-up ECHO ref resolver
|
|
379
377
|
* which already spans both the space DB and the hypergraph registry.
|
|
380
378
|
*/
|
|
381
379
|
private async _resolve<T extends Obj.Unknown>(refs: Iterable<Ref.Ref<T>>, current: T[]): Promise<T[]> {
|
|
@@ -398,23 +396,3 @@ export class Binder extends Resource {
|
|
|
398
396
|
.filter(isNonNullable);
|
|
399
397
|
}
|
|
400
398
|
}
|
|
401
|
-
|
|
402
|
-
export class Service extends Context.Tag('@dxos/assistant/AiContextService')<
|
|
403
|
-
Service,
|
|
404
|
-
{
|
|
405
|
-
binder: Binder;
|
|
406
|
-
}
|
|
407
|
-
>() {
|
|
408
|
-
static bindContext = ({ blueprints, objects }: BindingProps): Effect.Effect<void, never, Service> =>
|
|
409
|
-
Effect.gen(function* () {
|
|
410
|
-
const { binder } = yield* Service;
|
|
411
|
-
yield* Effect.promise(() => binder.bind({ blueprints, objects }));
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
static findObjects = <T extends Type.AnyObj>(type: T): Effect.Effect<Type.InstanceType<T>[], never, Service> => {
|
|
415
|
-
return Effect.gen(function* () {
|
|
416
|
-
const { binder } = yield* Service;
|
|
417
|
-
return binder.getObjects().filter(Obj.instanceOf(type));
|
|
418
|
-
});
|
|
419
|
-
};
|
|
420
|
-
}
|
|
@@ -27,7 +27,7 @@ describe('AiSession.Session.getHistory', () => {
|
|
|
27
27
|
const message = makeMessage('hello');
|
|
28
28
|
yield* Feed.append(feed, [message]);
|
|
29
29
|
|
|
30
|
-
const runtime = yield* Effect.runtime<
|
|
30
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
31
31
|
const session = new AiSession.Session({ feed, runtime });
|
|
32
32
|
|
|
33
33
|
const result = yield* Effect.promise(() => session.getHistory());
|
|
@@ -51,7 +51,7 @@ describe('AiSession.Session.getHistory', () => {
|
|
|
51
51
|
forkMsg,
|
|
52
52
|
]);
|
|
53
53
|
|
|
54
|
-
const runtime = yield* Effect.runtime<
|
|
54
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
55
55
|
const session = new AiSession.Session({ feed: forkFeed, runtime });
|
|
56
56
|
|
|
57
57
|
const result = yield* Effect.promise(() => session.getHistory());
|
|
@@ -76,7 +76,7 @@ describe('AiSession.Session.getHistory', () => {
|
|
|
76
76
|
Obj.make(SessionLink.SessionLink, { feedRef: Ref.make(sourceFeed), messageId: msg2.id }),
|
|
77
77
|
]);
|
|
78
78
|
|
|
79
|
-
const runtime = yield* Effect.runtime<
|
|
79
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
80
80
|
const session = new AiSession.Session({ feed: forkFeed, runtime });
|
|
81
81
|
|
|
82
82
|
const result = yield* Effect.promise(() => session.getHistory());
|
|
@@ -100,7 +100,7 @@ describe('AiSession.Session.getHistory', () => {
|
|
|
100
100
|
forkMsg,
|
|
101
101
|
]);
|
|
102
102
|
|
|
103
|
-
const runtime = yield* Effect.runtime<
|
|
103
|
+
const runtime = yield* Effect.runtime<Database.Service>();
|
|
104
104
|
const session = new AiSession.Session({ feed: forkFeed, runtime });
|
|
105
105
|
|
|
106
106
|
const result = yield* Effect.promise(() => session.getHistory());
|