@dxos/assistant 0.8.0 → 0.8.1-main.303c73a
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/index.mjs +976 -536
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/browser/testing/index.mjs.map +1 -1
- package/dist/lib/node/index.cjs +1172 -735
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +22 -22
- package/dist/lib/node/testing/index.cjs.map +2 -2
- package/dist/lib/node-esm/index.mjs +976 -536
- 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 +2 -2
- package/dist/lib/node-esm/testing/index.mjs.map +1 -1
- package/dist/types/src/ai-service/edge-client.d.ts +19 -0
- package/dist/types/src/ai-service/edge-client.d.ts.map +1 -0
- package/dist/types/src/ai-service/index.d.ts +4 -1
- package/dist/types/src/ai-service/index.d.ts.map +1 -1
- package/dist/types/src/ai-service/message-collector.d.ts +88 -0
- package/dist/types/src/ai-service/message-collector.d.ts.map +1 -0
- package/dist/types/src/ai-service/ollama-client.d.ts +43 -0
- package/dist/types/src/ai-service/ollama-client.d.ts.map +1 -0
- package/dist/types/src/ai-service/parser.d.ts +3 -1
- package/dist/types/src/ai-service/parser.d.ts.map +1 -1
- package/dist/types/src/ai-service/service.d.ts +9 -0
- package/dist/types/src/ai-service/service.d.ts.map +1 -0
- package/dist/types/src/ai-service/stream.d.ts +2 -1
- package/dist/types/src/ai-service/stream.d.ts.map +1 -1
- package/dist/types/src/ai-service/testing/mock.d.ts +2 -2
- package/dist/types/src/ai-service/testing/mock.d.ts.map +1 -1
- package/dist/types/src/ai-service/types.d.ts +1 -1
- package/dist/types/src/ai-service/types.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +3 -1
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/conversation/types.d.ts +1 -1
- package/dist/types/src/conversation/types.d.ts.map +1 -1
- package/dist/types/src/testing/query-promts.d.ts +1 -1
- package/dist/types/src/testing/query-promts.d.ts.map +1 -1
- package/dist/types/src/testing/test-data.d.ts +1 -1
- package/dist/types/src/testing/test-data.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +1 -1
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/package.json +17 -14
- package/src/ai-service/client.test.ts +94 -7
- package/src/ai-service/{client.ts → edge-client.ts} +15 -24
- package/src/ai-service/index.ts +4 -1
- package/src/ai-service/message-collector.ts +84 -0
- package/src/ai-service/ollama-client.ts +473 -0
- package/src/ai-service/parser.ts +7 -2
- package/src/ai-service/service.ts +15 -0
- package/src/ai-service/stream.ts +5 -3
- package/src/ai-service/testing/mock.ts +7 -2
- package/src/ai-service/types.ts +1 -1
- package/src/bin/chat.ts +2 -2
- package/src/conversation/conversation.test.ts +3 -3
- package/src/conversation/conversation.ts +3 -2
- package/src/conversation/types.ts +1 -1
- package/src/testing/artifacts.test.ts +2 -2
- package/src/testing/query-promts.ts +1 -1
- package/src/testing/query.test.ts +2 -2
- package/src/testing/test-data.ts +1 -1
- package/src/testing/test-schema.ts +1 -1
- package/dist/types/src/ai-service/client.d.ts +0 -25
- package/dist/types/src/ai-service/client.d.ts.map +0 -1
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema as S } from '
|
|
5
|
+
import { Schema as S } from 'effect';
|
|
6
6
|
import { test, describe } from 'vitest';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { toJsonSchema, ObjectId } from '@dxos/echo-schema';
|
|
8
|
+
import { defineTool, Message, ToolResult, type Tool } from '@dxos/artifact';
|
|
9
|
+
import { toJsonSchema, ObjectId, createStatic } from '@dxos/echo-schema';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { SpaceId } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
|
|
14
|
-
import { AIServiceClientImpl } from './client';
|
|
15
14
|
import { DEFAULT_LLM_MODEL } from './defs';
|
|
15
|
+
import { AIServiceEdgeClient } from './edge-client';
|
|
16
|
+
import { OllamaClient } from './ollama-client';
|
|
17
|
+
import { MixedStreamParser } from './parser';
|
|
16
18
|
import { ToolTypes } from './types';
|
|
17
19
|
import { AI_SERVICE_ENDPOINT } from '../testing';
|
|
18
20
|
|
|
@@ -20,7 +22,7 @@ import { AI_SERVICE_ENDPOINT } from '../testing';
|
|
|
20
22
|
|
|
21
23
|
describe.skip('AI Service Client', () => {
|
|
22
24
|
test('client generation', async () => {
|
|
23
|
-
const client = new
|
|
25
|
+
const client = new AIServiceEdgeClient({
|
|
24
26
|
endpoint: AI_SERVICE_ENDPOINT.LOCAL,
|
|
25
27
|
});
|
|
26
28
|
|
|
@@ -54,7 +56,7 @@ describe.skip('AI Service Client', () => {
|
|
|
54
56
|
});
|
|
55
57
|
|
|
56
58
|
test('tool calls', async () => {
|
|
57
|
-
const client = new
|
|
59
|
+
const client = new AIServiceEdgeClient({
|
|
58
60
|
endpoint: AI_SERVICE_ENDPOINT.LOCAL,
|
|
59
61
|
});
|
|
60
62
|
|
|
@@ -137,7 +139,7 @@ describe.skip('AI Service Client', () => {
|
|
|
137
139
|
});
|
|
138
140
|
|
|
139
141
|
test.skip('image generation', async () => {
|
|
140
|
-
const client = new
|
|
142
|
+
const client = new AIServiceEdgeClient({
|
|
141
143
|
endpoint: AI_SERVICE_ENDPOINT.LOCAL,
|
|
142
144
|
});
|
|
143
145
|
|
|
@@ -176,3 +178,88 @@ describe.skip('AI Service Client', () => {
|
|
|
176
178
|
log('full message', { message: await stream.complete() });
|
|
177
179
|
});
|
|
178
180
|
});
|
|
181
|
+
|
|
182
|
+
describe('Ollama Client', () => {
|
|
183
|
+
test('basic', async (ctx) => {
|
|
184
|
+
const isRunning = await OllamaClient.isRunning();
|
|
185
|
+
if (!isRunning) {
|
|
186
|
+
ctx.skip();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const client = OllamaClient.createClient();
|
|
190
|
+
const parser = new MixedStreamParser();
|
|
191
|
+
|
|
192
|
+
const messages = await parser.parse(
|
|
193
|
+
await client.exec({
|
|
194
|
+
prompt: createStatic(Message, {
|
|
195
|
+
role: 'user',
|
|
196
|
+
content: [{ type: 'text', text: 'Hello, world!' }],
|
|
197
|
+
}),
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
log.info('messages', { messages });
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('tool calls', async (ctx) => {
|
|
205
|
+
const isRunning = await OllamaClient.isRunning();
|
|
206
|
+
if (!isRunning) {
|
|
207
|
+
ctx.skip();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const client = OllamaClient.createClient({
|
|
211
|
+
tools: [
|
|
212
|
+
defineTool('test', {
|
|
213
|
+
name: 'encrypt',
|
|
214
|
+
description: 'Encrypt a message',
|
|
215
|
+
schema: S.Struct({
|
|
216
|
+
message: S.String.annotations({ description: 'The message to encrypt' }),
|
|
217
|
+
}),
|
|
218
|
+
execute: async ({ message }) => ToolResult.Success(message.split('').reverse().join('')),
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
});
|
|
222
|
+
const parser = new MixedStreamParser();
|
|
223
|
+
parser.streamEvent.on((event) => {
|
|
224
|
+
// log.info('event', { event });
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const messages = await parser.parse(
|
|
228
|
+
await client.exec({
|
|
229
|
+
prompt: createStatic(Message, {
|
|
230
|
+
role: 'user',
|
|
231
|
+
content: [{ type: 'text', text: 'What is the encrypted message for "Hello, world!"' }],
|
|
232
|
+
}),
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
log.info('messages', { messages });
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test('text-to-image', async (ctx) => {
|
|
240
|
+
const isRunning = await OllamaClient.isRunning();
|
|
241
|
+
if (!isRunning) {
|
|
242
|
+
ctx.skip();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const client = OllamaClient.createClient();
|
|
246
|
+
const parser = new MixedStreamParser();
|
|
247
|
+
|
|
248
|
+
const messages = await parser.parse(
|
|
249
|
+
await client.exec({
|
|
250
|
+
prompt: createStatic(Message, {
|
|
251
|
+
role: 'user',
|
|
252
|
+
content: [{ type: 'text', text: 'Generate an image of a cat' }],
|
|
253
|
+
}),
|
|
254
|
+
tools: [
|
|
255
|
+
{
|
|
256
|
+
name: 'text-to-image',
|
|
257
|
+
type: ToolTypes.TextToImage,
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
log.info('messages', { messages });
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -2,39 +2,32 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema as S } from '
|
|
5
|
+
import { Schema as S } from 'effect';
|
|
6
6
|
|
|
7
7
|
import { Message } from '@dxos/artifact';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import type { AIServiceClient, GenerationStream } from './service';
|
|
12
|
+
import { createGenerationStream } from './stream';
|
|
12
13
|
import { type GenerateRequest } from './types';
|
|
13
14
|
|
|
14
|
-
export
|
|
15
|
-
exec(request: GenerateRequest): Promise<GenerationStream>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface AIServiceClient extends AIService {
|
|
19
|
-
appendMessages(messages: Message[]): Promise<void>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type AIServiceClientParams = {
|
|
15
|
+
export type AIServiceEdgeClientOptions = {
|
|
23
16
|
endpoint: string;
|
|
24
17
|
};
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
* Edge GPT client.
|
|
28
|
-
*/
|
|
29
|
-
// TODO(burdon): Create mock.
|
|
30
|
-
export class AIServiceClientImpl implements AIServiceClient {
|
|
19
|
+
export class AIServiceEdgeClient implements AIServiceClient {
|
|
31
20
|
private readonly _endpoint: string;
|
|
32
21
|
|
|
33
|
-
constructor({ endpoint }:
|
|
22
|
+
constructor({ endpoint }: AIServiceEdgeClientOptions) {
|
|
34
23
|
invariant(endpoint, 'endpoint is required');
|
|
35
24
|
this._endpoint = endpoint;
|
|
36
25
|
}
|
|
37
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated
|
|
29
|
+
*/
|
|
30
|
+
// TODO(burdon): Remove.
|
|
38
31
|
async appendMessages(messages: Message[]): Promise<void> {
|
|
39
32
|
const url = `${this._endpoint}/message`;
|
|
40
33
|
const res = await fetch(url, {
|
|
@@ -54,19 +47,17 @@ export class AIServiceClientImpl implements AIServiceClient {
|
|
|
54
47
|
* Process request and open message stream.
|
|
55
48
|
*/
|
|
56
49
|
async exec(request: GenerateRequest): Promise<GenerationStream> {
|
|
57
|
-
// TODO(dmaretskyi): Errors if tools are not provided.
|
|
58
|
-
request = {
|
|
59
|
-
tools: request.tools ?? [],
|
|
60
|
-
...request,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
50
|
log.info('requesting', { endpoint: this._endpoint });
|
|
64
51
|
const controller = new AbortController();
|
|
65
52
|
const response = await fetch(`${this._endpoint}/generate`, {
|
|
66
53
|
signal: controller.signal,
|
|
67
54
|
method: 'POST',
|
|
68
55
|
headers: { 'Content-Type': 'application/json' },
|
|
69
|
-
body: JSON.stringify(
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
// TODO(dmaretskyi): Errors if tools are not provided.
|
|
58
|
+
tools: request.tools ?? [],
|
|
59
|
+
...request,
|
|
60
|
+
}),
|
|
70
61
|
});
|
|
71
62
|
|
|
72
63
|
invariant(response.body instanceof ReadableStream);
|
package/src/ai-service/index.ts
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './client';
|
|
6
5
|
export * from './defs';
|
|
6
|
+
export * from './edge-client';
|
|
7
|
+
export * from './message-collector';
|
|
8
|
+
export * from './ollama-client';
|
|
7
9
|
export * from './parser';
|
|
10
|
+
export * from './service';
|
|
8
11
|
export * from './stream';
|
|
9
12
|
export * from './transform';
|
|
10
13
|
export * from './types';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { Message } from '@dxos/artifact';
|
|
6
|
+
|
|
7
|
+
import type { GenerationStreamEvent } from './types';
|
|
8
|
+
|
|
9
|
+
export class MessageCollector {
|
|
10
|
+
private _messages: Message[] = [];
|
|
11
|
+
private _pendingMessage?: Message = undefined;
|
|
12
|
+
|
|
13
|
+
public get messages() {
|
|
14
|
+
return this._messages;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public get pendingMessage() {
|
|
18
|
+
return this._pendingMessage;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
push(event: GenerationStreamEvent) {
|
|
22
|
+
switch (event.type) {
|
|
23
|
+
case 'message_start':
|
|
24
|
+
this._pendingMessage = event.message;
|
|
25
|
+
break;
|
|
26
|
+
|
|
27
|
+
case 'message_stop':
|
|
28
|
+
if (this._pendingMessage) {
|
|
29
|
+
this._messages.push(this._pendingMessage);
|
|
30
|
+
this._pendingMessage = undefined;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
|
|
34
|
+
case 'content_block_start':
|
|
35
|
+
if (this._pendingMessage) {
|
|
36
|
+
// Ensure the content array exists
|
|
37
|
+
this._pendingMessage.content = this._pendingMessage.content || [];
|
|
38
|
+
// Add the new content block at the specified index
|
|
39
|
+
this._pendingMessage.content[event.index] = event.content;
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
case 'content_block_delta':
|
|
44
|
+
if (this._pendingMessage && this._pendingMessage.content) {
|
|
45
|
+
const block = this._pendingMessage.content[event.index];
|
|
46
|
+
if (block && event.delta.type === 'text_delta' && block.type === 'text') {
|
|
47
|
+
block.text = (block.text || '') + event.delta.text;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case 'content_block_stop':
|
|
53
|
+
// Mark the block as no longer pending if needed
|
|
54
|
+
if (this._pendingMessage && this._pendingMessage.content) {
|
|
55
|
+
const block = this._pendingMessage.content[event.index];
|
|
56
|
+
if (block) {
|
|
57
|
+
block.pending = false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
case 'message_delta':
|
|
63
|
+
// Apply any delta updates to the message
|
|
64
|
+
if (this._pendingMessage && event.delta) {
|
|
65
|
+
Object.assign(this._pendingMessage, event.delta);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pushMessage(message: Message) {
|
|
72
|
+
this._messages.push(message);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function* emitMessageAsEvents(message: Message): Iterable<GenerationStreamEvent> {
|
|
77
|
+
yield {
|
|
78
|
+
type: 'message_start',
|
|
79
|
+
message,
|
|
80
|
+
};
|
|
81
|
+
yield {
|
|
82
|
+
type: 'message_stop',
|
|
83
|
+
};
|
|
84
|
+
}
|