@dxos/assistant 0.7.4 → 0.7.5-labs.5f04cf6

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.
Files changed (109) hide show
  1. package/dist/lib/browser/chunk-37SDA65J.mjs +565 -0
  2. package/dist/lib/browser/chunk-37SDA65J.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +936 -47
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +14 -8
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/chunk-UYNIAO5N.cjs +577 -0
  9. package/dist/lib/node/chunk-UYNIAO5N.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +936 -54
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +20 -13
  14. package/dist/lib/node/testing/index.cjs.map +4 -4
  15. package/dist/lib/node-esm/chunk-AR24K7TY.mjs +567 -0
  16. package/dist/lib/node-esm/chunk-AR24K7TY.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +936 -47
  18. package/dist/lib/node-esm/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/lib/node-esm/testing/index.mjs +14 -8
  21. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  22. package/dist/types/src/ai-service/client.d.ts +16 -32
  23. package/dist/types/src/ai-service/client.d.ts.map +1 -1
  24. package/dist/types/src/ai-service/defs.d.ts +134 -0
  25. package/dist/types/src/ai-service/defs.d.ts.map +1 -0
  26. package/dist/types/src/ai-service/index.d.ts +3 -1
  27. package/dist/types/src/ai-service/index.d.ts.map +1 -1
  28. package/dist/types/src/ai-service/parser.d.ts +40 -0
  29. package/dist/types/src/ai-service/parser.d.ts.map +1 -0
  30. package/dist/types/src/ai-service/stream.d.ts +35 -0
  31. package/dist/types/src/ai-service/stream.d.ts.map +1 -0
  32. package/dist/types/src/ai-service/stream.test.d.ts +2 -0
  33. package/dist/types/src/ai-service/stream.test.d.ts.map +1 -0
  34. package/dist/types/src/ai-service/util/index.d.ts +2 -0
  35. package/dist/types/src/ai-service/util/index.d.ts.map +1 -0
  36. package/dist/types/src/ai-service/{sse.d.ts → util/sse.d.ts} +5 -0
  37. package/dist/types/src/ai-service/util/sse.d.ts.map +1 -0
  38. package/dist/types/src/conversation/conversation.d.ts +56 -5
  39. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  40. package/dist/types/src/conversation/index.d.ts +0 -1
  41. package/dist/types/src/conversation/index.d.ts.map +1 -1
  42. package/dist/types/src/conversation/types.d.ts +44 -13
  43. package/dist/types/src/conversation/types.d.ts.map +1 -1
  44. package/dist/types/src/cypher/combinators.d.ts.map +1 -1
  45. package/dist/types/src/cypher/parjs.d.ts +1 -1
  46. package/dist/types/src/cypher/parjs.d.ts.map +1 -1
  47. package/dist/types/src/cypher/schema.d.ts.map +1 -1
  48. package/dist/types/src/testing/artifacts.test.d.ts +1 -0
  49. package/dist/types/src/testing/artifacts.test.d.ts.map +1 -0
  50. package/dist/types/src/testing/data.d.ts +2 -0
  51. package/dist/types/src/testing/data.d.ts.map +1 -0
  52. package/dist/types/src/testing/defs.d.ts +5 -0
  53. package/dist/types/src/testing/defs.d.ts.map +1 -0
  54. package/dist/types/src/testing/index.d.ts +1 -0
  55. package/dist/types/src/testing/index.d.ts.map +1 -1
  56. package/dist/types/src/testing/logger.d.ts +1 -1
  57. package/dist/types/src/testing/logger.d.ts.map +1 -1
  58. package/dist/types/src/testing/query-promts.d.ts +1 -1
  59. package/dist/types/src/testing/query-promts.d.ts.map +1 -1
  60. package/dist/types/src/testing/test-data.d.ts +1 -1
  61. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  62. package/dist/types/src/testing/test-schema.d.ts +4 -4
  63. package/package.json +20 -18
  64. package/src/ai-service/client.test.ts +28 -28
  65. package/src/ai-service/client.ts +31 -177
  66. package/src/ai-service/defs.ts +98 -0
  67. package/src/ai-service/index.ts +3 -1
  68. package/src/ai-service/parser.ts +183 -0
  69. package/src/ai-service/stream.test.ts +106 -0
  70. package/src/ai-service/stream.test.txt +33 -0
  71. package/src/ai-service/stream.ts +182 -0
  72. package/src/ai-service/util/index.ts +5 -0
  73. package/src/ai-service/{sse.ts → util/sse.ts} +5 -0
  74. package/src/bin/chat.ts +8 -10
  75. package/src/conversation/conversation.test.ts +13 -17
  76. package/src/conversation/conversation.ts +113 -18
  77. package/src/conversation/index.ts +0 -1
  78. package/src/conversation/types.ts +55 -16
  79. package/src/cypher/combinators.test.ts +4 -4
  80. package/src/cypher/combinators.ts +0 -1
  81. package/src/cypher/execution-plan.test.ts +5 -3
  82. package/src/cypher/parjs-shims.d.ts +4 -0
  83. package/src/cypher/parjs.ts +2 -2
  84. package/src/cypher/query-executor.test.ts +1 -1
  85. package/src/cypher/schema.ts +0 -1
  86. package/src/index.ts +1 -1
  87. package/src/testing/artifacts.test.ts +182 -0
  88. package/src/testing/data.ts +13 -0
  89. package/src/testing/defs.ts +8 -0
  90. package/src/testing/index.ts +1 -0
  91. package/src/testing/logger.ts +3 -2
  92. package/src/testing/query-promts.ts +3 -3
  93. package/src/testing/query.test.ts +11 -10
  94. package/src/testing/test-data.ts +1 -1
  95. package/vendor/parjs-browser.mjs +4 -0
  96. package/vendor/parjs-default.mjs +8 -0
  97. package/dist/lib/browser/chunk-AKP45LQH.mjs +0 -1394
  98. package/dist/lib/browser/chunk-AKP45LQH.mjs.map +0 -7
  99. package/dist/lib/node/chunk-G6CGWEMO.cjs +0 -1418
  100. package/dist/lib/node/chunk-G6CGWEMO.cjs.map +0 -7
  101. package/dist/lib/node-esm/chunk-WUPUPEFB.mjs +0 -1396
  102. package/dist/lib/node-esm/chunk-WUPUPEFB.mjs.map +0 -7
  103. package/dist/types/src/ai-service/schema.d.ts +0 -296
  104. package/dist/types/src/ai-service/schema.d.ts.map +0 -1
  105. package/dist/types/src/ai-service/sse.d.ts.map +0 -1
  106. package/dist/types/src/sanity.test.d.ts +0 -2
  107. package/dist/types/src/sanity.test.d.ts.map +0 -1
  108. package/src/ai-service/schema.ts +0 -260
  109. package/src/sanity.test.ts +0 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/assistant",
