@dxos/assistant 0.8.0 → 0.8.1-main.81238a8
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-RFTY3OMK.mjs +2276 -0
- package/dist/lib/browser/chunk-RFTY3OMK.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +33 -1236
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +17 -3
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/chunk-4ZDZUCAS.cjs +2287 -0
- package/dist/lib/node/chunk-4ZDZUCAS.cjs.map +7 -0
- package/dist/lib/node/index.cjs +40 -1236
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +40 -29
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/lib/node-esm/chunk-JUVGBQBL.mjs +2278 -0
- package/dist/lib/node-esm/chunk-JUVGBQBL.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +33 -1236
- 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 +17 -3
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/ai-service/defs.d.ts +8 -2
- package/dist/types/src/ai-service/defs.d.ts.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 +39 -0
- package/dist/types/src/ai-service/ollama-client.d.ts.map +1 -0
- package/dist/types/src/ai-service/parser.d.ts +11 -9
- 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 +91 -157
- package/dist/types/src/ai-service/types.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +11 -9
- 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/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/ollama.d.ts +6 -0
- package/dist/types/src/testing/ollama.d.ts.map +1 -0
- 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 +100 -13
- package/src/ai-service/defs.ts +17 -2
- 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 +499 -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 +3 -3
- package/src/bin/chat.ts +3 -3
- package/src/conversation/conversation.test.ts +5 -5
- package/src/conversation/conversation.ts +3 -2
- package/src/conversation/types.ts +1 -1
- package/src/testing/artifacts.test.ts +4 -4
- package/src/testing/index.ts +1 -0
- package/src/testing/object-extraction.test.ts +1 -1
- package/src/testing/ollama.ts +15 -0
- package/src/testing/query-promts.ts +1 -1
- package/src/testing/query.test.ts +4 -4
- package/src/testing/test-data.ts +1 -1
- package/src/testing/test-schema.ts +1 -1
- package/dist/lib/browser/chunk-AXUUNA7O.mjs +0 -565
- package/dist/lib/browser/chunk-AXUUNA7O.mjs.map +0 -7
- package/dist/lib/node/chunk-QPHGQINW.cjs +0 -577
- package/dist/lib/node/chunk-QPHGQINW.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-GOVFOBIB.mjs +0 -567
- package/dist/lib/node-esm/chunk-GOVFOBIB.mjs.map +0 -7
- package/dist/types/src/ai-service/client.d.ts +0 -25
- package/dist/types/src/ai-service/client.d.ts.map +0 -1
|
@@ -1,1257 +1,54 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
+
AIServiceEdgeClient,
|
|
4
|
+
DEFAULT_EDGE_MODEL,
|
|
5
|
+
DEFAULT_EDGE_MODELS,
|
|
6
|
+
DEFAULT_OLLAMA_ENDPOINT,
|
|
7
|
+
DEFAULT_OLLAMA_MODEL,
|
|
8
|
+
DEFAULT_OLLAMA_MODELS,
|
|
3
9
|
EchoDataSource,
|
|
10
|
+
GenerateRequest,
|
|
11
|
+
GenerationStreamImpl,
|
|
12
|
+
LLMModel,
|
|
13
|
+
MessageCollector,
|
|
14
|
+
MixedStreamParser,
|
|
15
|
+
OllamaClient,
|
|
16
|
+
StreamTransform,
|
|
17
|
+
ToolTypes,
|
|
18
|
+
createArtifactElement,
|
|
19
|
+
createGenerationStream,
|
|
20
|
+
emitMessageAsEvents,
|
|
4
21
|
executeQuery,
|
|
5
22
|
executeQueryPlan,
|
|
6
23
|
formatInferredRelationshipLabel,
|
|
7
24
|
formatJsonSchemaForLLM,
|
|
8
25
|
formatNodeLabel,
|
|
9
26
|
isReference,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import { invariant } from "@dxos/invariant";
|
|
17
|
-
import { log as log2 } from "@dxos/log";
|
|
18
|
-
|
|
19
|
-
// packages/experimental/assistant/src/ai-service/stream.ts
|
|
20
|
-
import { Trigger } from "@dxos/async";
|
|
21
|
-
import { log } from "@dxos/log";
|
|
22
|
-
|
|
23
|
-
// packages/experimental/assistant/src/ai-service/util/sse.ts
|
|
24
|
-
async function* iterSSEMessages(response, controller) {
|
|
25
|
-
if (!response.body) {
|
|
26
|
-
controller.abort();
|
|
27
|
-
throw new Error("Attempted to iterate over a response with no body");
|
|
28
|
-
}
|
|
29
|
-
const sseDecoder = new SSEDecoder();
|
|
30
|
-
const lineDecoder = new LineDecoder();
|
|
31
|
-
const iter = readableStreamAsyncIterable(response.body);
|
|
32
|
-
for await (const sseChunk of iterSSEChunks(iter)) {
|
|
33
|
-
for (const line of lineDecoder.decode(sseChunk)) {
|
|
34
|
-
const sse = sseDecoder.decode(line);
|
|
35
|
-
if (sse) {
|
|
36
|
-
yield sse;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
for (const line of lineDecoder.flush()) {
|
|
41
|
-
const sse = sseDecoder.decode(line);
|
|
42
|
-
if (sse) {
|
|
43
|
-
yield sse;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async function* iterSSEChunks(iterator) {
|
|
48
|
-
let data = new Uint8Array();
|
|
49
|
-
for await (const chunk of iterator) {
|
|
50
|
-
if (chunk == null) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
|
|
54
|
-
const newData = new Uint8Array(data.length + binaryChunk.length);
|
|
55
|
-
newData.set(data);
|
|
56
|
-
newData.set(binaryChunk, data.length);
|
|
57
|
-
data = newData;
|
|
58
|
-
let patternIndex;
|
|
59
|
-
while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {
|
|
60
|
-
yield data.slice(0, patternIndex);
|
|
61
|
-
data = data.slice(patternIndex);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (data.length > 0) {
|
|
65
|
-
yield data;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
var findDoubleNewlineIndex = (buffer) => {
|
|
69
|
-
const newline = 10;
|
|
70
|
-
const carriage = 13;
|
|
71
|
-
for (let i = 0; i < buffer.length - 2; i++) {
|
|
72
|
-
if (buffer[i] === newline && buffer[i + 1] === newline) {
|
|
73
|
-
return i + 2;
|
|
74
|
-
}
|
|
75
|
-
if (buffer[i] === carriage && buffer[i + 1] === carriage) {
|
|
76
|
-
return i + 2;
|
|
77
|
-
}
|
|
78
|
-
if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {
|
|
79
|
-
return i + 4;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return -1;
|
|
83
|
-
};
|
|
84
|
-
var SSEDecoder = class {
|
|
85
|
-
constructor() {
|
|
86
|
-
this.event = null;
|
|
87
|
-
this.data = [];
|
|
88
|
-
this.chunks = [];
|
|
89
|
-
}
|
|
90
|
-
decode(line) {
|
|
91
|
-
if (line.endsWith("\r")) {
|
|
92
|
-
line = line.substring(0, line.length - 1);
|
|
93
|
-
}
|
|
94
|
-
if (!line) {
|
|
95
|
-
if (!this.event && !this.data.length) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
const sse = {
|
|
99
|
-
event: this.event,
|
|
100
|
-
data: this.data.join("\n"),
|
|
101
|
-
raw: this.chunks
|
|
102
|
-
};
|
|
103
|
-
this.event = null;
|
|
104
|
-
this.data = [];
|
|
105
|
-
this.chunks = [];
|
|
106
|
-
return sse;
|
|
107
|
-
}
|
|
108
|
-
this.chunks.push(line);
|
|
109
|
-
if (line.startsWith(":")) {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
let [fieldname, _, value] = partition(line, ":");
|
|
113
|
-
if (value.startsWith(" ")) {
|
|
114
|
-
value = value.substring(1);
|
|
115
|
-
}
|
|
116
|
-
if (fieldname === "event") {
|
|
117
|
-
this.event = value;
|
|
118
|
-
} else if (fieldname === "data") {
|
|
119
|
-
this.data.push(value);
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
var partition = (str, delimiter) => {
|
|
125
|
-
const index = str.indexOf(delimiter);
|
|
126
|
-
if (index !== -1) {
|
|
127
|
-
return [
|
|
128
|
-
str.substring(0, index),
|
|
129
|
-
delimiter,
|
|
130
|
-
str.substring(index + delimiter.length)
|
|
131
|
-
];
|
|
132
|
-
}
|
|
133
|
-
return [
|
|
134
|
-
str,
|
|
135
|
-
"",
|
|
136
|
-
""
|
|
137
|
-
];
|
|
138
|
-
};
|
|
139
|
-
function readableStreamAsyncIterable(stream) {
|
|
140
|
-
if (stream[Symbol.asyncIterator]) {
|
|
141
|
-
return stream;
|
|
142
|
-
}
|
|
143
|
-
const reader = stream.getReader();
|
|
144
|
-
return {
|
|
145
|
-
next: async () => {
|
|
146
|
-
try {
|
|
147
|
-
const result = await reader.read();
|
|
148
|
-
if (result?.done) {
|
|
149
|
-
reader.releaseLock();
|
|
150
|
-
}
|
|
151
|
-
return result;
|
|
152
|
-
} catch (e) {
|
|
153
|
-
reader.releaseLock();
|
|
154
|
-
throw e;
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
return: async () => {
|
|
158
|
-
const cancelPromise = reader.cancel();
|
|
159
|
-
reader.releaseLock();
|
|
160
|
-
await cancelPromise;
|
|
161
|
-
return {
|
|
162
|
-
done: true,
|
|
163
|
-
value: void 0
|
|
164
|
-
};
|
|
165
|
-
},
|
|
166
|
-
[Symbol.asyncIterator]() {
|
|
167
|
-
return this;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
var LineDecoder = class _LineDecoder {
|
|
172
|
-
static {
|
|
173
|
-
// prettier-ignore
|
|
174
|
-
this.NEWLINE_CHARS = /* @__PURE__ */ new Set([
|
|
175
|
-
"\n",
|
|
176
|
-
"\r"
|
|
177
|
-
]);
|
|
178
|
-
}
|
|
179
|
-
static {
|
|
180
|
-
this.NEWLINE_REGEXP = /\r\n|[\n\r]/g;
|
|
181
|
-
}
|
|
182
|
-
constructor() {
|
|
183
|
-
this.buffer = [];
|
|
184
|
-
this.trailingCR = false;
|
|
185
|
-
}
|
|
186
|
-
decode(chunk) {
|
|
187
|
-
let text = this.decodeText(chunk);
|
|
188
|
-
if (this.trailingCR) {
|
|
189
|
-
text = "\r" + text;
|
|
190
|
-
this.trailingCR = false;
|
|
191
|
-
}
|
|
192
|
-
if (text.endsWith("\r")) {
|
|
193
|
-
this.trailingCR = true;
|
|
194
|
-
text = text.slice(0, -1);
|
|
195
|
-
}
|
|
196
|
-
if (!text) {
|
|
197
|
-
return [];
|
|
198
|
-
}
|
|
199
|
-
const trailingNewline = _LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || "");
|
|
200
|
-
let lines = text.split(_LineDecoder.NEWLINE_REGEXP);
|
|
201
|
-
if (trailingNewline) {
|
|
202
|
-
lines.pop();
|
|
203
|
-
}
|
|
204
|
-
if (lines.length === 1 && !trailingNewline) {
|
|
205
|
-
this.buffer.push(lines[0]);
|
|
206
|
-
return [];
|
|
207
|
-
}
|
|
208
|
-
if (this.buffer.length > 0) {
|
|
209
|
-
lines = [
|
|
210
|
-
this.buffer.join("") + lines[0],
|
|
211
|
-
...lines.slice(1)
|
|
212
|
-
];
|
|
213
|
-
this.buffer = [];
|
|
214
|
-
}
|
|
215
|
-
if (!trailingNewline) {
|
|
216
|
-
this.buffer = [
|
|
217
|
-
lines.pop() || ""
|
|
218
|
-
];
|
|
219
|
-
}
|
|
220
|
-
return lines;
|
|
221
|
-
}
|
|
222
|
-
decodeText(bytes) {
|
|
223
|
-
if (bytes == null) {
|
|
224
|
-
return "";
|
|
225
|
-
}
|
|
226
|
-
if (typeof bytes === "string") {
|
|
227
|
-
return bytes;
|
|
228
|
-
}
|
|
229
|
-
if (typeof Buffer !== "undefined") {
|
|
230
|
-
if (bytes instanceof Buffer) {
|
|
231
|
-
return bytes.toString();
|
|
232
|
-
}
|
|
233
|
-
if (bytes instanceof Uint8Array) {
|
|
234
|
-
return Buffer.from(bytes).toString();
|
|
235
|
-
}
|
|
236
|
-
throw new Error(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`);
|
|
237
|
-
}
|
|
238
|
-
if (typeof TextDecoder !== "undefined") {
|
|
239
|
-
if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {
|
|
240
|
-
this.textDecoder ??= new TextDecoder("utf8");
|
|
241
|
-
return this.textDecoder.decode(bytes);
|
|
242
|
-
}
|
|
243
|
-
throw new Error(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);
|
|
244
|
-
}
|
|
245
|
-
throw new Error("Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.");
|
|
246
|
-
}
|
|
247
|
-
flush() {
|
|
248
|
-
if (!this.buffer.length && !this.trailingCR) {
|
|
249
|
-
return [];
|
|
250
|
-
}
|
|
251
|
-
const lines = [
|
|
252
|
-
this.buffer.join("")
|
|
253
|
-
];
|
|
254
|
-
this.buffer = [];
|
|
255
|
-
this.trailingCR = false;
|
|
256
|
-
return lines;
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// packages/experimental/assistant/src/ai-service/stream.ts
|
|
261
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/stream.ts";
|
|
262
|
-
var createGenerationStream = (response, controller = new AbortController()) => {
|
|
263
|
-
const iterator = async function* () {
|
|
264
|
-
for await (const sse of iterSSEMessages(response, controller)) {
|
|
265
|
-
if (sse.event === "completion") {
|
|
266
|
-
try {
|
|
267
|
-
yield JSON.parse(sse.data);
|
|
268
|
-
} catch (err) {
|
|
269
|
-
log.error("could not parse message into JSON:", {
|
|
270
|
-
data: sse.data,
|
|
271
|
-
raw: sse.raw
|
|
272
|
-
}, {
|
|
273
|
-
F: __dxlog_file,
|
|
274
|
-
L: 21,
|
|
275
|
-
S: this,
|
|
276
|
-
C: (f, a) => f(...a)
|
|
277
|
-
});
|
|
278
|
-
throw err;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
if (sse.event === "message_start" || sse.event === "message_delta" || sse.event === "message_stop" || sse.event === "content_block_start" || sse.event === "content_block_delta" || sse.event === "content_block_stop") {
|
|
282
|
-
try {
|
|
283
|
-
yield JSON.parse(sse.data);
|
|
284
|
-
} catch (err) {
|
|
285
|
-
log.error("could not parse message into JSON:", {
|
|
286
|
-
data: sse.data,
|
|
287
|
-
raw: sse.raw
|
|
288
|
-
}, {
|
|
289
|
-
F: __dxlog_file,
|
|
290
|
-
L: 37,
|
|
291
|
-
S: this,
|
|
292
|
-
C: (f, a) => f(...a)
|
|
293
|
-
});
|
|
294
|
-
throw err;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
if (sse.event === "ping") {
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
if (sse.event === "error") {
|
|
301
|
-
throw new Error(`Message generation error: ${sse.data}`);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
return new GenerationStream(controller, iterator);
|
|
306
|
-
};
|
|
307
|
-
var GenerationStream = class {
|
|
308
|
-
constructor(_controller, _getIterator) {
|
|
309
|
-
this._controller = _controller;
|
|
310
|
-
this._getIterator = _getIterator;
|
|
311
|
-
this._done = new Trigger();
|
|
312
|
-
this._iterator = void 0;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Returns an iterator over the stream.
|
|
316
|
-
*/
|
|
317
|
-
[Symbol.asyncIterator]() {
|
|
318
|
-
return this._createIterator();
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Aborts the stream.
|
|
322
|
-
*/
|
|
323
|
-
abort() {
|
|
324
|
-
this._controller.abort();
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Returns the complete message list generated by the AI service.
|
|
328
|
-
*/
|
|
329
|
-
async complete() {
|
|
330
|
-
await this._done.wait();
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Creates an iterator over the stream.
|
|
334
|
-
*/
|
|
335
|
-
_createIterator() {
|
|
336
|
-
const self = this;
|
|
337
|
-
return this._iterator ??= (() => {
|
|
338
|
-
const generator = async function* () {
|
|
339
|
-
try {
|
|
340
|
-
for await (const event of self._getIterator()) {
|
|
341
|
-
yield event;
|
|
342
|
-
}
|
|
343
|
-
this._done.wake();
|
|
344
|
-
} catch (err) {
|
|
345
|
-
this._done.throw(err);
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
return generator.call(this);
|
|
349
|
-
})();
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
// packages/experimental/assistant/src/ai-service/client.ts
|
|
354
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/client.ts";
|
|
355
|
-
var AIServiceClientImpl = class {
|
|
356
|
-
constructor({ endpoint }) {
|
|
357
|
-
invariant(endpoint, "endpoint is required", {
|
|
358
|
-
F: __dxlog_file2,
|
|
359
|
-
L: 34,
|
|
360
|
-
S: this,
|
|
361
|
-
A: [
|
|
362
|
-
"endpoint",
|
|
363
|
-
"'endpoint is required'"
|
|
364
|
-
]
|
|
365
|
-
});
|
|
366
|
-
this._endpoint = endpoint;
|
|
367
|
-
}
|
|
368
|
-
async appendMessages(messages) {
|
|
369
|
-
const url = `${this._endpoint}/message`;
|
|
370
|
-
const res = await fetch(url, {
|
|
371
|
-
method: "POST",
|
|
372
|
-
headers: {
|
|
373
|
-
"Content-Type": "application/json"
|
|
374
|
-
},
|
|
375
|
-
body: JSON.stringify({
|
|
376
|
-
messages: await S.encodePromise(S.Array(Message))(messages)
|
|
377
|
-
})
|
|
378
|
-
});
|
|
379
|
-
if (!res.ok) {
|
|
380
|
-
throw new Error(`${await res.text()} [${url}]`);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Process request and open message stream.
|
|
385
|
-
*/
|
|
386
|
-
async exec(request) {
|
|
387
|
-
request = {
|
|
388
|
-
tools: request.tools ?? [],
|
|
389
|
-
...request
|
|
390
|
-
};
|
|
391
|
-
log2.info("requesting", {
|
|
392
|
-
endpoint: this._endpoint
|
|
393
|
-
}, {
|
|
394
|
-
F: __dxlog_file2,
|
|
395
|
-
L: 63,
|
|
396
|
-
S: this,
|
|
397
|
-
C: (f, a) => f(...a)
|
|
398
|
-
});
|
|
399
|
-
const controller = new AbortController();
|
|
400
|
-
const response = await fetch(`${this._endpoint}/generate`, {
|
|
401
|
-
signal: controller.signal,
|
|
402
|
-
method: "POST",
|
|
403
|
-
headers: {
|
|
404
|
-
"Content-Type": "application/json"
|
|
405
|
-
},
|
|
406
|
-
body: JSON.stringify(request)
|
|
407
|
-
});
|
|
408
|
-
invariant(response.body instanceof ReadableStream, void 0, {
|
|
409
|
-
F: __dxlog_file2,
|
|
410
|
-
L: 72,
|
|
411
|
-
S: this,
|
|
412
|
-
A: [
|
|
413
|
-
"response.body instanceof ReadableStream",
|
|
414
|
-
""
|
|
415
|
-
]
|
|
416
|
-
});
|
|
417
|
-
return createGenerationStream(response, controller);
|
|
418
|
-
}
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
// packages/experimental/assistant/src/ai-service/defs.ts
|
|
422
|
-
var DEFAULT_LLM_MODEL = "@anthropic/claude-3-5-sonnet-20241022";
|
|
423
|
-
var DEFAULT_LLM_MODELS = [
|
|
424
|
-
// AI Gateway.
|
|
425
|
-
// https://developers.cloudflare.com/ai-gateway
|
|
426
|
-
"@anthropic/claude-3-5-haiku-20241022",
|
|
427
|
-
"@anthropic/claude-3-5-sonnet-20241022",
|
|
428
|
-
"@anthropic/claude-3-7-sonnet-20250219",
|
|
429
|
-
// Workers AI.
|
|
430
|
-
// https://developers.cloudflare.com/workers-ai/models
|
|
431
|
-
"@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
|
|
432
|
-
"@hf/nousresearch/hermes-2-pro-mistral-7b",
|
|
433
|
-
"@ollama/llama-3-1-nemotron-70b-instruct",
|
|
434
|
-
"@ollama/llama-3-1-nemotron-mini-4b-instruct",
|
|
435
|
-
"@ollama/llama-3-2-3b"
|
|
436
|
-
];
|
|
437
|
-
|
|
438
|
-
// packages/experimental/assistant/src/ai-service/parser.ts
|
|
439
|
-
import { Message as Message2 } from "@dxos/artifact";
|
|
440
|
-
import { Event } from "@dxos/async";
|
|
441
|
-
import { createStatic } from "@dxos/echo-schema";
|
|
442
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
443
|
-
import { log as log3 } from "@dxos/log";
|
|
444
|
-
import { isNotFalsy, safeParseJson } from "@dxos/util";
|
|
445
|
-
|
|
446
|
-
// packages/experimental/assistant/src/ai-service/transform.ts
|
|
447
|
-
import * as P from "parsimmon";
|
|
448
|
-
var textChunk = P.regexp(/[^<]+/).map((content) => ({
|
|
449
|
-
type: "text",
|
|
450
|
-
content
|
|
451
|
-
}));
|
|
452
|
-
var attribute = P.seq(P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/), P.string("=").trim(P.optWhitespace), P.alt(P.regexp(/"[^"]*"/).map((s) => s.slice(1, -1)), P.regexp(/'[^']*'/).map((s) => s.slice(1, -1)))).map(([name, _, value]) => [
|
|
453
|
-
name,
|
|
454
|
-
value
|
|
455
|
-
]);
|
|
456
|
-
var tagName = P.regexp(/[a-zA-Z_][a-zA-Z0-9_-]*/);
|
|
457
|
-
var selfClosingTag = P.seqMap(
|
|
458
|
-
//
|
|
459
|
-
P.string("<"),
|
|
460
|
-
tagName,
|
|
461
|
-
P.optWhitespace.then(attribute).many(),
|
|
462
|
-
P.optWhitespace.then(P.string("/>")),
|
|
463
|
-
P.optWhitespace,
|
|
464
|
-
(_, tag, attributes, __) => ({
|
|
465
|
-
type: "tag",
|
|
466
|
-
tag,
|
|
467
|
-
attributes: Object.fromEntries(attributes),
|
|
468
|
-
content: [],
|
|
469
|
-
selfClosing: true
|
|
470
|
-
})
|
|
471
|
-
);
|
|
472
|
-
var openTag = P.seqMap(
|
|
473
|
-
//
|
|
474
|
-
P.string("<"),
|
|
475
|
-
tagName,
|
|
476
|
-
P.optWhitespace.then(attribute).many(),
|
|
477
|
-
P.string(">"),
|
|
478
|
-
P.regexp(/[^<]*/),
|
|
479
|
-
(_, tag, attributes, __, content) => ({
|
|
480
|
-
type: "tag",
|
|
481
|
-
tag,
|
|
482
|
-
attributes: Object.fromEntries(attributes),
|
|
483
|
-
content: content.length ? [
|
|
484
|
-
{
|
|
485
|
-
type: "text",
|
|
486
|
-
content
|
|
487
|
-
}
|
|
488
|
-
] : []
|
|
489
|
-
})
|
|
490
|
-
);
|
|
491
|
-
var closeTag = P.seqMap(
|
|
492
|
-
//
|
|
493
|
-
P.string("</"),
|
|
494
|
-
tagName,
|
|
495
|
-
P.string(">"),
|
|
496
|
-
P.optWhitespace,
|
|
497
|
-
(_, tag) => ({
|
|
498
|
-
type: "tag",
|
|
499
|
-
tag,
|
|
500
|
-
content: [],
|
|
501
|
-
closing: true
|
|
502
|
-
})
|
|
503
|
-
);
|
|
504
|
-
var mixedChunk = P.alt(selfClosingTag, openTag, closeTag, textChunk);
|
|
505
|
-
var StreamTransform = class {
|
|
506
|
-
constructor() {
|
|
507
|
-
this._buffer = "";
|
|
508
|
-
}
|
|
509
|
-
transform(chunk) {
|
|
510
|
-
this._buffer += chunk;
|
|
511
|
-
const results = [];
|
|
512
|
-
const parser = mixedChunk.many().skip(P.optWhitespace);
|
|
513
|
-
const result = parser.parse(this._buffer);
|
|
514
|
-
if (result.status) {
|
|
515
|
-
for (const chunk2 of result.value) {
|
|
516
|
-
results.push(chunk2);
|
|
517
|
-
}
|
|
518
|
-
this._buffer = "";
|
|
519
|
-
}
|
|
520
|
-
return results;
|
|
521
|
-
}
|
|
522
|
-
// TODO(burdon): Process remaining buffer?
|
|
523
|
-
flush() {
|
|
524
|
-
const remaining = this._buffer;
|
|
525
|
-
this._buffer = "";
|
|
526
|
-
return remaining.length > 0 ? [
|
|
527
|
-
{
|
|
528
|
-
type: "text",
|
|
529
|
-
content: remaining
|
|
530
|
-
}
|
|
531
|
-
] : [];
|
|
532
|
-
}
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
// packages/experimental/assistant/src/ai-service/parser.ts
|
|
536
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/ai-service/parser.ts";
|
|
537
|
-
var MixedStreamParser = class {
|
|
538
|
-
constructor() {
|
|
539
|
-
/**
|
|
540
|
-
* New message.
|
|
541
|
-
*/
|
|
542
|
-
this.message = new Event();
|
|
543
|
-
/**
|
|
544
|
-
* Complete block added to Message.
|
|
545
|
-
*/
|
|
546
|
-
this.block = new Event();
|
|
547
|
-
/**
|
|
548
|
-
* Update partial block (while streaming).
|
|
549
|
-
*/
|
|
550
|
-
this.update = new Event();
|
|
551
|
-
}
|
|
552
|
-
_emitBlock(contentBlock, streamBlock) {
|
|
553
|
-
const messageBlock = streamBlock ? mergeMessageBlock(contentBlock, streamBlock) : contentBlock;
|
|
554
|
-
if (messageBlock) {
|
|
555
|
-
if (messageBlock.type === "text" && messageBlock.text.length === 0) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
invariant2(this._message, void 0, {
|
|
559
|
-
F: __dxlog_file3,
|
|
560
|
-
L: 46,
|
|
561
|
-
S: this,
|
|
562
|
-
A: [
|
|
563
|
-
"this._message",
|
|
564
|
-
""
|
|
565
|
-
]
|
|
566
|
-
});
|
|
567
|
-
this._message.content.push(messageBlock);
|
|
568
|
-
this.block.emit(messageBlock);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
_emitUpdate(contentBlock, streamBlock) {
|
|
572
|
-
const messageBlock = mergeMessageBlock(contentBlock, streamBlock);
|
|
573
|
-
if (messageBlock) {
|
|
574
|
-
messageBlock.pending = true;
|
|
575
|
-
this.update.emit(messageBlock);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Parse stream until end.
|
|
580
|
-
*/
|
|
581
|
-
async parse(stream) {
|
|
582
|
-
const transformer = new StreamTransform();
|
|
583
|
-
let contentBlock;
|
|
584
|
-
let streamBlock;
|
|
585
|
-
const stack = [];
|
|
586
|
-
const messagesCollected = [];
|
|
587
|
-
for await (const event of stream) {
|
|
588
|
-
switch (event.type) {
|
|
589
|
-
//
|
|
590
|
-
// Messages.
|
|
591
|
-
//
|
|
592
|
-
case "message_start": {
|
|
593
|
-
if (this._message) {
|
|
594
|
-
log3.warn("unexpected message_start", void 0, {
|
|
595
|
-
F: __dxlog_file3,
|
|
596
|
-
L: 88,
|
|
597
|
-
S: this,
|
|
598
|
-
C: (f, a) => f(...a)
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
this._message = createStatic(Message2, {
|
|
602
|
-
role: "assistant",
|
|
603
|
-
content: []
|
|
604
|
-
});
|
|
605
|
-
this.message.emit(this._message);
|
|
606
|
-
break;
|
|
607
|
-
}
|
|
608
|
-
case "message_delta": {
|
|
609
|
-
if (!this._message) {
|
|
610
|
-
log3.warn("unexpected message_delta", void 0, {
|
|
611
|
-
F: __dxlog_file3,
|
|
612
|
-
L: 98,
|
|
613
|
-
S: this,
|
|
614
|
-
C: (f, a) => f(...a)
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
break;
|
|
618
|
-
}
|
|
619
|
-
case "message_stop": {
|
|
620
|
-
if (!this._message) {
|
|
621
|
-
log3.warn("unexpected message_stop", void 0, {
|
|
622
|
-
F: __dxlog_file3,
|
|
623
|
-
L: 106,
|
|
624
|
-
S: this,
|
|
625
|
-
C: (f, a) => f(...a)
|
|
626
|
-
});
|
|
627
|
-
} else {
|
|
628
|
-
messagesCollected.push(this._message);
|
|
629
|
-
this._message = void 0;
|
|
630
|
-
}
|
|
631
|
-
break;
|
|
632
|
-
}
|
|
633
|
-
//
|
|
634
|
-
// Content blocks.
|
|
635
|
-
//
|
|
636
|
-
case "content_block_start": {
|
|
637
|
-
if (contentBlock) {
|
|
638
|
-
log3.warn("unexpected content_block_start", {
|
|
639
|
-
content: contentBlock
|
|
640
|
-
}, {
|
|
641
|
-
F: __dxlog_file3,
|
|
642
|
-
L: 120,
|
|
643
|
-
S: this,
|
|
644
|
-
C: (f, a) => f(...a)
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
contentBlock = event.content;
|
|
648
|
-
break;
|
|
649
|
-
}
|
|
650
|
-
case "content_block_delta": {
|
|
651
|
-
if (!contentBlock) {
|
|
652
|
-
log3.warn("unexpected content_block_delta", void 0, {
|
|
653
|
-
F: __dxlog_file3,
|
|
654
|
-
L: 130,
|
|
655
|
-
S: this,
|
|
656
|
-
C: (f, a) => f(...a)
|
|
657
|
-
});
|
|
658
|
-
break;
|
|
659
|
-
}
|
|
660
|
-
switch (event.delta.type) {
|
|
661
|
-
//
|
|
662
|
-
// Text
|
|
663
|
-
//
|
|
664
|
-
case "text_delta": {
|
|
665
|
-
const chunks = transformer.transform(event.delta.text);
|
|
666
|
-
for (const chunk of chunks) {
|
|
667
|
-
switch (streamBlock?.type) {
|
|
668
|
-
//
|
|
669
|
-
// XML Fragment.
|
|
670
|
-
//
|
|
671
|
-
case "tag": {
|
|
672
|
-
if (chunk.type === "tag") {
|
|
673
|
-
if (chunk.selfClosing) {
|
|
674
|
-
streamBlock.content.push(chunk);
|
|
675
|
-
} else if (chunk.closing) {
|
|
676
|
-
if (stack.length > 0) {
|
|
677
|
-
const top = stack.pop();
|
|
678
|
-
invariant2(top && top.type === "tag", void 0, {
|
|
679
|
-
F: __dxlog_file3,
|
|
680
|
-
L: 154,
|
|
681
|
-
S: this,
|
|
682
|
-
A: [
|
|
683
|
-
"top && top.type === 'tag'",
|
|
684
|
-
""
|
|
685
|
-
]
|
|
686
|
-
});
|
|
687
|
-
top.content.push(streamBlock);
|
|
688
|
-
streamBlock = top;
|
|
689
|
-
} else {
|
|
690
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
691
|
-
streamBlock = void 0;
|
|
692
|
-
}
|
|
693
|
-
} else {
|
|
694
|
-
stack.push(streamBlock);
|
|
695
|
-
streamBlock = chunk;
|
|
696
|
-
}
|
|
697
|
-
} else {
|
|
698
|
-
if (streamBlock.content.length === 0) {
|
|
699
|
-
streamBlock.content.push(chunk);
|
|
700
|
-
} else {
|
|
701
|
-
const last = streamBlock.content.at(-1);
|
|
702
|
-
invariant2(last, void 0, {
|
|
703
|
-
F: __dxlog_file3,
|
|
704
|
-
L: 171,
|
|
705
|
-
S: this,
|
|
706
|
-
A: [
|
|
707
|
-
"last",
|
|
708
|
-
""
|
|
709
|
-
]
|
|
710
|
-
});
|
|
711
|
-
if (last.type === "text") {
|
|
712
|
-
last.content += chunk.content;
|
|
713
|
-
} else {
|
|
714
|
-
streamBlock.content.push(chunk);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
break;
|
|
719
|
-
}
|
|
720
|
-
//
|
|
721
|
-
// Text Fragment.
|
|
722
|
-
//
|
|
723
|
-
case "text": {
|
|
724
|
-
if (chunk.type === "tag") {
|
|
725
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
726
|
-
if (chunk.selfClosing) {
|
|
727
|
-
this._emitBlock(contentBlock, chunk);
|
|
728
|
-
streamBlock = void 0;
|
|
729
|
-
} else {
|
|
730
|
-
streamBlock = chunk;
|
|
731
|
-
}
|
|
732
|
-
} else {
|
|
733
|
-
streamBlock.content += chunk.content;
|
|
734
|
-
}
|
|
735
|
-
break;
|
|
736
|
-
}
|
|
737
|
-
//
|
|
738
|
-
// No current chunk.
|
|
739
|
-
//
|
|
740
|
-
default: {
|
|
741
|
-
if (chunk.type === "tag" && chunk.selfClosing) {
|
|
742
|
-
this._emitBlock(contentBlock, chunk);
|
|
743
|
-
} else {
|
|
744
|
-
streamBlock = chunk;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
break;
|
|
750
|
-
}
|
|
751
|
-
//
|
|
752
|
-
// JSON
|
|
753
|
-
//
|
|
754
|
-
case "input_json_delta": {
|
|
755
|
-
if (!contentBlock) {
|
|
756
|
-
log3.warn("unexpected input_json_delta", {
|
|
757
|
-
contentBlock
|
|
758
|
-
}, {
|
|
759
|
-
F: __dxlog_file3,
|
|
760
|
-
L: 221,
|
|
761
|
-
S: this,
|
|
762
|
-
C: (f, a) => f(...a)
|
|
763
|
-
});
|
|
764
|
-
break;
|
|
765
|
-
}
|
|
766
|
-
if (streamBlock?.type === "json") {
|
|
767
|
-
streamBlock.content += event.delta.partial_json;
|
|
768
|
-
} else {
|
|
769
|
-
streamBlock = {
|
|
770
|
-
type: "json",
|
|
771
|
-
content: event.delta.partial_json
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
break;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
break;
|
|
778
|
-
}
|
|
779
|
-
case "content_block_stop": {
|
|
780
|
-
if (!contentBlock) {
|
|
781
|
-
log3.warn("unexpected content_block_stop", void 0, {
|
|
782
|
-
F: __dxlog_file3,
|
|
783
|
-
L: 238,
|
|
784
|
-
S: this,
|
|
785
|
-
C: (f, a) => f(...a)
|
|
786
|
-
});
|
|
787
|
-
break;
|
|
788
|
-
}
|
|
789
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
790
|
-
contentBlock = void 0;
|
|
791
|
-
streamBlock = void 0;
|
|
792
|
-
break;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
if (contentBlock && streamBlock) {
|
|
796
|
-
this._emitUpdate(contentBlock, streamBlock);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
return messagesCollected;
|
|
800
|
-
}
|
|
801
|
-
};
|
|
802
|
-
var mergeMessageBlock = (contentBlock, streamBlock) => {
|
|
803
|
-
log3("mergeMessageBlock", {
|
|
804
|
-
contentBlock,
|
|
805
|
-
streamBlock
|
|
806
|
-
}, {
|
|
807
|
-
F: __dxlog_file3,
|
|
808
|
-
L: 265,
|
|
809
|
-
S: void 0,
|
|
810
|
-
C: (f, a) => f(...a)
|
|
811
|
-
});
|
|
812
|
-
switch (streamBlock.type) {
|
|
813
|
-
//
|
|
814
|
-
// Text
|
|
815
|
-
//
|
|
816
|
-
case "text": {
|
|
817
|
-
return {
|
|
818
|
-
...contentBlock,
|
|
819
|
-
type: "text",
|
|
820
|
-
text: streamBlock.content
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
//
|
|
824
|
-
// XML
|
|
825
|
-
//
|
|
826
|
-
case "tag": {
|
|
827
|
-
switch (streamBlock.tag) {
|
|
828
|
-
case "cot": {
|
|
829
|
-
const content = streamBlock.content.map((block) => {
|
|
830
|
-
switch (block.type) {
|
|
831
|
-
case "text":
|
|
832
|
-
return block.content;
|
|
833
|
-
default:
|
|
834
|
-
return null;
|
|
835
|
-
}
|
|
836
|
-
}).filter(isNotFalsy).join("\n");
|
|
837
|
-
return {
|
|
838
|
-
...contentBlock,
|
|
839
|
-
type: "text",
|
|
840
|
-
disposition: "cot",
|
|
841
|
-
text: content
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
case "artifact": {
|
|
845
|
-
const { attributes } = streamBlock;
|
|
846
|
-
return {
|
|
847
|
-
type: "json",
|
|
848
|
-
disposition: "artifact",
|
|
849
|
-
json: JSON.stringify(attributes)
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
case "suggest": {
|
|
853
|
-
if (streamBlock.content.length === 1 && streamBlock.content[0].type === "text") {
|
|
854
|
-
return {
|
|
855
|
-
type: "json",
|
|
856
|
-
disposition: "suggest",
|
|
857
|
-
json: JSON.stringify({
|
|
858
|
-
text: streamBlock.content[0].content
|
|
859
|
-
})
|
|
860
|
-
};
|
|
861
|
-
}
|
|
862
|
-
break;
|
|
863
|
-
}
|
|
864
|
-
case "select": {
|
|
865
|
-
return {
|
|
866
|
-
type: "json",
|
|
867
|
-
disposition: "select",
|
|
868
|
-
json: JSON.stringify({
|
|
869
|
-
options: streamBlock.content.flatMap((content) => content.type === "tag" && content.content.length === 1 && content.content[0].type === "text" ? [
|
|
870
|
-
content.content[0].content
|
|
871
|
-
] : [])
|
|
872
|
-
})
|
|
873
|
-
};
|
|
874
|
-
}
|
|
875
|
-
case "tool-list": {
|
|
876
|
-
return {
|
|
877
|
-
type: "json",
|
|
878
|
-
disposition: "tool_list",
|
|
879
|
-
json: JSON.stringify({})
|
|
880
|
-
};
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
break;
|
|
884
|
-
}
|
|
885
|
-
//
|
|
886
|
-
// JSON
|
|
887
|
-
//
|
|
888
|
-
case "json": {
|
|
889
|
-
switch (contentBlock.type) {
|
|
890
|
-
case "tool_use": {
|
|
891
|
-
return {
|
|
892
|
-
...contentBlock,
|
|
893
|
-
input: safeParseJson(streamBlock.content) ?? {}
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
return {
|
|
898
|
-
...contentBlock,
|
|
899
|
-
type: "json",
|
|
900
|
-
disposition: "artifact",
|
|
901
|
-
json: streamBlock.content
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
};
|
|
906
|
-
|
|
907
|
-
// packages/experimental/assistant/src/ai-service/types.ts
|
|
908
|
-
import { Schema as S2 } from "@effect/schema";
|
|
909
|
-
import { Tool, Message as Message3, SpaceIdSchema } from "@dxos/artifact";
|
|
910
|
-
import { ObjectId } from "@dxos/echo-schema";
|
|
911
|
-
var createArtifactElement = (id) => `<artifact id=${id} />`;
|
|
912
|
-
var LLMModel = S2.Literal(...DEFAULT_LLM_MODELS);
|
|
913
|
-
var ToolTypes = Object.freeze({
|
|
914
|
-
// TODO(dmaretskyi): Not implemented yet.
|
|
915
|
-
// DatabaseQuery: 'database_query',
|
|
916
|
-
TextToImage: "text_to_image"
|
|
917
|
-
});
|
|
918
|
-
var GenerateRequest = S2.Struct({
|
|
919
|
-
spaceId: S2.optional(SpaceIdSchema),
|
|
920
|
-
threadId: S2.optional(ObjectId),
|
|
921
|
-
/**
|
|
922
|
-
* Preferred model or system default.
|
|
923
|
-
*/
|
|
924
|
-
model: S2.optional(LLMModel),
|
|
925
|
-
/**
|
|
926
|
-
* Tools available for the LLM.
|
|
927
|
-
*/
|
|
928
|
-
tools: S2.optional(S2.Array(Tool).pipe(S2.mutable)),
|
|
929
|
-
/**
|
|
930
|
-
* System instructions to the LLM.
|
|
931
|
-
*/
|
|
932
|
-
systemPrompt: S2.optional(S2.String),
|
|
933
|
-
/**
|
|
934
|
-
* History of messages to include in the context window.
|
|
935
|
-
*/
|
|
936
|
-
// TODO(burdon): Rename messages.
|
|
937
|
-
history: S2.optional(S2.Array(Message3)),
|
|
938
|
-
/**
|
|
939
|
-
* Current request.
|
|
940
|
-
*/
|
|
941
|
-
prompt: S2.optional(Message3)
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
// packages/experimental/assistant/src/conversation/conversation.ts
|
|
945
|
-
import { ToolResult, Message as Message4 } from "@dxos/artifact";
|
|
946
|
-
import { createStatic as createStatic2, ObjectId as ObjectId2 } from "@dxos/echo-schema";
|
|
947
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
948
|
-
import { log as log4 } from "@dxos/log";
|
|
949
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/experimental/assistant/src/conversation/conversation.ts";
|
|
950
|
-
var runLLM = async (params) => {
|
|
951
|
-
let conversationResult = null;
|
|
952
|
-
const history = params.history ?? [];
|
|
953
|
-
const generate = async () => {
|
|
954
|
-
log4("llm generate", {
|
|
955
|
-
tools: params.tools
|
|
956
|
-
}, {
|
|
957
|
-
F: __dxlog_file4,
|
|
958
|
-
L: 44,
|
|
959
|
-
S: void 0,
|
|
960
|
-
C: (f, a) => f(...a)
|
|
961
|
-
});
|
|
962
|
-
const beginTs = Date.now();
|
|
963
|
-
const stream = await params.client.exec({
|
|
964
|
-
model: params.model,
|
|
965
|
-
spaceId: params.spaceId,
|
|
966
|
-
threadId: params.threadId,
|
|
967
|
-
history,
|
|
968
|
-
systemPrompt: params.system,
|
|
969
|
-
tools: params.tools
|
|
970
|
-
});
|
|
971
|
-
for await (const event of stream) {
|
|
972
|
-
params.logger?.(event);
|
|
973
|
-
}
|
|
974
|
-
await stream.complete();
|
|
975
|
-
const messages = [];
|
|
976
|
-
const message = messages.at(-1);
|
|
977
|
-
invariant3(message, void 0, {
|
|
978
|
-
F: __dxlog_file4,
|
|
979
|
-
L: 63,
|
|
980
|
-
S: void 0,
|
|
981
|
-
A: [
|
|
982
|
-
"message",
|
|
983
|
-
""
|
|
984
|
-
]
|
|
985
|
-
});
|
|
986
|
-
log4("llm result", {
|
|
987
|
-
time: Date.now() - beginTs,
|
|
988
|
-
message
|
|
989
|
-
}, {
|
|
990
|
-
F: __dxlog_file4,
|
|
991
|
-
L: 65,
|
|
992
|
-
S: void 0,
|
|
993
|
-
C: (f, a) => f(...a)
|
|
994
|
-
});
|
|
995
|
-
invariant3(message, void 0, {
|
|
996
|
-
F: __dxlog_file4,
|
|
997
|
-
L: 66,
|
|
998
|
-
S: void 0,
|
|
999
|
-
A: [
|
|
1000
|
-
"message",
|
|
1001
|
-
""
|
|
1002
|
-
]
|
|
1003
|
-
});
|
|
1004
|
-
params.logger?.({
|
|
1005
|
-
type: "message",
|
|
1006
|
-
message
|
|
1007
|
-
});
|
|
1008
|
-
history.push(...messages.map((message2) => ({
|
|
1009
|
-
...message2,
|
|
1010
|
-
content: message2.content.filter((block) => block.type !== "image")
|
|
1011
|
-
})));
|
|
1012
|
-
const isToolUse2 = message.content.at(-1)?.type === "tool_use";
|
|
1013
|
-
if (isToolUse2) {
|
|
1014
|
-
const toolCalls = message.content.filter((block) => block.type === "tool_use");
|
|
1015
|
-
invariant3(toolCalls.length === 1, void 0, {
|
|
1016
|
-
F: __dxlog_file4,
|
|
1017
|
-
L: 77,
|
|
1018
|
-
S: void 0,
|
|
1019
|
-
A: [
|
|
1020
|
-
"toolCalls.length === 1",
|
|
1021
|
-
""
|
|
1022
|
-
]
|
|
1023
|
-
});
|
|
1024
|
-
const toolCall = toolCalls[0];
|
|
1025
|
-
const tool = params.tools.find((tool2) => tool2.name === toolCall.name);
|
|
1026
|
-
if (!tool) {
|
|
1027
|
-
throw new Error(`Tool not found: ${toolCall.name}`);
|
|
1028
|
-
}
|
|
1029
|
-
invariant3(tool.execute, void 0, {
|
|
1030
|
-
F: __dxlog_file4,
|
|
1031
|
-
L: 84,
|
|
1032
|
-
S: void 0,
|
|
1033
|
-
A: [
|
|
1034
|
-
"tool.execute",
|
|
1035
|
-
""
|
|
1036
|
-
]
|
|
1037
|
-
});
|
|
1038
|
-
const toolResult = await tool.execute(toolCall.input);
|
|
1039
|
-
switch (toolResult.kind) {
|
|
1040
|
-
case "error": {
|
|
1041
|
-
log4.warn("tool error", {
|
|
1042
|
-
message: toolResult.message
|
|
1043
|
-
}, {
|
|
1044
|
-
F: __dxlog_file4,
|
|
1045
|
-
L: 88,
|
|
1046
|
-
S: void 0,
|
|
1047
|
-
C: (f, a) => f(...a)
|
|
1048
|
-
});
|
|
1049
|
-
const resultMessage = {
|
|
1050
|
-
id: ObjectId2.random(),
|
|
1051
|
-
spaceId: params.spaceId,
|
|
1052
|
-
threadId: params.threadId,
|
|
1053
|
-
role: "user",
|
|
1054
|
-
content: [
|
|
1055
|
-
{
|
|
1056
|
-
type: "tool_result",
|
|
1057
|
-
toolUseId: toolCall.id,
|
|
1058
|
-
content: toolResult.message,
|
|
1059
|
-
isError: true
|
|
1060
|
-
}
|
|
1061
|
-
]
|
|
1062
|
-
};
|
|
1063
|
-
params.logger?.({
|
|
1064
|
-
type: "message",
|
|
1065
|
-
message: resultMessage
|
|
1066
|
-
});
|
|
1067
|
-
history.push(resultMessage);
|
|
1068
|
-
return true;
|
|
1069
|
-
}
|
|
1070
|
-
case "success": {
|
|
1071
|
-
log4("tool success", {
|
|
1072
|
-
result: toolResult.result
|
|
1073
|
-
}, {
|
|
1074
|
-
F: __dxlog_file4,
|
|
1075
|
-
L: 110,
|
|
1076
|
-
S: void 0,
|
|
1077
|
-
C: (f, a) => f(...a)
|
|
1078
|
-
});
|
|
1079
|
-
const resultMessage = {
|
|
1080
|
-
id: ObjectId2.random(),
|
|
1081
|
-
spaceId: params.spaceId,
|
|
1082
|
-
threadId: params.threadId,
|
|
1083
|
-
role: "user",
|
|
1084
|
-
content: [
|
|
1085
|
-
{
|
|
1086
|
-
type: "tool_result",
|
|
1087
|
-
toolUseId: toolCall.id,
|
|
1088
|
-
content: JSON.stringify(toolResult.result)
|
|
1089
|
-
}
|
|
1090
|
-
]
|
|
1091
|
-
};
|
|
1092
|
-
params.logger?.({
|
|
1093
|
-
type: "message",
|
|
1094
|
-
message: resultMessage
|
|
1095
|
-
});
|
|
1096
|
-
history.push(resultMessage);
|
|
1097
|
-
return true;
|
|
1098
|
-
}
|
|
1099
|
-
case "break": {
|
|
1100
|
-
log4("tool break", {
|
|
1101
|
-
result: toolResult.result
|
|
1102
|
-
}, {
|
|
1103
|
-
F: __dxlog_file4,
|
|
1104
|
-
L: 131,
|
|
1105
|
-
S: void 0,
|
|
1106
|
-
C: (f, a) => f(...a)
|
|
1107
|
-
});
|
|
1108
|
-
conversationResult = toolResult.result;
|
|
1109
|
-
return false;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
return false;
|
|
1114
|
-
};
|
|
1115
|
-
while (await generate()) {
|
|
1116
|
-
}
|
|
1117
|
-
return {
|
|
1118
|
-
result: conversationResult,
|
|
1119
|
-
history
|
|
1120
|
-
};
|
|
1121
|
-
};
|
|
1122
|
-
var isToolUse = (message) => {
|
|
1123
|
-
const block = message.content.at(-1);
|
|
1124
|
-
invariant3(block, void 0, {
|
|
1125
|
-
F: __dxlog_file4,
|
|
1126
|
-
L: 152,
|
|
1127
|
-
S: void 0,
|
|
1128
|
-
A: [
|
|
1129
|
-
"block",
|
|
1130
|
-
""
|
|
1131
|
-
]
|
|
1132
|
-
});
|
|
1133
|
-
return block.type === "tool_use";
|
|
1134
|
-
};
|
|
1135
|
-
var runTools = async ({ message, tools, extensions }) => {
|
|
1136
|
-
const toolCalls = message.content.filter((block) => block.type === "tool_use");
|
|
1137
|
-
invariant3(toolCalls.length === 1, void 0, {
|
|
1138
|
-
F: __dxlog_file4,
|
|
1139
|
-
L: 174,
|
|
1140
|
-
S: void 0,
|
|
1141
|
-
A: [
|
|
1142
|
-
"toolCalls.length === 1",
|
|
1143
|
-
""
|
|
1144
|
-
]
|
|
1145
|
-
});
|
|
1146
|
-
const toolCall = toolCalls[0];
|
|
1147
|
-
const tool = tools.find((tool2) => tool2.name === toolCall.name);
|
|
1148
|
-
if (!tool) {
|
|
1149
|
-
throw new Error(`Tool not found: ${toolCall.name}`);
|
|
1150
|
-
}
|
|
1151
|
-
let toolResult;
|
|
1152
|
-
try {
|
|
1153
|
-
invariant3(tool.execute, void 0, {
|
|
1154
|
-
F: __dxlog_file4,
|
|
1155
|
-
L: 183,
|
|
1156
|
-
S: void 0,
|
|
1157
|
-
A: [
|
|
1158
|
-
"tool.execute",
|
|
1159
|
-
""
|
|
1160
|
-
]
|
|
1161
|
-
});
|
|
1162
|
-
toolResult = await tool.execute(toolCall.input, {
|
|
1163
|
-
extensions
|
|
1164
|
-
});
|
|
1165
|
-
} catch (error) {
|
|
1166
|
-
log4("tool error", {
|
|
1167
|
-
error
|
|
1168
|
-
}, {
|
|
1169
|
-
F: __dxlog_file4,
|
|
1170
|
-
L: 186,
|
|
1171
|
-
S: void 0,
|
|
1172
|
-
C: (f, a) => f(...a)
|
|
1173
|
-
});
|
|
1174
|
-
toolResult = ToolResult.Error(error.message);
|
|
1175
|
-
}
|
|
1176
|
-
switch (toolResult.kind) {
|
|
1177
|
-
case "error": {
|
|
1178
|
-
log4("tool error", {
|
|
1179
|
-
message: toolResult.message
|
|
1180
|
-
}, {
|
|
1181
|
-
F: __dxlog_file4,
|
|
1182
|
-
L: 192,
|
|
1183
|
-
S: void 0,
|
|
1184
|
-
C: (f, a) => f(...a)
|
|
1185
|
-
});
|
|
1186
|
-
const resultMessage = createStatic2(Message4, {
|
|
1187
|
-
role: "user",
|
|
1188
|
-
content: [
|
|
1189
|
-
{
|
|
1190
|
-
type: "tool_result",
|
|
1191
|
-
toolUseId: toolCall.id,
|
|
1192
|
-
content: toolResult.message,
|
|
1193
|
-
isError: true
|
|
1194
|
-
}
|
|
1195
|
-
]
|
|
1196
|
-
});
|
|
1197
|
-
return {
|
|
1198
|
-
type: "continue",
|
|
1199
|
-
message: resultMessage
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
case "success": {
|
|
1203
|
-
log4("tool success", {
|
|
1204
|
-
result: toolResult.result
|
|
1205
|
-
}, {
|
|
1206
|
-
F: __dxlog_file4,
|
|
1207
|
-
L: 213,
|
|
1208
|
-
S: void 0,
|
|
1209
|
-
C: (f, a) => f(...a)
|
|
1210
|
-
});
|
|
1211
|
-
const resultMessage = createStatic2(Message4, {
|
|
1212
|
-
role: "user",
|
|
1213
|
-
content: [
|
|
1214
|
-
{
|
|
1215
|
-
type: "tool_result",
|
|
1216
|
-
toolUseId: toolCall.id,
|
|
1217
|
-
content: typeof toolResult.result === "string" ? toolResult.result : JSON.stringify(toolResult.result) ?? ""
|
|
1218
|
-
}
|
|
1219
|
-
]
|
|
1220
|
-
});
|
|
1221
|
-
return {
|
|
1222
|
-
type: "continue",
|
|
1223
|
-
message: resultMessage
|
|
1224
|
-
};
|
|
1225
|
-
}
|
|
1226
|
-
case "break": {
|
|
1227
|
-
log4("tool break", {
|
|
1228
|
-
result: toolResult.result
|
|
1229
|
-
}, {
|
|
1230
|
-
F: __dxlog_file4,
|
|
1231
|
-
L: 233,
|
|
1232
|
-
S: void 0,
|
|
1233
|
-
C: (f, a) => f(...a)
|
|
1234
|
-
});
|
|
1235
|
-
return {
|
|
1236
|
-
type: "break",
|
|
1237
|
-
result: toolResult.result
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
};
|
|
27
|
+
isToolUse,
|
|
28
|
+
mergeMessageBlock,
|
|
29
|
+
parseCypherQuery,
|
|
30
|
+
runLLM,
|
|
31
|
+
runTools
|
|
32
|
+
} from "./chunk-JUVGBQBL.mjs";
|
|
1242
33
|
export {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
34
|
+
AIServiceEdgeClient,
|
|
35
|
+
DEFAULT_EDGE_MODEL,
|
|
36
|
+
DEFAULT_EDGE_MODELS,
|
|
37
|
+
DEFAULT_OLLAMA_ENDPOINT,
|
|
38
|
+
DEFAULT_OLLAMA_MODEL,
|
|
39
|
+
DEFAULT_OLLAMA_MODELS,
|
|
1246
40
|
EchoDataSource,
|
|
1247
41
|
GenerateRequest,
|
|
1248
|
-
|
|
42
|
+
GenerationStreamImpl,
|
|
1249
43
|
LLMModel,
|
|
44
|
+
MessageCollector,
|
|
1250
45
|
MixedStreamParser,
|
|
46
|
+
OllamaClient,
|
|
1251
47
|
StreamTransform,
|
|
1252
48
|
ToolTypes,
|
|
1253
49
|
createArtifactElement,
|
|
1254
50
|
createGenerationStream,
|
|
51
|
+
emitMessageAsEvents,
|
|
1255
52
|
executeQuery,
|
|
1256
53
|
executeQueryPlan,
|
|
1257
54
|
formatInferredRelationshipLabel,
|