@dxos/assistant 0.8.4-main.fd6878d → 0.8.4-main.fffef41
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/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/extraction/index.mjs +121 -165
- package/dist/lib/browser/extraction/index.mjs.map +4 -4
- package/dist/lib/browser/index.mjs +1097 -161
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/extraction/index.mjs +121 -165
- package/dist/lib/node-esm/extraction/index.mjs.map +4 -4
- package/dist/lib/node-esm/index.mjs +1097 -161
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/conversation/context.d.ts +23 -10
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +22 -31
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/diff.d.ts +15 -0
- package/dist/types/src/diff.d.ts.map +1 -0
- package/dist/types/src/diff.test.d.ts +2 -0
- package/dist/types/src/diff.test.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +45 -13
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/execution-graph.d.ts +85 -0
- package/dist/types/src/execution-graph.d.ts.map +1 -0
- package/dist/types/src/execution-graph.test.d.ts +2 -0
- package/dist/types/src/execution-graph.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +1 -1
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +82 -43
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +262 -225
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +1 -1
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +18 -5
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/session/GenericToolkit.d.ts +84 -0
- package/dist/types/src/session/GenericToolkit.d.ts.map +1 -0
- package/dist/types/src/session/artifact-diff.d.ts +2 -2
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
- package/dist/types/src/session/error-handling.d.ts +4 -0
- package/dist/types/src/session/error-handling.d.ts.map +1 -0
- package/dist/types/src/session/format.d.ts +5 -161
- package/dist/types/src/session/format.d.ts.map +1 -1
- 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/observer.d.ts +22 -0
- package/dist/types/src/session/observer.d.ts.map +1 -0
- package/dist/types/src/session/session.d.ts +22 -138
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +15 -0
- package/dist/types/src/session/toolkit.d.ts.map +1 -0
- package/dist/types/src/session/version-pin.d.ts +3 -3
- package/dist/types/src/session/version-pin.d.ts.map +1 -1
- package/dist/types/src/templates/system.d.ts +8 -12
- package/dist/types/src/templates/system.d.ts.map +1 -1
- package/dist/types/src/types/artifact.d.ts +20 -0
- package/dist/types/src/types/artifact.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -31
- package/src/conversation/context.ts +75 -22
- package/src/conversation/conversation.ts +80 -77
- package/src/diff.test.ts +43 -0
- package/src/diff.ts +84 -0
- package/src/errors.ts +6 -1
- package/src/execution-graph.test.ts +740 -0
- package/src/execution-graph.ts +509 -0
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +9 -9
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +47 -56
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +16 -16
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +42 -43
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +12 -6
- package/src/extraction/extraction-ner-function/named-entity-recognition.ts +2 -0
- package/src/extraction/extraction.ts +7 -6
- package/src/extraction/quotes.test.ts +2 -2
- package/src/extraction/quotes.ts +3 -3
- package/src/functions/services.ts +104 -56
- package/src/index.ts +3 -1
- package/src/session/GenericToolkit.ts +130 -0
- package/src/session/artifact-diff.ts +8 -4
- package/src/session/error-handling.ts +41 -0
- package/src/session/format.test.ts +5 -4
- package/src/session/format.ts +27 -22
- package/src/session/index.ts +4 -0
- package/src/session/observer.ts +59 -0
- package/src/session/session.conversations.json +1 -0
- package/src/session/session.test.ts +35 -191
- package/src/session/session.ts +119 -185
- package/src/session/toolkit.ts +48 -0
- package/src/session/version-pin.ts +4 -5
- package/src/templates/{format.tpl → instructions/format.tpl} +8 -2
- package/src/templates/{system.tpl → instructions/system.tpl} +15 -14
- package/src/templates/system.ts +25 -16
- package/src/{types.ts → types/artifact.ts} +22 -3
- package/src/types/index.ts +5 -0
- package/dist/lib/browser/chunk-6WRGDEMH.mjs +0 -89
- package/dist/lib/browser/chunk-6WRGDEMH.mjs.map +0 -7
- package/dist/lib/browser/chunk-NZGGCEF3.mjs +0 -341
- package/dist/lib/browser/chunk-NZGGCEF3.mjs.map +0 -7
- package/dist/lib/browser/named-entity-recognition-O46UTCLR.mjs +0 -13
- package/dist/lib/node-esm/chunk-3UU5V4FS.mjs +0 -91
- package/dist/lib/node-esm/chunk-3UU5V4FS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-XOOPGSGW.mjs +0 -343
- package/dist/lib/node-esm/chunk-XOOPGSGW.mjs.map +0 -7
- package/dist/lib/node-esm/named-entity-recognition-W4VMRCH6.mjs +0 -14
- package/dist/types/src/session/version-pin.test.d.ts +0 -2
- package/dist/types/src/session/version-pin.test.d.ts.map +0 -1
- package/dist/types/src/summarization/summarization.test.d.ts +0 -2
- package/dist/types/src/summarization/summarization.test.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -16
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/session/__snapshots__/session.test.ts.snap +0 -32
- package/src/session/version-pin.test.ts +0 -7
- package/src/summarization/summarization.test.ts +0 -197
- /package/dist/lib/browser/{named-entity-recognition-O46UTCLR.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/node-esm/{named-entity-recognition-W4VMRCH6.mjs.map → chunk-HSLMI22Q.mjs.map} +0 -0
- /package/src/extraction/extraction-llm-function/{instructions.tpl → transcription-instructions.tpl} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/assistant",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.fffef41",
|
|
4
4
|
"description": "Natural language interface to DXOS",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -38,40 +38,38 @@
|
|
|
38
38
|
"src"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@
|
|
42
|
-
"@effect/ai
|
|
43
|
-
"@effect/
|
|
44
|
-
"@effect/platform
|
|
45
|
-
"@preact/signals-core": "^1.
|
|
41
|
+
"@automerge/automerge": "3.1.2",
|
|
42
|
+
"@effect/ai": "0.29.1",
|
|
43
|
+
"@effect/experimental": "0.56.0",
|
|
44
|
+
"@effect/platform": "^0.92.1",
|
|
45
|
+
"@preact/signals-core": "^1.12.1",
|
|
46
46
|
"@xenova/transformers": "^2.17.2",
|
|
47
|
-
"chalk": "^4.1.0",
|
|
48
|
-
"handlebars": "4.7.8",
|
|
49
47
|
"lodash.defaultsdeep": "^4.6.1",
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/blueprints": "0.8.4-main.
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/echo": "0.8.4-main.
|
|
56
|
-
"@dxos/echo-protocol": "0.8.4-main.
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/graph": "0.8.4-main.
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/keys": "0.8.4-main.
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/node-std": "0.8.4-main.
|
|
67
|
-
"@dxos/schema": "0.8.4-main.
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
48
|
+
"@dxos/ai": "0.8.4-main.fffef41",
|
|
49
|
+
"@dxos/async": "0.8.4-main.fffef41",
|
|
50
|
+
"@dxos/blueprints": "0.8.4-main.fffef41",
|
|
51
|
+
"@dxos/echo": "0.8.4-main.fffef41",
|
|
52
|
+
"@dxos/debug": "0.8.4-main.fffef41",
|
|
53
|
+
"@dxos/echo-db": "0.8.4-main.fffef41",
|
|
54
|
+
"@dxos/echo-protocol": "0.8.4-main.fffef41",
|
|
55
|
+
"@dxos/context": "0.8.4-main.fffef41",
|
|
56
|
+
"@dxos/effect": "0.8.4-main.fffef41",
|
|
57
|
+
"@dxos/errors": "0.8.4-main.fffef41",
|
|
58
|
+
"@dxos/functions": "0.8.4-main.fffef41",
|
|
59
|
+
"@dxos/functions-runtime": "0.8.4-main.fffef41",
|
|
60
|
+
"@dxos/graph": "0.8.4-main.fffef41",
|
|
61
|
+
"@dxos/invariant": "0.8.4-main.fffef41",
|
|
62
|
+
"@dxos/keys": "0.8.4-main.fffef41",
|
|
63
|
+
"@dxos/live-object": "0.8.4-main.fffef41",
|
|
64
|
+
"@dxos/node-std": "0.8.4-main.fffef41",
|
|
65
|
+
"@dxos/schema": "0.8.4-main.fffef41",
|
|
66
|
+
"@dxos/log": "0.8.4-main.fffef41",
|
|
67
|
+
"@dxos/types": "0.8.4-main.fffef41",
|
|
68
|
+
"@dxos/util": "0.8.4-main.fffef41"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
|
72
71
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
73
|
-
"effect": "3.
|
|
74
|
-
"inquirer": "^12.0.0"
|
|
72
|
+
"effect": "3.18.3"
|
|
75
73
|
},
|
|
76
74
|
"peerDependencies": {
|
|
77
75
|
"effect": "^3.13.3"
|
|
@@ -81,6 +79,6 @@
|
|
|
81
79
|
},
|
|
82
80
|
"beast": {},
|
|
83
81
|
"scripts": {
|
|
84
|
-
"run:chat": "
|
|
82
|
+
"run:chat": "vite-node ./bin/chat.ts"
|
|
85
83
|
}
|
|
86
84
|
}
|
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type ReadonlySignal, computed } from '@preact/signals-core';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import * as Array from 'effect/Array';
|
|
7
|
+
import * as Context from 'effect/Context';
|
|
8
|
+
import * as Function from 'effect/Function';
|
|
9
|
+
import * as Schema from 'effect/Schema';
|
|
8
10
|
|
|
9
11
|
import { Blueprint } from '@dxos/blueprints';
|
|
10
|
-
import {
|
|
12
|
+
import { Resource } from '@dxos/context';
|
|
13
|
+
import { DXN, Filter, Obj, Query, type Ref, type Relation, Type } from '@dxos/echo';
|
|
11
14
|
import { type Queue } from '@dxos/echo-db';
|
|
15
|
+
import { invariant } from '@dxos/invariant';
|
|
12
16
|
import { ComplexSet } from '@dxos/util';
|
|
13
17
|
|
|
14
18
|
/**
|
|
15
19
|
* Thread message that binds or unbinds contextual objects to a conversation.
|
|
16
20
|
*/
|
|
17
|
-
// TODO(burdon): Move to @dxos/schema ContentBlock
|
|
21
|
+
// TODO(burdon): Move to @dxos/schema ContentBlock?
|
|
18
22
|
export const ContextBinding = Schema.Struct({
|
|
19
23
|
blueprints: Schema.Struct({
|
|
20
24
|
added: Schema.Array(Type.Ref(Blueprint.Blueprint)),
|
|
@@ -42,7 +46,8 @@ export type BindingProps = Partial<{
|
|
|
42
46
|
|
|
43
47
|
export class Bindings {
|
|
44
48
|
readonly blueprints = new ComplexSet<Ref.Ref<Blueprint.Blueprint>>((ref) => ref.dxn.toString());
|
|
45
|
-
|
|
49
|
+
// TODO(burdon): Some DXNs have the Space prefix so only compare the object ID.
|
|
50
|
+
readonly objects = new ComplexSet<Ref.Ref<Type.Expando>>((ref) => ref.dxn.asEchoDXN()?.echoId);
|
|
46
51
|
|
|
47
52
|
toJSON() {
|
|
48
53
|
return {
|
|
@@ -55,43 +60,78 @@ export class Bindings {
|
|
|
55
60
|
/**
|
|
56
61
|
* Manages bindings of blueprints and objects to a conversation.
|
|
57
62
|
*/
|
|
58
|
-
|
|
63
|
+
// TODO(burdon): Context should manage ephemeral state of bindings until prompt is issued?
|
|
64
|
+
export class AiContextBinder extends Resource {
|
|
59
65
|
/**
|
|
60
66
|
* Reactive query of all bindings.
|
|
61
67
|
*/
|
|
62
68
|
// TODO(burdon): Cache value?
|
|
63
|
-
|
|
69
|
+
private _bindings?: ReadonlySignal<Bindings>;
|
|
70
|
+
private _blueprints?: ReadonlySignal<Ref.Ref<Blueprint.Blueprint>[]>;
|
|
71
|
+
private _objects?: ReadonlySignal<Ref.Ref<Type.Expando>[]>;
|
|
64
72
|
|
|
65
|
-
readonly
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
constructor(private readonly _queue: Queue) {
|
|
74
|
+
super();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get bindings() {
|
|
78
|
+
invariant(this._bindings, 'AiContextBinder not open');
|
|
79
|
+
return this._bindings;
|
|
80
|
+
}
|
|
68
81
|
|
|
69
|
-
|
|
82
|
+
get blueprints() {
|
|
83
|
+
invariant(this._blueprints, 'AiContextBinder not open');
|
|
84
|
+
return this._blueprints;
|
|
85
|
+
}
|
|
70
86
|
|
|
71
|
-
|
|
87
|
+
get objects() {
|
|
88
|
+
invariant(this._objects, 'AiContextBinder not open');
|
|
89
|
+
return this._objects;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO(wittjosiah): Use parent context?
|
|
93
|
+
protected override async _open(): Promise<void> {
|
|
94
|
+
const query = this._queue.query(Query.select(Filter.everything()));
|
|
95
|
+
this._ctx.onDispose(query.subscribe(() => {}));
|
|
96
|
+
this._bindings = computed(() => this._reduce(query.objects));
|
|
97
|
+
this._blueprints = computed(() => [...this.bindings.value.blueprints]);
|
|
98
|
+
this._objects = computed(() => [...this.bindings.value.objects]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected override async _close(): Promise<void> {
|
|
102
|
+
this._bindings = undefined;
|
|
103
|
+
this._blueprints = undefined;
|
|
104
|
+
this._objects = undefined;
|
|
105
|
+
}
|
|
72
106
|
|
|
73
107
|
/**
|
|
74
108
|
* Asynchronous query of all bindings.
|
|
75
109
|
*/
|
|
76
110
|
async query(): Promise<Bindings> {
|
|
77
|
-
const
|
|
78
|
-
return this._reduce(
|
|
111
|
+
const { objects } = await this._queue.query(Query.select(Filter.everything())).run();
|
|
112
|
+
return this._reduce(objects);
|
|
79
113
|
}
|
|
80
114
|
|
|
81
115
|
// TODO(burdon): Pass in Blueprint obj (from registry?) and create reference.
|
|
82
116
|
async bind(props: BindingProps): Promise<void> {
|
|
83
|
-
|
|
117
|
+
const blueprints =
|
|
118
|
+
props.blueprints?.filter((ref) => !this.blueprints.peek().find((b) => b.dxn.toString() === ref.dxn.toString())) ??
|
|
119
|
+
[];
|
|
120
|
+
const objects =
|
|
121
|
+
props.objects?.filter((ref) => !this.objects.peek().find((o) => o.dxn.toString() === ref.dxn.toString())) ?? [];
|
|
122
|
+
|
|
123
|
+
if (!blueprints.length && !objects.length) {
|
|
84
124
|
return;
|
|
85
125
|
}
|
|
86
126
|
|
|
87
127
|
await this._queue.append([
|
|
88
128
|
Obj.make(ContextBinding, {
|
|
89
129
|
blueprints: {
|
|
90
|
-
added:
|
|
130
|
+
added: blueprints,
|
|
91
131
|
removed: [],
|
|
92
132
|
},
|
|
93
133
|
objects: {
|
|
94
|
-
added:
|
|
134
|
+
added: objects,
|
|
95
135
|
removed: [],
|
|
96
136
|
},
|
|
97
137
|
}),
|
|
@@ -118,16 +158,29 @@ export class AiContextBinder {
|
|
|
118
158
|
}
|
|
119
159
|
|
|
120
160
|
private _reduce(items: (Obj.Any | Relation.Any)[]): Bindings {
|
|
121
|
-
return pipe(
|
|
161
|
+
return Function.pipe(
|
|
122
162
|
items,
|
|
123
163
|
Array.filter(Obj.instanceOf(ContextBinding)),
|
|
124
164
|
Array.reduce(new Bindings(), (context, item) => {
|
|
125
|
-
item.blueprints.removed.forEach((
|
|
126
|
-
item.blueprints.added.forEach((
|
|
127
|
-
item.objects.removed.forEach((
|
|
128
|
-
|
|
165
|
+
item.blueprints.removed.forEach((ref) => context.blueprints.delete(ref));
|
|
166
|
+
item.blueprints.added.forEach((ref) => context.blueprints.add(ref));
|
|
167
|
+
item.objects.removed.forEach((ref) => {
|
|
168
|
+
for (const obj of context.objects) {
|
|
169
|
+
if (DXN.equalsEchoId(obj.dxn, ref.dxn)) {
|
|
170
|
+
context.objects.delete(obj);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
item.objects.added.forEach((ref) => context.objects.add(ref));
|
|
129
175
|
return context;
|
|
130
176
|
}),
|
|
131
177
|
);
|
|
132
178
|
}
|
|
133
179
|
}
|
|
180
|
+
|
|
181
|
+
export class AiContextService extends Context.Tag('@dxos/assistant/AiContextService')<
|
|
182
|
+
AiContextService,
|
|
183
|
+
{
|
|
184
|
+
binder: AiContextBinder;
|
|
185
|
+
}
|
|
186
|
+
>() {}
|
|
@@ -2,124 +2,127 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import type * as Toolkit from '@effect/ai/Toolkit';
|
|
6
|
+
import * as Array from 'effect/Array';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
7
9
|
|
|
8
|
-
import {
|
|
9
|
-
type AiInputPreprocessingError,
|
|
10
|
-
type AiToolNotFoundError,
|
|
11
|
-
type ToolExecutionService,
|
|
12
|
-
type ToolResolverService,
|
|
13
|
-
} from '@dxos/ai';
|
|
14
|
-
import { Event } from '@dxos/async';
|
|
10
|
+
import { Resource } from '@dxos/context';
|
|
15
11
|
import { Obj } from '@dxos/echo';
|
|
16
12
|
import { type Queue } from '@dxos/echo-db';
|
|
17
|
-
import { DatabaseService } from '@dxos/
|
|
13
|
+
import { DatabaseService } from '@dxos/echo-db';
|
|
18
14
|
import { log } from '@dxos/log';
|
|
19
|
-
import {
|
|
15
|
+
import { Message } from '@dxos/types';
|
|
20
16
|
|
|
21
|
-
import {
|
|
22
|
-
|
|
17
|
+
import {
|
|
18
|
+
AiSession,
|
|
19
|
+
type AiSessionRunError,
|
|
20
|
+
type AiSessionRunRequirements,
|
|
21
|
+
type GenerationObserver,
|
|
22
|
+
createToolkit,
|
|
23
|
+
} from '../session';
|
|
23
24
|
|
|
24
|
-
import { AiContextBinder, type ContextBinding } from './context';
|
|
25
|
+
import { AiContextBinder, AiContextService, type ContextBinding } from './context';
|
|
25
26
|
|
|
26
|
-
export interface AiConversationRunParams
|
|
27
|
+
export interface AiConversationRunParams {
|
|
27
28
|
prompt: string;
|
|
28
29
|
system?: string;
|
|
29
|
-
toolkit?: AiToolkit.AiToolkit<Tools>;
|
|
30
30
|
observer?: GenerationObserver;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @deprecated Remove
|
|
34
|
-
*/
|
|
35
|
-
session?: AiSession;
|
|
36
31
|
}
|
|
37
32
|
|
|
38
|
-
export type AiConversationOptions = {
|
|
39
|
-
queue: Queue<DataType.Message | ContextBinding>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
33
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* Backed by a Queue.
|
|
34
|
+
* Durable conversation state (initiated by users and agents) backed by a Queue.
|
|
35
|
+
* Executes tools based on AI responses and supports cancellation of in-progress requests.
|
|
46
36
|
*/
|
|
47
|
-
export class AiConversation {
|
|
48
|
-
|
|
37
|
+
export class AiConversation extends Resource {
|
|
38
|
+
/**
|
|
39
|
+
* Message and binding queue.
|
|
40
|
+
*/
|
|
41
|
+
private readonly _queue: Queue<Message.Message | ContextBinding>;
|
|
49
42
|
|
|
50
43
|
/**
|
|
51
44
|
* Blueprints bound to the conversation.
|
|
52
45
|
*/
|
|
53
|
-
|
|
46
|
+
private readonly _context: AiContextBinder;
|
|
54
47
|
|
|
55
48
|
/**
|
|
56
|
-
*
|
|
57
|
-
* This is called before the first message is sent.
|
|
58
|
-
*
|
|
59
|
-
* @deprecated Pass in a session instead.
|
|
49
|
+
* Toolkit from the current session request.
|
|
60
50
|
*/
|
|
61
|
-
|
|
62
|
-
public readonly onBegin = new Event<AiSession>();
|
|
51
|
+
private _toolkit: Toolkit.WithHandler<any> | undefined;
|
|
63
52
|
|
|
64
|
-
constructor(
|
|
65
|
-
|
|
53
|
+
public constructor(queue: Queue<Message.Message | ContextBinding>) {
|
|
54
|
+
super();
|
|
55
|
+
this._queue = queue;
|
|
66
56
|
this._context = new AiContextBinder(this._queue);
|
|
67
57
|
}
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
protected override async _open(): Promise<void> {
|
|
60
|
+
// TODO(wittjosiah): Pass in parent context?
|
|
61
|
+
await this._context.open();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected override async _close(): Promise<void> {
|
|
65
|
+
await this._context.close();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public get context() {
|
|
70
69
|
return this._context;
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
public get toolkit() {
|
|
73
|
+
return this._toolkit;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public async getHistory(): Promise<Message.Message[]> {
|
|
74
77
|
const queueItems = await this._queue.queryObjects();
|
|
75
|
-
return queueItems.filter(Obj.instanceOf(
|
|
78
|
+
return queueItems.filter(Obj.instanceOf(Message.Message));
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
/**
|
|
79
|
-
*
|
|
80
|
-
* Each invocation creates a new `AiSession`, which handles potential tool calls.
|
|
82
|
+
* Creates a new cancelable request effect.
|
|
81
83
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
DataType.Message[],
|
|
88
|
-
AiAssistantError | AiInputPreprocessingError | AiError.AiError | AiToolNotFoundError,
|
|
89
|
-
AiLanguageModel.AiLanguageModel | ToolResolverService | ToolExecutionService | AiTool.ToHandler<Tools>
|
|
90
|
-
> =>
|
|
91
|
-
Effect.gen(this, function* () {
|
|
84
|
+
createRequest(
|
|
85
|
+
params: AiConversationRunParams,
|
|
86
|
+
): Effect.Effect<Message.Message[], AiSessionRunError, AiSessionRunRequirements> {
|
|
87
|
+
return Effect.gen(this, function* () {
|
|
88
|
+
const session = new AiSession();
|
|
92
89
|
const history = yield* Effect.promise(() => this.getHistory());
|
|
93
|
-
const context = yield* Effect.promise(() => this.context.query());
|
|
94
|
-
const blueprints = yield* Effect.forEach(context.blueprints.values(), DatabaseService.load);
|
|
95
90
|
|
|
96
|
-
//
|
|
97
|
-
const
|
|
91
|
+
// Get context objects.
|
|
92
|
+
const context = yield* Effect.promise(() => this.context.query());
|
|
93
|
+
const blueprints = yield* Effect.forEach(context.blueprints.values(), DatabaseService.loadOption).pipe(
|
|
94
|
+
Effect.map(Array.filter(Option.isSome)),
|
|
95
|
+
Effect.map(Array.map((option) => option.value)),
|
|
96
|
+
);
|
|
97
|
+
const objects = yield* Effect.forEach(context.objects.values(), DatabaseService.loadOption).pipe(
|
|
98
|
+
Effect.map(Array.filter(Option.isSome)),
|
|
99
|
+
Effect.map(Array.map((option) => option.value)),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Create toolkit.
|
|
103
|
+
const toolkit = yield* createToolkit({ blueprints });
|
|
104
|
+
this._toolkit = toolkit;
|
|
98
105
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
system: params.system,
|
|
106
|
+
const start = Date.now();
|
|
107
|
+
log('run', {
|
|
102
108
|
history: history.length,
|
|
103
|
-
objects: objects.length,
|
|
104
109
|
blueprints: blueprints.length,
|
|
105
|
-
|
|
110
|
+
objects: objects.length,
|
|
111
|
+
tools: this._toolkit?.tools.length ?? 0,
|
|
106
112
|
});
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
history,
|
|
115
|
-
objects,
|
|
116
|
-
blueprints,
|
|
117
|
-
toolkit: params.toolkit,
|
|
118
|
-
observer: params.observer,
|
|
119
|
-
});
|
|
114
|
+
// Process request.
|
|
115
|
+
const messages = yield* session.run({ history, blueprints, objects, toolkit, ...params }).pipe(
|
|
116
|
+
Effect.provideService(AiContextService, {
|
|
117
|
+
binder: this.context,
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
120
|
|
|
121
|
-
log
|
|
121
|
+
log('result', { messages: messages.length, duration: Date.now() - start });
|
|
122
|
+
|
|
123
|
+
// Append to queue.
|
|
122
124
|
yield* Effect.promise(() => this._queue.append(messages));
|
|
123
125
|
return messages;
|
|
124
|
-
}).pipe(Effect.withSpan('AiConversation.
|
|
126
|
+
}).pipe(Effect.withSpan('AiConversation.request'));
|
|
127
|
+
}
|
|
125
128
|
}
|
package/src/diff.test.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { createDocAccessor } from '@dxos/echo-db';
|
|
8
|
+
import { EchoTestBuilder } from '@dxos/echo-db/testing';
|
|
9
|
+
import { Text } from '@dxos/schema';
|
|
10
|
+
import { trim } from '@dxos/util';
|
|
11
|
+
|
|
12
|
+
import { applyDiffs } from './diff';
|
|
13
|
+
|
|
14
|
+
describe('diff', () => {
|
|
15
|
+
it('should apply diffs', async () => {
|
|
16
|
+
const builder = new EchoTestBuilder();
|
|
17
|
+
const { db, graph } = await builder.createDatabase();
|
|
18
|
+
graph.schemaRegistry.addSchema([Text.Text]);
|
|
19
|
+
|
|
20
|
+
const document = trim`
|
|
21
|
+
# Hello World
|
|
22
|
+
There'z a typo in this sentence.
|
|
23
|
+
And another oon here.
|
|
24
|
+
But not this one.
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const text = db.add(Text.make(document));
|
|
28
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
29
|
+
const result = applyDiffs(accessor, [
|
|
30
|
+
`- There'z a typo in this sentence.`,
|
|
31
|
+
`+ There is a typo in this sentence.`,
|
|
32
|
+
`- And another oon here.`,
|
|
33
|
+
`+ And another one here.`,
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
expect(result).toBe(trim`
|
|
37
|
+
# Hello World
|
|
38
|
+
There is a typo in this sentence.
|
|
39
|
+
And another one here.
|
|
40
|
+
But not this one.
|
|
41
|
+
`);
|
|
42
|
+
});
|
|
43
|
+
});
|
package/src/diff.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { next as A, type Doc } from '@automerge/automerge';
|
|
6
|
+
|
|
7
|
+
import { DocAccessor, toCursorRange } from '@dxos/echo-db';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
import { isNonNullable } from '@dxos/util';
|
|
10
|
+
|
|
11
|
+
// Relevant info:
|
|
12
|
+
// https://github.com/Minahil-official/GPT-4.1-Promting-Guide?tab=readme-ov-file#-apply-patch-tool-format-v4a-diff
|
|
13
|
+
|
|
14
|
+
// TODO(burdon): Anthropic only.
|
|
15
|
+
// https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/text-editor-tool#example-str-replace-command
|
|
16
|
+
// AI_TOOL_NOT_FOUND: str_replace_based_edit_tool
|
|
17
|
+
// 'str_replace_based_edit_tool',
|
|
18
|
+
|
|
19
|
+
// TOOD(burdon): Support append to end (no "-").
|
|
20
|
+
|
|
21
|
+
export type Diff = {
|
|
22
|
+
match: string;
|
|
23
|
+
replace: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convert a list of diffs into a list of operations.
|
|
28
|
+
*/
|
|
29
|
+
export const reduceDiffs = (diffs: readonly string[]): Diff[] => {
|
|
30
|
+
return diffs.reduce<Diff[]>((acc, diff) => {
|
|
31
|
+
const current = acc[acc.length - 1];
|
|
32
|
+
const [op, ...rest] = diff.split(' ');
|
|
33
|
+
switch (op) {
|
|
34
|
+
case '-': {
|
|
35
|
+
if (current && !current.match) {
|
|
36
|
+
current.match += rest.join(' ');
|
|
37
|
+
} else {
|
|
38
|
+
acc.push({ match: rest.join(' '), replace: '' });
|
|
39
|
+
}
|
|
40
|
+
return acc;
|
|
41
|
+
}
|
|
42
|
+
case '+': {
|
|
43
|
+
if (current && !current.replace) {
|
|
44
|
+
current.replace += rest.join(' ');
|
|
45
|
+
} else {
|
|
46
|
+
acc.push({ match: '', replace: rest.join(' ') });
|
|
47
|
+
}
|
|
48
|
+
return acc;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return acc;
|
|
53
|
+
}, []);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const computeDiffsWithCursors = <T>(accessor: DocAccessor<T>, diffs: readonly string[]) => {
|
|
57
|
+
return reduceDiffs(diffs)
|
|
58
|
+
.map((diff) => {
|
|
59
|
+
const text = DocAccessor.getValue<string>(accessor);
|
|
60
|
+
const idx = text.indexOf(diff.match);
|
|
61
|
+
if (idx !== -1) {
|
|
62
|
+
return { cursor: toCursorRange(accessor, idx, idx + diff.match.length), text: diff.replace };
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
.filter(isNonNullable);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const applyDiffs = <T>(accessor: DocAccessor<T>, diffs: readonly string[]): string => {
|
|
69
|
+
for (const diff of reduceDiffs(diffs)) {
|
|
70
|
+
accessor.handle.change((doc: Doc<T>) => {
|
|
71
|
+
const text = DocAccessor.getValue<string>(accessor);
|
|
72
|
+
const idx = text.indexOf(diff.match);
|
|
73
|
+
if (idx !== -1) {
|
|
74
|
+
// TODO(burdon): Replace smallest substring.
|
|
75
|
+
// NOTE: This only replaces the first match.
|
|
76
|
+
A.splice(doc, accessor.path as A.Prop[], idx, diff.match.length, diff.replace);
|
|
77
|
+
} else {
|
|
78
|
+
log.warn('diff not found', diff);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return DocAccessor.getValue<string>(accessor);
|
|
84
|
+
};
|
package/src/errors.ts
CHANGED
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { BaseError } from '@dxos/errors';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Generic error from AI model.
|
|
9
|
+
*/
|
|
10
|
+
export class AiModelError extends BaseError.extend('AI_MODEL_ERROR', 'AI model error') {}
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Generic error for AI agent execution.
|
|
9
14
|
*/
|
|
10
|
-
export class AiAssistantError extends BaseError.extend('AI_ASSISTANT_ERROR') {}
|
|
15
|
+
export class AiAssistantError extends BaseError.extend('AI_ASSISTANT_ERROR', 'AI assistant error') {}
|