@dxos/assistant 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef
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 +4 -21
- package/dist/lib/neutral/extraction/index.mjs.map +3 -3
- package/dist/lib/neutral/index.mjs +1259 -79
- package/dist/lib/neutral/index.mjs.map +4 -4
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/types/src/conversation/context.d.ts +9 -12
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/index.d.ts +1 -1
- package/dist/types/src/conversation/index.d.ts.map +1 -1
- package/dist/types/src/conversation/session.d.ts +78 -0
- package/dist/types/src/conversation/session.d.ts.map +1 -0
- package/dist/types/src/diff.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +12 -12
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/execution-graph.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 +461 -455
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +7 -29
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
- package/dist/types/src/session/error-handling.d.ts.map +1 -1
- package/dist/types/src/session/format.d.ts +6 -3
- package/dist/types/src/session/format.d.ts.map +1 -1
- package/dist/types/src/session/index.d.ts +1 -1
- package/dist/types/src/session/{session.d.ts → request.d.ts} +25 -33
- package/dist/types/src/session/request.d.ts.map +1 -0
- package/dist/types/src/session/toolkit.d.ts +5 -7
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/templates/system.d.ts +1 -1
- package/dist/types/src/templates/system.d.ts.map +1 -1
- package/dist/types/src/tracing.d.ts +64 -95
- package/dist/types/src/tracing.d.ts.map +1 -1
- package/dist/types/src/types/artifact.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +21 -38
- package/src/conversation/context.ts +1 -1
- package/src/conversation/index.ts +1 -1
- package/src/conversation/session.ts +334 -0
- package/src/execution-graph.ts +15 -5
- package/src/extraction/extraction.ts +1 -1
- package/src/functions/services.ts +12 -127
- package/src/functions.conversations.json +1 -1
- package/src/index.ts +0 -1
- package/src/session/format.ts +14 -9
- package/src/session/index.ts +1 -1
- package/src/session/request.conversations.json +1 -0
- package/src/session/{session.ts → request.ts} +44 -51
- package/src/session/toolkit.ts +18 -15
- package/src/templates/instructions/system.tpl +11 -0
- package/src/templates/system.ts +1 -1
- package/src/tracing.ts +13 -69
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UAWIXKF6.mjs +0 -1875
- package/dist/lib/neutral/chunk-UAWIXKF6.mjs.map +0 -7
- package/dist/lib/neutral/testing/index.mjs +0 -114
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
- package/dist/types/src/conversation/conversation.d.ts +0 -68
- package/dist/types/src/conversation/conversation.d.ts.map +0 -1
- package/dist/types/src/conversation/conversation.test.d.ts +0 -2
- package/dist/types/src/conversation/conversation.test.d.ts.map +0 -1
- package/dist/types/src/functions.test.d.ts +0 -2
- package/dist/types/src/functions.test.d.ts.map +0 -1
- package/dist/types/src/service/AgentService.d.ts +0 -61
- package/dist/types/src/service/AgentService.d.ts.map +0 -1
- package/dist/types/src/service/AgentService.test.d.ts +0 -2
- package/dist/types/src/service/AgentService.test.d.ts.map +0 -1
- package/dist/types/src/service/agent-process.d.ts +0 -17
- package/dist/types/src/service/agent-process.d.ts.map +0 -1
- package/dist/types/src/service/index.d.ts +0 -3
- package/dist/types/src/service/index.d.ts.map +0 -1
- package/dist/types/src/session/format.test.d.ts +0 -2
- package/dist/types/src/session/format.test.d.ts.map +0 -1
- package/dist/types/src/session/session.d.ts.map +0 -1
- package/dist/types/src/session/session.test.d.ts +0 -2
- package/dist/types/src/session/session.test.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/layer.d.ts +0 -35
- package/dist/types/src/testing/layer.d.ts.map +0 -1
- package/src/conversation/conversation.test.ts +0 -58
- package/src/conversation/conversation.ts +0 -275
- package/src/functions.test.ts +0 -82
- package/src/service/AgentService.conversations.json +0 -1
- package/src/service/AgentService.test.ts +0 -169
- package/src/service/AgentService.ts +0 -165
- package/src/service/agent-process.ts +0 -359
- package/src/service/index.ts +0 -6
- package/src/session/format.test.ts +0 -132
- package/src/session/session.conversations.json +0 -1
- package/src/session/session.test.ts +0 -190
- package/src/testing/index.ts +0 -5
- package/src/testing/layer.ts +0 -259
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.abd8ff62ef",
|
|
4
4
|
"description": "Natural language interface to DXOS",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -22,24 +22,9 @@
|
|
|
22
22
|
"source": "./src/extraction/index.ts",
|
|
23
23
|
"types": "./dist/types/src/extraction/index.d.ts",
|
|
24
24
|
"default": "./dist/lib/neutral/extraction/index.mjs"
|
|
25
|
-
},
|
|
26
|
-
"./testing": {
|
|
27
|
-
"source": "./src/testing/index.ts",
|
|
28
|
-
"types": "./dist/types/src/testing/index.d.ts",
|
|
29
|
-
"default": "./dist/lib/neutral/testing/index.mjs"
|
|
30
25
|
}
|
|
31
26
|
},
|
|
32
27
|
"types": "dist/types/src/index.d.ts",
|
|
33
|
-
"typesVersions": {
|
|
34
|
-
"*": {
|
|
35
|
-
"types": [
|
|
36
|
-
"dist/types/src/types/index.d.ts"
|
|
37
|
-
],
|
|
38
|
-
"extraction": [
|
|
39
|
-
"dist/types/src/extraction/index.d.ts"
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
28
|
"files": [
|
|
44
29
|
"dist",
|
|
45
30
|
"src"
|
|
@@ -53,28 +38,26 @@
|
|
|
53
38
|
"@effect/platform": "0.94.4",
|
|
54
39
|
"@xenova/transformers": "^2.17.2",
|
|
55
40
|
"lodash.defaultsdeep": "^4.6.1",
|
|
56
|
-
"@dxos/ai": "0.8.4-main.
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/echo": "0.8.4-main.
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/functions
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/types": "0.8.4-main.9be5663bfe",
|
|
77
|
-
"@dxos/util": "0.8.4-main.9be5663bfe"
|
|
41
|
+
"@dxos/ai": "0.8.4-main.abd8ff62ef",
|
|
42
|
+
"@dxos/context": "0.8.4-main.abd8ff62ef",
|
|
43
|
+
"@dxos/compute": "0.8.4-main.abd8ff62ef",
|
|
44
|
+
"@dxos/async": "0.8.4-main.abd8ff62ef",
|
|
45
|
+
"@dxos/echo-db": "0.8.4-main.abd8ff62ef",
|
|
46
|
+
"@dxos/debug": "0.8.4-main.abd8ff62ef",
|
|
47
|
+
"@dxos/echo": "0.8.4-main.abd8ff62ef",
|
|
48
|
+
"@dxos/echo-protocol": "0.8.4-main.abd8ff62ef",
|
|
49
|
+
"@dxos/errors": "0.8.4-main.abd8ff62ef",
|
|
50
|
+
"@dxos/effect": "0.8.4-main.abd8ff62ef",
|
|
51
|
+
"@dxos/functions": "0.8.4-main.abd8ff62ef",
|
|
52
|
+
"@dxos/invariant": "0.8.4-main.abd8ff62ef",
|
|
53
|
+
"@dxos/mcp-client": "0.8.4-main.abd8ff62ef",
|
|
54
|
+
"@dxos/keys": "0.8.4-main.abd8ff62ef",
|
|
55
|
+
"@dxos/log": "0.8.4-main.abd8ff62ef",
|
|
56
|
+
"@dxos/node-std": "0.8.4-main.abd8ff62ef",
|
|
57
|
+
"@dxos/schema": "0.8.4-main.abd8ff62ef",
|
|
58
|
+
"@dxos/util": "0.8.4-main.abd8ff62ef",
|
|
59
|
+
"@dxos/graph": "0.8.4-main.abd8ff62ef",
|
|
60
|
+
"@dxos/types": "0.8.4-main.abd8ff62ef"
|
|
78
61
|
},
|
|
79
62
|
"devDependencies": {
|
|
80
63
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
@@ -10,7 +10,7 @@ import * as Function from 'effect/Function';
|
|
|
10
10
|
import * as Runtime from 'effect/Runtime';
|
|
11
11
|
import * as Schema from 'effect/Schema';
|
|
12
12
|
|
|
13
|
-
import { Blueprint } from '@dxos/
|
|
13
|
+
import { Blueprint } from '@dxos/compute';
|
|
14
14
|
import { Resource } from '@dxos/context';
|
|
15
15
|
import { DXN, Feed, Obj, type QueryResult, Query, Ref, Type } from '@dxos/echo';
|
|
16
16
|
import { assertArgument } from '@dxos/invariant';
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { Registry } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Array from 'effect/Array';
|
|
7
|
+
import * as Context from 'effect/Context';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import * as Either from 'effect/Either';
|
|
10
|
+
import { pipe } from 'effect/Function';
|
|
11
|
+
import * as Layer from 'effect/Layer';
|
|
12
|
+
import * as Record from 'effect/Record';
|
|
13
|
+
import * as Runtime from 'effect/Runtime';
|
|
14
|
+
|
|
15
|
+
import { type OpaqueToolkit, type ToolExecutionService, type ToolResolverService } from '@dxos/ai';
|
|
16
|
+
import { type Blueprint, type OperationRegistry, Operation, Trace } from '@dxos/compute';
|
|
17
|
+
import { Resource } from '@dxos/context';
|
|
18
|
+
import { Database, Feed, Filter, Obj } from '@dxos/echo';
|
|
19
|
+
import { acquireReleaseResource } from '@dxos/effect';
|
|
20
|
+
import { invariant } from '@dxos/invariant';
|
|
21
|
+
import { log } from '@dxos/log';
|
|
22
|
+
import { McpToolkit } from '@dxos/mcp-client';
|
|
23
|
+
import { Message, type ContentBlock } from '@dxos/types';
|
|
24
|
+
|
|
25
|
+
import { ToolExecutionServices } from '../functions';
|
|
26
|
+
import {
|
|
27
|
+
AiRequest,
|
|
28
|
+
type AiRequestRunError,
|
|
29
|
+
type AiRequestRunRequirements,
|
|
30
|
+
type GenerationObserver,
|
|
31
|
+
createToolkit,
|
|
32
|
+
formatSystemPrompt,
|
|
33
|
+
} from '../session';
|
|
34
|
+
import { McpServerError } from '../tracing';
|
|
35
|
+
import { AiContextBinder, AiContextService } from './context';
|
|
36
|
+
|
|
37
|
+
export interface McpServerConfig {
|
|
38
|
+
url: string;
|
|
39
|
+
protocol: 'sse' | 'http';
|
|
40
|
+
apiKey?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AiSessionRunProps<R = never> {
|
|
44
|
+
prompt: string | ContentBlock.Any[];
|
|
45
|
+
system?: string;
|
|
46
|
+
observer?: GenerationObserver;
|
|
47
|
+
toolkit?: OpaqueToolkit.OpaqueToolkit<R>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Space-level MCP servers to connect alongside blueprint-defined ones.
|
|
51
|
+
*/
|
|
52
|
+
mcpServers?: readonly McpServerConfig[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type AiSessionOptions = {
|
|
56
|
+
feed: Feed.Feed;
|
|
57
|
+
runtime: Runtime.Runtime<Feed.FeedService>;
|
|
58
|
+
registry?: Registry.Registry;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// TODO(dmaretskyi): Take from model characteristics. opus has 200k max tokens.
|
|
62
|
+
/**
|
|
63
|
+
* Summarization threshold in tokens.
|
|
64
|
+
*/
|
|
65
|
+
const SUMMARY_THRESHOLD = 80_000;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Durable conversation state (initiated by users and agents) backed by a Feed.
|
|
69
|
+
* Executes tools based on AI responses and supports cancellation of in-progress requests.
|
|
70
|
+
*/
|
|
71
|
+
export class AiSession extends Resource {
|
|
72
|
+
/**
|
|
73
|
+
* Blueprints and objects bound to the session.
|
|
74
|
+
*/
|
|
75
|
+
private readonly _binder: AiContextBinder;
|
|
76
|
+
private readonly _feed: Feed.Feed;
|
|
77
|
+
private readonly _runtime: Runtime.Runtime<Feed.FeedService>;
|
|
78
|
+
|
|
79
|
+
public constructor(options: AiSessionOptions) {
|
|
80
|
+
super();
|
|
81
|
+
this._feed = options.feed;
|
|
82
|
+
this._runtime = options.runtime;
|
|
83
|
+
invariant(this._feed);
|
|
84
|
+
invariant(this._runtime);
|
|
85
|
+
this._binder = new AiContextBinder({ feed: this._feed, runtime: this._runtime, registry: options.registry });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
protected override async _open(): Promise<void> {
|
|
89
|
+
await this._binder.open(this._ctx);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public get feed() {
|
|
93
|
+
return this._feed;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public get context() {
|
|
97
|
+
return this._binder;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public async getHistory(): Promise<Message.Message[]> {
|
|
101
|
+
const queryResult = await Runtime.runPromise(this._runtime)(Feed.query(this._feed, Filter.type(Message.Message)));
|
|
102
|
+
const items = await queryResult.run();
|
|
103
|
+
return items.filter(Obj.instanceOf(Message.Message));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getTools(): Effect.Effect<
|
|
107
|
+
Record<string, import('@effect/ai/Tool').Any>,
|
|
108
|
+
never,
|
|
109
|
+
ToolExecutionService | ToolResolverService
|
|
110
|
+
> {
|
|
111
|
+
return Effect.gen(this, function* () {
|
|
112
|
+
const toolkit = yield* createToolkit({ blueprints: this.context.getBlueprints() });
|
|
113
|
+
return toolkit.toolkit.tools;
|
|
114
|
+
}).pipe(Effect.orDie);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Not provided by default, since users might want to override them.
|
|
119
|
+
*/
|
|
120
|
+
makeToolExecutionServices(): Layer.Layer<
|
|
121
|
+
ToolExecutionService | ToolResolverService,
|
|
122
|
+
never,
|
|
123
|
+
OpaqueToolkit.OpaqueToolkitProvider | Operation.Service | OperationRegistry.Service
|
|
124
|
+
> {
|
|
125
|
+
return ToolExecutionServices.pipe(
|
|
126
|
+
Layer.provide(Operation.withInvocationOptions({ conversation: Obj.getDXN(this._feed).toString() })),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Creates a new cancelable request effect.
|
|
131
|
+
*/
|
|
132
|
+
public createRequest<R = never>(
|
|
133
|
+
params: AiSessionRunProps<R>,
|
|
134
|
+
): Effect.Effect<Message.Message[], AiRequestRunError, AiRequestRunRequirements | R> {
|
|
135
|
+
return Effect.gen(this, function* () {
|
|
136
|
+
const history = yield* Effect.promise(() => this.getHistory());
|
|
137
|
+
const blueprints = this.context.getBlueprints();
|
|
138
|
+
const objects = this.context.getObjects();
|
|
139
|
+
|
|
140
|
+
log('run', {
|
|
141
|
+
history: history.length,
|
|
142
|
+
blueprints: blueprints.length,
|
|
143
|
+
objects: objects.length,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const request = new AiRequest({
|
|
147
|
+
summarizationThreshold: SUMMARY_THRESHOLD,
|
|
148
|
+
observer: params.observer,
|
|
149
|
+
onOutput: (message) =>
|
|
150
|
+
Effect.promise(() => Runtime.runPromise(this._runtime)(Feed.append(this._feed, [message]))),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
yield* request.begin({
|
|
154
|
+
history,
|
|
155
|
+
blueprints,
|
|
156
|
+
objects,
|
|
157
|
+
prompt: params.prompt,
|
|
158
|
+
system: params.system,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Turn loop: recompute toolkit and system prompt between turns to pick up dynamically enabled blueprints.
|
|
162
|
+
do {
|
|
163
|
+
yield* Effect.promise(() => this.context.sync());
|
|
164
|
+
const currentBlueprints = this.context.getBlueprints();
|
|
165
|
+
const mcps = yield* connectMcpServers(currentBlueprints, params.mcpServers);
|
|
166
|
+
const toolkit = yield* createToolkit({
|
|
167
|
+
toolkit: params.toolkit,
|
|
168
|
+
blueprints: currentBlueprints,
|
|
169
|
+
opaqueToolkits: mcps,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
log('toolkit', { tools: Record.keys(toolkit.toolkit.tools) });
|
|
173
|
+
const system = yield* formatSystemPrompt({
|
|
174
|
+
system: params.system,
|
|
175
|
+
blueprints: currentBlueprints,
|
|
176
|
+
objects: this.context.getObjects(),
|
|
177
|
+
}).pipe(Effect.orDie);
|
|
178
|
+
|
|
179
|
+
const { done } = yield* request.runAgentTurn({ system, toolkit });
|
|
180
|
+
if (done) {
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
yield* request.runTools({ toolkit });
|
|
185
|
+
} while (true);
|
|
186
|
+
|
|
187
|
+
log('result', {
|
|
188
|
+
messages: request.pending.length,
|
|
189
|
+
duration: request.duration,
|
|
190
|
+
toolCalls: request.toolCalls,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return [...request.pending];
|
|
194
|
+
}).pipe(
|
|
195
|
+
Effect.provide(
|
|
196
|
+
Layer.mergeAll(
|
|
197
|
+
Layer.succeed(AiContextService, {
|
|
198
|
+
binder: this.context,
|
|
199
|
+
}),
|
|
200
|
+
Layer.succeed(AiSessionService, this),
|
|
201
|
+
Operation.withInvocationOptions({ conversation: Obj.getDXN(this._feed).toString() }),
|
|
202
|
+
),
|
|
203
|
+
),
|
|
204
|
+
Effect.withSpan('AiSession.createRequest'),
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Gives access to the ai session.
|
|
211
|
+
*/
|
|
212
|
+
export class AiSessionService extends Context.Tag('@dxos/assistant/AiSessionService')<AiSessionService, AiSession>() {
|
|
213
|
+
/**
|
|
214
|
+
* Create a new session layer from options.
|
|
215
|
+
*/
|
|
216
|
+
static layer = (options: AiSessionOptions): Layer.Layer<AiSessionService | AiContextService> =>
|
|
217
|
+
aiContextFromSession.pipe(
|
|
218
|
+
Layer.provideMerge(
|
|
219
|
+
Layer.scoped(
|
|
220
|
+
AiSessionService,
|
|
221
|
+
Effect.gen(function* () {
|
|
222
|
+
const session = yield* acquireReleaseResource(() => new AiSession(options));
|
|
223
|
+
return session;
|
|
224
|
+
}),
|
|
225
|
+
),
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Create a new session with a new feed.
|
|
231
|
+
*/
|
|
232
|
+
static layerNewFeed = (
|
|
233
|
+
options?: Omit<AiSessionOptions, 'feed' | 'runtime'>,
|
|
234
|
+
): Layer.Layer<AiSessionService | AiContextService, never, Database.Service | Feed.FeedService> =>
|
|
235
|
+
Layer.unwrapScoped(
|
|
236
|
+
Effect.gen(function* () {
|
|
237
|
+
const feed = Feed.make();
|
|
238
|
+
yield* Database.add(feed);
|
|
239
|
+
const runtime = yield* Effect.runtime<Feed.FeedService>();
|
|
240
|
+
return AiSessionService.layer({
|
|
241
|
+
...options,
|
|
242
|
+
feed,
|
|
243
|
+
runtime,
|
|
244
|
+
});
|
|
245
|
+
}),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Run a prompt in the current session.
|
|
250
|
+
*/
|
|
251
|
+
static run = <R = never>(
|
|
252
|
+
params: AiSessionRunProps<R>,
|
|
253
|
+
): Effect.Effect<Message.Message[], AiRequestRunError, AiRequestRunRequirements | AiSessionService | R> =>
|
|
254
|
+
Effect.gen(function* () {
|
|
255
|
+
const session = yield* AiSessionService;
|
|
256
|
+
return yield* session.createRequest(params);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const aiContextFromSession = Layer.effect(
|
|
261
|
+
AiContextService,
|
|
262
|
+
Effect.gen(function* () {
|
|
263
|
+
const session = yield* AiSessionService;
|
|
264
|
+
return {
|
|
265
|
+
binder: session.context,
|
|
266
|
+
};
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const connectMcpServers = (
|
|
271
|
+
blueprints: readonly Blueprint.Blueprint[],
|
|
272
|
+
spaceMcpServers: readonly McpServerConfig[] = [],
|
|
273
|
+
): Effect.Effect<OpaqueToolkit.OpaqueToolkit[], never, Trace.TraceService> => {
|
|
274
|
+
const blueprintServers: McpToolkit.McpToolkitOptions[] = pipe(
|
|
275
|
+
blueprints,
|
|
276
|
+
Array.flatMap((_) => _.mcpServers ?? []),
|
|
277
|
+
Array.map(({ url, protocol }) => ({ url, kind: protocol })),
|
|
278
|
+
);
|
|
279
|
+
const spaceServers: McpToolkit.McpToolkitOptions[] = spaceMcpServers.map(({ url, protocol, apiKey }) => ({
|
|
280
|
+
url,
|
|
281
|
+
kind: protocol,
|
|
282
|
+
apiKey,
|
|
283
|
+
}));
|
|
284
|
+
const allServers = [...blueprintServers, ...spaceServers];
|
|
285
|
+
|
|
286
|
+
return pipe(
|
|
287
|
+
allServers,
|
|
288
|
+
Effect.forEach((options) =>
|
|
289
|
+
McpToolkit.make(options).pipe(
|
|
290
|
+
// NOTE: Type-inference fails here without explicit void return.
|
|
291
|
+
Effect.tap((toolkit): void =>
|
|
292
|
+
log.info('Connected to MCP server', { url: options.url, tools: Object.keys(toolkit.toolkit.tools).length }),
|
|
293
|
+
),
|
|
294
|
+
// Surface typed connection failures via ephemeral trace + warn log, then drop the server.
|
|
295
|
+
Effect.tapError((error) =>
|
|
296
|
+
Effect.gen(function* () {
|
|
297
|
+
log.warn('Failed to connect to MCP server', {
|
|
298
|
+
url: error.url,
|
|
299
|
+
kind: error.kind,
|
|
300
|
+
message: error.message,
|
|
301
|
+
});
|
|
302
|
+
yield* Trace.write(McpServerError, {
|
|
303
|
+
url: error.url,
|
|
304
|
+
kind: error.kind,
|
|
305
|
+
message: error.message,
|
|
306
|
+
});
|
|
307
|
+
}),
|
|
308
|
+
),
|
|
309
|
+
// Catch unexpected defects too (e.g. malformed tool schemas) so a single broken
|
|
310
|
+
// server can never abort the whole turn — surface them through the same channel.
|
|
311
|
+
Effect.catchAllDefect((defect) =>
|
|
312
|
+
Effect.gen(function* () {
|
|
313
|
+
const message = defect instanceof Error ? defect.message : String(defect);
|
|
314
|
+
log.warn('Unexpected MCP defect', { url: options.url, message });
|
|
315
|
+
yield* Trace.write(McpServerError, {
|
|
316
|
+
url: options.url,
|
|
317
|
+
kind: options.kind,
|
|
318
|
+
message: `Unexpected MCP failure: ${message}`,
|
|
319
|
+
});
|
|
320
|
+
return yield* Effect.fail(
|
|
321
|
+
new McpToolkit.McpConnectionError({
|
|
322
|
+
url: options.url,
|
|
323
|
+
kind: options.kind,
|
|
324
|
+
message,
|
|
325
|
+
}),
|
|
326
|
+
);
|
|
327
|
+
}),
|
|
328
|
+
),
|
|
329
|
+
Effect.either,
|
|
330
|
+
),
|
|
331
|
+
),
|
|
332
|
+
Effect.map(Array.filterMap((_) => Either.getRight(_))),
|
|
333
|
+
);
|
|
334
|
+
};
|
package/src/execution-graph.ts
CHANGED
|
@@ -199,13 +199,19 @@ export class ExecutionGraph {
|
|
|
199
199
|
*/
|
|
200
200
|
private _updatePendingToolResults(toolCallId: string, agentStatusId: string) {
|
|
201
201
|
const toolResultId = this._pendingToolResults.get(toolCallId);
|
|
202
|
-
if (!toolResultId)
|
|
202
|
+
if (!toolResultId) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
203
205
|
|
|
204
206
|
const toolResultCommit = this._commits.find((c) => c.id === toolResultId);
|
|
205
|
-
if (!toolResultCommit)
|
|
207
|
+
if (!toolResultCommit) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
206
210
|
|
|
207
211
|
const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
|
|
208
|
-
if (!toolCallCommitId)
|
|
212
|
+
if (!toolCallCommitId) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
209
215
|
|
|
210
216
|
// Replace tool call commit with AgentStatus commit.
|
|
211
217
|
const toolCallIndex = toolResultCommit.parents.indexOf(toolCallCommitId);
|
|
@@ -221,7 +227,9 @@ export class ExecutionGraph {
|
|
|
221
227
|
*/
|
|
222
228
|
private _handleLateToolResultUpdate(toolCallId: string, toolResultId: string) {
|
|
223
229
|
const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
|
|
224
|
-
if (!toolCallCommitId)
|
|
230
|
+
if (!toolCallCommitId) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
225
233
|
|
|
226
234
|
const messageId = toolCallCommitId.split('_toolCall_')[0];
|
|
227
235
|
const toolCallBranch = `${messageId}_${toolCallId}`;
|
|
@@ -372,7 +380,9 @@ const createBlockCommit = (
|
|
|
372
380
|
const timestamp = new Date(message.created);
|
|
373
381
|
switch (block._tag) {
|
|
374
382
|
case 'text':
|
|
375
|
-
if (!block.text.trim().length)
|
|
383
|
+
if (!block.text.trim().length) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
376
386
|
return {
|
|
377
387
|
id: getGenericBlockId(message.id, idx),
|
|
378
388
|
branch,
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
+
import { Operation } from '@dxos/compute';
|
|
7
8
|
import { Obj } from '@dxos/echo';
|
|
8
9
|
import { log } from '@dxos/log';
|
|
9
|
-
import { Operation } from '@dxos/operation';
|
|
10
10
|
import { Message } from '@dxos/types';
|
|
11
11
|
|
|
12
12
|
export const ExtractionInput = Schema.Struct({
|
|
@@ -13,122 +13,30 @@ import * as Schema from 'effect/Schema';
|
|
|
13
13
|
import * as SchemaAST from 'effect/SchemaAST';
|
|
14
14
|
|
|
15
15
|
import { AiToolNotFoundError, ToolExecutionService, ToolResolverService } from '@dxos/ai';
|
|
16
|
-
import {
|
|
16
|
+
import { OpaqueToolkit } from '@dxos/ai';
|
|
17
|
+
import { Operation, OperationRegistry } from '@dxos/compute';
|
|
17
18
|
import { todo } from '@dxos/debug';
|
|
18
19
|
import { Ref } from '@dxos/echo';
|
|
19
|
-
import { FunctionInvocationService, FunctionNotFoundError } from '@dxos/functions';
|
|
20
20
|
import { invariant } from '@dxos/invariant';
|
|
21
|
-
import { Operation, OperationRegistry } from '@dxos/operation';
|
|
22
21
|
|
|
23
22
|
import { RefFromLLM } from '../types';
|
|
24
23
|
|
|
25
|
-
/**
|
|
26
|
-
* Constructs a `ToolResolverService` whose `resolve(id)` looks up tools in the following order:
|
|
27
|
-
* 1. Toolkit: return an existing tool from the provided `toolkit` if one is present under `id`.
|
|
28
|
-
* 2. Operations in DB: query by `key=id`; if found, deserialize and project to a tool.
|
|
29
|
-
* 3. Registered operations: fall back to a matching `Operation.Definition` from the handler set.
|
|
30
|
-
*
|
|
31
|
-
* If none of the above yield a match, the effect fails with `AiToolNotFoundError`.
|
|
32
|
-
*
|
|
33
|
-
* Requires `Database.Service` in the environment.
|
|
34
|
-
*
|
|
35
|
-
* @deprecated Moving to operation-based services.
|
|
36
|
-
*/
|
|
37
|
-
export const makeToolResolverFromFunctions = (): Layer.Layer<
|
|
38
|
-
ToolResolverService,
|
|
39
|
-
never,
|
|
40
|
-
GenericToolkit.GenericToolkitProvider | FunctionInvocationService
|
|
41
|
-
> => {
|
|
42
|
-
return Layer.effect(
|
|
43
|
-
ToolResolverService,
|
|
44
|
-
Effect.gen(function* () {
|
|
45
|
-
const toolkitProvider = yield* GenericToolkit.GenericToolkitProvider;
|
|
46
|
-
const functionInvocationService = yield* FunctionInvocationService;
|
|
47
|
-
return {
|
|
48
|
-
resolve: (id): Effect.Effect<Tool.Any, AiToolNotFoundError> =>
|
|
49
|
-
Effect.gen(function* () {
|
|
50
|
-
const toolkit = toolkitProvider.getToolkit();
|
|
51
|
-
|
|
52
|
-
const tool = toolkit.toolkit.tools[id];
|
|
53
|
-
if (tool) {
|
|
54
|
-
return tool;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return yield* functionInvocationService.resolveFunction(id).pipe(
|
|
58
|
-
Effect.map(projectFunctionToTool),
|
|
59
|
-
Effect.catchTag('FunctionNotFound', () => Effect.fail(new AiToolNotFoundError(id))),
|
|
60
|
-
);
|
|
61
|
-
}),
|
|
62
|
-
} satisfies Context.Tag.Service<ToolResolverService>;
|
|
63
|
-
}),
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @deprecated Moving to operation-based services.
|
|
69
|
-
*/
|
|
70
|
-
export const makeToolExecutionServiceFromFunctions = (): Layer.Layer<
|
|
71
|
-
ToolExecutionService,
|
|
72
|
-
never,
|
|
73
|
-
FunctionInvocationService | GenericToolkit.GenericToolkitProvider
|
|
74
|
-
> => {
|
|
75
|
-
return Layer.effect(
|
|
76
|
-
ToolExecutionService,
|
|
77
|
-
Effect.gen(function* () {
|
|
78
|
-
const toolkitProvider = yield* GenericToolkit.GenericToolkitProvider;
|
|
79
|
-
const toolkit = toolkitProvider.getToolkit();
|
|
80
|
-
|
|
81
|
-
const toolkitHandler = yield* toolkit.toolkit.pipe(Effect.provide(toolkit.layer));
|
|
82
|
-
invariant(isHandlerLike(toolkitHandler));
|
|
83
|
-
const functionInvocationService = yield* FunctionInvocationService;
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
handlersFor: (toolkit) => {
|
|
87
|
-
const makeHandler = (tool: Tool.Any): ((params: unknown) => Effect.Effect<unknown, any, any>) => {
|
|
88
|
-
return Effect.fn(`toolFunctionHandler ${tool.name}`)(function* (input: any) {
|
|
89
|
-
if (toolkitHandler.tools[tool.name]) {
|
|
90
|
-
if (Tool.isProviderDefined(tool)) {
|
|
91
|
-
throw new Error('Attempted to call a provider-defined tool');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// TODO(wittjosiah): Everything is `never` here.
|
|
95
|
-
const { result } = yield* (toolkitHandler.handle as any)(tool.name, input);
|
|
96
|
-
return result;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const functionDef = getOperationFromTool(tool).pipe(Option.getOrThrow);
|
|
100
|
-
|
|
101
|
-
return yield* functionInvocationService
|
|
102
|
-
.invokeFunction(functionDef, input as any)
|
|
103
|
-
.pipe(Effect.catchAllDefect((defect) => Effect.fail(defect)));
|
|
104
|
-
});
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
return toolkit.of(
|
|
108
|
-
Record.map(toolkit.tools, (tool, _name) => (Tool.isUserDefined(tool) ? makeHandler(tool) : null)) as any,
|
|
109
|
-
) as any;
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}),
|
|
113
|
-
);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
24
|
export const makeToolResolverFromOperations = <R = never>({
|
|
117
|
-
toolkit: extraToolkit =
|
|
118
|
-
}: { toolkit?:
|
|
25
|
+
toolkit: extraToolkit = OpaqueToolkit.empty,
|
|
26
|
+
}: { toolkit?: OpaqueToolkit.OpaqueToolkit<never, never, R> } = {}): Layer.Layer<
|
|
119
27
|
ToolResolverService,
|
|
120
28
|
never,
|
|
121
|
-
|
|
29
|
+
OpaqueToolkit.OpaqueToolkitProvider | OperationRegistry.Service | R
|
|
122
30
|
> => {
|
|
123
31
|
return Layer.effect(
|
|
124
32
|
ToolResolverService,
|
|
125
33
|
Effect.gen(function* () {
|
|
126
|
-
const toolkitProvider = yield*
|
|
34
|
+
const toolkitProvider = yield* OpaqueToolkit.OpaqueToolkitProvider;
|
|
127
35
|
const operationRegistry = yield* OperationRegistry.Service;
|
|
128
36
|
return {
|
|
129
37
|
resolve: (id): Effect.Effect<Tool.Any, AiToolNotFoundError> =>
|
|
130
38
|
Effect.gen(function* () {
|
|
131
|
-
const toolkit =
|
|
39
|
+
const toolkit = OpaqueToolkit.merge(extraToolkit, toolkitProvider.getToolkit());
|
|
132
40
|
|
|
133
41
|
const tool = toolkit.toolkit.tools[id];
|
|
134
42
|
if (tool) {
|
|
@@ -151,11 +59,11 @@ export const makeToolResolverFromOperations = <R = never>({
|
|
|
151
59
|
|
|
152
60
|
export const makeToolExecutionService = <E, R>(opts: {
|
|
153
61
|
invoke: (tool: Tool.Any, input: unknown) => Effect.Effect<unknown>;
|
|
154
|
-
}): Layer.Layer<ToolExecutionService, never,
|
|
62
|
+
}): Layer.Layer<ToolExecutionService, never, OpaqueToolkit.OpaqueToolkitProvider> =>
|
|
155
63
|
Layer.effect(
|
|
156
64
|
ToolExecutionService,
|
|
157
65
|
Effect.gen(function* () {
|
|
158
|
-
const toolkitProvider = yield*
|
|
66
|
+
const toolkitProvider = yield* OpaqueToolkit.OpaqueToolkitProvider;
|
|
159
67
|
const toolkit = toolkitProvider.getToolkit();
|
|
160
68
|
|
|
161
69
|
const toolkitHandler = yield* toolkit.toolkit.pipe(Effect.provide(toolkit.layer));
|
|
@@ -190,7 +98,7 @@ export const makeToolExecutionService = <E, R>(opts: {
|
|
|
190
98
|
export const makeToolExecutionServiceFromOperationInvoker = (): Layer.Layer<
|
|
191
99
|
ToolExecutionService,
|
|
192
100
|
never,
|
|
193
|
-
Operation.Service |
|
|
101
|
+
Operation.Service | OpaqueToolkit.OpaqueToolkitProvider
|
|
194
102
|
> => {
|
|
195
103
|
return Layer.unwrapEffect(
|
|
196
104
|
Effect.gen(function* () {
|
|
@@ -208,32 +116,9 @@ export const makeToolExecutionServiceFromOperationInvoker = (): Layer.Layer<
|
|
|
208
116
|
);
|
|
209
117
|
};
|
|
210
118
|
|
|
211
|
-
/**
|
|
212
|
-
* @deprecated Bridge beetwen deprecated function invocataion service and operation services until we remove function invocation service.
|
|
213
|
-
*/
|
|
214
|
-
export const functionInvocationServiceFromOperations: Layer.Layer<
|
|
215
|
-
FunctionInvocationService,
|
|
216
|
-
never,
|
|
217
|
-
OperationRegistry.Service | Operation.Service
|
|
218
|
-
> = Layer.effect(
|
|
219
|
-
FunctionInvocationService,
|
|
220
|
-
Effect.gen(function* () {
|
|
221
|
-
const operationRegistry = yield* OperationRegistry.Service;
|
|
222
|
-
const operationInvoker = yield* Operation.Service;
|
|
223
|
-
return {
|
|
224
|
-
invokeFunction: (operationDef, input) => operationInvoker.invoke(operationDef, input).pipe(Effect.orDie),
|
|
225
|
-
resolveFunction: (key) =>
|
|
226
|
-
operationRegistry.resolve(key).pipe(
|
|
227
|
-
Effect.flatten,
|
|
228
|
-
Effect.catchTag('NoSuchElementException', () => Effect.fail(new FunctionNotFoundError(key))),
|
|
229
|
-
),
|
|
230
|
-
} satisfies Context.Tag.Service<FunctionInvocationService>;
|
|
231
|
-
}),
|
|
232
|
-
);
|
|
233
|
-
|
|
234
119
|
export const ToolExecutionServices = Layer.mergeAll(
|
|
235
|
-
|
|
236
|
-
|
|
120
|
+
makeToolResolverFromOperations(),
|
|
121
|
+
makeToolExecutionServiceFromOperationInvoker(),
|
|
237
122
|
);
|
|
238
123
|
|
|
239
124
|
class FunctionToolAnnotation extends Context.Tag('@dxos/assistant/FunctionToolAnnotation')<
|