3
- "version": "0.7.4",
3
+ "version": "0.7.5-labs.5f04cf6",
4
4
  "description": "Natural language interface to DXOS",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -33,26 +33,25 @@
33
33
  "types": "dist/types/src/index.d.ts",
34
34
  "files": [
35
35
  "dist",
36
+ "vendor",
36
37
  "src"
37
38
  ],
38
- "scripts": {
39
- "run:chat": "tsx src/bin/chat.ts"
40
- },
41
39
  "dependencies": {
42
- "@dxos/async": "workspace:*",
43
- "@dxos/context": "workspace:*",
44
- "@dxos/debug": "workspace:*",
45
- "@dxos/echo-db": "workspace:*",
46
- "@dxos/echo-schema": "workspace:*",
47
- "@dxos/invariant": "workspace:*",
48
- "@dxos/keys": "workspace:*",
49
- "@dxos/live-object": "workspace:*",
50
- "@dxos/log": "workspace:*",
51
- "@dxos/node-std": "workspace:*",
52
- "@dxos/util": "workspace:*",
53
40
  "@effect/schema": "^0.75.5",
54
41
  "parjs": "^1.3.9",
55
- "ulidx": "^2.3.0"
42
+ "ulidx": "^2.3.0",
43
+ "@dxos/async": "0.7.5-labs.5f04cf6",
44
+ "@dxos/context": "0.7.5-labs.5f04cf6",
45
+ "@dxos/artifact": "0.7.5-labs.5f04cf6",
46
+ "@dxos/debug": "0.7.5-labs.5f04cf6",
47
+ "@dxos/echo-db": "0.7.5-labs.5f04cf6",
48
+ "@dxos/echo-schema": "0.7.5-labs.5f04cf6",
49
+ "@dxos/invariant": "0.7.5-labs.5f04cf6",
50
+ "@dxos/keys": "0.7.5-labs.5f04cf6",
51
+ "@dxos/log": "0.7.5-labs.5f04cf6",
52
+ "@dxos/live-object": "0.7.5-labs.5f04cf6",
53
+ "@dxos/node-std": "0.7.5-labs.5f04cf6",
54
+ "@dxos/util": "0.7.5-labs.5f04cf6"
56
55
  },
