@dxos/assistant 0.9.1-main.c7dcc2e112 → 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 +1 -1
- package/dist/lib/neutral/extraction/index.mjs.map +1 -1
- package/dist/lib/neutral/index.mjs +387 -230
- 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/proper-noun-extraction.d.ts +1 -202
- package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.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 +13 -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 +5 -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/proper-noun-extraction.ts +1 -1
- package/src/index.ts +1 -1
- package/src/request/AiRequest.ts +35 -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 +43 -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/functions/index.d.ts.map +0 -1
- package/dist/types/src/functions/services.d.ts.map +0 -1
- /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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/assistant",
|
|
3
|
-
"version": "0.9.1-
|
|
3
|
+
"version": "0.9.1-staging.ee54ba693a",
|
|
4
4
|
"description": "Natural language interface to DXOS",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -30,41 +30,44 @@
|
|
|
30
30
|
"src"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@automerge/automerge": "3.3.0-fragments.
|
|
33
|
+
"@automerge/automerge": "3.3.0-fragments.2",
|
|
34
34
|
"@effect-atom/atom": "^0.5.3",
|
|
35
35
|
"@effect-atom/atom-react": "^0.5.0",
|
|
36
36
|
"@effect/ai": "0.36.0",
|
|
37
37
|
"@effect/experimental": "0.60.0",
|
|
38
|
-
"@effect/platform": "0.96.
|
|
38
|
+
"@effect/platform": "0.96.2",
|
|
39
|
+
"@effect/rpc": "0.75.1",
|
|
39
40
|
"@xenova/transformers": "^2.17.2",
|
|
40
41
|
"lodash.defaultsdeep": "^4.6.1",
|
|
41
|
-
"@dxos/ai": "0.9.1-
|
|
42
|
-
"@dxos/async": "0.9.1-
|
|
43
|
-
"@dxos/compute": "0.9.1-
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/debug": "0.9.1-
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/echo-client": "0.9.1-
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
42
|
+
"@dxos/ai": "0.9.1-staging.ee54ba693a",
|
|
43
|
+
"@dxos/async": "0.9.1-staging.ee54ba693a",
|
|
44
|
+
"@dxos/compute": "0.9.1-staging.ee54ba693a",
|
|
45
|
+
"@dxos/compute-runtime": "0.9.1-staging.ee54ba693a",
|
|
46
|
+
"@dxos/debug": "0.9.1-staging.ee54ba693a",
|
|
47
|
+
"@dxos/context": "0.9.1-staging.ee54ba693a",
|
|
48
|
+
"@dxos/echo-client": "0.9.1-staging.ee54ba693a",
|
|
49
|
+
"@dxos/echo-doc": "0.9.1-staging.ee54ba693a",
|
|
50
|
+
"@dxos/effect": "0.9.1-staging.ee54ba693a",
|
|
51
|
+
"@dxos/echo": "0.9.1-staging.ee54ba693a",
|
|
52
|
+
"@dxos/echo-protocol": "0.9.1-staging.ee54ba693a",
|
|
53
|
+
"@dxos/errors": "0.9.1-staging.ee54ba693a",
|
|
54
|
+
"@dxos/functions": "0.9.1-staging.ee54ba693a",
|
|
55
|
+
"@dxos/graph": "0.9.1-staging.ee54ba693a",
|
|
56
|
+
"@dxos/keys": "0.9.1-staging.ee54ba693a",
|
|
57
|
+
"@dxos/log": "0.9.1-staging.ee54ba693a",
|
|
58
|
+
"@dxos/invariant": "0.9.1-staging.ee54ba693a",
|
|
59
|
+
"@dxos/mcp-client": "0.9.1-staging.ee54ba693a",
|
|
60
|
+
"@dxos/node-std": "0.9.1-staging.ee54ba693a",
|
|
61
|
+
"@dxos/schema": "0.9.1-staging.ee54ba693a",
|
|
62
|
+
"@dxos/types": "0.9.1-staging.ee54ba693a",
|
|
63
|
+
"@dxos/util": "0.9.1-staging.ee54ba693a"
|
|
61
64
|
},
|
|
62
65
|
"devDependencies": {
|
|
63
66
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
64
|
-
"effect": "3.21.
|
|
67
|
+
"effect": "3.21.4"
|
|
65
68
|
},
|
|
66
69
|
"peerDependencies": {
|
|
67
|
-
"effect": "3.21.
|
|
70
|
+
"effect": "3.21.4"
|
|
68
71
|
},
|
|
69
72
|
"publishConfig": {
|
|
70
73
|
"access": "public"
|
|
@@ -12,7 +12,7 @@ import { Message } from '@dxos/types';
|
|
|
12
12
|
|
|
13
13
|
import { findReferences, insertReferences } from '../quotes';
|
|
14
14
|
|
|
15
|
-
const EXTRACTION_MODEL = '
|
|
15
|
+
const EXTRACTION_MODEL = 'com.anthropic.model.claude-haiku-4-5.default';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Proper nouns extracted from transcript text.
|
package/src/index.ts
CHANGED
package/src/request/AiRequest.ts
CHANGED
|
@@ -19,19 +19,19 @@ import {
|
|
|
19
19
|
AiPreprocessor,
|
|
20
20
|
AiSummarizer,
|
|
21
21
|
type AiToolNotFoundError,
|
|
22
|
-
callTool,
|
|
23
22
|
type OpaqueToolkit,
|
|
24
23
|
type PromptPreprocessingError,
|
|
25
24
|
type ToolExecutionService,
|
|
26
25
|
type ToolResolverService,
|
|
26
|
+
callTool,
|
|
27
27
|
withoutToolCallParising,
|
|
28
28
|
} from '@dxos/ai';
|
|
29
|
-
import { type
|
|
29
|
+
import { Operation, type Skill, Trace } from '@dxos/compute';
|
|
30
30
|
import { Database, Obj, Registry } from '@dxos/echo';
|
|
31
31
|
import { log } from '@dxos/log';
|
|
32
32
|
import { ContentBlock, Message } from '@dxos/types';
|
|
33
33
|
|
|
34
|
-
import { getOperationFromTool } from '../
|
|
34
|
+
import { getOperationFromTool } from '../tool-runtime/services';
|
|
35
35
|
import { type AiAssistantError, CompleteBlock, PartialBlock } from '../util';
|
|
36
36
|
import { formatSystemPrompt, formatUserPrompt } from './format';
|
|
37
37
|
import { GenerationObserver } from './observer';
|
|
@@ -75,7 +75,7 @@ export type RunProps<R = never> = {
|
|
|
75
75
|
system?: string;
|
|
76
76
|
history?: Message.Message[];
|
|
77
77
|
objects?: Obj.Unknown[];
|
|
78
|
-
|
|
78
|
+
skills?: readonly Skill.Skill[];
|
|
79
79
|
toolkit?: OpaqueToolkit.OpaqueToolkit<R>;
|
|
80
80
|
};
|
|
81
81
|
|
|
@@ -84,7 +84,7 @@ export type BeginProps = {
|
|
|
84
84
|
system?: string;
|
|
85
85
|
history?: Message.Message[];
|
|
86
86
|
objects?: Obj.Unknown[];
|
|
87
|
-
|
|
87
|
+
skills?: readonly Skill.Skill[];
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
export type TurnProps<R = never> = {
|
|
@@ -95,6 +95,12 @@ export type TurnProps<R = never> = {
|
|
|
95
95
|
export type TurnResult = {
|
|
96
96
|
messages: Message.Message[];
|
|
97
97
|
done: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Provider finish reason for this turn. `pause` means the provider paused a server-tool turn
|
|
100
|
+
* mid-execution (e.g. Anthropic `pause_turn`) and the turn must be resumed by issuing another
|
|
101
|
+
* request without mutating the trailing assistant content.
|
|
102
|
+
*/
|
|
103
|
+
finishReason?: ContentBlock.FinishReason;
|
|
98
104
|
};
|
|
99
105
|
|
|
100
106
|
/**
|
|
@@ -183,7 +189,7 @@ export class Request {
|
|
|
183
189
|
prompt,
|
|
184
190
|
system,
|
|
185
191
|
history = [],
|
|
186
|
-
|
|
192
|
+
skills = [],
|
|
187
193
|
objects = [],
|
|
188
194
|
}: BeginProps): Effect.Effect<void, RunError, RunRequirements> =>
|
|
189
195
|
Effect.gen(this, function* () {
|
|
@@ -191,7 +197,7 @@ export class Request {
|
|
|
191
197
|
this._history = [...history];
|
|
192
198
|
this._pending = [];
|
|
193
199
|
|
|
194
|
-
const systemPrompt = yield* formatSystemPrompt({ system,
|
|
200
|
+
const systemPrompt = yield* formatSystemPrompt({ system, skills, objects }).pipe(Effect.orDie);
|
|
195
201
|
|
|
196
202
|
if (this._options.summarizationThreshold !== undefined) {
|
|
197
203
|
const tokenCount = yield* AiPreprocessor.estimateTokens(
|
|
@@ -210,7 +216,7 @@ export class Request {
|
|
|
210
216
|
|
|
211
217
|
/**
|
|
212
218
|
* Execute a single turn: one LLM generation followed by tool execution.
|
|
213
|
-
* The toolkit and system prompt can be updated between turns to reflect context changes (e.g. dynamically enabled
|
|
219
|
+
* The toolkit and system prompt can be updated between turns to reflect context changes (e.g. dynamically enabled skills).
|
|
214
220
|
*/
|
|
215
221
|
runAgentTurn = <const R = never>({
|
|
216
222
|
system,
|
|
@@ -232,6 +238,7 @@ export class Request {
|
|
|
232
238
|
|
|
233
239
|
const observer = this._observer;
|
|
234
240
|
let currentMessageId: Obj.ID | null = null;
|
|
241
|
+
let finishReason: ContentBlock.FinishReason | undefined;
|
|
235
242
|
|
|
236
243
|
const messages = yield* LanguageModel.streamText({
|
|
237
244
|
prompt,
|
|
@@ -250,6 +257,9 @@ export class Request {
|
|
|
250
257
|
Stream.mapEffect(
|
|
251
258
|
(block) =>
|
|
252
259
|
Effect.gen(this, function* () {
|
|
260
|
+
if (block._tag === 'stats' && block.finishReason !== undefined) {
|
|
261
|
+
finishReason = block.finishReason;
|
|
262
|
+
}
|
|
253
263
|
if (block.pending) {
|
|
254
264
|
currentMessageId ??= Obj.ID.random();
|
|
255
265
|
log('emit ephemeral message', { id: currentMessageId, type: block._tag });
|
|
@@ -281,16 +291,23 @@ export class Request {
|
|
|
281
291
|
);
|
|
282
292
|
log('messages', { messages });
|
|
283
293
|
|
|
294
|
+
// A paused server-tool turn (e.g. Anthropic `pause_turn`) is not complete: the provider
|
|
295
|
+
// expects the assistant content to be resent so it can finish executing the server tool.
|
|
296
|
+
// No local tool execution is needed — just another request.
|
|
297
|
+
if (finishReason === 'pause') {
|
|
298
|
+
return { messages, done: false, finishReason };
|
|
299
|
+
}
|
|
300
|
+
|
|
284
301
|
const toolCalls = this.getToolCalls();
|
|
285
302
|
|
|
286
303
|
if (toolCalls.length === 0) {
|
|
287
304
|
this._ended = Date.now();
|
|
288
|
-
return { messages, done: true };
|
|
305
|
+
return { messages, done: true, finishReason };
|
|
289
306
|
} else if (!toolkit) {
|
|
290
307
|
throw new Error('No toolkit provided');
|
|
291
308
|
}
|
|
292
309
|
|
|
293
|
-
return { messages, done: false };
|
|
310
|
+
return { messages, done: false, finishReason };
|
|
294
311
|
}).pipe(Effect.withSpan('AiRequest.runAgentTurn'));
|
|
295
312
|
|
|
296
313
|
runTools = <const R = never>({
|
|
@@ -327,19 +344,23 @@ export class Request {
|
|
|
327
344
|
system: systemTemplate,
|
|
328
345
|
history = [],
|
|
329
346
|
objects = [],
|
|
330
|
-
|
|
347
|
+
skills = [],
|
|
331
348
|
toolkit,
|
|
332
349
|
}: RunProps<R>): Effect.Effect<Message.Message[], RunError, RunRequirements | R> =>
|
|
333
350
|
Effect.gen(this, function* () {
|
|
334
|
-
yield* this.begin({ prompt, system: systemTemplate, history, objects,
|
|
351
|
+
yield* this.begin({ prompt, system: systemTemplate, history, objects, skills });
|
|
335
352
|
|
|
336
|
-
const system = yield* formatSystemPrompt({ system: systemTemplate,
|
|
353
|
+
const system = yield* formatSystemPrompt({ system: systemTemplate, skills, objects }).pipe(Effect.orDie);
|
|
337
354
|
|
|
338
355
|
do {
|
|
339
|
-
const { done } = yield* this.runAgentTurn({ system, toolkit });
|
|
356
|
+
const { done, finishReason } = yield* this.runAgentTurn({ system, toolkit });
|
|
340
357
|
if (done) {
|
|
341
358
|
break;
|
|
342
359
|
}
|
|
360
|
+
// A paused server-tool turn resumes with another request and no local tool execution.
|
|
361
|
+
if (finishReason === 'pause') {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
343
364
|
yield* this.runTools({ toolkit });
|
|
344
365
|
} while (true);
|
|
345
366
|
|
package/src/request/format.ts
CHANGED
|
@@ -25,31 +25,29 @@ import { ArtifactDiffResolver } from './artifact-diff';
|
|
|
25
25
|
// TODO(burdon): Move to AiPreprocessor.
|
|
26
26
|
export const formatSystemPrompt = ({
|
|
27
27
|
system,
|
|
28
|
-
|
|
28
|
+
skills = [],
|
|
29
29
|
objects = [],
|
|
30
|
-
}: Pick<AiRequest.RunProps, 'system' | '
|
|
30
|
+
}: Pick<AiRequest.RunProps, 'system' | 'skills' | 'objects'>): Effect.Effect<
|
|
31
31
|
string,
|
|
32
32
|
FunctionNotFoundError | EntityNotFoundError,
|
|
33
33
|
Database.Service | Registry.Service | Operation.Service
|
|
34
34
|
> =>
|
|
35
35
|
Effect.gen(function* () {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
Effect.forEach((
|
|
36
|
+
const skillDefs = yield* Function.pipe(
|
|
37
|
+
skills,
|
|
38
|
+
Effect.forEach((skill) => Effect.succeed(skill.instructions)),
|
|
39
39
|
Effect.flatMap(
|
|
40
40
|
Effect.forEach((template) =>
|
|
41
41
|
Effect.gen(function* () {
|
|
42
42
|
return trim`
|
|
43
|
-
<
|
|
43
|
+
<skill>
|
|
44
44
|
${yield* Template.processTemplate(template)}
|
|
45
|
-
</
|
|
45
|
+
</skill>
|
|
46
46
|
`;
|
|
47
47
|
}),
|
|
48
48
|
),
|
|
49
49
|
),
|
|
50
|
-
Effect.map((
|
|
51
|
-
blueprints.length > 0 ? ['## Blueprints Definitions', ...blueprints].join('\n\n') : undefined,
|
|
52
|
-
),
|
|
50
|
+
Effect.map((skills) => (skills.length > 0 ? ['## Skills Definitions', ...skills].join('\n\n') : undefined)),
|
|
53
51
|
);
|
|
54
52
|
|
|
55
53
|
const objectDefs = yield* Function.pipe(
|
|
@@ -66,7 +64,7 @@ export const formatSystemPrompt = ({
|
|
|
66
64
|
);
|
|
67
65
|
|
|
68
66
|
return yield* Function.pipe(
|
|
69
|
-
Effect.succeed([system,
|
|
67
|
+
Effect.succeed([system, skillDefs, objectDefs].filter((def): def is string => def !== undefined)),
|
|
70
68
|
Effect.map((parts) => parts.join('\n\n')),
|
|
71
69
|
);
|
|
72
70
|
}).pipe(Effect.withSpan('formatSystemPrompt'));
|
|
@@ -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
|
});
|