@dxos/assistant 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
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/README.md +1 -0
- package/dist/lib/neutral/chunk-BE6SRJ4N.mjs +193 -0
- package/dist/lib/neutral/chunk-BE6SRJ4N.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/extraction/index.mjs +4 -6
- package/dist/lib/neutral/extraction/index.mjs.map +7 -0
- package/dist/lib/{node-esm → neutral}/index.mjs +546 -69
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/testing/index.mjs +38 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/conversation/context.d.ts +20 -3
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +26 -1
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/diff.d.ts +3 -1
- package/dist/types/src/diff.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +13 -5
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +16 -12
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +5 -6
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/session/index.d.ts +1 -1
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/observer.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +12 -7
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +6 -2
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/testing/layer.d.ts +6 -5
- package/dist/types/src/testing/layer.d.ts.map +1 -1
- package/dist/types/src/types/artifact.d.ts +5 -5
- package/dist/types/src/types/artifact.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -33
- package/src/conversation/context.test.ts +1 -1
- package/src/conversation/context.ts +35 -8
- package/src/conversation/conversation.ts +136 -14
- package/src/diff.test.ts +35 -4
- package/src/diff.ts +13 -4
- package/src/execution-graph.test.ts +2 -2
- package/src/execution-graph.ts +2 -2
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +1 -1
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +1 -1
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +1 -1
- package/src/extraction/extraction.ts +2 -2
- package/src/functions/services.ts +59 -30
- package/src/functions.conversations.json +1 -1
- package/src/functions.test.ts +7 -7
- package/src/session/format.test.ts +2 -2
- package/src/session/index.ts +1 -2
- package/src/session/observer.ts +3 -2
- package/src/session/session.conversations.json +1 -1
- package/src/session/session.test.ts +52 -4
- package/src/session/session.ts +68 -51
- package/src/session/toolkit.ts +12 -7
- package/src/templates/instructions/format.tpl +0 -4
- package/src/testing/layer.ts +24 -17
- package/src/types/artifact.ts +17 -10
- package/dist/lib/browser/chunk-7CDDG6LL.mjs +0 -578
- package/dist/lib/browser/chunk-7CDDG6LL.mjs.map +0 -7
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/browser/extraction/index.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -850
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs +0 -32
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CC7ER6Q3.mjs +0 -579
- package/dist/lib/node-esm/chunk-CC7ER6Q3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/extraction/index.mjs +0 -226
- package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -33
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/session/GenericToolkit.d.ts +0 -85
- package/dist/types/src/session/GenericToolkit.d.ts.map +0 -1
- package/src/session/GenericToolkit.ts +0 -131
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.6fa680abb7",
|
|
4
4
|
"description": "Natural language interface to DXOS",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,20 +16,17 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"source": "./src/index.ts",
|
|
18
18
|
"types": "./dist/types/src/index.d.ts",
|
|
19
|
-
"
|
|
20
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
|
+
"default": "./dist/lib/neutral/index.mjs"
|
|
21
20
|
},
|
|
22
21
|
"./extraction": {
|
|
23
22
|
"source": "./src/extraction/index.ts",
|
|
24
23
|
"types": "./dist/types/src/extraction/index.d.ts",
|
|
25
|
-
"
|
|
26
|
-
"node": "./dist/lib/node-esm/extraction/index.mjs"
|
|
24
|
+
"default": "./dist/lib/neutral/extraction/index.mjs"
|
|
27
25
|
},
|
|
28
26
|
"./testing": {
|
|
29
27
|
"source": "./src/testing/index.ts",
|
|
30
28
|
"types": "./dist/types/src/testing/index.d.ts",
|
|
31
|
-
"
|
|
32
|
-
"node": "./dist/lib/node-esm/testing/index.mjs"
|
|
29
|
+
"default": "./dist/lib/neutral/testing/index.mjs"
|
|
33
30
|
}
|
|
34
31
|
},
|
|
35
32
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -49,39 +46,41 @@
|
|
|
49
46
|
],
|
|
50
47
|
"dependencies": {
|
|
51
48
|
"@automerge/automerge": "3.2.3",
|
|
52
|
-
"@effect-atom/atom
|
|
53
|
-
"@effect/
|
|
54
|
-
"@effect/
|
|
55
|
-
"@effect/
|
|
49
|
+
"@effect-atom/atom": "^0.5.1",
|
|
50
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
51
|
+
"@effect/ai": "0.33.2",
|
|
52
|
+
"@effect/experimental": "0.58.0",
|
|
53
|
+
"@effect/platform": "0.94.4",
|
|
56
54
|
"@xenova/transformers": "^2.17.2",
|
|
57
55
|
"lodash.defaultsdeep": "^4.6.1",
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/echo-
|
|
65
|
-
"@dxos/echo-
|
|
66
|
-
"@dxos/errors": "0.8.4-main.
|
|
67
|
-
"@dxos/effect": "0.8.4-main.
|
|
68
|
-
"@dxos/functions": "0.8.4-main.
|
|
69
|
-
"@dxos/functions-runtime": "0.8.4-main.
|
|
70
|
-
"@dxos/graph": "0.8.4-main.
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/node-std": "0.8.4-main.
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
56
|
+
"@dxos/blueprints": "0.8.4-main.6fa680abb7",
|
|
57
|
+
"@dxos/ai": "0.8.4-main.6fa680abb7",
|
|
58
|
+
"@dxos/context": "0.8.4-main.6fa680abb7",
|
|
59
|
+
"@dxos/debug": "0.8.4-main.6fa680abb7",
|
|
60
|
+
"@dxos/async": "0.8.4-main.6fa680abb7",
|
|
61
|
+
"@dxos/echo": "0.8.4-main.6fa680abb7",
|
|
62
|
+
"@dxos/echo-protocol": "0.8.4-main.6fa680abb7",
|
|
63
|
+
"@dxos/echo-db": "0.8.4-main.6fa680abb7",
|
|
64
|
+
"@dxos/errors": "0.8.4-main.6fa680abb7",
|
|
65
|
+
"@dxos/effect": "0.8.4-main.6fa680abb7",
|
|
66
|
+
"@dxos/functions": "0.8.4-main.6fa680abb7",
|
|
67
|
+
"@dxos/functions-runtime": "0.8.4-main.6fa680abb7",
|
|
68
|
+
"@dxos/graph": "0.8.4-main.6fa680abb7",
|
|
69
|
+
"@dxos/invariant": "0.8.4-main.6fa680abb7",
|
|
70
|
+
"@dxos/keys": "0.8.4-main.6fa680abb7",
|
|
71
|
+
"@dxos/mcp-client": "0.8.4-main.6fa680abb7",
|
|
72
|
+
"@dxos/node-std": "0.8.4-main.6fa680abb7",
|
|
73
|
+
"@dxos/log": "0.8.4-main.6fa680abb7",
|
|
74
|
+
"@dxos/schema": "0.8.4-main.6fa680abb7",
|
|
75
|
+
"@dxos/types": "0.8.4-main.6fa680abb7",
|
|
76
|
+
"@dxos/util": "0.8.4-main.6fa680abb7"
|
|
78
77
|
},
|
|
79
78
|
"devDependencies": {
|
|
80
79
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
81
|
-
"effect": "3.19.
|
|
80
|
+
"effect": "3.19.16"
|
|
82
81
|
},
|
|
83
82
|
"peerDependencies": {
|
|
84
|
-
"effect": "3.19.
|
|
83
|
+
"effect": "3.19.16"
|
|
85
84
|
},
|
|
86
85
|
"publishConfig": {
|
|
87
86
|
"access": "public"
|
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
import { Atom, Registry } from '@effect-atom/atom-react';
|
|
6
6
|
import * as EArray from 'effect/Array';
|
|
7
7
|
import * as Context from 'effect/Context';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
8
9
|
import * as Function from 'effect/Function';
|
|
9
10
|
import * as Schema from 'effect/Schema';
|
|
10
11
|
|
|
11
12
|
import { Blueprint } from '@dxos/blueprints';
|
|
12
13
|
import { Resource } from '@dxos/context';
|
|
13
|
-
import { DXN, Obj, Query,
|
|
14
|
+
import { DXN, Obj, Query, Ref, Type } from '@dxos/echo';
|
|
14
15
|
import { type Queue } from '@dxos/echo-db';
|
|
16
|
+
import { assertArgument } from '@dxos/invariant';
|
|
15
17
|
import { log } from '@dxos/log';
|
|
16
18
|
import { ComplexSet, isTruthy } from '@dxos/util';
|
|
17
19
|
|
|
@@ -21,17 +23,17 @@ import { ComplexSet, isTruthy } from '@dxos/util';
|
|
|
21
23
|
// TODO(burdon): Move to @dxos/schema ContentBlock?
|
|
22
24
|
export const ContextBinding = Schema.Struct({
|
|
23
25
|
blueprints: Schema.Struct({
|
|
24
|
-
added: Schema.Array(
|
|
25
|
-
removed: Schema.Array(
|
|
26
|
+
added: Schema.Array(Ref.Ref(Blueprint.Blueprint)),
|
|
27
|
+
removed: Schema.Array(Ref.Ref(Blueprint.Blueprint)),
|
|
26
28
|
}),
|
|
27
29
|
|
|
28
30
|
objects: Schema.Struct({
|
|
29
|
-
added: Schema.Array(
|
|
30
|
-
removed: Schema.Array(
|
|
31
|
+
added: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
32
|
+
removed: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
31
33
|
}),
|
|
32
34
|
}).pipe(
|
|
33
35
|
Type.object({
|
|
34
|
-
typename: 'dxos.
|
|
36
|
+
typename: 'org.dxos.type.context-binding',
|
|
35
37
|
version: '0.1.0',
|
|
36
38
|
}),
|
|
37
39
|
);
|
|
@@ -74,6 +76,7 @@ export class AiContextBinder extends Resource {
|
|
|
74
76
|
|
|
75
77
|
constructor(options: AiContextBinderOptions) {
|
|
76
78
|
super();
|
|
79
|
+
assertArgument(options.queue, 'options.queue', 'Queue is required');
|
|
77
80
|
this._queue = options.queue;
|
|
78
81
|
this._registry = options.registry ?? Registry.make();
|
|
79
82
|
}
|
|
@@ -278,7 +281,7 @@ export class AiContextBinder extends Resource {
|
|
|
278
281
|
const refArray = [...refs];
|
|
279
282
|
|
|
280
283
|
// Load all refs that need loading.
|
|
281
|
-
await Promise.all(refArray.map((ref) => ref.
|
|
284
|
+
await Promise.all(refArray.map((ref) => ref.tryLoad()));
|
|
282
285
|
|
|
283
286
|
return refArray
|
|
284
287
|
.map((ref) => {
|
|
@@ -300,4 +303,28 @@ export class AiContextService extends Context.Tag('@dxos/assistant/AiContextServ
|
|
|
300
303
|
{
|
|
301
304
|
binder: AiContextBinder;
|
|
302
305
|
}
|
|
303
|
-
>() {
|
|
306
|
+
>() {
|
|
307
|
+
static bindContext = ({ blueprints, objects }: BindingProps): Effect.Effect<void, never, AiContextService> =>
|
|
308
|
+
Effect.gen(function* () {
|
|
309
|
+
const { binder } = yield* AiContextService;
|
|
310
|
+
yield* Effect.promise(() => binder.bind({ blueprints, objects }));
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
static findObjects = <T extends Type.AnyEntity>(
|
|
314
|
+
type: T,
|
|
315
|
+
): Effect.Effect<Schema.Schema.Type<T>[], never, AiContextService> => {
|
|
316
|
+
return Effect.gen(function* () {
|
|
317
|
+
const { binder } = yield* AiContextService;
|
|
318
|
+
return binder.getObjects().filter(Obj.instanceOf(type));
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Glorified type cast until we figure out function service typing.
|
|
324
|
+
* For context, the AiContextService is provided to functions called from tool calls, but it's not implemented in types yet.
|
|
325
|
+
* @deprecated
|
|
326
|
+
*/
|
|
327
|
+
static fixFunctionHandlerType = <A, E, R>(
|
|
328
|
+
eff: Effect.Effect<A, E, R>,
|
|
329
|
+
): Effect.Effect<A, E, Exclude<R, AiContextService>> => eff as any;
|
|
330
|
+
}
|
|
@@ -2,15 +2,27 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type * as Tool from '@effect/ai/Tool';
|
|
5
6
|
import type * as Toolkit from '@effect/ai/Toolkit';
|
|
6
7
|
import type { Registry } from '@effect-atom/atom-react';
|
|
8
|
+
import * as Array from 'effect/Array';
|
|
9
|
+
import * as Context from 'effect/Context';
|
|
7
10
|
import * as Effect from 'effect/Effect';
|
|
11
|
+
import * as Either from 'effect/Either';
|
|
12
|
+
import { pipe } from 'effect/Function';
|
|
13
|
+
import * as Layer from 'effect/Layer';
|
|
8
14
|
|
|
15
|
+
import { type ToolExecutionService, type ToolResolverService } from '@dxos/ai';
|
|
16
|
+
import { type GenericToolkit } from '@dxos/ai';
|
|
17
|
+
import { type Blueprint } from '@dxos/blueprints';
|
|
9
18
|
import { Resource } from '@dxos/context';
|
|
10
19
|
import { Obj } from '@dxos/echo';
|
|
11
20
|
import { type Queue } from '@dxos/echo-db';
|
|
21
|
+
import { acquireReleaseResource } from '@dxos/effect';
|
|
22
|
+
import { QueueService } from '@dxos/functions';
|
|
12
23
|
import { invariant } from '@dxos/invariant';
|
|
13
24
|
import { log } from '@dxos/log';
|
|
25
|
+
import { McpToolkit } from '@dxos/mcp-client';
|
|
14
26
|
import { Message } from '@dxos/types';
|
|
15
27
|
|
|
16
28
|
import {
|
|
@@ -35,6 +47,12 @@ export type AiConversationOptions = {
|
|
|
35
47
|
registry?: Registry.Registry;
|
|
36
48
|
};
|
|
37
49
|
|
|
50
|
+
// TODO(dmaretskyi): Take from model characteristics. opus has 200k max tokens.
|
|
51
|
+
/**
|
|
52
|
+
* Summarization threshold in tokens.
|
|
53
|
+
*/
|
|
54
|
+
const SUMMARY_THRESHOLD = 80_000;
|
|
55
|
+
|
|
38
56
|
/**
|
|
39
57
|
* Durable conversation state (initiated by users and agents) backed by a Queue.
|
|
40
58
|
* Executes tools based on AI responses and supports cancellation of in-progress requests.
|
|
@@ -76,25 +94,36 @@ export class AiConversation extends Resource {
|
|
|
76
94
|
return queueItems.filter(Obj.instanceOf(Message.Message));
|
|
77
95
|
}
|
|
78
96
|
|
|
97
|
+
getTools(): Effect.Effect<Record<string, Tool.Any>, never, ToolExecutionService | ToolResolverService> {
|
|
98
|
+
return Effect.gen(this, function* () {
|
|
99
|
+
const blueprints = this.context.getBlueprints();
|
|
100
|
+
const tookit = yield* createToolkit({ toolkit: this._toolkit, blueprints });
|
|
101
|
+
return tookit.tools;
|
|
102
|
+
}).pipe(Effect.orDie);
|
|
103
|
+
}
|
|
104
|
+
|
|
79
105
|
/**
|
|
80
106
|
* Creates a new cancelable request effect.
|
|
81
107
|
*/
|
|
82
108
|
public createRequest(
|
|
83
109
|
params: AiConversationRunProps,
|
|
84
110
|
): Effect.Effect<Message.Message[], AiSessionRunError, AiSessionRunRequirements> {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const history = yield* Effect.promise(() => self.getHistory());
|
|
111
|
+
return Effect.gen(this, function* () {
|
|
112
|
+
const history = yield* Effect.promise(() => this.getHistory());
|
|
88
113
|
|
|
89
114
|
// Create toolkit.
|
|
90
|
-
const blueprints =
|
|
115
|
+
const blueprints = this.context.getBlueprints();
|
|
116
|
+
|
|
117
|
+
const mcps = yield* connectMcpServers(blueprints);
|
|
118
|
+
|
|
91
119
|
const toolkit = yield* createToolkit({
|
|
92
|
-
toolkit:
|
|
120
|
+
toolkit: this._toolkit,
|
|
93
121
|
blueprints,
|
|
122
|
+
genericToolkits: mcps,
|
|
94
123
|
});
|
|
95
124
|
|
|
96
125
|
// Context objects.
|
|
97
|
-
const objects =
|
|
126
|
+
const objects = this.context.getObjects();
|
|
98
127
|
|
|
99
128
|
log('run', {
|
|
100
129
|
history: history.length,
|
|
@@ -104,12 +133,28 @@ export class AiConversation extends Resource {
|
|
|
104
133
|
});
|
|
105
134
|
|
|
106
135
|
// Process request.
|
|
107
|
-
const session = new AiSession(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
136
|
+
const session = new AiSession({
|
|
137
|
+
summarizationThreshold: SUMMARY_THRESHOLD,
|
|
138
|
+
});
|
|
139
|
+
const messages = yield* session
|
|
140
|
+
.run({
|
|
141
|
+
history,
|
|
142
|
+
blueprints,
|
|
143
|
+
toolkit,
|
|
144
|
+
objects,
|
|
145
|
+
...params,
|
|
146
|
+
onOutput: (message) => Effect.promise(() => this._queue.append([message])),
|
|
147
|
+
})
|
|
148
|
+
.pipe(
|
|
149
|
+
Effect.provide(
|
|
150
|
+
Layer.mergeAll(
|
|
151
|
+
Layer.succeed(AiContextService, {
|
|
152
|
+
binder: this.context,
|
|
153
|
+
}),
|
|
154
|
+
Layer.succeed(AiConversationService, this),
|
|
155
|
+
),
|
|
156
|
+
),
|
|
157
|
+
);
|
|
113
158
|
|
|
114
159
|
log('result', {
|
|
115
160
|
messages: messages.length,
|
|
@@ -117,9 +162,86 @@ export class AiConversation extends Resource {
|
|
|
117
162
|
toolCalls: session.toolCalls,
|
|
118
163
|
});
|
|
119
164
|
|
|
120
|
-
// Append to queue.
|
|
121
|
-
yield* Effect.promise(() => self._queue.append(messages));
|
|
122
165
|
return messages;
|
|
123
166
|
});
|
|
124
167
|
}
|
|
125
168
|
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Gives access to the ai conversation.
|
|
172
|
+
*/
|
|
173
|
+
export class AiConversationService extends Context.Tag('@dxos/assistant/AiConversationService')<
|
|
174
|
+
AiConversationService,
|
|
175
|
+
AiConversation
|
|
176
|
+
>() {
|
|
177
|
+
/**
|
|
178
|
+
* Create a new conversation layer from options.
|
|
179
|
+
*/
|
|
180
|
+
static layer = (options: AiConversationOptions): Layer.Layer<AiConversationService | AiContextService> =>
|
|
181
|
+
aiContextFromConversation.pipe(
|
|
182
|
+
Layer.provideMerge(
|
|
183
|
+
Layer.scoped(
|
|
184
|
+
AiConversationService,
|
|
185
|
+
Effect.gen(function* () {
|
|
186
|
+
const conversation = yield* acquireReleaseResource(() => new AiConversation(options));
|
|
187
|
+
return conversation;
|
|
188
|
+
}),
|
|
189
|
+
),
|
|
190
|
+
),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create a new conversation with a new queue.
|
|
195
|
+
*/
|
|
196
|
+
static layerNewQueue = (
|
|
197
|
+
options?: Omit<AiConversationOptions, 'queue'>,
|
|
198
|
+
): Layer.Layer<AiConversationService | AiContextService, never, QueueService> =>
|
|
199
|
+
Layer.unwrapScoped(
|
|
200
|
+
Effect.gen(function* () {
|
|
201
|
+
return AiConversationService.layer({
|
|
202
|
+
...options,
|
|
203
|
+
queue: yield* QueueService.createQueue<Message.Message | ContextBinding>(),
|
|
204
|
+
});
|
|
205
|
+
}),
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Run a prompt in the current conversation.
|
|
210
|
+
*/
|
|
211
|
+
static run = (
|
|
212
|
+
params: AiConversationRunProps,
|
|
213
|
+
): Effect.Effect<Message.Message[], AiSessionRunError, AiSessionRunRequirements | AiConversationService> =>
|
|
214
|
+
Effect.gen(function* () {
|
|
215
|
+
const conversation = yield* AiConversationService;
|
|
216
|
+
return yield* conversation.createRequest(params);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const aiContextFromConversation = Layer.effect(
|
|
221
|
+
AiContextService,
|
|
222
|
+
Effect.gen(function* () {
|
|
223
|
+
const conversation = yield* AiConversationService;
|
|
224
|
+
return {
|
|
225
|
+
binder: conversation.context,
|
|
226
|
+
};
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const connectMcpServers = (
|
|
231
|
+
blueprints: readonly Blueprint.Blueprint[],
|
|
232
|
+
): Effect.Effect<GenericToolkit.GenericToolkit[]> =>
|
|
233
|
+
pipe(
|
|
234
|
+
blueprints,
|
|
235
|
+
Array.flatMap((_) => _.mcpServers ?? []),
|
|
236
|
+
Effect.forEach(({ url, protocol }) =>
|
|
237
|
+
McpToolkit.make({ url, kind: protocol }).pipe(
|
|
238
|
+
// NOTE: Type-inference fails here without explicit void return.
|
|
239
|
+
Effect.tap((toolkit): void =>
|
|
240
|
+
log.info('Connected to MCP server', { url, tools: Object.keys(toolkit.toolkit.tools).length }),
|
|
241
|
+
),
|
|
242
|
+
Effect.tapDefect((error) => Effect.sync(() => log.warn('Failed to connect to MCP server', { error }))),
|
|
243
|
+
Effect.either,
|
|
244
|
+
),
|
|
245
|
+
),
|
|
246
|
+
Effect.map(Array.filterMap((_) => Either.getRight(_))),
|
|
247
|
+
);
|
package/src/diff.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { createDocAccessor } from '@dxos/echo-db';
|
|
8
8
|
import { EchoTestBuilder } from '@dxos/echo-db/testing';
|
|
@@ -12,10 +12,17 @@ import { trim } from '@dxos/util';
|
|
|
12
12
|
import { applyDiffs } from './diff';
|
|
13
13
|
|
|
14
14
|
describe('diff', () => {
|
|
15
|
+
let builder: EchoTestBuilder;
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
builder = await new EchoTestBuilder().open();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await builder.close();
|
|
22
|
+
});
|
|
23
|
+
|
|
15
24
|
it('should apply diffs', async () => {
|
|
16
|
-
const
|
|
17
|
-
const { db, graph } = await builder.createDatabase();
|
|
18
|
-
await graph.schemaRegistry.register([Text.Text]);
|
|
25
|
+
const { db } = await builder.createDatabase({ types: [Text.Text] });
|
|
19
26
|
|
|
20
27
|
const document = trim`
|
|
21
28
|
# Hello World
|
|
@@ -40,4 +47,28 @@ describe('diff', () => {
|
|
|
40
47
|
But not this one.
|
|
41
48
|
`);
|
|
42
49
|
});
|
|
50
|
+
|
|
51
|
+
it('should apply diffs that append content at the end', async () => {
|
|
52
|
+
const { db } = await builder.createDatabase({ types: [Text.Text] });
|
|
53
|
+
|
|
54
|
+
const document = '# Shopping list';
|
|
55
|
+
|
|
56
|
+
const text = db.add(Text.make(document));
|
|
57
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
58
|
+
const result = applyDiffs(accessor, ['- # Shopping list', '+ # Shopping list\n- Milk']);
|
|
59
|
+
|
|
60
|
+
expect(result).toBe('# Shopping list\n- Milk');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should append text to an empty document', async () => {
|
|
64
|
+
const builder = new EchoTestBuilder();
|
|
65
|
+
const { db, graph } = await builder.createDatabase();
|
|
66
|
+
await graph.schemaRegistry.register([Text.Text]);
|
|
67
|
+
|
|
68
|
+
const text = db.add(Text.make(''));
|
|
69
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
70
|
+
const result = applyDiffs(accessor, ['+ # Shopping list']);
|
|
71
|
+
|
|
72
|
+
expect(result).toBe('# Shopping list');
|
|
73
|
+
});
|
|
43
74
|
});
|
package/src/diff.ts
CHANGED
|
@@ -47,9 +47,10 @@ export const reduceDiffs = (diffs: readonly string[]): Diff[] => {
|
|
|
47
47
|
}
|
|
48
48
|
return acc;
|
|
49
49
|
}
|
|
50
|
+
default: {
|
|
51
|
+
throw new Error(`Invalid diff format: each line must start with "- " or "+ ", got: ${JSON.stringify(diff)}`);
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
return acc;
|
|
53
54
|
}, []);
|
|
54
55
|
};
|
|
55
56
|
|
|
@@ -65,7 +66,11 @@ export const computeDiffsWithCursors = <T>(accessor: DocAccessor<T>, diffs: read
|
|
|
65
66
|
.filter(isNonNullable);
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
export const applyDiffs = <T>(
|
|
69
|
+
export const applyDiffs = <T>(
|
|
70
|
+
accessor: DocAccessor<T>,
|
|
71
|
+
diffs: readonly string[],
|
|
72
|
+
{ errorOnNotFound = false }: { errorOnNotFound?: boolean } = {},
|
|
73
|
+
): string => {
|
|
69
74
|
for (const diff of reduceDiffs(diffs)) {
|
|
70
75
|
accessor.handle.change((doc: Doc<T>) => {
|
|
71
76
|
const text = DocAccessor.getValue<string>(accessor);
|
|
@@ -75,7 +80,11 @@ export const applyDiffs = <T>(accessor: DocAccessor<T>, diffs: readonly string[]
|
|
|
75
80
|
// NOTE: This only replaces the first match.
|
|
76
81
|
A.splice(doc, accessor.path as A.Prop[], idx, diff.match.length, diff.replace);
|
|
77
82
|
} else {
|
|
78
|
-
|
|
83
|
+
if (errorOnNotFound) {
|
|
84
|
+
throw new Error(`Diff not found: ${diff.match}`);
|
|
85
|
+
} else {
|
|
86
|
+
log.warn('diff not found', diff);
|
|
87
|
+
}
|
|
79
88
|
}
|
|
80
89
|
});
|
|
81
90
|
}
|
|
@@ -71,7 +71,7 @@ describe('ExecutionGraph', () => {
|
|
|
71
71
|
blocks: [
|
|
72
72
|
{
|
|
73
73
|
_tag: 'text',
|
|
74
|
-
text: '{"id":"01K6AXZKK79H4E54RKP1YZDARK","@type":"dxn:type:dxos.
|
|
74
|
+
text: '{"id":"01K6AXZKK79H4E54RKP1YZDARK","@type":"dxn:type:org.dxos.type.organization:0.1.0","@meta":{"keys":[]},"name":"Blue Yard","website":"https://blueyard.com"}',
|
|
75
75
|
},
|
|
76
76
|
],
|
|
77
77
|
properties: {},
|
|
@@ -619,7 +619,7 @@ describe('ExecutionGraph', () => {
|
|
|
619
619
|
{ _tag: 'reasoning', reasoningText: 'I need to think about this' },
|
|
620
620
|
{ _tag: 'toolCall', toolCallId: 'tool1', name: 'analyze', input: '{}', providerExecuted: false },
|
|
621
621
|
{
|
|
622
|
-
_tag: '
|
|
622
|
+
_tag: 'stats',
|
|
623
623
|
message: 'OK',
|
|
624
624
|
duration: 1000,
|
|
625
625
|
toolCalls: 1,
|
package/src/execution-graph.ts
CHANGED
|
@@ -412,7 +412,7 @@ const createBlockCommit = (
|
|
|
412
412
|
message: block.error ? 'Tool error: ' + block.error : 'Tool call succeeded',
|
|
413
413
|
} satisfies Commit;
|
|
414
414
|
|
|
415
|
-
case '
|
|
415
|
+
case 'stats':
|
|
416
416
|
return {
|
|
417
417
|
id: getGenericBlockId(message.id, idx),
|
|
418
418
|
branch,
|
|
@@ -420,7 +420,7 @@ const createBlockCommit = (
|
|
|
420
420
|
timestamp,
|
|
421
421
|
icon: IconType.ROCKET,
|
|
422
422
|
level: LogLevel.INFO,
|
|
423
|
-
message: ContentBlock.
|
|
423
|
+
message: ContentBlock.createStatsMessage(block),
|
|
424
424
|
} satisfies Commit;
|
|
425
425
|
|
|
426
426
|
case 'status':
|
|
@@ -7,7 +7,7 @@ import { type FunctionDefinition, defineFunction } from '@dxos/functions';
|
|
|
7
7
|
import { ExtractionInput, ExtractionOutput } from '../extraction';
|
|
8
8
|
|
|
9
9
|
export const extractionAnthropicFunction: FunctionDefinition<ExtractionInput, ExtractionOutput> = defineFunction({
|
|
10
|
-
key: 'dxos.
|
|
10
|
+
key: 'org.dxos.function.extraction.extract-entities',
|
|
11
11
|
name: 'Extract Entities',
|
|
12
12
|
description: 'Extract entities from the transcript message and add them to the message.',
|
|
13
13
|
inputSchema: ExtractionInput,
|
|
@@ -35,7 +35,7 @@ describe.skip('NER EntityExtraction', () => {
|
|
|
35
35
|
beforeAll(async () => {
|
|
36
36
|
// TODO(dmaretskyi): Helper to scaffold this from a config.
|
|
37
37
|
builder = await new EchoTestBuilder().open();
|
|
38
|
-
const { db: db1 } = await builder.createDatabase(
|
|
38
|
+
const { db: db1 } = await builder.createDatabase();
|
|
39
39
|
db = db1;
|
|
40
40
|
await db.graph.schemaRegistry.register(TYPES);
|
|
41
41
|
const data = createTestData();
|
|
@@ -11,7 +11,7 @@ import { ExtractionInput, ExtractionOutput } from '../extraction';
|
|
|
11
11
|
*/
|
|
12
12
|
// TODO(mykola): Make it use vector index to query objects and not pass objects as input.
|
|
13
13
|
export const extractionNerFunction = defineFunction({
|
|
14
|
-
key: 'dxos.
|
|
14
|
+
key: 'org.dxos.function.extraction.extract-entities',
|
|
15
15
|
name: 'Extract Entities',
|
|
16
16
|
description: 'Extracts named entities from a text',
|
|
17
17
|
inputSchema: ExtractionInput,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout } from '@dxos/async';
|
|
8
|
-
import {
|
|
8
|
+
import { Obj } from '@dxos/echo';
|
|
9
9
|
import { type FunctionDefinition } from '@dxos/functions';
|
|
10
10
|
import { type FunctionExecutor } from '@dxos/functions-runtime';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
@@ -13,7 +13,7 @@ import { Message } from '@dxos/types';
|
|
|
13
13
|
|
|
14
14
|
export const ExtractionInput = Schema.Struct({
|
|
15
15
|
message: Message.Message,
|
|
16
|
-
objects: Schema.optional(Schema.Array(
|
|
16
|
+
objects: Schema.optional(Schema.Array(Obj.Unknown)),
|
|
17
17
|
options: Schema.optional(
|
|
18
18
|
Schema.Struct({
|
|
19
19
|
timeout: Schema.optional(Schema.Number),
|