@dxos/assistant 0.8.2-main.5885341 → 0.8.2-main.600d381
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-DEIGOD4U.mjs → chunk-YSYP7S4W.mjs} +706 -242
- package/dist/lib/browser/chunk-YSYP7S4W.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +4 -443
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +64 -27
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/{chunk-7VH7NMIM.cjs → chunk-FTIDW4BA.cjs} +716 -259
- package/dist/lib/node/chunk-FTIDW4BA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +34 -470
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +53 -18
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/lib/node-esm/{chunk-7JI4MDGL.mjs → chunk-GCJNPQDJ.mjs} +706 -242
- package/dist/lib/node-esm/chunk-GCJNPQDJ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +4 -443
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +64 -27
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/ai-service/parser.d.ts.map +1 -1
- package/dist/types/src/ai-service/stream.d.ts.map +1 -1
- package/dist/types/src/ai-service/testing/test-stream.d.ts.map +1 -1
- package/dist/types/src/ai-service/types.d.ts +130 -130
- package/dist/types/src/ai-service/types.d.ts.map +1 -1
- package/dist/types/src/ai-service/util/sse.d.ts.map +1 -1
- package/dist/types/src/{conversation → experimental/conversation}/conversation.d.ts +2 -18
- package/dist/types/src/experimental/conversation/conversation.d.ts.map +1 -0
- package/dist/types/src/experimental/conversation/conversation.test.d.ts.map +1 -0
- package/dist/types/src/experimental/conversation/index.d.ts.map +1 -0
- package/dist/types/src/{conversation → experimental/conversation}/types.d.ts +9 -9
- package/dist/types/src/experimental/conversation/types.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/ast.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/combinators.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/combinators.test.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/echo-data-source.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/execution-plan.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/execution-plan.test.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/index.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/parjs.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/parser.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/query-executor.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/query-executor.test.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/schema.d.ts.map +1 -0
- package/dist/types/src/experimental/cypher/schema.test.d.ts.map +1 -0
- package/dist/types/src/experimental/index.d.ts +3 -0
- package/dist/types/src/experimental/index.d.ts.map +1 -0
- package/dist/types/src/experimental/ner/ner.test.d.ts +2 -0
- package/dist/types/src/experimental/ner/ner.test.d.ts.map +1 -0
- package/dist/types/src/experimental/research/exa.d.ts +6 -0
- package/dist/types/src/experimental/research/exa.d.ts.map +1 -0
- package/dist/types/src/experimental/research/research.test.d.ts +2 -0
- package/dist/types/src/experimental/research/research.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/session/index.d.ts +1 -0
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +4 -3
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/tools.d.ts +18 -0
- package/dist/types/src/session/tools.d.ts.map +1 -0
- package/dist/types/src/session/version-pin.d.ts +5 -0
- package/dist/types/src/session/version-pin.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/logger.d.ts +1 -1
- package/dist/types/src/testing/logger.d.ts.map +1 -1
- package/dist/types/src/testing/ollama.d.ts.map +1 -1
- package/dist/types/src/testing/printer.d.ts +6 -0
- package/dist/types/src/testing/printer.d.ts.map +1 -0
- package/dist/types/src/testing/query-promts.d.ts +4 -4
- package/dist/types/src/testing/query-promts.d.ts.map +1 -1
- package/dist/types/src/testing/test-data.d.ts +5 -5
- package/dist/types/src/testing/test-data.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +25 -23
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/dist/types/src/util/trim.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -13
- package/src/ai-service/client.test.ts +5 -5
- package/src/ai-service/ollama-client.ts +8 -8
- package/src/ai-service/types.ts +14 -14
- package/src/bin/chat.ts +1 -1
- package/src/{conversation → experimental/conversation}/conversation.test.ts +5 -5
- package/src/{conversation → experimental/conversation}/conversation.ts +3 -112
- package/src/{conversation → experimental/conversation}/types.ts +10 -10
- package/src/{cypher → experimental/cypher}/echo-data-source.ts +7 -5
- package/src/{cypher → experimental/cypher}/query-executor.test.ts +1 -1
- package/src/{cypher → experimental/cypher}/schema.test.ts +1 -1
- package/src/{cypher → experimental/cypher}/schema.ts +1 -1
- package/src/experimental/index.ts +6 -0
- package/src/experimental/ner/ner.test.ts +163 -0
- package/src/experimental/research/exa.ts +38 -0
- package/src/experimental/research/instructions.tpl +64 -0
- package/src/experimental/research/research.test.ts +263 -0
- package/src/index.ts +3 -2
- package/src/session/index.ts +1 -0
- package/src/session/session.test.ts +28 -57
- package/src/session/session.ts +25 -15
- package/src/session/tools.ts +117 -0
- package/src/session/version-pin.ts +6 -0
- package/src/testing/artifacts.test.ts +22 -22
- package/src/testing/index.ts +1 -0
- package/src/testing/logger.ts +1 -1
- package/src/testing/printer.ts +41 -0
- package/src/testing/query-promts.ts +6 -6
- package/src/testing/query.test.ts +1 -2
- package/src/testing/test-data.ts +5 -5
- package/src/testing/test-schema.ts +27 -28
- package/src/typedefs.d.ts +8 -0
- package/dist/lib/browser/chunk-DEIGOD4U.mjs.map +0 -7
- package/dist/lib/node/chunk-7VH7NMIM.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-7JI4MDGL.mjs.map +0 -7
- package/dist/types/src/conversation/conversation.d.ts.map +0 -1
- package/dist/types/src/conversation/conversation.test.d.ts.map +0 -1
- package/dist/types/src/conversation/index.d.ts.map +0 -1
- package/dist/types/src/conversation/types.d.ts.map +0 -1
- package/dist/types/src/cypher/ast.d.ts.map +0 -1
- package/dist/types/src/cypher/combinators.d.ts.map +0 -1
- package/dist/types/src/cypher/combinators.test.d.ts.map +0 -1
- package/dist/types/src/cypher/echo-data-source.d.ts.map +0 -1
- package/dist/types/src/cypher/execution-plan.d.ts.map +0 -1
- package/dist/types/src/cypher/execution-plan.test.d.ts.map +0 -1
- package/dist/types/src/cypher/index.d.ts.map +0 -1
- package/dist/types/src/cypher/parjs.d.ts.map +0 -1
- package/dist/types/src/cypher/parser.d.ts.map +0 -1
- package/dist/types/src/cypher/query-executor.d.ts.map +0 -1
- package/dist/types/src/cypher/query-executor.test.d.ts.map +0 -1
- package/dist/types/src/cypher/schema.d.ts.map +0 -1
- package/dist/types/src/cypher/schema.test.d.ts.map +0 -1
- /package/dist/types/src/{conversation → experimental/conversation}/conversation.test.d.ts +0 -0
- /package/dist/types/src/{conversation → experimental/conversation}/index.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/ast.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/combinators.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/combinators.test.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/echo-data-source.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/execution-plan.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/execution-plan.test.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/index.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/parjs.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/parser.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/query-executor.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/query-executor.test.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/schema.d.ts +0 -0
- /package/dist/types/src/{cypher → experimental/cypher}/schema.test.d.ts +0 -0
- /package/src/{conversation → experimental/conversation}/index.ts +0 -0
- /package/src/{cypher → experimental/cypher}/ast.ts +0 -0
- /package/src/{cypher → experimental/cypher}/combinators.test.ts +0 -0
- /package/src/{cypher → experimental/cypher}/combinators.ts +0 -0
- /package/src/{cypher → experimental/cypher}/execution-plan.test.ts +0 -0
- /package/src/{cypher → experimental/cypher}/execution-plan.ts +0 -0
- /package/src/{cypher → experimental/cypher}/index.ts +0 -0
- /package/src/{cypher → experimental/cypher}/parjs-shims.d.ts +0 -0
- /package/src/{cypher → experimental/cypher}/parjs.ts +0 -0
- /package/src/{cypher → experimental/cypher}/parser.ts +0 -0
- /package/src/{cypher → experimental/cypher}/query-executor.ts +0 -0
|
@@ -2,35 +2,33 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema
|
|
6
|
-
import { inspect } from 'node:util';
|
|
5
|
+
import { Schema } from 'effect';
|
|
7
6
|
import { describe, test } from 'vitest';
|
|
8
7
|
|
|
9
|
-
import {
|
|
10
|
-
ArtifactId,
|
|
11
|
-
defineArtifact,
|
|
12
|
-
defineTool,
|
|
13
|
-
ToolResult,
|
|
14
|
-
type Message,
|
|
15
|
-
type MessageContentBlock,
|
|
16
|
-
} from '@dxos/artifact';
|
|
8
|
+
import { ArtifactId, defineArtifact, defineTool, ToolResult } from '@dxos/artifact';
|
|
17
9
|
import { AIServiceEdgeClient } from '@dxos/assistant';
|
|
18
|
-
import {
|
|
10
|
+
import { Type } from '@dxos/echo';
|
|
11
|
+
import { create, ObjectId } from '@dxos/echo-schema';
|
|
19
12
|
import { DXN } from '@dxos/keys';
|
|
20
13
|
import { log } from '@dxos/log';
|
|
21
14
|
|
|
22
15
|
import { AISession } from './session';
|
|
23
|
-
import { AI_SERVICE_ENDPOINT } from '../testing';
|
|
16
|
+
import { AI_SERVICE_ENDPOINT, ConsolePrinter } from '../testing';
|
|
24
17
|
|
|
25
18
|
// Define a calendar event artifact schema.
|
|
26
|
-
const CalendarEventSchema =
|
|
27
|
-
title:
|
|
28
|
-
startTime:
|
|
29
|
-
endTime:
|
|
30
|
-
description:
|
|
31
|
-
}).pipe(
|
|
19
|
+
const CalendarEventSchema = Schema.Struct({
|
|
20
|
+
title: Schema.String,
|
|
21
|
+
startTime: Schema.String,
|
|
22
|
+
endTime: Schema.String,
|
|
23
|
+
description: Schema.String,
|
|
24
|
+
}).pipe(
|
|
25
|
+
Type.def({
|
|
26
|
+
typename: 'example.com/type/CalendarEvent',
|
|
27
|
+
version: '0.1.0',
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
32
30
|
|
|
33
|
-
type CalendarEvent =
|
|
31
|
+
type CalendarEvent = Schema.Schema.Type<typeof CalendarEventSchema>;
|
|
34
32
|
|
|
35
33
|
// TODO(burdon): Flaky.
|
|
36
34
|
describe.skip('AISession with Ollama', () => {
|
|
@@ -53,7 +51,7 @@ describe.skip('AISession with Ollama', () => {
|
|
|
53
51
|
defineTool('calendar', {
|
|
54
52
|
name: 'query',
|
|
55
53
|
description: 'Query the calendar for events',
|
|
56
|
-
schema:
|
|
54
|
+
schema: Schema.Struct({}),
|
|
57
55
|
execute: async () => {
|
|
58
56
|
return ToolResult.Success(CALENDAR_EVENTS);
|
|
59
57
|
},
|
|
@@ -65,13 +63,13 @@ describe.skip('AISession with Ollama', () => {
|
|
|
65
63
|
id: 'artifact:dxos.org/plugin/table',
|
|
66
64
|
name: 'Table',
|
|
67
65
|
instructions: 'Use this to create and manage tables. Each table has a unique id.',
|
|
68
|
-
schema:
|
|
66
|
+
schema: Schema.Struct({}),
|
|
69
67
|
tools: [
|
|
70
68
|
defineTool('table', {
|
|
71
69
|
name: 'create',
|
|
72
70
|
description: 'Create a table',
|
|
73
|
-
schema:
|
|
74
|
-
data:
|
|
71
|
+
schema: Schema.Struct({
|
|
72
|
+
data: Schema.Array(Schema.Any).annotations({ description: 'Array of data payloads to add as rows' }),
|
|
75
73
|
}),
|
|
76
74
|
execute: async ({ data }) => {
|
|
77
75
|
log('create table', { data });
|
|
@@ -89,12 +87,12 @@ describe.skip('AISession with Ollama', () => {
|
|
|
89
87
|
name: 'Map',
|
|
90
88
|
instructions:
|
|
91
89
|
'Use this to create and manage maps. Maps source data from tables. Table id is required to create a map.',
|
|
92
|
-
schema:
|
|
90
|
+
schema: Schema.Struct({}),
|
|
93
91
|
tools: [
|
|
94
92
|
defineTool('map', {
|
|
95
93
|
name: 'create',
|
|
96
94
|
description: 'Create a map',
|
|
97
|
-
schema:
|
|
95
|
+
schema: Schema.Struct({
|
|
98
96
|
source: ArtifactId.annotations({
|
|
99
97
|
description: 'The table that will be used as the source of the map',
|
|
100
98
|
}),
|
|
@@ -119,7 +117,7 @@ describe.skip('AISession with Ollama', () => {
|
|
|
119
117
|
id: 'artifact:dxos.org/plugin/script',
|
|
120
118
|
name: 'Script',
|
|
121
119
|
instructions: 'Use this to create and manage scripts',
|
|
122
|
-
schema:
|
|
120
|
+
schema: Schema.Struct({}),
|
|
123
121
|
tools: [],
|
|
124
122
|
});
|
|
125
123
|
|
|
@@ -127,9 +125,10 @@ describe.skip('AISession with Ollama', () => {
|
|
|
127
125
|
// printStreamEvent(event);
|
|
128
126
|
// });
|
|
129
127
|
|
|
130
|
-
|
|
131
|
-
session.
|
|
132
|
-
session.
|
|
128
|
+
const printer = new ConsolePrinter();
|
|
129
|
+
session.message.on((message) => printer.printMessage(message));
|
|
130
|
+
session.userMessage.on((message) => printer.printMessage(message));
|
|
131
|
+
session.block.on((block) => printer.printContentBlock(block));
|
|
133
132
|
|
|
134
133
|
// session.update.on((update) => {
|
|
135
134
|
// log('update', { update });
|
|
@@ -189,34 +188,6 @@ const CALENDAR_EVENTS: CalendarEvent[] = [
|
|
|
189
188
|
}),
|
|
190
189
|
];
|
|
191
190
|
|
|
192
|
-
const printMessage = (message: Message) => {
|
|
193
|
-
console.log(`${message.role.toUpperCase()}\n`);
|
|
194
|
-
for (const content of message.content) {
|
|
195
|
-
printContentBlock(content);
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const printContentBlock = (content: MessageContentBlock) => {
|
|
200
|
-
switch (content.type) {
|
|
201
|
-
case 'text':
|
|
202
|
-
console.log(content.text);
|
|
203
|
-
break;
|
|
204
|
-
case 'tool_use':
|
|
205
|
-
console.log(`⚙️ [Tool Use] ${content.name} ${inspect(content.input, { depth: null, colors: true })}`);
|
|
206
|
-
break;
|
|
207
|
-
case 'tool_result': {
|
|
208
|
-
let data: any;
|
|
209
|
-
try {
|
|
210
|
-
data = JSON.parse(content.content);
|
|
211
|
-
} catch {
|
|
212
|
-
data = content.content;
|
|
213
|
-
}
|
|
214
|
-
console.log(`⚙️ [Tool Result] ${content.toolUseId} ${inspect(data, { depth: null, colors: true })}`);
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
191
|
// const printStreamEvent = (event: GenerationStreamEvent) => {
|
|
221
192
|
// switch (event.type) {
|
|
222
193
|
// case 'message_start': {
|
package/src/session/session.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Option, Schema
|
|
5
|
+
import { Option, Schema } from 'effect';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
defineTool,
|
|
9
9
|
Message,
|
|
10
|
+
structuredOutputParser,
|
|
10
11
|
ToolResult,
|
|
11
12
|
type ArtifactDefinition,
|
|
12
13
|
type MessageContentBlock,
|
|
@@ -18,9 +19,9 @@ import { create, type ObjectId } from '@dxos/echo-schema';
|
|
|
18
19
|
import { invariant } from '@dxos/invariant';
|
|
19
20
|
import { log } from '@dxos/log';
|
|
20
21
|
|
|
22
|
+
import { isToolUse, runTools } from './tools';
|
|
21
23
|
import { VersionPin } from './version-pin';
|
|
22
24
|
import { MixedStreamParser, type AIServiceClient, type GenerateRequest, type GenerationStream } from '../ai-service';
|
|
23
|
-
import { isToolUse, runTools } from '../conversation';
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Contains message history, tools, current context.
|
|
@@ -245,6 +246,15 @@ export class AISession {
|
|
|
245
246
|
return this._pending;
|
|
246
247
|
}
|
|
247
248
|
|
|
249
|
+
async runStructured<S extends Schema.Schema.AnyNoContext>(schema: S, options: SessionRunOptions) {
|
|
250
|
+
const parser = structuredOutputParser(schema);
|
|
251
|
+
const result = await this.run({
|
|
252
|
+
...options,
|
|
253
|
+
tools: [...options.tools, parser.tool],
|
|
254
|
+
});
|
|
255
|
+
return parser.getResult(result);
|
|
256
|
+
}
|
|
257
|
+
|
|
248
258
|
private async _formatUserPrompt(
|
|
249
259
|
artifactDiffResolver: ArtifactDiffResolver | undefined,
|
|
250
260
|
prompt: string,
|
|
@@ -287,7 +297,7 @@ export class AISession {
|
|
|
287
297
|
return defineTool('system', {
|
|
288
298
|
name: 'query_artifact_definitions',
|
|
289
299
|
description: 'Query the available artifact definitions',
|
|
290
|
-
schema:
|
|
300
|
+
schema: Schema.Struct({}),
|
|
291
301
|
execute: async () => {
|
|
292
302
|
return ToolResult.Success({
|
|
293
303
|
artifactDefinitions: artifacts.map((artifact) => ({
|
|
@@ -308,8 +318,8 @@ export class AISession {
|
|
|
308
318
|
name: 'require_artifact_definitions',
|
|
309
319
|
description:
|
|
310
320
|
'Require the use of specific artifact definitions. This will allow the model to interact with artifact definitions and use their tools.',
|
|
311
|
-
schema:
|
|
312
|
-
artifactDefinitionIds:
|
|
321
|
+
schema: Schema.Struct({
|
|
322
|
+
artifactDefinitionIds: Schema.Array(Schema.String).annotations({
|
|
313
323
|
description: 'The ids of the artifact definitions to require',
|
|
314
324
|
examples: [['artifact:dxos.org/example/Test']],
|
|
315
325
|
}),
|
|
@@ -336,20 +346,20 @@ export class AISession {
|
|
|
336
346
|
name: 'create_plan',
|
|
337
347
|
description:
|
|
338
348
|
'Create a plan. Make sure that each step is independent and can be executed solely on the data returned by the previous step. The steps only share the data that is specified in the plan.',
|
|
339
|
-
schema:
|
|
340
|
-
goal:
|
|
341
|
-
steps:
|
|
342
|
-
|
|
343
|
-
action:
|
|
349
|
+
schema: Schema.Struct({
|
|
350
|
+
goal: Schema.String.annotations({ description: 'The goal that the plan will achieve.' }),
|
|
351
|
+
steps: Schema.Array(
|
|
352
|
+
Schema.Struct({
|
|
353
|
+
action: Schema.String.annotations({
|
|
344
354
|
description: 'Complete, detailed action to perform.',
|
|
345
355
|
}),
|
|
346
|
-
input:
|
|
356
|
+
input: Schema.String.annotations({
|
|
347
357
|
description: 'The required input data for this step. First step must not require any data.',
|
|
348
358
|
}),
|
|
349
|
-
output:
|
|
359
|
+
output: Schema.String.annotations({
|
|
350
360
|
description: 'The output data from this step. This is passed to the next step as input.',
|
|
351
361
|
}),
|
|
352
|
-
requiredArtifactIds:
|
|
362
|
+
requiredArtifactIds: Schema.Array(Schema.String).annotations({
|
|
353
363
|
description: 'The ids of the artifacts required to perform this step.',
|
|
354
364
|
examples: [['artifact:dxos.org/example/Test']],
|
|
355
365
|
}),
|
|
@@ -473,7 +483,7 @@ const createBaseInstructions = ({
|
|
|
473
483
|
${availableArtifacts.length > 0 ? `Artifacts already in context: ${availableArtifacts.join('\n')}` : ''}
|
|
474
484
|
`;
|
|
475
485
|
|
|
476
|
-
export class AIServiecOverloadedError extends
|
|
486
|
+
export class AIServiecOverloadedError extends Schema.TaggedError<AIServiecOverloadedError>()(
|
|
477
487
|
'AIServiecOverloadedError',
|
|
478
488
|
{},
|
|
479
489
|
) {}
|
|
@@ -483,7 +493,7 @@ const gatherObjectVersions = (messages: Message[]): Map<ObjectId, ObjectVersion>
|
|
|
483
493
|
for (const message of messages) {
|
|
484
494
|
for (const block of message.content) {
|
|
485
495
|
if (block.type === 'json' && block.disposition === VersionPin.DISPOSITION) {
|
|
486
|
-
const pin = VersionPin.pipe(
|
|
496
|
+
const pin = VersionPin.pipe(Schema.decodeOption)(JSON.parse(block.json)).pipe(Option.getOrUndefined);
|
|
487
497
|
if (!pin) {
|
|
488
498
|
continue;
|
|
489
499
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Message, type Tool, ToolResult } from '@dxos/artifact';
|
|
6
|
+
import { create } from '@dxos/echo-schema';
|
|
7
|
+
import { invariant } from '@dxos/invariant';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
|
|
10
|
+
export const isToolUse = (message: Message, { onlyToolNames }: { onlyToolNames?: string[] } = {}) => {
|
|
11
|
+
const block = message.content.at(-1);
|
|
12
|
+
invariant(block);
|
|
13
|
+
return block.type === 'tool_use' && (!onlyToolNames || onlyToolNames.includes(block.name));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type RunToolsOptions = {
|
|
17
|
+
message: Message;
|
|
18
|
+
tools: Tool[];
|
|
19
|
+
extensions?: ToolContextExtensions;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type RunToolsResult =
|
|
23
|
+
| {
|
|
24
|
+
type: 'continue';
|
|
25
|
+
message: Message;
|
|
26
|
+
}
|
|
27
|
+
| {
|
|
28
|
+
type: 'break';
|
|
29
|
+
result: unknown;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const runTools = async ({ message, tools, extensions }: RunToolsOptions): Promise<RunToolsResult> => {
|
|
33
|
+
const toolCalls = message.content.filter((block) => block.type === 'tool_use');
|
|
34
|
+
invariant(toolCalls.length === 1);
|
|
35
|
+
const toolCall = toolCalls[0];
|
|
36
|
+
const tool = tools.find((tool) => tool.name === toolCall.name);
|
|
37
|
+
if (!tool) {
|
|
38
|
+
const resultMessage = create(Message, {
|
|
39
|
+
role: 'user',
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'tool_result',
|
|
43
|
+
toolUseId: toolCall.id,
|
|
44
|
+
content: `Tool not found: ${toolCall.name}`,
|
|
45
|
+
isError: true,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// TODO(burdon): Retry count?
|
|
51
|
+
return {
|
|
52
|
+
type: 'continue',
|
|
53
|
+
message: resultMessage,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let toolResult: ToolResult;
|
|
58
|
+
try {
|
|
59
|
+
invariant(tool.execute);
|
|
60
|
+
toolResult = await tool.execute(toolCall.input, { extensions });
|
|
61
|
+
} catch (error: any) {
|
|
62
|
+
log('tool error', { error });
|
|
63
|
+
toolResult = ToolResult.Error(error.message);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
switch (toolResult.kind) {
|
|
67
|
+
case 'error': {
|
|
68
|
+
log('tool error', { message: toolResult.message });
|
|
69
|
+
const resultMessage = create(Message, {
|
|
70
|
+
role: 'user',
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: 'tool_result',
|
|
74
|
+
toolUseId: toolCall.id,
|
|
75
|
+
content: toolResult.message,
|
|
76
|
+
isError: true,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// TODO(burdon): Retry count?
|
|
82
|
+
return {
|
|
83
|
+
type: 'continue',
|
|
84
|
+
message: resultMessage,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
case 'success': {
|
|
89
|
+
log('tool success', { result: toolResult.result });
|
|
90
|
+
const resultMessage = create(Message, {
|
|
91
|
+
role: 'user',
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: 'tool_result',
|
|
95
|
+
toolUseId: toolCall.id,
|
|
96
|
+
content:
|
|
97
|
+
typeof toolResult.result === 'string' ? toolResult.result : JSON.stringify(toolResult.result) ?? '',
|
|
98
|
+
},
|
|
99
|
+
...(toolResult.extractContentBlocks ?? []),
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
type: 'continue',
|
|
105
|
+
message: resultMessage,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case 'break': {
|
|
110
|
+
log('tool break', { result: toolResult.result });
|
|
111
|
+
return {
|
|
112
|
+
type: 'break',
|
|
113
|
+
result: toolResult.result,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
@@ -18,6 +18,12 @@ const VersionPinSchema = Schema.Struct({
|
|
|
18
18
|
// TODO(dmaretskyi): Could be opaque
|
|
19
19
|
version: ObjectVersionSchema,
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Used to pin a specific version of an object during the course of a conversation.
|
|
24
|
+
*
|
|
25
|
+
* This allows us to detect when the object changes during the course of the conversation.
|
|
26
|
+
*/
|
|
21
27
|
export interface VersionPin extends Schema.Schema.Type<typeof VersionPinSchema> {}
|
|
22
28
|
|
|
23
29
|
export const VersionPin: typeof VersionPinSchema & {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
|
-
import { Schema
|
|
6
|
+
import { Schema } from '@effect/schema';
|
|
7
7
|
import { describe, test } from 'vitest';
|
|
8
8
|
|
|
9
9
|
import { ObjectId, toJsonSchema } from '@dxos/echo-schema';
|
|
@@ -15,26 +15,26 @@ import { AIServiceEdgeClient, Tool } from '../ai-service';
|
|
|
15
15
|
import { defineTool, ToolResult } from '../conversation';
|
|
16
16
|
|
|
17
17
|
// TODO(dmaretskyi): Effect schema.
|
|
18
|
-
const ArtifactDef =
|
|
19
|
-
typename:
|
|
20
|
-
description:
|
|
21
|
-
schema:
|
|
22
|
-
actions:
|
|
23
|
-
}).pipe(
|
|
18
|
+
const ArtifactDef = Schema.Struct({
|
|
19
|
+
typename: Schema.String,
|
|
20
|
+
description: Schema.String,
|
|
21
|
+
schema: Schema.Any,
|
|
22
|
+
actions: Schema.Array(Tool),
|
|
23
|
+
}).pipe(Schema.mutable);
|
|
24
24
|
|
|
25
|
-
type ArtifactDef =
|
|
25
|
+
type ArtifactDef = Schema.Schema.Type<typeof ArtifactDef>;
|
|
26
26
|
|
|
27
|
-
const ListItem =
|
|
28
|
-
name:
|
|
27
|
+
const ListItem = Schema.Struct({
|
|
28
|
+
name: Schema.String,
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const ListSchema =
|
|
31
|
+
const ListSchema = Schema.Struct({
|
|
32
32
|
id: ObjectId,
|
|
33
|
-
title:
|
|
34
|
-
items:
|
|
35
|
-
}).pipe(
|
|
33
|
+
title: Schema.String,
|
|
34
|
+
items: Schema.Array(ListItem).pipe(Schema.mutable),
|
|
35
|
+
}).pipe(Schema.mutable);
|
|
36
36
|
|
|
37
|
-
type ListSchema =
|
|
37
|
+
type ListSchema = Schema.Schema.Type<typeof ListSchema>;
|
|
38
38
|
|
|
39
39
|
const list: ArtifactDef = {
|
|
40
40
|
typename: 'example.com/type/List',
|
|
@@ -44,7 +44,7 @@ const list: ArtifactDef = {
|
|
|
44
44
|
defineTool('list', {
|
|
45
45
|
name: 'query',
|
|
46
46
|
description: 'Query all lists',
|
|
47
|
-
schema:
|
|
47
|
+
schema: Schema.Struct({}),
|
|
48
48
|
execute: async ({}, context) => {
|
|
49
49
|
return ToolResult.Success(LISTS[id]);
|
|
50
50
|
},
|
|
@@ -52,7 +52,7 @@ const list: ArtifactDef = {
|
|
|
52
52
|
defineTool('list', {
|
|
53
53
|
name: 'inspect',
|
|
54
54
|
description: 'Get contents of the list',
|
|
55
|
-
schema:
|
|
55
|
+
schema: Schema.Struct({
|
|
56
56
|
id: ObjectId.annotations({ description: 'The list to inspect' }),
|
|
57
57
|
}),
|
|
58
58
|
execute: async ({ id }, context) => {
|
|
@@ -62,9 +62,9 @@ const list: ArtifactDef = {
|
|
|
62
62
|
defineTool('list', {
|
|
63
63
|
name: 'create',
|
|
64
64
|
description: 'Add one or more items to an existing list',
|
|
65
|
-
schema:
|
|
65
|
+
schema: Schema.Struct({
|
|
66
66
|
id: ObjectId.annotations({ description: 'The list to add items to' }),
|
|
67
|
-
items:
|
|
67
|
+
items: Schema.Array(ListItem).annotations({ description: 'The items to add to the list' }),
|
|
68
68
|
}),
|
|
69
69
|
execute: async ({ id, items }, context) => {
|
|
70
70
|
LISTS[id].items.push(...items);
|
|
@@ -81,7 +81,7 @@ const artifacts = [list];
|
|
|
81
81
|
const getArtifactDefinitions = defineTool('system', {
|
|
82
82
|
name: 'getArtifactDefinitions',
|
|
83
83
|
description: 'Queries the definitions and metadata of artifacts defined in the system',
|
|
84
|
-
schema:
|
|
84
|
+
schema: Schema.Any,
|
|
85
85
|
execute: async (_, context) => {
|
|
86
86
|
return ToolResult.Success(
|
|
87
87
|
artifacts.map((artifact) => ({
|
|
@@ -116,8 +116,8 @@ describe('Artifacts', () => {
|
|
|
116
116
|
name: 'custodian',
|
|
117
117
|
description: 'Custodian can tell you the password if you say the magic word',
|
|
118
118
|
parameters: toJsonSchema(
|
|
119
|
-
|
|
120
|
-
magicWord:
|
|
119
|
+
Schema.Struct({
|
|
120
|
+
magicWord: Schema.String.annotations({ description: 'The magic word. Should be exactly "pretty please"' }),
|
|
121
121
|
}),
|
|
122
122
|
),
|
|
123
123
|
};
|
package/src/testing/index.ts
CHANGED
package/src/testing/logger.ts
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { inspect } from 'node:util';
|
|
6
|
+
|
|
7
|
+
import type { Message, MessageContentBlock } from '@dxos/artifact';
|
|
8
|
+
|
|
9
|
+
export class ConsolePrinter {
|
|
10
|
+
printMessage = (message: Message) => {
|
|
11
|
+
// eslint-disable-next-line no-console
|
|
12
|
+
console.log(`${message.role.toUpperCase()}\n`);
|
|
13
|
+
for (const content of message.content) {
|
|
14
|
+
this.printContentBlock(content);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
printContentBlock = (content: MessageContentBlock) => {
|
|
19
|
+
switch (content.type) {
|
|
20
|
+
case 'text':
|
|
21
|
+
// eslint-disable-next-line no-console
|
|
22
|
+
console.log(content.text);
|
|
23
|
+
break;
|
|
24
|
+
case 'tool_use':
|
|
25
|
+
// eslint-disable-next-line no-console
|
|
26
|
+
console.log(`⚙️ [Tool Use] ${content.name} ${inspect(content.input, { depth: null, colors: true })}`);
|
|
27
|
+
break;
|
|
28
|
+
case 'tool_result': {
|
|
29
|
+
let data: any;
|
|
30
|
+
try {
|
|
31
|
+
data = JSON.parse(content.content);
|
|
32
|
+
} catch {
|
|
33
|
+
data = content.content;
|
|
34
|
+
}
|
|
35
|
+
// eslint-disable-next-line no-console
|
|
36
|
+
console.log(`⚙️ [Tool Result] ${content.toolUseId} ${inspect(data, { depth: null, colors: true })}`);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
6
|
|
|
7
7
|
import { defineTool, ToolResult } from '@dxos/artifact';
|
|
8
8
|
import { toJsonSchema } from '@dxos/echo-schema';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
|
|
11
|
-
import { executeQuery, formatJsonSchemaForLLM, type DataSource } from '../
|
|
11
|
+
import { executeQuery, formatJsonSchemaForLLM, type DataSource } from '../experimental';
|
|
12
12
|
import { trim } from '../util';
|
|
13
13
|
|
|
14
|
-
export const createCypherTool = (dataSource: DataSource, schemaTypes:
|
|
14
|
+
export const createCypherTool = (dataSource: DataSource, schemaTypes: Schema.Schema.Any[] = []) =>
|
|
15
15
|
defineTool('dxos.org/echo', {
|
|
16
16
|
name: 'query',
|
|
17
17
|
description:
|
|
18
18
|
'Query the ECHO graph database in cypher query language. Returns data from the database.' +
|
|
19
19
|
(schemaTypes.length > 0 ? `\n\n${createSystemPrompt(schemaTypes)}` : ''),
|
|
20
|
-
schema:
|
|
21
|
-
query:
|
|
20
|
+
schema: Schema.Struct({
|
|
21
|
+
query: Schema.String.annotations({
|
|
22
22
|
description: `
|
|
23
23
|
A valid cypher query string to execute.
|
|
24
24
|
Query must have one MATCH clause.
|
|
@@ -55,7 +55,7 @@ export const createCypherTool = (dataSource: DataSource, schemaTypes: S.Schema.A
|
|
|
55
55
|
},
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
export const createSystemPrompt = (schemaTypes:
|
|
58
|
+
export const createSystemPrompt = (schemaTypes: Schema.Schema.Any[]) => trim`
|
|
59
59
|
You have access to ECHO graph database. You can query the database to get data to satisfy user prompts.
|
|
60
60
|
|
|
61
61
|
Database schema is defined in pseud-cypher syntax. The schema is:
|
|
@@ -16,8 +16,7 @@ import { createCypherTool, createSystemPrompt } from './query-promts';
|
|
|
16
16
|
import { createTestData, seedTestData } from './test-data';
|
|
17
17
|
import { Contact, Organization, Project, Task } from './test-schema';
|
|
18
18
|
import { AIServiceEdgeClient, DEFAULT_EDGE_MODEL } from '../ai-service';
|
|
19
|
-
import { runLLM } from '../
|
|
20
|
-
import { EchoDataSource } from '../cypher';
|
|
19
|
+
import { runLLM, EchoDataSource } from '../experimental';
|
|
21
20
|
|
|
22
21
|
const client = new AIServiceEdgeClient({
|
|
23
22
|
endpoint: AI_SERVICE_ENDPOINT.LOCAL,
|
package/src/testing/test-data.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Schema
|
|
5
|
+
import { type Schema } from 'effect';
|
|
6
6
|
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
8
|
import type { EchoDatabase } from '@dxos/echo-db';
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
type Relationship,
|
|
24
24
|
formatInferredRelationshipLabel,
|
|
25
25
|
formatNodeLabel,
|
|
26
|
-
} from '../
|
|
26
|
+
} from '../experimental';
|
|
27
27
|
import { Contact, Organization, Project, Task } from '../testing';
|
|
28
28
|
|
|
29
29
|
export const seedTestData = (db: EchoDatabase) => {
|
|
@@ -254,7 +254,7 @@ export class MockDataSource implements DataSource {
|
|
|
254
254
|
objects: Record<
|
|
255
255
|
string,
|
|
256
256
|
{
|
|
257
|
-
schema:
|
|
257
|
+
schema: Schema.Schema.All;
|
|
258
258
|
typeDxn: string;
|
|
259
259
|
id: string;
|
|
260
260
|
data: unknown;
|
|
@@ -265,7 +265,7 @@ export class MockDataSource implements DataSource {
|
|
|
265
265
|
string,
|
|
266
266
|
{
|
|
267
267
|
json: JsonSchemaType;
|
|
268
|
-
instance:
|
|
268
|
+
instance: Schema.Schema.All;
|
|
269
269
|
}
|
|
270
270
|
> = {};
|
|
271
271
|
|
|
@@ -280,7 +280,7 @@ export class MockDataSource implements DataSource {
|
|
|
280
280
|
return this.relationships.filter((relationship) => !label || relationship.label === label);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
add<S extends
|
|
283
|
+
add<S extends Schema.Schema.All>(schema: S, data: Schema.Schema.Type<S>) {
|
|
284
284
|
invariant(typeof data.id === 'string', 'Data must have an id');
|
|
285
285
|
const jsonSchema = toJsonSchema(schema);
|
|
286
286
|
if (!this.schema[jsonSchema.$id!]) {
|