@dxos/assistant 0.8.4-main.e098934 → 0.8.4-main.e8ec1fe
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/extraction/index.mjs +118 -161
- package/dist/lib/browser/extraction/index.mjs.map +4 -4
- package/dist/lib/browser/index.mjs +977 -156
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/extraction/index.mjs +118 -161
- package/dist/lib/node-esm/extraction/index.mjs.map +4 -4
- package/dist/lib/node-esm/index.mjs +977 -156
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/conversation/context.d.ts +14 -7
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +11 -12
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/diff.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +14 -18
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/execution-graph.d.ts +85 -0
- package/dist/types/src/execution-graph.d.ts.map +1 -0
- package/dist/types/src/execution-graph.test.d.ts +2 -0
- package/dist/types/src/execution-graph.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +60 -52
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +24 -13
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +1 -1
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +18 -5
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/session/GenericToolkit.d.ts +84 -0
- package/dist/types/src/session/GenericToolkit.d.ts.map +1 -0
- package/dist/types/src/session/artifact-diff.d.ts +2 -2
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
- package/dist/types/src/session/error-handling.d.ts +2 -2
- package/dist/types/src/session/error-handling.d.ts.map +1 -1
- package/dist/types/src/session/format.d.ts +4 -174
- package/dist/types/src/session/format.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/observer.d.ts +3 -3
- package/dist/types/src/session/observer.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +15 -11
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +7 -6
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/session/version-pin.d.ts +3 -3
- package/dist/types/src/session/version-pin.d.ts.map +1 -1
- package/dist/types/src/types/artifact.d.ts +20 -0
- package/dist/types/src/types/artifact.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -31
- package/src/conversation/context.ts +49 -17
- package/src/conversation/conversation.ts +28 -23
- package/src/diff.test.ts +3 -3
- package/src/diff.ts +5 -0
- package/src/execution-graph.test.ts +740 -0
- package/src/execution-graph.ts +509 -0
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +2 -2
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +46 -54
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +10 -9
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +38 -44
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +12 -6
- package/src/extraction/extraction.ts +7 -6
- package/src/extraction/quotes.ts +2 -2
- package/src/functions/services.ts +93 -50
- package/src/index.ts +2 -1
- package/src/session/GenericToolkit.ts +130 -0
- package/src/session/artifact-diff.ts +2 -2
- package/src/session/error-handling.ts +6 -4
- package/src/session/format.test.ts +5 -4
- package/src/session/format.ts +17 -12
- package/src/session/index.ts +2 -0
- package/src/session/observer.ts +4 -3
- package/src/session/session.conversations.json +1 -0
- package/src/session/session.test.ts +51 -210
- package/src/session/session.ts +40 -28
- package/src/session/toolkit.ts +19 -13
- package/src/session/version-pin.ts +4 -5
- package/src/templates/{format.tpl → instructions/format.tpl} +1 -0
- package/src/templates/{system.tpl → instructions/system.tpl} +10 -12
- package/src/templates/system.ts +2 -2
- package/src/{types.ts → types/artifact.ts} +22 -3
- package/src/types/index.ts +5 -0
- package/dist/lib/browser/chunk-3K5SRE5A.mjs +0 -404
- package/dist/lib/browser/chunk-3K5SRE5A.mjs.map +0 -7
- package/dist/lib/browser/chunk-UB26N5UF.mjs +0 -89
- package/dist/lib/browser/chunk-UB26N5UF.mjs.map +0 -7
- package/dist/lib/browser/named-entity-recognition-QPYHML66.mjs +0 -13
- package/dist/lib/node-esm/chunk-BCFXTNSK.mjs +0 -91
- package/dist/lib/node-esm/chunk-BCFXTNSK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-W7AIB6DP.mjs +0 -406
- package/dist/lib/node-esm/chunk-W7AIB6DP.mjs.map +0 -7
- package/dist/lib/node-esm/named-entity-recognition-2HDF46YX.mjs +0 -14
- package/dist/types/src/session/version-pin.test.d.ts +0 -2
- package/dist/types/src/session/version-pin.test.d.ts.map +0 -1
- package/dist/types/src/summarization/summarization.test.d.ts +0 -2
- package/dist/types/src/summarization/summarization.test.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -16
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/session/__snapshots__/session.test.ts.snap +0 -32
- package/src/session/version-pin.test.ts +0 -7
- package/src/summarization/summarization.test.ts +0 -197
- /package/dist/lib/browser/{named-entity-recognition-QPYHML66.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/node-esm/{named-entity-recognition-2HDF46YX.mjs.map → chunk-HSLMI22Q.mjs.map} +0 -0
- /package/src/extraction/extraction-llm-function/{instructions.tpl → transcription-instructions.tpl} +0 -0
package/src/session/format.ts
CHANGED
|
@@ -2,21 +2,23 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Array from 'effect/Array';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Function from 'effect/Function';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
6
9
|
|
|
7
10
|
import { Template } from '@dxos/blueprints';
|
|
8
11
|
import { Obj } from '@dxos/echo';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { DatabaseService } from '@dxos/functions';
|
|
12
|
+
import { type ObjectId } from '@dxos/echo/internal';
|
|
13
|
+
import { DatabaseService, ObjectVersion } from '@dxos/echo-db';
|
|
12
14
|
import { log } from '@dxos/log';
|
|
13
|
-
import { type ContentBlock,
|
|
15
|
+
import { type ContentBlock, Message } from '@dxos/types';
|
|
14
16
|
import { trim } from '@dxos/util';
|
|
15
17
|
|
|
16
18
|
import { AiAssistantError } from '../errors';
|
|
17
19
|
|
|
18
20
|
import { ArtifactDiffResolver } from './artifact-diff';
|
|
19
|
-
import { type AiSessionRunParams } from './session';
|
|
21
|
+
import { type AiSessionRunError, type AiSessionRunParams } from './session';
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Formats the system prompt.
|
|
@@ -28,7 +30,7 @@ export const formatSystemPrompt = ({
|
|
|
28
30
|
objects = [],
|
|
29
31
|
}: Pick<AiSessionRunParams<any>, 'system' | 'blueprints' | 'objects'>) =>
|
|
30
32
|
Effect.gen(function* () {
|
|
31
|
-
const blueprintDefs = yield* pipe(
|
|
33
|
+
const blueprintDefs = yield* Function.pipe(
|
|
32
34
|
blueprints,
|
|
33
35
|
Effect.forEach((blueprint) => Effect.succeed(blueprint.instructions)),
|
|
34
36
|
Effect.flatMap(Effect.forEach((template) => DatabaseService.loadOption(template.source))),
|
|
@@ -47,7 +49,7 @@ export const formatSystemPrompt = ({
|
|
|
47
49
|
),
|
|
48
50
|
);
|
|
49
51
|
|
|
50
|
-
const objectDefs = yield* pipe(
|
|
52
|
+
const objectDefs = yield* Function.pipe(
|
|
51
53
|
objects,
|
|
52
54
|
Effect.forEach((object) =>
|
|
53
55
|
Effect.succeed(trim`
|
|
@@ -60,7 +62,7 @@ export const formatSystemPrompt = ({
|
|
|
60
62
|
Effect.map((objects) => (objects.length > 0 ? ['## Context Objects', ...objects].join('\n\n') : undefined)),
|
|
61
63
|
);
|
|
62
64
|
|
|
63
|
-
return yield* pipe(
|
|
65
|
+
return yield* Function.pipe(
|
|
64
66
|
Effect.succeed([system, blueprintDefs, objectDefs].filter((def): def is string => def !== undefined)),
|
|
65
67
|
Effect.map((parts) => parts.join('\n\n')),
|
|
66
68
|
);
|
|
@@ -71,7 +73,10 @@ export const formatSystemPrompt = ({
|
|
|
71
73
|
*/
|
|
72
74
|
// TODO(burdon): Move to AiPreprocessor.
|
|
73
75
|
// TODO(burdon): Convert util below to `Effect.fn` (to preserve stack info)
|
|
74
|
-
export const formatUserPrompt = ({
|
|
76
|
+
export const formatUserPrompt = ({
|
|
77
|
+
prompt,
|
|
78
|
+
history = [],
|
|
79
|
+
}: Pick<AiSessionRunParams<any>, 'prompt' | 'history'>): Effect.Effect<Message.Message, AiSessionRunError> =>
|
|
75
80
|
Effect.gen(function* () {
|
|
76
81
|
const blocks: ContentBlock.Any[] = [];
|
|
77
82
|
|
|
@@ -102,14 +107,14 @@ export const formatUserPrompt = ({ prompt, history = [] }: Pick<AiSessionRunPara
|
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
return Obj.make(
|
|
110
|
+
return Obj.make(Message.Message, {
|
|
106
111
|
created: new Date().toISOString(),
|
|
107
112
|
sender: { role: 'user' },
|
|
108
113
|
blocks: [...blocks, { _tag: 'text', text: prompt }],
|
|
109
114
|
});
|
|
110
115
|
});
|
|
111
116
|
|
|
112
|
-
const gatherObjectVersions = (messages:
|
|
117
|
+
const gatherObjectVersions = (messages: Message.Message[]): Map<ObjectId, ObjectVersion> => {
|
|
113
118
|
const artifactIds = new Map<ObjectId, ObjectVersion>();
|
|
114
119
|
for (const message of messages) {
|
|
115
120
|
for (const block of message.blocks) {
|
package/src/session/index.ts
CHANGED
package/src/session/observer.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Function from 'effect/Function';
|
|
6
7
|
|
|
7
8
|
import { type AiParser, type ConsolePrinter } from '@dxos/ai';
|
|
8
|
-
import { type
|
|
9
|
+
import { type Message } from '@dxos/types';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Live observer of the generation process.
|
|
@@ -15,7 +16,7 @@ export interface GenerationObserver extends AiParser.ParseResponseCallbacks {
|
|
|
15
16
|
* Complete messages fired during the session, both from the model and from the user.
|
|
16
17
|
* This message will contain all message blocks emitted through the `onBlock` callback.
|
|
17
18
|
*/
|
|
18
|
-
onMessage: (message:
|
|
19
|
+
onMessage: (message: Message.Message) => Effect.Effect<void>;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const GenerationObserver = Object.freeze({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"conversations":[{"parameters":{"model":"@anthropic/claude-3-5-sonnet-20241022","stream":true,"tools":[]},"prompt":{"content":[{"role":"user","content":"Hello world!","options":{}}]},"response":[{"type":"response-metadata","id":"msg_01Bm496JGgDMgC9YwdYTFFHo","modelId":"claude-3-5-sonnet-20241022","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"Hi","metadata":{}},{"type":"text-delta","id":"0","delta":"!","metadata":{}},{"type":"text-delta","id":"0","delta":" How can","metadata":{}},{"type":"text-delta","id":"0","delta":" I help you today?","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":10,"outputTokens":12,"totalTokens":22},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":10,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-3-5-sonnet-20241022","stream":true,"tools":[{"name":"Calculator","description":"Basic calculator tool","inputSchema":{"type":"object","required":["input"],"properties":{"input":{"type":"string","description":"The calculation to perform."}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"user","content":"What is 10 + 30?","options":{}}]},"response":[{"type":"response-metadata","id":"msg_01UNTbjtTHEpdFgGunu2k8Br","modelId":"claude-3-5-sonnet-20241022","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I","metadata":{}},{"type":"text-delta","id":"0","delta":"'ll help","metadata":{}},{"type":"text-delta","id":"0","delta":" you calculate","metadata":{}},{"type":"text-delta","id":"0","delta":" ","metadata":{}},{"type":"text-delta","id":"0","delta":"10 + 30","metadata":{}},{"type":"text-delta","id":"0","delta":" using the","metadata":{}},{"type":"text-delta","id":"0","delta":" Calculator tool.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"tool-params-start","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","name":"Calculator","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","delta":"{\"input\": \"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","delta":"10 + 30","metadata":{}},{"type":"tool-params-delta","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","delta":"\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","metadata":{}},{"type":"tool-call","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","name":"Calculator","params":{"input":"10 + 30"},"providerExecuted":false,"metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":394,"outputTokens":73,"totalTokens":467},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":394,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-3-5-sonnet-20241022","stream":true,"tools":[{"name":"Calculator","description":"Basic calculator tool","inputSchema":{"type":"object","required":["input"],"properties":{"input":{"type":"string","description":"The calculation to perform."}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"user","content":"What is 10 + 30?","options":{}},{"role":"assistant","content":[{"type":"text","text":"I'll help you calculate 10 + 30 using the Calculator tool.","options":{}},{"type":"tool-call","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","name":"Calculator","params":{"input":"10 + 30"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01LTGUgfihCQtVchm1b37xHQ","name":"Calculator","result":{"result":40},"options":{}}],"options":{}}]},"response":[{"type":"response-metadata","id":"msg_01AKio3GheJGn38BhvAp33rs","modelId":"claude-3-5-sonnet-20241022","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"The result","metadata":{}},{"type":"text-delta","id":"0","delta":" of 10 +","metadata":{}},{"type":"text-delta","id":"0","delta":" 30 is ","metadata":{}},{"type":"text-delta","id":"0","delta":"40.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":482,"outputTokens":18,"totalTokens":500},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":482,"output_tokens":3,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Tool from '@effect/ai/Tool';
|
|
6
|
+
import * as Toolkit from '@effect/ai/Toolkit';
|
|
6
7
|
import { describe, it } from '@effect/vitest';
|
|
7
|
-
import
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import * as Layer from 'effect/Layer';
|
|
10
|
+
import * as Schema from 'effect/Schema';
|
|
8
11
|
|
|
9
|
-
import { AiService, ToolExecutionService, ToolResolverService } from '@dxos/ai';
|
|
12
|
+
import { AiService, MemoizedAiService, ToolExecutionService, ToolResolverService } from '@dxos/ai';
|
|
10
13
|
import { AiServiceTestingPreset } from '@dxos/ai/testing';
|
|
11
14
|
import { Obj, Type } from '@dxos/echo';
|
|
15
|
+
import { TestHelpers } from '@dxos/effect';
|
|
12
16
|
import { TracingService } from '@dxos/functions';
|
|
13
17
|
import { log } from '@dxos/log';
|
|
14
18
|
|
|
@@ -29,8 +33,8 @@ const CalendarEventSchema = Schema.Struct({
|
|
|
29
33
|
|
|
30
34
|
type CalendarEvent = Schema.Schema.Type<typeof CalendarEventSchema>;
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
const TestToolkit = Toolkit.make(
|
|
37
|
+
Tool.make('Calculator', {
|
|
34
38
|
description: 'Basic calculator tool',
|
|
35
39
|
parameters: {
|
|
36
40
|
input: Schema.String.annotations({
|
|
@@ -42,7 +46,7 @@ class TestToolkit extends AiToolkit.make(
|
|
|
42
46
|
}),
|
|
43
47
|
failure: Schema.Never,
|
|
44
48
|
}),
|
|
45
|
-
)
|
|
49
|
+
);
|
|
46
50
|
|
|
47
51
|
// Tool handlers.
|
|
48
52
|
const toolkitLayer = TestToolkit.toLayer({
|
|
@@ -61,175 +65,52 @@ const toolkitLayer = TestToolkit.toLayer({
|
|
|
61
65
|
}),
|
|
62
66
|
});
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
Layer.mergeAll(
|
|
76
|
-
toolkitLayer,
|
|
77
|
-
AiService.model('@anthropic/claude-3-5-sonnet-20241022').pipe(
|
|
78
|
-
Layer.provideMerge(ToolResolverService.layerEmpty),
|
|
79
|
-
Layer.provideMerge(ToolExecutionService.layerEmpty),
|
|
80
|
-
Layer.provideMerge(AiServiceTestingPreset('direct')),
|
|
81
|
-
Layer.provideMerge(TracingService.layerNoop),
|
|
82
|
-
),
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
|
-
),
|
|
86
|
-
);
|
|
68
|
+
const TestLayer = Layer.mergeAll(
|
|
69
|
+
toolkitLayer,
|
|
70
|
+
AiService.model('@anthropic/claude-3-5-sonnet-20241022'),
|
|
71
|
+
TracingService.layerNoop,
|
|
72
|
+
ToolResolverService.layerEmpty,
|
|
73
|
+
ToolExecutionService.layerEmpty,
|
|
74
|
+
).pipe(
|
|
75
|
+
//
|
|
76
|
+
Layer.provideMerge(MemoizedAiService.layerTest()),
|
|
77
|
+
Layer.provide(AiServiceTestingPreset('direct')),
|
|
78
|
+
);
|
|
87
79
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
AiService.model('@anthropic/claude-3-5-sonnet-20241022').pipe(
|
|
103
|
-
Layer.provideMerge(AiServiceTestingPreset('direct')),
|
|
104
|
-
),
|
|
105
|
-
ToolResolverService.layerEmpty,
|
|
106
|
-
ToolExecutionService.layerEmpty,
|
|
107
|
-
toolkitLayer,
|
|
108
|
-
),
|
|
109
|
-
),
|
|
80
|
+
describe('AiSession', () => {
|
|
81
|
+
it.effect(
|
|
82
|
+
'no tools',
|
|
83
|
+
Effect.fnUntraced(
|
|
84
|
+
function* (_) {
|
|
85
|
+
const session = new AiSession({ operationModel: 'configured' });
|
|
86
|
+
const response = yield* session.run({
|
|
87
|
+
prompt: 'Hello world!',
|
|
88
|
+
history: [],
|
|
89
|
+
});
|
|
90
|
+
log.info('response', { response });
|
|
91
|
+
},
|
|
92
|
+
Effect.provide(TestLayer),
|
|
93
|
+
TestHelpers.provideTestContext,
|
|
110
94
|
),
|
|
111
95
|
);
|
|
112
96
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
schema: CalendarEventSchema,
|
|
126
|
-
tools: [
|
|
127
|
-
createTool('calendar', {
|
|
128
|
-
name: 'query',
|
|
129
|
-
description: 'Query the calendar for events',
|
|
130
|
-
schema: Schema.Struct({}),
|
|
131
|
-
execute: async () => {
|
|
132
|
-
return ToolResult.Success(CALENDAR_EVENTS);
|
|
133
|
-
},
|
|
134
|
-
}),
|
|
135
|
-
],
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const tableArtifact = defineArtifact({
|
|
139
|
-
id: 'artifact:dxos.org/plugin/table',
|
|
140
|
-
name: 'Table',
|
|
141
|
-
instructions: 'Use this to create and manage tables. Each table has a unique id.',
|
|
142
|
-
schema: Schema.Struct({}),
|
|
143
|
-
tools: [
|
|
144
|
-
createTool('table', {
|
|
145
|
-
name: 'create',
|
|
146
|
-
description: 'Create a table',
|
|
147
|
-
schema: Schema.Struct({
|
|
148
|
-
data: Schema.Array(Schema.Any).annotations({ description: 'Array of data payloads to add as rows' }),
|
|
149
|
-
}),
|
|
150
|
-
execute: async ({ data }) => {
|
|
151
|
-
log('create table', { data });
|
|
152
|
-
const id = DXN.fromLocalObjectId(ObjectId.random()).toString();
|
|
153
|
-
objects.add(id);
|
|
154
|
-
// TODO(dmaretskyi): consider xml for refs instead of @dxn:echo:@:XXXXX
|
|
155
|
-
return ToolResult.Success(`table @${id}`);
|
|
156
|
-
},
|
|
157
|
-
}),
|
|
158
|
-
],
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const mapArtifact = defineArtifact({
|
|
162
|
-
id: 'artifact:dxos.org/plugin/map',
|
|
163
|
-
name: 'Map',
|
|
164
|
-
instructions:
|
|
165
|
-
'Use this to create and manage maps. Maps source data from tables. Table id is required to create a map.',
|
|
166
|
-
schema: Schema.Struct({}),
|
|
167
|
-
tools: [
|
|
168
|
-
createTool('map', {
|
|
169
|
-
name: 'create',
|
|
170
|
-
description: 'Create a map',
|
|
171
|
-
schema: Schema.Struct({
|
|
172
|
-
source: ArtifactId.annotations({
|
|
173
|
-
description: 'The table that will be used as the source of the map',
|
|
174
|
-
}),
|
|
175
|
-
}),
|
|
176
|
-
execute: async ({ source }) => {
|
|
177
|
-
// TODO(dmaretskyi): Use effect-schema decode instead of manual parsing.
|
|
178
|
-
const sourceId = ArtifactId.toDXN(source);
|
|
179
|
-
if (!objects.has(sourceId.toString())) {
|
|
180
|
-
return ToolResult.Error(`table id=${source} not found`);
|
|
181
|
-
}
|
|
182
|
-
log('create map', { sourceId });
|
|
183
|
-
const id = DXN.fromLocalObjectId(ObjectId.random()).toString();
|
|
184
|
-
objects.add(id);
|
|
185
|
-
// TODO(dmaretskyi): consider xml for refs instead of @dxn:echo:@:XXXXX
|
|
186
|
-
return ToolResult.Success(`map @${id}`);
|
|
187
|
-
},
|
|
188
|
-
}),
|
|
189
|
-
],
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const scriptArtifact = defineArtifact({
|
|
193
|
-
id: 'artifact:dxos.org/plugin/script',
|
|
194
|
-
name: 'Script',
|
|
195
|
-
instructions: 'Use this to create and manage scripts',
|
|
196
|
-
schema: Schema.Struct({}),
|
|
197
|
-
tools: [],
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// session.streamEvent.on((event) => {
|
|
201
|
-
// printStreamEvent(event);
|
|
202
|
-
// });
|
|
203
|
-
|
|
204
|
-
const printer = new ConsolePrinter();
|
|
205
|
-
session.message.on((message) => printer.printMessage(message));
|
|
206
|
-
session.userMessage.on((message) => printer.printMessage(message));
|
|
207
|
-
session.block.on((block) => printer.printContentBlock(block));
|
|
208
|
-
|
|
209
|
-
// session.update.on((update) => {
|
|
210
|
-
// log('update', { update });
|
|
211
|
-
// });
|
|
212
|
-
|
|
213
|
-
// Test creating an itinerary
|
|
214
|
-
const response = await session.run({
|
|
215
|
-
client: aiClient,
|
|
216
|
-
tools: [],
|
|
217
|
-
artifacts: [calendarArtifact, tableArtifact, mapArtifact, scriptArtifact],
|
|
218
|
-
requiredArtifactIds: [calendarArtifact.id, tableArtifact.id, mapArtifact.id, scriptArtifact.id],
|
|
219
|
-
history: [],
|
|
220
|
-
generationOptions: {
|
|
221
|
-
model: '@anthropic/claude-3-5-haiku-20241022',
|
|
97
|
+
it.effect(
|
|
98
|
+
'calculator',
|
|
99
|
+
Effect.fnUntraced(
|
|
100
|
+
function* (_) {
|
|
101
|
+
const session = new AiSession({ operationModel: 'configured' });
|
|
102
|
+
const toolkit = yield* TestToolkit;
|
|
103
|
+
const response = yield* session.run({
|
|
104
|
+
toolkit,
|
|
105
|
+
prompt: 'What is 10 + 30?',
|
|
106
|
+
history: [],
|
|
107
|
+
});
|
|
108
|
+
log.info('response', { response });
|
|
222
109
|
},
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
log('result', {
|
|
228
|
-
objects,
|
|
229
|
-
finalMessage: response.at(-1),
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
*/
|
|
110
|
+
Effect.provide(TestLayer),
|
|
111
|
+
TestHelpers.provideTestContext,
|
|
112
|
+
),
|
|
113
|
+
);
|
|
233
114
|
});
|
|
234
115
|
|
|
235
116
|
// Travel to rome, florence, livorno, siena, madrid for conferences
|
|
@@ -266,43 +147,3 @@ const _CALENDAR_EVENTS: CalendarEvent[] = [
|
|
|
266
147
|
description: 'Travel to Madrid',
|
|
267
148
|
}),
|
|
268
149
|
];
|
|
269
|
-
|
|
270
|
-
// const printStreamEvent = (event: GenerationStreamEvent) => {
|
|
271
|
-
// switch (event.type) {
|
|
272
|
-
// case 'message_start': {
|
|
273
|
-
// process.stdout.write(`${event.message.role.toUpperCase()}\n\n`);
|
|
274
|
-
// for (const content of event.message.content) {
|
|
275
|
-
// printContentBlock(content);
|
|
276
|
-
// }
|
|
277
|
-
// break;
|
|
278
|
-
// }
|
|
279
|
-
// case 'content_block_start': {
|
|
280
|
-
// printContentBlock(event.content);
|
|
281
|
-
// break;
|
|
282
|
-
// }
|
|
283
|
-
// case 'content_block_delta': {
|
|
284
|
-
// switch (event.delta.type) {
|
|
285
|
-
// case 'text_delta': {
|
|
286
|
-
// process.stdout.write(event.delta.text);
|
|
287
|
-
// break;
|
|
288
|
-
// }
|
|
289
|
-
// case 'input_json_delta': {
|
|
290
|
-
// process.stdout.write(event.delta.partial_json);
|
|
291
|
-
// break;
|
|
292
|
-
// }
|
|
293
|
-
// }
|
|
294
|
-
// break;
|
|
295
|
-
// }
|
|
296
|
-
// case 'content_block_stop': {
|
|
297
|
-
// process.stdout.write('\n');
|
|
298
|
-
// break;
|
|
299
|
-
// }
|
|
300
|
-
// case 'message_delta': {
|
|
301
|
-
// break;
|
|
302
|
-
// }
|
|
303
|
-
// case 'message_stop': {
|
|
304
|
-
// process.stdout.write('\n\n');
|
|
305
|
-
// break;
|
|
306
|
-
// }
|
|
307
|
-
// }
|
|
308
|
-
// };
|
package/src/session/session.ts
CHANGED
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import type * as AiError from '@effect/ai/AiError';
|
|
6
|
+
import * as LanguageModel from '@effect/ai/LanguageModel';
|
|
7
|
+
import type * as Tool from '@effect/ai/Tool';
|
|
8
|
+
import type * as Toolkit from '@effect/ai/Toolkit';
|
|
9
|
+
import * as Chunk from 'effect/Chunk';
|
|
10
|
+
import * as Effect from 'effect/Effect';
|
|
11
|
+
import type * as Schema from 'effect/Schema';
|
|
12
|
+
import * as Stream from 'effect/Stream';
|
|
7
13
|
|
|
8
14
|
import {
|
|
9
|
-
type AiInputPreprocessingError,
|
|
10
15
|
AiParser,
|
|
11
16
|
AiPreprocessor,
|
|
12
17
|
type AiToolNotFoundError,
|
|
18
|
+
type PromptPreprocessingError,
|
|
13
19
|
type ToolExecutionService,
|
|
14
20
|
type ToolResolverService,
|
|
15
21
|
callTool,
|
|
@@ -20,29 +26,29 @@ import { todo } from '@dxos/debug';
|
|
|
20
26
|
import { Obj } from '@dxos/echo';
|
|
21
27
|
import { TracingService } from '@dxos/functions';
|
|
22
28
|
import { log } from '@dxos/log';
|
|
23
|
-
import {
|
|
29
|
+
import { Message } from '@dxos/types';
|
|
24
30
|
|
|
25
31
|
import { type AiAssistantError } from '../errors';
|
|
26
32
|
|
|
27
|
-
import { mapAiError } from './error-handling';
|
|
28
33
|
import { formatSystemPrompt, formatUserPrompt } from './format';
|
|
29
34
|
import { GenerationObserver } from './observer';
|
|
30
35
|
|
|
31
|
-
export type AiSessionRunError = AiError.AiError |
|
|
36
|
+
export type AiSessionRunError = AiError.AiError | PromptPreprocessingError | AiToolNotFoundError | AiAssistantError;
|
|
32
37
|
|
|
33
38
|
export type AiSessionRunRequirements =
|
|
34
|
-
|
|
|
39
|
+
| LanguageModel.LanguageModel
|
|
35
40
|
| ToolExecutionService
|
|
36
41
|
| ToolResolverService
|
|
37
42
|
| TracingService;
|
|
38
43
|
|
|
39
|
-
export type AiSessionRunParams<Tools extends
|
|
44
|
+
export type AiSessionRunParams<Tools extends Record<string, Tool.Any>> = {
|
|
40
45
|
prompt: string;
|
|
46
|
+
// TODO(wittjosiah): Rename to systemPrompt.
|
|
41
47
|
system?: string;
|
|
42
|
-
history?:
|
|
48
|
+
history?: Message.Message[];
|
|
43
49
|
objects?: Obj.Any[];
|
|
44
50
|
blueprints?: Blueprint.Blueprint[];
|
|
45
|
-
toolkit?:
|
|
51
|
+
toolkit?: Toolkit.WithHandler<Tools>;
|
|
46
52
|
observer?: GenerationObserver;
|
|
47
53
|
};
|
|
48
54
|
|
|
@@ -64,14 +70,14 @@ export class AiSession {
|
|
|
64
70
|
|
|
65
71
|
/** Message history from queue. */
|
|
66
72
|
// TODO(burdon): Evolve into supporting a git-like graph of messages.
|
|
67
|
-
private _history:
|
|
73
|
+
private _history: Message.Message[] = [];
|
|
68
74
|
|
|
69
75
|
/** Pending messages for this session (incl. the current prompt). */
|
|
70
|
-
private _pending:
|
|
76
|
+
private _pending: Message.Message[] = [];
|
|
71
77
|
|
|
72
78
|
constructor(private readonly _options: AiSessionOptions = {}) {}
|
|
73
79
|
|
|
74
|
-
run = <Tools extends
|
|
80
|
+
run = <Tools extends Record<string, Tool.Any>>({
|
|
75
81
|
prompt,
|
|
76
82
|
system: systemTemplate,
|
|
77
83
|
history = [],
|
|
@@ -79,13 +85,13 @@ export class AiSession {
|
|
|
79
85
|
blueprints = [],
|
|
80
86
|
toolkit,
|
|
81
87
|
observer = GenerationObserver.noop(),
|
|
82
|
-
}: AiSessionRunParams<Tools>): Effect.Effect<
|
|
88
|
+
}: AiSessionRunParams<Tools>): Effect.Effect<Message.Message[], AiSessionRunError, AiSessionRunRequirements> =>
|
|
83
89
|
Effect.gen(this, function* () {
|
|
84
90
|
this._history = [...history];
|
|
85
91
|
this._pending = [];
|
|
86
92
|
const pending = this._pending;
|
|
87
93
|
|
|
88
|
-
const submitMessage = Effect.fnUntraced(function* (message:
|
|
94
|
+
const submitMessage = Effect.fnUntraced(function* (message: Message.Message) {
|
|
89
95
|
pending.push(message);
|
|
90
96
|
yield* observer.onMessage(message);
|
|
91
97
|
yield* TracingService.emitConverationMessage(message);
|
|
@@ -109,21 +115,16 @@ export class AiSession {
|
|
|
109
115
|
objects: objects?.length ?? 0,
|
|
110
116
|
});
|
|
111
117
|
|
|
112
|
-
const prompt = yield* AiPreprocessor.
|
|
118
|
+
const prompt = yield* AiPreprocessor.preprocessPrompt([...this._history, ...this._pending], { system });
|
|
113
119
|
|
|
114
120
|
// Execute the stream request.
|
|
115
|
-
|
|
121
|
+
// logDump('prompt', Prompt.Prompt.pipe(Schema.encodeSync)(prompt));
|
|
122
|
+
const blocks = yield* LanguageModel.streamText({
|
|
116
123
|
prompt,
|
|
117
|
-
system,
|
|
118
124
|
toolkit,
|
|
119
125
|
disableToolCallResolution: true,
|
|
120
126
|
}).pipe(
|
|
121
|
-
|
|
122
|
-
'AiError',
|
|
123
|
-
Effect.fnUntraced(function* (err) {
|
|
124
|
-
return yield* Effect.fail(yield* mapAiError(err));
|
|
125
|
-
}),
|
|
126
|
-
),
|
|
127
|
+
// TOOD(dmaretskyi): Error mapping.
|
|
127
128
|
AiParser.parseResponse({
|
|
128
129
|
onBegin: () => observer.onBegin(),
|
|
129
130
|
onBlock: (block) => observer.onBlock(block),
|
|
@@ -136,7 +137,7 @@ export class AiSession {
|
|
|
136
137
|
|
|
137
138
|
// Create the response message.
|
|
138
139
|
const response = yield* submitMessage(
|
|
139
|
-
Obj.make(
|
|
140
|
+
Obj.make(Message.Message, {
|
|
140
141
|
created: new Date().toISOString(),
|
|
141
142
|
sender: { role: 'assistant' },
|
|
142
143
|
blocks,
|
|
@@ -166,10 +167,12 @@ export class AiSession {
|
|
|
166
167
|
});
|
|
167
168
|
|
|
168
169
|
// Add to queue and continue loop.
|
|
170
|
+
// TODO(wittjosiah): Sometimes tool error results are added to the queue before the tool agent statuses.
|
|
171
|
+
// This results in a broken execution graph.
|
|
169
172
|
yield* submitMessage(
|
|
170
|
-
Obj.make(
|
|
173
|
+
Obj.make(Message.Message, {
|
|
171
174
|
created: new Date().toISOString(),
|
|
172
|
-
sender: { role: '
|
|
175
|
+
sender: { role: 'tool' },
|
|
173
176
|
blocks: toolResults,
|
|
174
177
|
}),
|
|
175
178
|
);
|
|
@@ -185,7 +188,7 @@ export class AiSession {
|
|
|
185
188
|
// TODO(burdon): Implement or remove.
|
|
186
189
|
async runStructured<S extends Schema.Schema.AnyNoContext>(
|
|
187
190
|
_schema: S,
|
|
188
|
-
_options: AiSessionRunParams<
|
|
191
|
+
_options: AiSessionRunParams<any>,
|
|
189
192
|
): Promise<Schema.Schema.Type<S>> {
|
|
190
193
|
return todo();
|
|
191
194
|
// const parser = structuredOutputParser(schema);
|
|
@@ -199,3 +202,12 @@ export class AiSession {
|
|
|
199
202
|
|
|
200
203
|
const createSnippet = (text: string, len = 32) =>
|
|
201
204
|
text.length <= len * 2 ? text : [text.slice(0, len), '...', text.slice(-len)].join('');
|
|
205
|
+
|
|
206
|
+
// TODO(dmaretskyi): Extract as a general util.
|
|
207
|
+
const logDump = (message: string, data: unknown) => {
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
209
|
+
const { writeFileSync } = require('node:fs');
|
|
210
|
+
const path = `/tmp/log-data-${Date.now()}.json`;
|
|
211
|
+
writeFileSync(path, JSON.stringify(data, null, 2));
|
|
212
|
+
log.info(message, { path });
|
|
213
|
+
};
|
package/src/session/toolkit.ts
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import type * as Tool from '@effect/ai/Tool';
|
|
6
|
+
import * as Toolkit from '@effect/ai/Toolkit';
|
|
7
|
+
import type * as Context from 'effect/Context';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
7
9
|
|
|
8
|
-
import { ToolExecutionService, type ToolId, ToolResolverService } from '@dxos/ai';
|
|
10
|
+
import { type AiToolNotFoundError, ToolExecutionService, type ToolId, ToolResolverService } from '@dxos/ai';
|
|
9
11
|
import { type Blueprint } from '@dxos/blueprints';
|
|
10
|
-
import {
|
|
12
|
+
import { isTruthy } from '@dxos/util';
|
|
11
13
|
|
|
12
|
-
export type ToolkitParams<Tools extends
|
|
13
|
-
toolkit?:
|
|
14
|
+
export type ToolkitParams<Tools extends Record<string, Tool.Any>> = {
|
|
15
|
+
toolkit?: Toolkit.Toolkit<Tools>;
|
|
14
16
|
toolIds?: ToolId[];
|
|
15
17
|
blueprints?: Blueprint.Blueprint[];
|
|
16
18
|
};
|
|
@@ -18,25 +20,29 @@ export type ToolkitParams<Tools extends AiTool.Any> = {
|
|
|
18
20
|
/**
|
|
19
21
|
* Build a combined toolkit from the blueprint tools and the provided toolkit.
|
|
20
22
|
*/
|
|
21
|
-
export const createToolkit = <Tools extends
|
|
23
|
+
export const createToolkit = <Tools extends Record<string, Tool.Any> = {}>({
|
|
22
24
|
toolkit: toolkitParam,
|
|
23
25
|
toolIds = [],
|
|
24
26
|
blueprints = [],
|
|
25
|
-
}: ToolkitParams<Tools>)
|
|
27
|
+
}: ToolkitParams<Tools>): Effect.Effect<
|
|
28
|
+
Toolkit.WithHandler<any>,
|
|
29
|
+
AiToolNotFoundError,
|
|
30
|
+
ToolResolverService | ToolExecutionService | Tool.HandlersFor<Tools>
|
|
31
|
+
> =>
|
|
26
32
|
Effect.gen(function* () {
|
|
27
33
|
const blueprintToolkit = yield* ToolResolverService.resolveToolkit([
|
|
28
34
|
...blueprints.flatMap(({ tools }) => tools),
|
|
29
35
|
...toolIds,
|
|
30
36
|
]);
|
|
31
37
|
|
|
32
|
-
const blueprintToolkitHandler: Context.Context<
|
|
38
|
+
const blueprintToolkitHandler: Context.Context<Tool.HandlersFor<any>> = yield* blueprintToolkit.toContext(
|
|
33
39
|
ToolExecutionService.handlersFor(blueprintToolkit),
|
|
34
40
|
);
|
|
35
41
|
|
|
36
|
-
const toolkit =
|
|
37
|
-
return yield* toolkit.pipe(Effect.provide(blueprintToolkitHandler)) as Effect.Effect<
|
|
38
|
-
|
|
42
|
+
const toolkit = Toolkit.merge(...[toolkitParam, blueprintToolkit].filter(isTruthy));
|
|
43
|
+
return yield* toolkit.pipe(Effect.provide(blueprintToolkitHandler)) as any as Effect.Effect<
|
|
44
|
+
Toolkit.WithHandler<any>,
|
|
39
45
|
never,
|
|
40
|
-
|
|
46
|
+
Tool.HandlersFor<Tools>
|
|
41
47
|
>;
|
|
42
48
|
});
|