57
56
  "devDependencies": {
58
57
  "inquirer": "^12.0.0"
@@ -60,5 +59,8 @@
60
59
  "publishConfig": {
61
60
  "access": "restricted"
62
61
  },
63
- "beast": {}
64
- }
62
+ "beast": {},
63
+ "scripts": {
64
+ "run:chat": "tsx src/bin/chat.ts"
65
+ }
66
+ }
@@ -5,26 +5,28 @@
5
5
  import { Schema as S } from '@effect/schema';
6
6
  import { test, describe } from 'vitest';
7
7
 
8
- import { toJsonSchema } from '@dxos/echo-schema';
8
+ import { type Tool } from '@dxos/artifact';
9
+ import { toJsonSchema, ObjectId } from '@dxos/echo-schema';
9
10
  import { invariant } from '@dxos/invariant';
10
11
  import { SpaceId } from '@dxos/keys';
11
12
  import { log } from '@dxos/log';
12
13
 
13
14
  import { AIServiceClientImpl } from './client';
14
- import { ObjectId, ToolTypes, type LLMTool } from './schema';
15
+ import { ToolTypes } from './defs';
16
+ import { AI_SERVICE_ENDPOINT } from '../testing';
15
17
 
16
- const ENDPOINT = 'http://localhost:8787';
18
+ // log.config({ filter: 'debug' });
17
19
 
