@dxos/assistant 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/lib/neutral/chunk-BE6SRJ4N.mjs +193 -0
- package/dist/lib/neutral/chunk-BE6SRJ4N.mjs.map +7 -0
- package/dist/lib/neutral/extraction/index.mjs +223 -0
- package/dist/lib/neutral/extraction/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +1328 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/testing/index.mjs +38 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/conversation/context.d.ts +109 -60
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/context.test.d.ts +2 -0
- package/dist/types/src/conversation/context.test.d.ts.map +1 -0
- package/dist/types/src/conversation/conversation.d.ts +41 -16
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.test.d.ts +2 -0
- package/dist/types/src/conversation/conversation.test.d.ts.map +1 -0
- package/dist/types/src/diff.d.ts +3 -1
- package/dist/types/src/diff.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +22 -30
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/execution-graph.d.ts +5 -2
- package/dist/types/src/execution-graph.d.ts.map +1 -1
- 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 +282 -268
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +348 -303
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +2 -2
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +6 -6
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/functions.test.d.ts +2 -0
- package/dist/types/src/functions.test.d.ts.map +1 -0
- package/dist/types/src/session/artifact-diff.d.ts +1 -1
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
- package/dist/types/src/session/format.d.ts +4 -176
- 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 +6 -5
- package/dist/types/src/session/observer.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +25 -15
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +9 -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/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/layer.d.ts +22 -0
- package/dist/types/src/testing/layer.d.ts.map +1 -0
- package/dist/types/src/types/artifact.d.ts +28 -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 +41 -31
- package/src/conversation/context.test.ts +46 -0
- package/src/conversation/context.ts +223 -49
- package/src/conversation/conversation.test.ts +65 -0
- package/src/conversation/conversation.ts +179 -53
- package/src/diff.test.ts +37 -6
- package/src/diff.ts +18 -4
- package/src/errors.ts +2 -2
- package/src/execution-graph.test.ts +46 -44
- package/src/execution-graph.ts +25 -16
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +2 -2
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +44 -54
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +15 -14
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +36 -44
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +10 -5
- package/src/extraction/extraction.ts +9 -8
- package/src/extraction/quotes.ts +4 -5
- package/src/functions/services.ts +88 -37
- package/src/functions.conversations.json +1 -0
- package/src/functions.test.ts +74 -0
- package/src/session/artifact-diff.ts +1 -1
- package/src/session/format.test.ts +103 -39
- package/src/session/format.ts +17 -16
- package/src/session/index.ts +1 -0
- package/src/session/observer.ts +6 -3
- package/src/session/session.conversations.json +1 -1
- package/src/session/session.test.ts +60 -18
- package/src/session/session.ts +99 -60
- package/src/session/toolkit.ts +21 -25
- package/src/session/version-pin.ts +6 -6
- package/src/templates/{format.tpl → instructions/format.tpl} +1 -4
- package/src/templates/system.ts +2 -2
- package/src/testing/index.ts +5 -0
- package/src/testing/layer.ts +85 -0
- package/src/{types.ts → types/artifact.ts} +43 -6
- package/src/types/index.ts +5 -0
- package/dist/lib/browser/chunk-CWGVG235.mjs +0 -380
- package/dist/lib/browser/chunk-CWGVG235.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/extraction/index.mjs +0 -272
- package/dist/lib/browser/extraction/index.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -869
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/named-entity-recognition-QPYHML66.mjs +0 -13
- package/dist/lib/browser/named-entity-recognition-QPYHML66.mjs.map +0 -7
- 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-OV5PMQPB.mjs +0 -382
- package/dist/lib/node-esm/chunk-OV5PMQPB.mjs.map +0 -7
- package/dist/lib/node-esm/extraction/index.mjs +0 -273
- package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -870
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/named-entity-recognition-2HDF46YX.mjs +0 -14
- package/dist/lib/node-esm/named-entity-recognition-2HDF46YX.mjs.map +0 -7
- 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/summarization/summarization.test.ts +0 -202
- /package/src/extraction/extraction-llm-function/{instructions.tpl → transcription-instructions.tpl} +0 -0
- /package/src/templates/{system.tpl → instructions/system.tpl} +0 -0
package/src/session/session.ts
CHANGED
|
@@ -8,25 +8,24 @@ import type * as Tool from '@effect/ai/Tool';
|
|
|
8
8
|
import type * as Toolkit from '@effect/ai/Toolkit';
|
|
9
9
|
import * as Chunk from 'effect/Chunk';
|
|
10
10
|
import * as Effect from 'effect/Effect';
|
|
11
|
-
import type * as Schema from 'effect/Schema';
|
|
12
11
|
import * as Stream from 'effect/Stream';
|
|
13
12
|
|
|
14
13
|
import {
|
|
15
14
|
AiParser,
|
|
16
15
|
AiPreprocessor,
|
|
16
|
+
AiSummarizer,
|
|
17
17
|
type AiToolNotFoundError,
|
|
18
18
|
type PromptPreprocessingError,
|
|
19
19
|
type ToolExecutionService,
|
|
20
20
|
type ToolResolverService,
|
|
21
21
|
callTool,
|
|
22
|
-
|
|
22
|
+
withoutToolCallParising,
|
|
23
23
|
} from '@dxos/ai';
|
|
24
24
|
import { type Blueprint } from '@dxos/blueprints';
|
|
25
|
-
import { todo } from '@dxos/debug';
|
|
26
25
|
import { Obj } from '@dxos/echo';
|
|
27
|
-
import { TracingService } from '@dxos/functions';
|
|
26
|
+
import { type FunctionInvocationService, TracingService } from '@dxos/functions';
|
|
28
27
|
import { log } from '@dxos/log';
|
|
29
|
-
import {
|
|
28
|
+
import { type ContentBlock, Message } from '@dxos/types';
|
|
30
29
|
|
|
31
30
|
import { type AiAssistantError } from '../errors';
|
|
32
31
|
|
|
@@ -39,20 +38,33 @@ export type AiSessionRunRequirements =
|
|
|
39
38
|
| LanguageModel.LanguageModel
|
|
40
39
|
| ToolExecutionService
|
|
41
40
|
| ToolResolverService
|
|
42
|
-
| TracingService
|
|
41
|
+
| TracingService
|
|
42
|
+
| FunctionInvocationService;
|
|
43
43
|
|
|
44
|
-
export type
|
|
44
|
+
export type AiSessionOptions = {
|
|
45
|
+
/**
|
|
46
|
+
* Summarize before executing the prompt if the existing history exceeds this threshold.
|
|
47
|
+
*/
|
|
48
|
+
summarizationThreshold?: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type AiSessionRunProps<Tools extends Record<string, Tool.Any>> = {
|
|
45
52
|
prompt: string;
|
|
53
|
+
// TODO(wittjosiah): Rename to systemPrompt.
|
|
46
54
|
system?: string;
|
|
47
|
-
history?:
|
|
48
|
-
objects?: Obj.
|
|
49
|
-
blueprints?: Blueprint.Blueprint[];
|
|
55
|
+
history?: Message.Message[];
|
|
56
|
+
objects?: Obj.Unknown[];
|
|
57
|
+
blueprints?: readonly Blueprint.Blueprint[];
|
|
50
58
|
toolkit?: Toolkit.WithHandler<Tools>;
|
|
51
|
-
observer?: GenerationObserver
|
|
59
|
+
observer?: GenerationObserver<Tools>;
|
|
60
|
+
/**
|
|
61
|
+
* Callback for when a message is received from the user, model, or tool.
|
|
62
|
+
* This is useful for streaming the output to a queue.
|
|
63
|
+
*/
|
|
64
|
+
// TODO(dmaretskyi): This is duplicated by generation observer. Better solution would be to convert the return type from effect to stream.
|
|
65
|
+
onOutput?: (message: Message.Message) => Effect.Effect<void, never, never>;
|
|
52
66
|
};
|
|
53
67
|
|
|
54
|
-
export type AiSessionOptions = {};
|
|
55
|
-
|
|
56
68
|
/**
|
|
57
69
|
* Contains message history, tools, current context.
|
|
58
70
|
* Current context means the state of the app, time of day, and other contextual information.
|
|
@@ -69,13 +81,25 @@ export class AiSession {
|
|
|
69
81
|
|
|
70
82
|
/** Message history from queue. */
|
|
71
83
|
// TODO(burdon): Evolve into supporting a git-like graph of messages.
|
|
72
|
-
private _history:
|
|
84
|
+
private _history: Message.Message[] = [];
|
|
73
85
|
|
|
74
86
|
/** Pending messages for this session (incl. the current prompt). */
|
|
75
|
-
private _pending:
|
|
87
|
+
private _pending: Message.Message[] = [];
|
|
88
|
+
|
|
89
|
+
private _started = 0;
|
|
90
|
+
private _ended = 0;
|
|
91
|
+
private _toolCalls = 0;
|
|
76
92
|
|
|
77
93
|
constructor(private readonly _options: AiSessionOptions = {}) {}
|
|
78
94
|
|
|
95
|
+
get duration(): number {
|
|
96
|
+
return this._ended - this._started;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get toolCalls(): number {
|
|
100
|
+
return this._toolCalls;
|
|
101
|
+
}
|
|
102
|
+
|
|
79
103
|
run = <Tools extends Record<string, Tool.Any>>({
|
|
80
104
|
prompt,
|
|
81
105
|
system: systemTemplate,
|
|
@@ -84,25 +108,41 @@ export class AiSession {
|
|
|
84
108
|
blueprints = [],
|
|
85
109
|
toolkit,
|
|
86
110
|
observer = GenerationObserver.noop(),
|
|
87
|
-
|
|
111
|
+
onOutput = () => Effect.void,
|
|
112
|
+
}: AiSessionRunProps<Tools>): Effect.Effect<Message.Message[], AiSessionRunError, AiSessionRunRequirements> =>
|
|
88
113
|
Effect.gen(this, function* () {
|
|
114
|
+
this._started = Date.now();
|
|
89
115
|
this._history = [...history];
|
|
90
116
|
this._pending = [];
|
|
91
|
-
const pending = this._pending;
|
|
92
117
|
|
|
93
|
-
const submitMessage =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
const submitMessage = (message: Message.Message) =>
|
|
119
|
+
Effect.gen(this, function* () {
|
|
120
|
+
this._pending.push(message);
|
|
121
|
+
yield* observer.onMessage(message);
|
|
122
|
+
yield* TracingService.emitConverationMessage(message);
|
|
123
|
+
yield* onOutput(message);
|
|
124
|
+
return message;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const system = yield* formatSystemPrompt({ system: systemTemplate, blueprints, objects }).pipe(Effect.orDie);
|
|
128
|
+
|
|
129
|
+
if (this._options.summarizationThreshold !== undefined) {
|
|
130
|
+
const tokenCount = yield* AiPreprocessor.estimateTokens(
|
|
131
|
+
yield* AiPreprocessor.preprocessPrompt([...this._history], {
|
|
132
|
+
system,
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
if (tokenCount > this._options.summarizationThreshold) {
|
|
136
|
+
const summary = yield* AiSummarizer.summarize([...this._history]);
|
|
137
|
+
yield* submitMessage(summary);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
99
140
|
|
|
100
141
|
// Submit the prompt.
|
|
101
142
|
// TODO(burdon): Remove if cancelled?
|
|
102
143
|
const promptMessage = yield* submitMessage(yield* formatUserPrompt({ prompt, history }));
|
|
103
144
|
|
|
104
145
|
// Generate system and prompt messages.
|
|
105
|
-
const system = yield* formatSystemPrompt({ system: systemTemplate, blueprints, objects });
|
|
106
146
|
|
|
107
147
|
// Tool call loop.
|
|
108
148
|
do {
|
|
@@ -114,15 +154,19 @@ export class AiSession {
|
|
|
114
154
|
objects: objects?.length ?? 0,
|
|
115
155
|
});
|
|
116
156
|
|
|
117
|
-
const prompt = yield* AiPreprocessor.preprocessPrompt([...this._history, ...this._pending], {
|
|
157
|
+
const prompt = yield* AiPreprocessor.preprocessPrompt([...this._history, ...this._pending], {
|
|
158
|
+
system,
|
|
159
|
+
cacheControl: 'ephemeral',
|
|
160
|
+
});
|
|
118
161
|
|
|
119
162
|
// Execute the stream request.
|
|
120
|
-
|
|
121
|
-
const blocks = yield* LanguageModel.streamText({
|
|
163
|
+
const messages = yield* LanguageModel.streamText({
|
|
122
164
|
prompt,
|
|
123
165
|
toolkit,
|
|
124
166
|
disableToolCallResolution: true,
|
|
125
167
|
}).pipe(
|
|
168
|
+
// Disable tool call parsing so that we can handle parameter schema errors on a per-tool call basis.
|
|
169
|
+
withoutToolCallParising,
|
|
126
170
|
// TOOD(dmaretskyi): Error mapping.
|
|
127
171
|
AiParser.parseResponse({
|
|
128
172
|
onBegin: () => observer.onBegin(),
|
|
@@ -130,21 +174,29 @@ export class AiSession {
|
|
|
130
174
|
onPart: (part) => observer.onPart(part),
|
|
131
175
|
onEnd: (summary) => observer.onEnd(summary),
|
|
132
176
|
}),
|
|
177
|
+
Stream.mapEffect((block) =>
|
|
178
|
+
Effect.gen(function* () {
|
|
179
|
+
return yield* submitMessage(
|
|
180
|
+
Obj.make(Message.Message, {
|
|
181
|
+
created: new Date().toISOString(),
|
|
182
|
+
sender: { role: 'assistant' },
|
|
183
|
+
blocks: [block],
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
}),
|
|
187
|
+
),
|
|
133
188
|
Stream.runCollect,
|
|
134
189
|
Effect.map(Chunk.toArray),
|
|
135
190
|
);
|
|
136
191
|
|
|
137
|
-
// Create the response message.
|
|
138
|
-
const response = yield* submitMessage(
|
|
139
|
-
Obj.make(DataType.Message, {
|
|
140
|
-
created: new Date().toISOString(),
|
|
141
|
-
sender: { role: 'assistant' },
|
|
142
|
-
blocks,
|
|
143
|
-
}),
|
|
144
|
-
);
|
|
145
|
-
|
|
146
192
|
// Parse the response for tool calls.
|
|
147
|
-
const toolCalls =
|
|
193
|
+
const toolCalls = messages.flatMap((message) =>
|
|
194
|
+
message.blocks
|
|
195
|
+
.filter(
|
|
196
|
+
(block): block is ContentBlock.ToolCall => block._tag === 'toolCall' && block.providerExecuted === false,
|
|
197
|
+
)
|
|
198
|
+
.map((block) => ({ block, message })),
|
|
199
|
+
);
|
|
148
200
|
if (toolCalls.length === 0) {
|
|
149
201
|
break;
|
|
150
202
|
} else if (!toolkit) {
|
|
@@ -153,13 +205,13 @@ export class AiSession {
|
|
|
153
205
|
|
|
154
206
|
// Execute the tool calls.
|
|
155
207
|
// TODO(burdon): Retry errors? Write result when each completes individually?
|
|
156
|
-
const toolResults = yield* Effect.forEach(toolCalls, (
|
|
157
|
-
return callTool(toolkit,
|
|
208
|
+
const toolResults = yield* Effect.forEach(toolCalls, ({ block, message }) => {
|
|
209
|
+
return callTool(toolkit, block).pipe(
|
|
158
210
|
Effect.provide(
|
|
159
211
|
TracingService.layerSubframe((context) => ({
|
|
160
212
|
...context,
|
|
161
|
-
parentMessage:
|
|
162
|
-
toolCallId:
|
|
213
|
+
parentMessage: message.id,
|
|
214
|
+
toolCallId: block.toolCallId,
|
|
163
215
|
})),
|
|
164
216
|
),
|
|
165
217
|
);
|
|
@@ -168,35 +220,22 @@ export class AiSession {
|
|
|
168
220
|
// Add to queue and continue loop.
|
|
169
221
|
// TODO(wittjosiah): Sometimes tool error results are added to the queue before the tool agent statuses.
|
|
170
222
|
// This results in a broken execution graph.
|
|
223
|
+
// TODO(dmaretskyi): Stream tool results one by one.
|
|
171
224
|
yield* submitMessage(
|
|
172
|
-
Obj.make(
|
|
225
|
+
Obj.make(Message.Message, {
|
|
173
226
|
created: new Date().toISOString(),
|
|
174
227
|
sender: { role: 'tool' },
|
|
175
228
|
blocks: toolResults,
|
|
176
229
|
}),
|
|
177
230
|
);
|
|
231
|
+
|
|
232
|
+
this._toolCalls++;
|
|
178
233
|
} while (true);
|
|
179
234
|
|
|
180
|
-
|
|
235
|
+
this._ended = Date.now();
|
|
236
|
+
log('done', { pending: this._pending.length, duration: this.duration, tools: this._toolCalls });
|
|
181
237
|
return this._pending;
|
|
182
238
|
}).pipe(this._semaphore.withPermits(1), Effect.withSpan('AiSession.run'));
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* @deprecated
|
|
186
|
-
*/
|
|
187
|
-
// TODO(burdon): Implement or remove.
|
|
188
|
-
async runStructured<S extends Schema.Schema.AnyNoContext>(
|
|
189
|
-
_schema: S,
|
|
190
|
-
_options: AiSessionRunParams<any>,
|
|
191
|
-
): Promise<Schema.Schema.Type<S>> {
|
|
192
|
-
return todo();
|
|
193
|
-
// const parser = structuredOutputParser(schema);
|
|
194
|
-
// const result = await this.run({
|
|
195
|
-
// ...options,
|
|
196
|
-
// executableTools: [...(options.executableTools ?? []), parser.tool],
|
|
197
|
-
// });
|
|
198
|
-
// return parser.getResult(result);
|
|
199
|
-
}
|
|
200
239
|
}
|
|
201
240
|
|
|
202
241
|
const createSnippet = (text: string, len = 32) =>
|
package/src/session/toolkit.ts
CHANGED
|
@@ -4,45 +4,41 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Tool from '@effect/ai/Tool';
|
|
6
6
|
import * as Toolkit from '@effect/ai/Toolkit';
|
|
7
|
-
import type * as Context from 'effect/Context';
|
|
8
7
|
import * as Effect from 'effect/Effect';
|
|
9
8
|
|
|
10
|
-
import { type AiToolNotFoundError,
|
|
9
|
+
import { type AiToolNotFoundError, GenericToolkit, ToolExecutionService, ToolResolverService } from '@dxos/ai';
|
|
11
10
|
import { type Blueprint } from '@dxos/blueprints';
|
|
12
11
|
import { isTruthy } from '@dxos/util';
|
|
13
12
|
|
|
14
|
-
export type
|
|
15
|
-
toolkit?: Toolkit.
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
export type CreateToolkitProps = {
|
|
14
|
+
toolkit?: Toolkit.Any;
|
|
15
|
+
blueprints?: readonly Blueprint.Blueprint[];
|
|
16
|
+
/**
|
|
17
|
+
* Self-contained with handlers toolkits.
|
|
18
|
+
*/
|
|
19
|
+
genericToolkits?: readonly GenericToolkit.GenericToolkit[];
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Build a combined toolkit from the blueprint tools and the provided toolkit.
|
|
22
24
|
*/
|
|
23
|
-
export const createToolkit =
|
|
24
|
-
toolkit:
|
|
25
|
-
toolIds = [],
|
|
25
|
+
export const createToolkit = ({
|
|
26
|
+
toolkit: toolkitProp,
|
|
26
27
|
blueprints = [],
|
|
27
|
-
|
|
28
|
+
genericToolkits = [],
|
|
29
|
+
}: CreateToolkitProps): Effect.Effect<
|
|
28
30
|
Toolkit.WithHandler<any>,
|
|
29
31
|
AiToolNotFoundError,
|
|
30
|
-
ToolResolverService | ToolExecutionService | Tool.HandlersFor<
|
|
32
|
+
ToolResolverService | ToolExecutionService | Tool.HandlersFor<any>
|
|
31
33
|
> =>
|
|
32
34
|
Effect.gen(function* () {
|
|
33
|
-
const blueprintToolkit = yield* ToolResolverService.resolveToolkit(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
]);
|
|
35
|
+
const blueprintToolkit = yield* ToolResolverService.resolveToolkit(blueprints.flatMap(({ tools }) => tools));
|
|
36
|
+
const blueprintToolHandler = yield* blueprintToolkit.toContext(ToolExecutionService.handlersFor(blueprintToolkit));
|
|
37
|
+
const genericToolkit = GenericToolkit.merge(...genericToolkits);
|
|
37
38
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return yield* toolkit.pipe(Effect.provide(blueprintToolkitHandler)) as any as Effect.Effect<
|
|
44
|
-
Toolkit.WithHandler<any>,
|
|
45
|
-
never,
|
|
46
|
-
Tool.HandlersFor<Tools>
|
|
47
|
-
>;
|
|
39
|
+
const toolkit = Toolkit.merge(...[toolkitProp, blueprintToolkit, genericToolkit.toolkit].filter(isTruthy));
|
|
40
|
+
return yield* toolkit.pipe(
|
|
41
|
+
Effect.provide(blueprintToolHandler),
|
|
42
|
+
Effect.provide(genericToolkit.layer),
|
|
43
|
+
) as any as Effect.Effect<Toolkit.WithHandler<any>, never, Tool.HandlersFor<any>>;
|
|
48
44
|
});
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
8
|
-
import { type ObjectVersion } from '@dxos/echo-db';
|
|
9
|
-
import {
|
|
10
|
-
import { type ContentBlock } from '@dxos/
|
|
7
|
+
import { type Obj } from '@dxos/echo';
|
|
8
|
+
import { type ObjectVersion, getVersion } from '@dxos/echo-db';
|
|
9
|
+
import { ObjectId } from '@dxos/keys';
|
|
10
|
+
import { type ContentBlock } from '@dxos/types';
|
|
11
11
|
|
|
12
12
|
// TODO(dmaretskyi): Extract.
|
|
13
13
|
const ObjectVersionSchema = Schema.Unknown as Schema.Schema<ObjectVersion>;
|
|
@@ -27,11 +27,11 @@ export interface VersionPin extends Schema.Schema.Type<typeof VersionPinSchema>
|
|
|
27
27
|
|
|
28
28
|
export const VersionPin: typeof VersionPinSchema & {
|
|
29
29
|
DISPOSITION: 'version-pin';
|
|
30
|
-
fromObject: (object:
|
|
30
|
+
fromObject: (object: Obj.Unknown) => VersionPin;
|
|
31
31
|
createBlock: (pin: VersionPin) => ContentBlock.Any;
|
|
32
32
|
} = class extends VersionPinSchema {
|
|
33
33
|
static readonly DISPOSITION = 'version-pin';
|
|
34
|
-
static fromObject(object:
|
|
34
|
+
static fromObject(object: Obj.Unknown): VersionPin {
|
|
35
35
|
return VersionPin.make({
|
|
36
36
|
objectId: object.id,
|
|
37
37
|
version: getVersion(object),
|
|
@@ -45,16 +45,13 @@ You can reply with a block reference for objects if you have the DXN. For exampl
|
|
|
45
45
|
|
|
46
46
|
Each suggestion must in the form of a proposed action enclosed in a <suggestion> tag.
|
|
47
47
|
Example: <suggestion>Show on a map</suggestion>
|
|
48
|
+
Do not use bullets when listing suggestions.
|
|
48
49
|
|
|
49
50
|
### Multiple choice questions
|
|
50
51
|
|
|
51
52
|
You may ask multiple choice questions by wrapping consise options inside <option> tags inside a well formed <select> tag.
|
|
52
53
|
Example: <select><option>Yes</option><option>No</option></select>
|
|
53
54
|
|
|
54
|
-
## Toolkit
|
|
55
|
-
|
|
56
|
-
If the user asks for a list of tools, then just emit a single self-closing <toolkit/> tag instead of listing the tools.
|
|
57
|
-
|
|
58
55
|
## Context
|
|
59
56
|
|
|
60
57
|
The current date and time is {{DATETIME}}.
|
package/src/templates/system.ts
CHANGED
|
@@ -7,8 +7,8 @@ import defaultsDeep from 'lodash.defaultsdeep';
|
|
|
7
7
|
import { type ModelCapabilities } from '@dxos/ai';
|
|
8
8
|
import { Template } from '@dxos/blueprints';
|
|
9
9
|
|
|
10
|
-
import FORMAT from './format.tpl?raw';
|
|
11
|
-
import SYSTEM from './system.tpl?raw';
|
|
10
|
+
import FORMAT from './instructions/format.tpl?raw';
|
|
11
|
+
import SYSTEM from './instructions/system.tpl?raw';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* System template variables.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Registry } from '@effect-atom/atom';
|
|
6
|
+
import * as Layer from 'effect/Layer';
|
|
7
|
+
import * as Match from 'effect/Match';
|
|
8
|
+
|
|
9
|
+
import { AiService, type ModelName } from '@dxos/ai';
|
|
10
|
+
import { GenericToolkit } from '@dxos/ai';
|
|
11
|
+
import { TestAiService } from '@dxos/ai/testing';
|
|
12
|
+
import { Feed, type Type } from '@dxos/echo';
|
|
13
|
+
import { CredentialsService, type FunctionDefinition, type ServiceCredential, TracingService } from '@dxos/functions';
|
|
14
|
+
import { TracingServiceExt, TriggerDispatcher, TriggerStateStore } from '@dxos/functions-runtime';
|
|
15
|
+
import { FunctionInvocationServiceLayerTest, TestDatabaseLayer } from '@dxos/functions-runtime/testing';
|
|
16
|
+
|
|
17
|
+
import { ToolExecutionServices } from '../functions';
|
|
18
|
+
|
|
19
|
+
interface TestLayerOptions {
|
|
20
|
+
aiServicePreset?: 'direct' | 'edge-local' | 'edge-remote';
|
|
21
|
+
model?: ModelName;
|
|
22
|
+
functions?: FunctionDefinition.Any[];
|
|
23
|
+
toolkits?: GenericToolkit.GenericToolkit[];
|
|
24
|
+
types?: Type.AnyEntity[];
|
|
25
|
+
credentials?: ServiceCredential[];
|
|
26
|
+
/*
|
|
27
|
+
* Tracing configuration.
|
|
28
|
+
* @default 'noop'
|
|
29
|
+
*/
|
|
30
|
+
tracing?: 'noop' | 'console' | 'pretty';
|
|
31
|
+
|
|
32
|
+
disableLlmMemoization?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const AssistantTestLayer = ({
|
|
36
|
+
aiServicePreset = 'direct',
|
|
37
|
+
model = '@anthropic/claude-opus-4-6',
|
|
38
|
+
functions = [],
|
|
39
|
+
toolkits = [],
|
|
40
|
+
types = [],
|
|
41
|
+
credentials = [],
|
|
42
|
+
tracing = 'noop',
|
|
43
|
+
disableLlmMemoization = false,
|
|
44
|
+
}: TestLayerOptions = {}) => {
|
|
45
|
+
const toolkit = GenericToolkit.merge(...toolkits);
|
|
46
|
+
return Layer.mergeAll(AiService.model(model), ToolExecutionServices).pipe(
|
|
47
|
+
Layer.provideMerge(
|
|
48
|
+
FunctionInvocationServiceLayerTest({
|
|
49
|
+
functions,
|
|
50
|
+
}),
|
|
51
|
+
),
|
|
52
|
+
Layer.provideMerge(
|
|
53
|
+
Layer.mergeAll(
|
|
54
|
+
TestAiService({ preset: aiServicePreset, disableMemoization: disableLlmMemoization }),
|
|
55
|
+
TestDatabaseLayer({
|
|
56
|
+
spaceKey: 'fixed',
|
|
57
|
+
types,
|
|
58
|
+
}),
|
|
59
|
+
CredentialsService.configuredLayer(credentials),
|
|
60
|
+
Feed.notAvailable,
|
|
61
|
+
Match.value(tracing).pipe(
|
|
62
|
+
Match.when('noop', () => TracingService.layerNoop),
|
|
63
|
+
Match.when('console', () => TracingServiceExt.layerLogInfo()),
|
|
64
|
+
Match.when('pretty', () =>
|
|
65
|
+
TracingServiceExt.layerConsolePrettyPrint({
|
|
66
|
+
toolkit: (toolkits.length > 0 ? GenericToolkit.merge(...toolkits) : GenericToolkit.empty).toolkit as any,
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
Match.exhaustive,
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
Layer.provideMerge(GenericToolkit.providerLayer(toolkit)),
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
interface TestLayerWithTriggersOptions extends TestLayerOptions {}
|
|
78
|
+
|
|
79
|
+
export const AssistantTestLayerWithTriggers = (options: TestLayerWithTriggersOptions) =>
|
|
80
|
+
Layer.mergeAll(
|
|
81
|
+
AssistantTestLayer(options),
|
|
82
|
+
TriggerDispatcher.layer({ timeControl: 'manual', startingTime: new Date('2025-09-05T15:01:00.000Z') }).pipe(
|
|
83
|
+
Layer.provide(Registry.layer),
|
|
84
|
+
),
|
|
85
|
+
).pipe(Layer.provideMerge(TriggerStateStore.layerMemory));
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type * as Effect from 'effect/Effect';
|
|
5
6
|
import * as Schema from 'effect/Schema';
|
|
6
7
|
|
|
7
|
-
import { type
|
|
8
|
-
import {
|
|
8
|
+
import { type Err, Obj, Ref, type Type } from '@dxos/echo';
|
|
9
|
+
import { Database } from '@dxos/echo';
|
|
10
|
+
import { EncodedReference } from '@dxos/echo-protocol';
|
|
11
|
+
import { DXN, LOCAL_SPACE_TAG, type ObjectId, type SpaceId } from '@dxos/keys';
|
|
9
12
|
import { trim } from '@dxos/util';
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -13,21 +16,33 @@ import { trim } from '@dxos/util';
|
|
|
13
16
|
*/
|
|
14
17
|
export const createArtifactElement = (id: ObjectId) => `<artifact id=${id} />`;
|
|
15
18
|
|
|
19
|
+
// TODO(burdon): Rename RefFromLLM? -- yes -dm
|
|
16
20
|
/**
|
|
17
21
|
* A model-friendly way to reference an object.
|
|
18
22
|
* Supports vairous formats that will be normalized to a DXN.
|
|
23
|
+
*
|
|
24
|
+
* @deprecated Use `Ref.Ref(XXX)` instead.
|
|
19
25
|
*/
|
|
20
|
-
// TODO(burdon): Rename ObjectReference?
|
|
21
26
|
export const ArtifactId: Schema.Schema<string> & {
|
|
22
27
|
toDXN: (reference: ArtifactId, owningSpaceId?: SpaceId) => DXN;
|
|
28
|
+
resolve: <S extends Type.AnyEntity>(
|
|
29
|
+
schema: S,
|
|
30
|
+
ref: ArtifactId,
|
|
31
|
+
) => Effect.Effect<Schema.Schema.Type<S>, Err.ObjectNotFoundError, Database.Service>;
|
|
23
32
|
} = class extends Schema.String.annotations({
|
|
33
|
+
// TODO(dmaretskyi): This section gets overriden.
|
|
24
34
|
description: trim`
|
|
25
35
|
The ID of the referenced object. Formats accepted:
|
|
26
|
-
- DXN (dxn:echo:@:
|
|
36
|
+
- DXN (dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4). DXNs can be prepended with an @ symbol for compatibility with in-text references.
|
|
27
37
|
- space ID, object ID tuple (spaceID:objectID)
|
|
28
|
-
- Only object ID that is assumed to be in the current space (
|
|
38
|
+
- Only object ID that is assumed to be in the current space (01KG7R1ZXWFMWQ4DA1Q6TN1DG4)
|
|
29
39
|
`,
|
|
30
|
-
examples: [
|
|
40
|
+
examples: [
|
|
41
|
+
'dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
42
|
+
'@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
43
|
+
'BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
44
|
+
'01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
45
|
+
],
|
|
31
46
|
}) {
|
|
32
47
|
static toDXN(reference: ArtifactId, owningSpaceId?: SpaceId): DXN {
|
|
33
48
|
// Allow @dxn: prefix for compatibility with in-text references.
|
|
@@ -47,6 +62,28 @@ export const ArtifactId: Schema.Schema<string> & {
|
|
|
47
62
|
throw new Error(`Unable to parse object reference: ${reference}`);
|
|
48
63
|
}
|
|
49
64
|
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolves an artifact ID to an object.
|
|
68
|
+
*/
|
|
69
|
+
static resolve<S extends Type.AnyEntity>(
|
|
70
|
+
schema: S,
|
|
71
|
+
ref: ArtifactId,
|
|
72
|
+
): Effect.Effect<Schema.Schema.Type<S>, Err.ObjectNotFoundError, Database.Service> {
|
|
73
|
+
const dxn = ArtifactId.toDXN(ref);
|
|
74
|
+
return Database.resolve(dxn, schema);
|
|
75
|
+
}
|
|
50
76
|
};
|
|
51
77
|
|
|
52
78
|
export type ArtifactId = Schema.Schema.Type<typeof ArtifactId>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Schema that decodes ECHO reference object from an LLM-friendly input.
|
|
82
|
+
*/
|
|
83
|
+
export const RefFromLLM = Schema.transform(ArtifactId, Ref.Ref(Obj.Unknown), {
|
|
84
|
+
decode: (fromA, fromI) => EncodedReference.fromDXN(ArtifactId.toDXN(fromA)),
|
|
85
|
+
encode: (toI, toA) => EncodedReference.toDXN(toI).toString(),
|
|
86
|
+
strict: false,
|
|
87
|
+
}).annotations({
|
|
88
|
+
description: ArtifactId.ast.annotations.description as string,
|
|
89
|
+
});
|