18
- describe('AI Service Client', () => {
20
+ describe.skip('AI Service Client', () => {
19
21
  test('client generation', async () => {
20
22
  const client = new AIServiceClientImpl({
21
- endpoint: ENDPOINT,
23
+ endpoint: AI_SERVICE_ENDPOINT.LOCAL,
22
24
  });
23
25
 
24
26
  const spaceId = SpaceId.random();
25
27
  const threadId = ObjectId.random();
26
28
 
27
- await client.insertMessages([
29
+ await client.appendMessages([
28
30
  {
29
31
  id: ObjectId.random(),
30
32
  spaceId,
@@ -42,20 +44,20 @@ describe('AI Service Client', () => {
42
44
  tools: [],
43
45
  });
44
46
  for await (const event of stream) {
45
- log.info('event', event);
47
+ log('event', event);
46
48
  }
47
49
 
48
- log.info('full message', {
50
+ log('full message', {
49
51
  message: await stream.complete(),
50
52
  });
51
53
  });
52
54
 
53
55
  test('tool calls', async () => {
54
56
  const client = new AIServiceClientImpl({
55
- endpoint: ENDPOINT,
57
+ endpoint: AI_SERVICE_ENDPOINT.LOCAL,
56
58
  });
57
59
 
58
- const custodian: LLMTool = {
60
+ const custodian: Tool = {
59
61
  name: 'custodian',
60
62
  description: 'Custodian can tell you the password if you say the magic word',
61
63
  parameters: toJsonSchema(
@@ -68,7 +70,7 @@ describe('AI Service Client', () => {
68
70
  const spaceId = SpaceId.random();
69
71
  const threadId = ObjectId.random();
70
72
 
71
- await client.insertMessages([
73
+ await client.appendMessages([
72
74
  {
73
75
  id: ObjectId.random(),
74
76
  spaceId,
@@ -86,17 +88,15 @@ describe('AI Service Client', () => {
86
88
  tools: [custodian],
87
89
  });
88
90
  for await (const event of stream) {
89
- log.info('event', event);
91
+ log('event', event);
90
92
  }
91
93
  const [message] = await stream.complete();
92
- log.info('full message', {
93
- message,
94
- });
95
- await client.insertMessages([message]);
94
+ log('full message', { message });
95
+ await client.appendMessages([message]);
96
96
 
97
97
  const toolUse = message.content.find(({ type }) => type === 'tool_use')!;
98
98
  invariant(toolUse.type === 'tool_use');
99
- await client.insertMessages([
99
+ await client.appendMessages([
100
100
  {
101
101
  id: ObjectId.random(),
102
102
  spaceId,
@@ -114,23 +114,21 @@ describe('AI Service Client', () => {
114
114
  tools: [custodian],
115
115
  });
116
116
  for await (const event of stream2) {
117
- log.info('event', event);
117
+ log('event', event);
118
118
  }
119
119
  const [message2] = await stream2.complete();
120
- log.info('full message', {
121
- message: message2,
122
- });
120
+ log('full message', { message: message2 });
123
121
  });
124
122
 
125
- test.only('image generation', async () => {
123
+ test.skip('image generation', async () => {
126
124
  const client = new AIServiceClientImpl({
127
- endpoint: ENDPOINT,
125
+ endpoint: AI_SERVICE_ENDPOINT.LOCAL,
128
126
  });
129
127
 
130
128
  const spaceId = SpaceId.random();
131
129
  const threadId = ObjectId.random();
132
130
 
133
- await client.insertMessages([
131
+ await client.appendMessages([
134
132
  {
135
133
  id: ObjectId.random(),
136
134
  spaceId,
@@ -148,15 +146,17 @@ describe('AI Service Client', () => {
148
146
  {
149
147
  name: 'text-to-image',
150
148
  type: ToolTypes.TextToImage,
149
+ // options: {
150
+ // model: '@cf/stabilityai/stable-diffusion-xl-base-1.0',
151
+ // },
151
152
  },
152
153
  ],
153
154
  });
155
+
154
156
  for await (const event of stream) {
155
- log.info('event', event);
157
+ log('event', event);
156
158
  }
157
159
 
158
- log.info('full message', {
159
- message: await stream.complete(),
160
- });
160
+ log('full message', { message: await stream.complete() });
161
161
  });
162
162
  });
@@ -2,41 +2,38 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- /* eslint-disable no-console */
6
-
7
5
  import { Schema as S } from '@effect/schema';
8
6
 
9
- import { Trigger } from '@dxos/async';
7
+ import { Message, type Space, type Thread } from '@dxos/artifact';
10
8
  import { invariant } from '@dxos/invariant';
11
- import type { SpaceId } from '@dxos/keys';
12
-
13
- import {
14
- Message,
15
- type GenerateRequest,
16
- type ObjectId,
17
- type ResultStreamEvent,
18
- type Space,
19
- type Thread,
20
- } from './schema';
21
- import { iterSSEMessages } from './sse';
22
- import { log } from '@dxos/log';
9
+ import { type SpaceId } from '@dxos/keys';
23
10
 
24
- export type AIServiceClientParams = {
25
- endpoint: string;
26
- };
11
+ import { type GenerateRequest } from './defs';
12
+ import { GenerationStream } from './stream';
27
13
 
14
+ // TODO(burdon): Rename.
28
15
  export interface AIServiceClient {
29
16
  getSpace(spaceId: SpaceId): Promise<Space>;
30
17
  getThread(spaceId: SpaceId, threadId: string): Promise<Thread>;
31
- getMessagesInThread(spaceId: SpaceId, threadId: string): Promise<Message[]>;
32
- insertMessages(messages: Message[]): Promise<void>;
18
+ getMessages(spaceId: SpaceId, threadId: string): Promise<Message[]>;
19
+ appendMessages(messages: Message[]): Promise<void>;
33
20
  updateMessage(spaceId: SpaceId, threadId: string, messageId: string, message: Message): Promise<void>;
34
21
  generate(request: GenerateRequest): Promise<GenerationStream>;
35
22
  }
36
23
 
24
+ export type AIServiceClientParams = {
25
+ endpoint: string;
26
+ };
27
+
28
+ /**
29
+ * Edge GPT client.
30
+ */
31
+ // TODO(burdon): Create mock.
37
32
  export class AIServiceClientImpl implements AIServiceClient {
38
33
  private readonly _endpoint: string;
34
+
39
35
  constructor({ endpoint }: AIServiceClientParams) {
36
+ invariant(endpoint, 'endpoint is required');
40
37
  this._endpoint = endpoint;
41
38
  }
42
39
 
@@ -48,13 +45,14 @@ export class AIServiceClientImpl implements AIServiceClient {
48
45
  throw new Error('Not implemented');
49
46
  }
50
47
 
51
- async getMessagesInThread(spaceId: SpaceId, threadId: string): Promise<Message[]> {
48
+ async getMessages(spaceId: SpaceId, threadId: string): Promise<Message[]> {
52
49
  const res = await fetch(`${this._endpoint}/space/${spaceId}/thread/${threadId}/message`);
53
50
  return S.decodePromise(S.Array(Message).pipe(S.mutable))((await res.json()).data.results);
54
51
  }
55
52
 
56
- async insertMessages(messages: Message[]): Promise<void> {
57
- const res = await fetch(`${this._endpoint}/message`, {
53
+ async appendMessages(messages: Message[]): Promise<void> {
54
+ const url = `${this._endpoint}/message`;
55
+ const res = await fetch(url, {
58
56
  method: 'POST',
59
57
  headers: { 'Content-Type': 'application/json' },
60
58
  body: JSON.stringify({
@@ -63,7 +61,7 @@ export class AIServiceClientImpl implements AIServiceClient {
63
61
  });
64
62
 
65
63
  if (!res.ok) {
66
- throw new Error(await res.text());
64
+ throw new Error(`${await res.text()} [${url}]`);
67
65
  }
68
66
  }
69
67
 
@@ -72,172 +70,28 @@ export class AIServiceClientImpl implements AIServiceClient {
72
70
  throw new Error('Not implemented');
73
71
  }
74
72
 
73
+ /**
74
+ * Open message stream.
75
+ */
75
76
  async generate(request: GenerateRequest): Promise<GenerationStream> {
77
+ const controller = new AbortController();
78
+ const signal = controller.signal;
79
+
76
80
  const response = await fetch(`${this._endpoint}/generate`, {
77
81
  method: 'POST',
78
82
  headers: { 'Content-Type': 'application/json' },
79
83
  body: JSON.stringify(request),
84
+ signal,
80
85
  });
81
- invariant(response.body instanceof ReadableStream);
82
86
 
87
+ invariant(response.body instanceof ReadableStream);
83
88
  return GenerationStream.fromSSEResponse(
84
89
  {
85
90
  spaceId: request.spaceId,
86
91
  threadId: request.threadId,
87
92
  },
88
93
  response,
94
+ controller,
89
95
  );
90
96
  }
91
97
  }
92
-
93
- type GenerationParams = {
94
- spaceId: SpaceId;
95
- threadId: ObjectId;
96
- };
97
-
98
- export class GenerationStream implements AsyncIterable<ResultStreamEvent> {
99
- static fromSSEResponse(params: GenerationParams, response: Response) {
100
- const controller = new AbortController();
101
- const iterator = async function* () {
102
- for await (const sse of iterSSEMessages(response, controller)) {
103
- if (sse.event === 'completion') {
104
- try {
105
- yield JSON.parse(sse.data);
106
- } catch (e) {
107
- console.error('Could not parse message into JSON:', sse.data);
108
- console.error('From chunk:', sse.raw);
109
- throw e;
110
- }
111
- }
112
-
113
- if (
114
- sse.event === 'message_start' ||
115
- sse.event === 'message_delta' ||
116
- sse.event === 'message_stop' ||
117
- sse.event === 'content_block_start' ||
118
- sse.event === 'content_block_delta' ||
119
- sse.event === 'content_block_stop'
120
- ) {
121
- try {
122
- yield JSON.parse(sse.data);
123
- } catch (e) {
124
- console.error('Could not parse message into JSON:', sse.data);
125
- console.error('From chunk:', sse.raw);
126
- throw e;
127
- }
128
- }
129
-
130
- if (sse.event === 'ping') {
131
- continue;
132
- }
133
-
134
- if (sse.event === 'error') {
135
- throw new Error(`Message generation error: ${sse.data}`);
136
- }
137
- }
138
- };
139
- return new GenerationStream(params, iterator);
140
- }
141
-
142
- private _previousMessages: Message[] = [];
143
- private _accumulatedMessage?: Message = undefined;
144
- private _done = new Trigger();
145
- private _iterator?: AsyncIterator<ResultStreamEvent> = undefined;
146
-
147
- constructor(
148
- private readonly _params: GenerationParams,
149
- private readonly _getIterator: () => AsyncIterableIterator<ResultStreamEvent>,
150
- ) {}
151
-
152
- [Symbol.asyncIterator](): AsyncIterator<ResultStreamEvent> {
153
- return this._createIterator();
154
- }
155
-
156
- cancel() {
157
- throw new Error('Not implemented');
158
- }
159
-
160
- get accumulatedMessages(): Message[] {
161
- // TODO(dmaretskyi): Support multiple accumulated messages.
162
- return [...this._previousMessages, ...(this._accumulatedMessage == null ? [] : [this._accumulatedMessage])];
163
- }
164
-
165
- /**
166
- * Returns the complete message list generated by the AI service.
167
- */
168
- async complete(): Promise<Message[]> {
169
- await this._done.wait();
170
- return this.accumulatedMessages;
171
- }
172
-
173
- private _createIterator(): AsyncIterator<ResultStreamEvent> {
174
- const self = this;
175
- return (this._iterator ??= (async function* () {
176
- for await (const event of self._getIterator()) {
177
- self._processEvent(event);
178
- yield event;
179
- }
180
- })());
181
- }
182
-
183
- private _processEvent(event: ResultStreamEvent) {
184
- // TODO(dmaretskyi): Support multiple message, e.g. for service-defined tools.
185
- switch (event.type) {
186
- case 'message_start': {
187
- if (this._accumulatedMessage) {
188
- this._previousMessages.push(this._accumulatedMessage);
189
- this._accumulatedMessage = undefined;
190
- }
191
- this._accumulatedMessage = {
192
- ...event.message,
193
- threadId: this._params.threadId,
194
- spaceId: this._params.spaceId,
195
- };
196
- break;
197
- }
198
- case 'message_delta': {
199
- if (this._accumulatedMessage === undefined) {
200
- throw new Error('Received message delta without a message start');
201
- }
202
- break;
203
- }
204
- case 'message_stop': {
205
- if (this._accumulatedMessage === undefined) {
206
- throw new Error('Received message stop without a message start');
207
- }
208
-
209
- break;
210
- }
211
- case 'content_block_start': {
212
- invariant(this._accumulatedMessage);
213
- this._accumulatedMessage.content.push(event.content);
214
- break;
215
- }
216
- case 'content_block_delta': {
217
- invariant(this._accumulatedMessage);
218
- const snapshotContent = this._accumulatedMessage.content.at(event.index);
219
- if (snapshotContent?.type === 'text' && event.delta.type === 'text_delta') {
220
- snapshotContent.text += event.delta.text;
221
- } else if (snapshotContent?.type === 'tool_use' && event.delta.type === 'input_json_delta') {
222
- snapshotContent.inputJson ??= '';
223
- snapshotContent.inputJson += event.delta.partial_json;
224
-
225
- // TODO(dmaretskyi): Partial parsing.
226
- // if (jsonBuf) {
227
- // snapshotContent.input = partialParse(jsonBuf);
228
- // }
229
- }
230
- break;
231
- }
232
- case 'content_block_stop': {
233
- invariant(this._accumulatedMessage);
234
- const lastBlock = this._accumulatedMessage.content.at(-1);
235
- if (lastBlock?.type === 'tool_use') {
236
- lastBlock.input = JSON.parse(lastBlock.inputJson ?? '');
237
- }
238
- break;
239
- }
240
- }
241
- this._done.wake();
242
- }
243
- }
@@ -0,0 +1,98 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Schema as S } from '@effect/schema';
6
+
7
+ import { Tool, Message, type MessageContentBlock, SpaceIdSchema } from '@dxos/artifact';
8
+ import { ObjectId } from '@dxos/echo-schema';
9
+
10
+ export const createArtifactElement = (id: ObjectId) => `<artifact id=${id} />`;
11
+
12
+ export const LLMModel = S.Literal(
13
+ '@anthropic/claude-3-5-haiku-20241022',
14
+ '@anthropic/claude-3-5-sonnet-20241022',
15
+ '@cf/deepseek-ai/deepseek-r1-distill-qwen-32b',
16
+ '@hf/nousresearch/hermes-2-pro-mistral-7b',
17
+ '@ollama/llama-3-2-3b',
18
+ '@ollama/llama-3-1-nemotron-70b-instruct',
19
+ '@ollama/llama-3-1-nemotron-mini-4b-instruct',
20
+ '@cf/deepseek-ai/deepseek-r1-distill-qwen-32b',
21
+ );
22
+ export type LLMModel = S.Schema.Type<typeof LLMModel>;
23
+
24
+ export const ToolTypes = Object.freeze({
25
+ // TODO(dmaretskyi): Not implemented yet.
26
+ // DatabaseQuery: 'database_query',
27
+ TextToImage: 'text_to_image',
28
+ });
29
+
30
+ /**
31
+ *
32
+ */
33
+ export const GenerateRequest = S.Struct({
34
+ spaceId: S.optional(SpaceIdSchema),
35
+ threadId: S.optional(ObjectId),
36
+ model: LLMModel,
37
+
38
+ /**
39
+ * History of messages to include in the context window.
40
+ */
41
+ history: S.optional(S.Array(Message)),
42
+
43
+ /**
44
+ * System instructions to the LLM.
45
+ */
46
+ // TODO(dmaretskyi): Should this be part of the thread?.
47
+ systemPrompt: S.optional(S.String),
48
+
49
+ /**
50
+ * Tools available for the LLM.
51
+ */
52
+ tools: S.optional(S.Array(Tool).pipe(S.mutable)),
53
+ });
54
+
55
+ export type GenerateRequest = S.Schema.Type<typeof GenerateRequest>;
56
+
57
+ export type LLMStopReason = 'tool_use' | 'end_turn';
58
+
59
+ // TODO(dmaretskyi): Effect schema.
60
+ // TODO(dmaretskyi): Rename GenerationStreamEvent.
61
+ export type ResultStreamEvent =
62
+ | {
63
+ // TODO(dmaretskyi): Normalize types to our schema.
64
+ type: 'message_start';
65
+ message: Omit<Message, 'spaceId' | 'threadId'>;
66
+ }
67
+ | {
68
+ type: 'message_delta';
69
+ delta: {
70
+ stopReason: LLMStopReason;
71
+ };
72
+ }
73
+ | {
74
+ type: 'message_stop';
75
+ }
76
+ | {
77
+ type: 'content_block_start';
78
+ index: number;
79
+ content: MessageContentBlock;
80
+ }
81
+ | {
82
+ type: 'content_block_delta';
83
+ index: number;
84
+ delta:
85
+ | {
86
+ type: 'text_delta';
87
+ text: string;
88
+ }
89
+ | {
90
+ partial_json: string;
91
+
92
+ type: 'input_json_delta';
93
+ };
94
+ }
95
+ | {
96
+ type: 'content_block_stop';
97
+ index: number;
98
+ };
@@ -3,4 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './client';
6
- export * from './schema';
6
+ export * from './defs';
7
+ export * from './parser';
8
+ export * from './stream';