@reactive-agents/llm-provider 0.1.1 → 0.3.0
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/index.d.ts +30 -2
- package/dist/index.js +1333 -182
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -1,9 +1,1124 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
1
3
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
4
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
5
|
}) : x)(function(x) {
|
|
4
6
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
7
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
8
|
});
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// ../../node_modules/whatwg-fetch/fetch.js
|
|
18
|
+
function isDataView(obj) {
|
|
19
|
+
return obj && DataView.prototype.isPrototypeOf(obj);
|
|
20
|
+
}
|
|
21
|
+
function normalizeName(name) {
|
|
22
|
+
if (typeof name !== "string") {
|
|
23
|
+
name = String(name);
|
|
24
|
+
}
|
|
25
|
+
if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === "") {
|
|
26
|
+
throw new TypeError('Invalid character in header field name: "' + name + '"');
|
|
27
|
+
}
|
|
28
|
+
return name.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
function normalizeValue(value) {
|
|
31
|
+
if (typeof value !== "string") {
|
|
32
|
+
value = String(value);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function iteratorFor(items) {
|
|
37
|
+
var iterator = {
|
|
38
|
+
next: function() {
|
|
39
|
+
var value = items.shift();
|
|
40
|
+
return { done: value === void 0, value };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
if (support.iterable) {
|
|
44
|
+
iterator[Symbol.iterator] = function() {
|
|
45
|
+
return iterator;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return iterator;
|
|
49
|
+
}
|
|
50
|
+
function Headers2(headers) {
|
|
51
|
+
this.map = {};
|
|
52
|
+
if (headers instanceof Headers2) {
|
|
53
|
+
headers.forEach(function(value, name) {
|
|
54
|
+
this.append(name, value);
|
|
55
|
+
}, this);
|
|
56
|
+
} else if (Array.isArray(headers)) {
|
|
57
|
+
headers.forEach(function(header) {
|
|
58
|
+
if (header.length != 2) {
|
|
59
|
+
throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length);
|
|
60
|
+
}
|
|
61
|
+
this.append(header[0], header[1]);
|
|
62
|
+
}, this);
|
|
63
|
+
} else if (headers) {
|
|
64
|
+
Object.getOwnPropertyNames(headers).forEach(function(name) {
|
|
65
|
+
this.append(name, headers[name]);
|
|
66
|
+
}, this);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function consumed(body) {
|
|
70
|
+
if (body._noBody) return;
|
|
71
|
+
if (body.bodyUsed) {
|
|
72
|
+
return Promise.reject(new TypeError("Already read"));
|
|
73
|
+
}
|
|
74
|
+
body.bodyUsed = true;
|
|
75
|
+
}
|
|
76
|
+
function fileReaderReady(reader) {
|
|
77
|
+
return new Promise(function(resolve2, reject) {
|
|
78
|
+
reader.onload = function() {
|
|
79
|
+
resolve2(reader.result);
|
|
80
|
+
};
|
|
81
|
+
reader.onerror = function() {
|
|
82
|
+
reject(reader.error);
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function readBlobAsArrayBuffer(blob) {
|
|
87
|
+
var reader = new FileReader();
|
|
88
|
+
var promise = fileReaderReady(reader);
|
|
89
|
+
reader.readAsArrayBuffer(blob);
|
|
90
|
+
return promise;
|
|
91
|
+
}
|
|
92
|
+
function readBlobAsText(blob) {
|
|
93
|
+
var reader = new FileReader();
|
|
94
|
+
var promise = fileReaderReady(reader);
|
|
95
|
+
var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type);
|
|
96
|
+
var encoding = match ? match[1] : "utf-8";
|
|
97
|
+
reader.readAsText(blob, encoding);
|
|
98
|
+
return promise;
|
|
99
|
+
}
|
|
100
|
+
function readArrayBufferAsText(buf) {
|
|
101
|
+
var view = new Uint8Array(buf);
|
|
102
|
+
var chars = new Array(view.length);
|
|
103
|
+
for (var i = 0; i < view.length; i++) {
|
|
104
|
+
chars[i] = String.fromCharCode(view[i]);
|
|
105
|
+
}
|
|
106
|
+
return chars.join("");
|
|
107
|
+
}
|
|
108
|
+
function bufferClone(buf) {
|
|
109
|
+
if (buf.slice) {
|
|
110
|
+
return buf.slice(0);
|
|
111
|
+
} else {
|
|
112
|
+
var view = new Uint8Array(buf.byteLength);
|
|
113
|
+
view.set(new Uint8Array(buf));
|
|
114
|
+
return view.buffer;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function Body() {
|
|
118
|
+
this.bodyUsed = false;
|
|
119
|
+
this._initBody = function(body) {
|
|
120
|
+
this.bodyUsed = this.bodyUsed;
|
|
121
|
+
this._bodyInit = body;
|
|
122
|
+
if (!body) {
|
|
123
|
+
this._noBody = true;
|
|
124
|
+
this._bodyText = "";
|
|
125
|
+
} else if (typeof body === "string") {
|
|
126
|
+
this._bodyText = body;
|
|
127
|
+
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
|
|
128
|
+
this._bodyBlob = body;
|
|
129
|
+
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
|
|
130
|
+
this._bodyFormData = body;
|
|
131
|
+
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
132
|
+
this._bodyText = body.toString();
|
|
133
|
+
} else if (support.arrayBuffer && support.blob && isDataView(body)) {
|
|
134
|
+
this._bodyArrayBuffer = bufferClone(body.buffer);
|
|
135
|
+
this._bodyInit = new Blob([this._bodyArrayBuffer]);
|
|
136
|
+
} else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
|
|
137
|
+
this._bodyArrayBuffer = bufferClone(body);
|
|
138
|
+
} else {
|
|
139
|
+
this._bodyText = body = Object.prototype.toString.call(body);
|
|
140
|
+
}
|
|
141
|
+
if (!this.headers.get("content-type")) {
|
|
142
|
+
if (typeof body === "string") {
|
|
143
|
+
this.headers.set("content-type", "text/plain;charset=UTF-8");
|
|
144
|
+
} else if (this._bodyBlob && this._bodyBlob.type) {
|
|
145
|
+
this.headers.set("content-type", this._bodyBlob.type);
|
|
146
|
+
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
147
|
+
this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
if (support.blob) {
|
|
152
|
+
this.blob = function() {
|
|
153
|
+
var rejected = consumed(this);
|
|
154
|
+
if (rejected) {
|
|
155
|
+
return rejected;
|
|
156
|
+
}
|
|
157
|
+
if (this._bodyBlob) {
|
|
158
|
+
return Promise.resolve(this._bodyBlob);
|
|
159
|
+
} else if (this._bodyArrayBuffer) {
|
|
160
|
+
return Promise.resolve(new Blob([this._bodyArrayBuffer]));
|
|
161
|
+
} else if (this._bodyFormData) {
|
|
162
|
+
throw new Error("could not read FormData body as blob");
|
|
163
|
+
} else {
|
|
164
|
+
return Promise.resolve(new Blob([this._bodyText]));
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
this.arrayBuffer = function() {
|
|
169
|
+
if (this._bodyArrayBuffer) {
|
|
170
|
+
var isConsumed = consumed(this);
|
|
171
|
+
if (isConsumed) {
|
|
172
|
+
return isConsumed;
|
|
173
|
+
} else if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
|
|
174
|
+
return Promise.resolve(
|
|
175
|
+
this._bodyArrayBuffer.buffer.slice(
|
|
176
|
+
this._bodyArrayBuffer.byteOffset,
|
|
177
|
+
this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
return Promise.resolve(this._bodyArrayBuffer);
|
|
182
|
+
}
|
|
183
|
+
} else if (support.blob) {
|
|
184
|
+
return this.blob().then(readBlobAsArrayBuffer);
|
|
185
|
+
} else {
|
|
186
|
+
throw new Error("could not read as ArrayBuffer");
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
this.text = function() {
|
|
190
|
+
var rejected = consumed(this);
|
|
191
|
+
if (rejected) {
|
|
192
|
+
return rejected;
|
|
193
|
+
}
|
|
194
|
+
if (this._bodyBlob) {
|
|
195
|
+
return readBlobAsText(this._bodyBlob);
|
|
196
|
+
} else if (this._bodyArrayBuffer) {
|
|
197
|
+
return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
|
|
198
|
+
} else if (this._bodyFormData) {
|
|
199
|
+
throw new Error("could not read FormData body as text");
|
|
200
|
+
} else {
|
|
201
|
+
return Promise.resolve(this._bodyText);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
if (support.formData) {
|
|
205
|
+
this.formData = function() {
|
|
206
|
+
return this.text().then(decode);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
this.json = function() {
|
|
210
|
+
return this.text().then(JSON.parse);
|
|
211
|
+
};
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
function normalizeMethod(method) {
|
|
215
|
+
var upcased = method.toUpperCase();
|
|
216
|
+
return methods.indexOf(upcased) > -1 ? upcased : method;
|
|
217
|
+
}
|
|
218
|
+
function Request(input, options) {
|
|
219
|
+
if (!(this instanceof Request)) {
|
|
220
|
+
throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
|
|
221
|
+
}
|
|
222
|
+
options = options || {};
|
|
223
|
+
var body = options.body;
|
|
224
|
+
if (input instanceof Request) {
|
|
225
|
+
if (input.bodyUsed) {
|
|
226
|
+
throw new TypeError("Already read");
|
|
227
|
+
}
|
|
228
|
+
this.url = input.url;
|
|
229
|
+
this.credentials = input.credentials;
|
|
230
|
+
if (!options.headers) {
|
|
231
|
+
this.headers = new Headers2(input.headers);
|
|
232
|
+
}
|
|
233
|
+
this.method = input.method;
|
|
234
|
+
this.mode = input.mode;
|
|
235
|
+
this.signal = input.signal;
|
|
236
|
+
if (!body && input._bodyInit != null) {
|
|
237
|
+
body = input._bodyInit;
|
|
238
|
+
input.bodyUsed = true;
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
this.url = String(input);
|
|
242
|
+
}
|
|
243
|
+
this.credentials = options.credentials || this.credentials || "same-origin";
|
|
244
|
+
if (options.headers || !this.headers) {
|
|
245
|
+
this.headers = new Headers2(options.headers);
|
|
246
|
+
}
|
|
247
|
+
this.method = normalizeMethod(options.method || this.method || "GET");
|
|
248
|
+
this.mode = options.mode || this.mode || null;
|
|
249
|
+
this.signal = options.signal || this.signal || (function() {
|
|
250
|
+
if ("AbortController" in g) {
|
|
251
|
+
var ctrl = new AbortController();
|
|
252
|
+
return ctrl.signal;
|
|
253
|
+
}
|
|
254
|
+
})();
|
|
255
|
+
this.referrer = null;
|
|
256
|
+
if ((this.method === "GET" || this.method === "HEAD") && body) {
|
|
257
|
+
throw new TypeError("Body not allowed for GET or HEAD requests");
|
|
258
|
+
}
|
|
259
|
+
this._initBody(body);
|
|
260
|
+
if (this.method === "GET" || this.method === "HEAD") {
|
|
261
|
+
if (options.cache === "no-store" || options.cache === "no-cache") {
|
|
262
|
+
var reParamSearch = /([?&])_=[^&]*/;
|
|
263
|
+
if (reParamSearch.test(this.url)) {
|
|
264
|
+
this.url = this.url.replace(reParamSearch, "$1_=" + (/* @__PURE__ */ new Date()).getTime());
|
|
265
|
+
} else {
|
|
266
|
+
var reQueryString = /\?/;
|
|
267
|
+
this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + (/* @__PURE__ */ new Date()).getTime();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function decode(body) {
|
|
273
|
+
var form = new FormData();
|
|
274
|
+
body.trim().split("&").forEach(function(bytes) {
|
|
275
|
+
if (bytes) {
|
|
276
|
+
var split = bytes.split("=");
|
|
277
|
+
var name = split.shift().replace(/\+/g, " ");
|
|
278
|
+
var value = split.join("=").replace(/\+/g, " ");
|
|
279
|
+
form.append(decodeURIComponent(name), decodeURIComponent(value));
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
return form;
|
|
283
|
+
}
|
|
284
|
+
function parseHeaders(rawHeaders) {
|
|
285
|
+
var headers = new Headers2();
|
|
286
|
+
var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, " ");
|
|
287
|
+
preProcessedHeaders.split("\r").map(function(header) {
|
|
288
|
+
return header.indexOf("\n") === 0 ? header.substr(1, header.length) : header;
|
|
289
|
+
}).forEach(function(line) {
|
|
290
|
+
var parts = line.split(":");
|
|
291
|
+
var key = parts.shift().trim();
|
|
292
|
+
if (key) {
|
|
293
|
+
var value = parts.join(":").trim();
|
|
294
|
+
try {
|
|
295
|
+
headers.append(key, value);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.warn("Response " + error.message);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
return headers;
|
|
302
|
+
}
|
|
303
|
+
function Response(bodyInit, options) {
|
|
304
|
+
if (!(this instanceof Response)) {
|
|
305
|
+
throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
|
|
306
|
+
}
|
|
307
|
+
if (!options) {
|
|
308
|
+
options = {};
|
|
309
|
+
}
|
|
310
|
+
this.type = "default";
|
|
311
|
+
this.status = options.status === void 0 ? 200 : options.status;
|
|
312
|
+
if (this.status < 200 || this.status > 599) {
|
|
313
|
+
throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");
|
|
314
|
+
}
|
|
315
|
+
this.ok = this.status >= 200 && this.status < 300;
|
|
316
|
+
this.statusText = options.statusText === void 0 ? "" : "" + options.statusText;
|
|
317
|
+
this.headers = new Headers2(options.headers);
|
|
318
|
+
this.url = options.url || "";
|
|
319
|
+
this._initBody(bodyInit);
|
|
320
|
+
}
|
|
321
|
+
function fetch2(input, init) {
|
|
322
|
+
return new Promise(function(resolve2, reject) {
|
|
323
|
+
var request = new Request(input, init);
|
|
324
|
+
if (request.signal && request.signal.aborted) {
|
|
325
|
+
return reject(new DOMException("Aborted", "AbortError"));
|
|
326
|
+
}
|
|
327
|
+
var xhr = new XMLHttpRequest();
|
|
328
|
+
function abortXhr() {
|
|
329
|
+
xhr.abort();
|
|
330
|
+
}
|
|
331
|
+
xhr.onload = function() {
|
|
332
|
+
var options = {
|
|
333
|
+
statusText: xhr.statusText,
|
|
334
|
+
headers: parseHeaders(xhr.getAllResponseHeaders() || "")
|
|
335
|
+
};
|
|
336
|
+
if (request.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) {
|
|
337
|
+
options.status = 200;
|
|
338
|
+
} else {
|
|
339
|
+
options.status = xhr.status;
|
|
340
|
+
}
|
|
341
|
+
options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL");
|
|
342
|
+
var body = "response" in xhr ? xhr.response : xhr.responseText;
|
|
343
|
+
setTimeout(function() {
|
|
344
|
+
resolve2(new Response(body, options));
|
|
345
|
+
}, 0);
|
|
346
|
+
};
|
|
347
|
+
xhr.onerror = function() {
|
|
348
|
+
setTimeout(function() {
|
|
349
|
+
reject(new TypeError("Network request failed"));
|
|
350
|
+
}, 0);
|
|
351
|
+
};
|
|
352
|
+
xhr.ontimeout = function() {
|
|
353
|
+
setTimeout(function() {
|
|
354
|
+
reject(new TypeError("Network request timed out"));
|
|
355
|
+
}, 0);
|
|
356
|
+
};
|
|
357
|
+
xhr.onabort = function() {
|
|
358
|
+
setTimeout(function() {
|
|
359
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
360
|
+
}, 0);
|
|
361
|
+
};
|
|
362
|
+
function fixUrl(url) {
|
|
363
|
+
try {
|
|
364
|
+
return url === "" && g.location.href ? g.location.href : url;
|
|
365
|
+
} catch (e) {
|
|
366
|
+
return url;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
xhr.open(request.method, fixUrl(request.url), true);
|
|
370
|
+
if (request.credentials === "include") {
|
|
371
|
+
xhr.withCredentials = true;
|
|
372
|
+
} else if (request.credentials === "omit") {
|
|
373
|
+
xhr.withCredentials = false;
|
|
374
|
+
}
|
|
375
|
+
if ("responseType" in xhr) {
|
|
376
|
+
if (support.blob) {
|
|
377
|
+
xhr.responseType = "blob";
|
|
378
|
+
} else if (support.arrayBuffer) {
|
|
379
|
+
xhr.responseType = "arraybuffer";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (init && typeof init.headers === "object" && !(init.headers instanceof Headers2 || g.Headers && init.headers instanceof g.Headers)) {
|
|
383
|
+
var names = [];
|
|
384
|
+
Object.getOwnPropertyNames(init.headers).forEach(function(name) {
|
|
385
|
+
names.push(normalizeName(name));
|
|
386
|
+
xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
|
|
387
|
+
});
|
|
388
|
+
request.headers.forEach(function(value, name) {
|
|
389
|
+
if (names.indexOf(name) === -1) {
|
|
390
|
+
xhr.setRequestHeader(name, value);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
} else {
|
|
394
|
+
request.headers.forEach(function(value, name) {
|
|
395
|
+
xhr.setRequestHeader(name, value);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (request.signal) {
|
|
399
|
+
request.signal.addEventListener("abort", abortXhr);
|
|
400
|
+
xhr.onreadystatechange = function() {
|
|
401
|
+
if (xhr.readyState === 4) {
|
|
402
|
+
request.signal.removeEventListener("abort", abortXhr);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
xhr.send(typeof request._bodyInit === "undefined" ? null : request._bodyInit);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
var g, support, viewClasses, isArrayBufferView, methods, redirectStatuses, DOMException;
|
|
410
|
+
var init_fetch = __esm({
|
|
411
|
+
"../../node_modules/whatwg-fetch/fetch.js"() {
|
|
412
|
+
"use strict";
|
|
413
|
+
g = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || // eslint-disable-next-line no-undef
|
|
414
|
+
typeof global !== "undefined" && global || {};
|
|
415
|
+
support = {
|
|
416
|
+
searchParams: "URLSearchParams" in g,
|
|
417
|
+
iterable: "Symbol" in g && "iterator" in Symbol,
|
|
418
|
+
blob: "FileReader" in g && "Blob" in g && (function() {
|
|
419
|
+
try {
|
|
420
|
+
new Blob();
|
|
421
|
+
return true;
|
|
422
|
+
} catch (e) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
})(),
|
|
426
|
+
formData: "FormData" in g,
|
|
427
|
+
arrayBuffer: "ArrayBuffer" in g
|
|
428
|
+
};
|
|
429
|
+
if (support.arrayBuffer) {
|
|
430
|
+
viewClasses = [
|
|
431
|
+
"[object Int8Array]",
|
|
432
|
+
"[object Uint8Array]",
|
|
433
|
+
"[object Uint8ClampedArray]",
|
|
434
|
+
"[object Int16Array]",
|
|
435
|
+
"[object Uint16Array]",
|
|
436
|
+
"[object Int32Array]",
|
|
437
|
+
"[object Uint32Array]",
|
|
438
|
+
"[object Float32Array]",
|
|
439
|
+
"[object Float64Array]"
|
|
440
|
+
];
|
|
441
|
+
isArrayBufferView = ArrayBuffer.isView || function(obj) {
|
|
442
|
+
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
Headers2.prototype.append = function(name, value) {
|
|
446
|
+
name = normalizeName(name);
|
|
447
|
+
value = normalizeValue(value);
|
|
448
|
+
var oldValue = this.map[name];
|
|
449
|
+
this.map[name] = oldValue ? oldValue + ", " + value : value;
|
|
450
|
+
};
|
|
451
|
+
Headers2.prototype["delete"] = function(name) {
|
|
452
|
+
delete this.map[normalizeName(name)];
|
|
453
|
+
};
|
|
454
|
+
Headers2.prototype.get = function(name) {
|
|
455
|
+
name = normalizeName(name);
|
|
456
|
+
return this.has(name) ? this.map[name] : null;
|
|
457
|
+
};
|
|
458
|
+
Headers2.prototype.has = function(name) {
|
|
459
|
+
return this.map.hasOwnProperty(normalizeName(name));
|
|
460
|
+
};
|
|
461
|
+
Headers2.prototype.set = function(name, value) {
|
|
462
|
+
this.map[normalizeName(name)] = normalizeValue(value);
|
|
463
|
+
};
|
|
464
|
+
Headers2.prototype.forEach = function(callback, thisArg) {
|
|
465
|
+
for (var name in this.map) {
|
|
466
|
+
if (this.map.hasOwnProperty(name)) {
|
|
467
|
+
callback.call(thisArg, this.map[name], name, this);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
Headers2.prototype.keys = function() {
|
|
472
|
+
var items = [];
|
|
473
|
+
this.forEach(function(value, name) {
|
|
474
|
+
items.push(name);
|
|
475
|
+
});
|
|
476
|
+
return iteratorFor(items);
|
|
477
|
+
};
|
|
478
|
+
Headers2.prototype.values = function() {
|
|
479
|
+
var items = [];
|
|
480
|
+
this.forEach(function(value) {
|
|
481
|
+
items.push(value);
|
|
482
|
+
});
|
|
483
|
+
return iteratorFor(items);
|
|
484
|
+
};
|
|
485
|
+
Headers2.prototype.entries = function() {
|
|
486
|
+
var items = [];
|
|
487
|
+
this.forEach(function(value, name) {
|
|
488
|
+
items.push([name, value]);
|
|
489
|
+
});
|
|
490
|
+
return iteratorFor(items);
|
|
491
|
+
};
|
|
492
|
+
if (support.iterable) {
|
|
493
|
+
Headers2.prototype[Symbol.iterator] = Headers2.prototype.entries;
|
|
494
|
+
}
|
|
495
|
+
methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"];
|
|
496
|
+
Request.prototype.clone = function() {
|
|
497
|
+
return new Request(this, { body: this._bodyInit });
|
|
498
|
+
};
|
|
499
|
+
Body.call(Request.prototype);
|
|
500
|
+
Body.call(Response.prototype);
|
|
501
|
+
Response.prototype.clone = function() {
|
|
502
|
+
return new Response(this._bodyInit, {
|
|
503
|
+
status: this.status,
|
|
504
|
+
statusText: this.statusText,
|
|
505
|
+
headers: new Headers2(this.headers),
|
|
506
|
+
url: this.url
|
|
507
|
+
});
|
|
508
|
+
};
|
|
509
|
+
Response.error = function() {
|
|
510
|
+
var response = new Response(null, { status: 200, statusText: "" });
|
|
511
|
+
response.ok = false;
|
|
512
|
+
response.status = 0;
|
|
513
|
+
response.type = "error";
|
|
514
|
+
return response;
|
|
515
|
+
};
|
|
516
|
+
redirectStatuses = [301, 302, 303, 307, 308];
|
|
517
|
+
Response.redirect = function(url, status) {
|
|
518
|
+
if (redirectStatuses.indexOf(status) === -1) {
|
|
519
|
+
throw new RangeError("Invalid status code");
|
|
520
|
+
}
|
|
521
|
+
return new Response(null, { status, headers: { location: url } });
|
|
522
|
+
};
|
|
523
|
+
DOMException = g.DOMException;
|
|
524
|
+
try {
|
|
525
|
+
new DOMException();
|
|
526
|
+
} catch (err) {
|
|
527
|
+
DOMException = function(message, name) {
|
|
528
|
+
this.message = message;
|
|
529
|
+
this.name = name;
|
|
530
|
+
var error = Error(message);
|
|
531
|
+
this.stack = error.stack;
|
|
532
|
+
};
|
|
533
|
+
DOMException.prototype = Object.create(Error.prototype);
|
|
534
|
+
DOMException.prototype.constructor = DOMException;
|
|
535
|
+
}
|
|
536
|
+
fetch2.polyfill = true;
|
|
537
|
+
if (!g.fetch) {
|
|
538
|
+
g.fetch = fetch2;
|
|
539
|
+
g.Headers = Headers2;
|
|
540
|
+
g.Request = Request;
|
|
541
|
+
g.Response = Response;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// ../../node_modules/ollama/dist/browser.mjs
|
|
547
|
+
function getPlatform() {
|
|
548
|
+
if (typeof window !== "undefined" && window.navigator) {
|
|
549
|
+
const nav = navigator;
|
|
550
|
+
if ("userAgentData" in nav && nav.userAgentData?.platform) {
|
|
551
|
+
return `${nav.userAgentData.platform.toLowerCase()} Browser/${navigator.userAgent};`;
|
|
552
|
+
}
|
|
553
|
+
if (navigator.platform) {
|
|
554
|
+
return `${navigator.platform.toLowerCase()} Browser/${navigator.userAgent};`;
|
|
555
|
+
}
|
|
556
|
+
return `unknown Browser/${navigator.userAgent};`;
|
|
557
|
+
} else if (typeof process !== "undefined") {
|
|
558
|
+
return `${process.arch} ${process.platform} Node.js/${process.version}`;
|
|
559
|
+
}
|
|
560
|
+
return "";
|
|
561
|
+
}
|
|
562
|
+
function normalizeHeaders(headers) {
|
|
563
|
+
if (headers instanceof Headers) {
|
|
564
|
+
const obj = {};
|
|
565
|
+
headers.forEach((value, key) => {
|
|
566
|
+
obj[key] = value;
|
|
567
|
+
});
|
|
568
|
+
return obj;
|
|
569
|
+
} else if (Array.isArray(headers)) {
|
|
570
|
+
return Object.fromEntries(headers);
|
|
571
|
+
} else {
|
|
572
|
+
return headers || {};
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
var defaultPort, defaultHost, version, __defProp$1, __defNormalProp$1, __publicField$1, ResponseError, AbortableAsyncIterator, checkOk, readEnvVar, fetchWithHeaders, get, post, del, parseJSON, formatHost, __defProp2, __defNormalProp, __publicField, Ollama$1, browser;
|
|
576
|
+
var init_browser = __esm({
|
|
577
|
+
"../../node_modules/ollama/dist/browser.mjs"() {
|
|
578
|
+
"use strict";
|
|
579
|
+
init_fetch();
|
|
580
|
+
defaultPort = "11434";
|
|
581
|
+
defaultHost = `http://127.0.0.1:${defaultPort}`;
|
|
582
|
+
version = "0.6.3";
|
|
583
|
+
__defProp$1 = Object.defineProperty;
|
|
584
|
+
__defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
585
|
+
__publicField$1 = (obj, key, value) => {
|
|
586
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
587
|
+
return value;
|
|
588
|
+
};
|
|
589
|
+
ResponseError = class _ResponseError extends Error {
|
|
590
|
+
constructor(error, status_code) {
|
|
591
|
+
super(error);
|
|
592
|
+
this.error = error;
|
|
593
|
+
this.status_code = status_code;
|
|
594
|
+
this.name = "ResponseError";
|
|
595
|
+
if (Error.captureStackTrace) {
|
|
596
|
+
Error.captureStackTrace(this, _ResponseError);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
AbortableAsyncIterator = class {
|
|
601
|
+
constructor(abortController, itr, doneCallback) {
|
|
602
|
+
__publicField$1(this, "abortController");
|
|
603
|
+
__publicField$1(this, "itr");
|
|
604
|
+
__publicField$1(this, "doneCallback");
|
|
605
|
+
this.abortController = abortController;
|
|
606
|
+
this.itr = itr;
|
|
607
|
+
this.doneCallback = doneCallback;
|
|
608
|
+
}
|
|
609
|
+
abort() {
|
|
610
|
+
this.abortController.abort();
|
|
611
|
+
}
|
|
612
|
+
async *[Symbol.asyncIterator]() {
|
|
613
|
+
for await (const message of this.itr) {
|
|
614
|
+
if ("error" in message) {
|
|
615
|
+
throw new Error(message.error);
|
|
616
|
+
}
|
|
617
|
+
yield message;
|
|
618
|
+
if (message.done || message.status === "success") {
|
|
619
|
+
this.doneCallback();
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
throw new Error("Did not receive done or success response in stream.");
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
checkOk = async (response) => {
|
|
627
|
+
if (response.ok) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
let message = `Error ${response.status}: ${response.statusText}`;
|
|
631
|
+
let errorData = null;
|
|
632
|
+
if (response.headers.get("content-type")?.includes("application/json")) {
|
|
633
|
+
try {
|
|
634
|
+
errorData = await response.json();
|
|
635
|
+
message = errorData.error || message;
|
|
636
|
+
} catch (error) {
|
|
637
|
+
console.log("Failed to parse error response as JSON");
|
|
638
|
+
}
|
|
639
|
+
} else {
|
|
640
|
+
try {
|
|
641
|
+
console.log("Getting text from response");
|
|
642
|
+
const textResponse = await response.text();
|
|
643
|
+
message = textResponse || message;
|
|
644
|
+
} catch (error) {
|
|
645
|
+
console.log("Failed to get text from error response");
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
throw new ResponseError(message, response.status);
|
|
649
|
+
};
|
|
650
|
+
readEnvVar = (obj, key) => {
|
|
651
|
+
return obj[key];
|
|
652
|
+
};
|
|
653
|
+
fetchWithHeaders = async (fetch3, url, options = {}) => {
|
|
654
|
+
const defaultHeaders = {
|
|
655
|
+
"Content-Type": "application/json",
|
|
656
|
+
Accept: "application/json",
|
|
657
|
+
"User-Agent": `ollama-js/${version} (${getPlatform()})`
|
|
658
|
+
};
|
|
659
|
+
options.headers = normalizeHeaders(options.headers);
|
|
660
|
+
try {
|
|
661
|
+
const parsed = new URL(url);
|
|
662
|
+
if (parsed.protocol === "https:" && parsed.hostname === "ollama.com") {
|
|
663
|
+
const apiKey = typeof process === "object" && process !== null && typeof process.env === "object" && process.env !== null ? readEnvVar(process.env, "OLLAMA_API_KEY") : void 0;
|
|
664
|
+
const authorization = options.headers["authorization"] || options.headers["Authorization"];
|
|
665
|
+
if (!authorization && apiKey) {
|
|
666
|
+
options.headers["Authorization"] = `Bearer ${apiKey}`;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
} catch (error) {
|
|
670
|
+
console.error("error parsing url", error);
|
|
671
|
+
}
|
|
672
|
+
const customHeaders = Object.fromEntries(
|
|
673
|
+
Object.entries(options.headers).filter(
|
|
674
|
+
([key]) => !Object.keys(defaultHeaders).some(
|
|
675
|
+
(defaultKey) => defaultKey.toLowerCase() === key.toLowerCase()
|
|
676
|
+
)
|
|
677
|
+
)
|
|
678
|
+
);
|
|
679
|
+
options.headers = {
|
|
680
|
+
...defaultHeaders,
|
|
681
|
+
...customHeaders
|
|
682
|
+
};
|
|
683
|
+
return fetch3(url, options);
|
|
684
|
+
};
|
|
685
|
+
get = async (fetch3, host, options) => {
|
|
686
|
+
const response = await fetchWithHeaders(fetch3, host, {
|
|
687
|
+
headers: options?.headers
|
|
688
|
+
});
|
|
689
|
+
await checkOk(response);
|
|
690
|
+
return response;
|
|
691
|
+
};
|
|
692
|
+
post = async (fetch3, host, data, options) => {
|
|
693
|
+
const isRecord = (input) => {
|
|
694
|
+
return input !== null && typeof input === "object" && !Array.isArray(input);
|
|
695
|
+
};
|
|
696
|
+
const formattedData = isRecord(data) ? JSON.stringify(data) : data;
|
|
697
|
+
const response = await fetchWithHeaders(fetch3, host, {
|
|
698
|
+
method: "POST",
|
|
699
|
+
body: formattedData,
|
|
700
|
+
signal: options?.signal,
|
|
701
|
+
headers: options?.headers
|
|
702
|
+
});
|
|
703
|
+
await checkOk(response);
|
|
704
|
+
return response;
|
|
705
|
+
};
|
|
706
|
+
del = async (fetch3, host, data, options) => {
|
|
707
|
+
const response = await fetchWithHeaders(fetch3, host, {
|
|
708
|
+
method: "DELETE",
|
|
709
|
+
body: JSON.stringify(data),
|
|
710
|
+
headers: options?.headers
|
|
711
|
+
});
|
|
712
|
+
await checkOk(response);
|
|
713
|
+
return response;
|
|
714
|
+
};
|
|
715
|
+
parseJSON = async function* (itr) {
|
|
716
|
+
const decoder = new TextDecoder("utf-8");
|
|
717
|
+
let buffer = "";
|
|
718
|
+
const reader = itr.getReader();
|
|
719
|
+
while (true) {
|
|
720
|
+
const { done, value: chunk } = await reader.read();
|
|
721
|
+
if (done) {
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
725
|
+
const parts = buffer.split("\n");
|
|
726
|
+
buffer = parts.pop() ?? "";
|
|
727
|
+
for (const part of parts) {
|
|
728
|
+
try {
|
|
729
|
+
yield JSON.parse(part);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.warn("invalid json: ", part);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
buffer += decoder.decode();
|
|
736
|
+
for (const part of buffer.split("\n").filter((p) => p !== "")) {
|
|
737
|
+
try {
|
|
738
|
+
yield JSON.parse(part);
|
|
739
|
+
} catch (error) {
|
|
740
|
+
console.warn("invalid json: ", part);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
formatHost = (host) => {
|
|
745
|
+
if (!host) {
|
|
746
|
+
return defaultHost;
|
|
747
|
+
}
|
|
748
|
+
let isExplicitProtocol = host.includes("://");
|
|
749
|
+
if (host.startsWith(":")) {
|
|
750
|
+
host = `http://127.0.0.1${host}`;
|
|
751
|
+
isExplicitProtocol = true;
|
|
752
|
+
}
|
|
753
|
+
if (!isExplicitProtocol) {
|
|
754
|
+
host = `http://${host}`;
|
|
755
|
+
}
|
|
756
|
+
const url = new URL(host);
|
|
757
|
+
let port = url.port;
|
|
758
|
+
if (!port) {
|
|
759
|
+
if (!isExplicitProtocol) {
|
|
760
|
+
port = defaultPort;
|
|
761
|
+
} else {
|
|
762
|
+
port = url.protocol === "https:" ? "443" : "80";
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
let auth = "";
|
|
766
|
+
if (url.username) {
|
|
767
|
+
auth = url.username;
|
|
768
|
+
if (url.password) {
|
|
769
|
+
auth += `:${url.password}`;
|
|
770
|
+
}
|
|
771
|
+
auth += "@";
|
|
772
|
+
}
|
|
773
|
+
let formattedHost = `${url.protocol}//${auth}${url.hostname}:${port}${url.pathname}`;
|
|
774
|
+
if (formattedHost.endsWith("/")) {
|
|
775
|
+
formattedHost = formattedHost.slice(0, -1);
|
|
776
|
+
}
|
|
777
|
+
return formattedHost;
|
|
778
|
+
};
|
|
779
|
+
__defProp2 = Object.defineProperty;
|
|
780
|
+
__defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
781
|
+
__publicField = (obj, key, value) => {
|
|
782
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
783
|
+
return value;
|
|
784
|
+
};
|
|
785
|
+
Ollama$1 = class Ollama {
|
|
786
|
+
constructor(config) {
|
|
787
|
+
__publicField(this, "config");
|
|
788
|
+
__publicField(this, "fetch");
|
|
789
|
+
__publicField(this, "ongoingStreamedRequests", []);
|
|
790
|
+
this.config = {
|
|
791
|
+
host: "",
|
|
792
|
+
headers: config?.headers
|
|
793
|
+
};
|
|
794
|
+
if (!config?.proxy) {
|
|
795
|
+
this.config.host = formatHost(config?.host ?? defaultHost);
|
|
796
|
+
}
|
|
797
|
+
this.fetch = config?.fetch ?? fetch;
|
|
798
|
+
}
|
|
799
|
+
// Abort any ongoing streamed requests to Ollama
|
|
800
|
+
abort() {
|
|
801
|
+
for (const request of this.ongoingStreamedRequests) {
|
|
802
|
+
request.abort();
|
|
803
|
+
}
|
|
804
|
+
this.ongoingStreamedRequests.length = 0;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Processes a request to the Ollama server. If the request is streamable, it will return a
|
|
808
|
+
* AbortableAsyncIterator that yields the response messages. Otherwise, it will return the response
|
|
809
|
+
* object.
|
|
810
|
+
* @param endpoint {string} - The endpoint to send the request to.
|
|
811
|
+
* @param request {object} - The request object to send to the endpoint.
|
|
812
|
+
* @protected {T | AbortableAsyncIterator<T>} - The response object or a AbortableAsyncIterator that yields
|
|
813
|
+
* response messages.
|
|
814
|
+
* @throws {Error} - If the response body is missing or if the response is an error.
|
|
815
|
+
* @returns {Promise<T | AbortableAsyncIterator<T>>} - The response object or a AbortableAsyncIterator that yields the streamed response.
|
|
816
|
+
*/
|
|
817
|
+
async processStreamableRequest(endpoint, request) {
|
|
818
|
+
request.stream = request.stream ?? false;
|
|
819
|
+
const host = `${this.config.host}/api/${endpoint}`;
|
|
820
|
+
if (request.stream) {
|
|
821
|
+
const abortController = new AbortController();
|
|
822
|
+
const response2 = await post(this.fetch, host, request, {
|
|
823
|
+
signal: abortController.signal,
|
|
824
|
+
headers: this.config.headers
|
|
825
|
+
});
|
|
826
|
+
if (!response2.body) {
|
|
827
|
+
throw new Error("Missing body");
|
|
828
|
+
}
|
|
829
|
+
const itr = parseJSON(response2.body);
|
|
830
|
+
const abortableAsyncIterator = new AbortableAsyncIterator(
|
|
831
|
+
abortController,
|
|
832
|
+
itr,
|
|
833
|
+
() => {
|
|
834
|
+
const i = this.ongoingStreamedRequests.indexOf(abortableAsyncIterator);
|
|
835
|
+
if (i > -1) {
|
|
836
|
+
this.ongoingStreamedRequests.splice(i, 1);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
);
|
|
840
|
+
this.ongoingStreamedRequests.push(abortableAsyncIterator);
|
|
841
|
+
return abortableAsyncIterator;
|
|
842
|
+
}
|
|
843
|
+
const response = await post(this.fetch, host, request, {
|
|
844
|
+
headers: this.config.headers
|
|
845
|
+
});
|
|
846
|
+
return await response.json();
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Encodes an image to base64 if it is a Uint8Array.
|
|
850
|
+
* @param image {Uint8Array | string} - The image to encode.
|
|
851
|
+
* @returns {Promise<string>} - The base64 encoded image.
|
|
852
|
+
*/
|
|
853
|
+
async encodeImage(image) {
|
|
854
|
+
if (typeof image !== "string") {
|
|
855
|
+
const uint8Array = new Uint8Array(image);
|
|
856
|
+
let byteString = "";
|
|
857
|
+
const len = uint8Array.byteLength;
|
|
858
|
+
for (let i = 0; i < len; i++) {
|
|
859
|
+
byteString += String.fromCharCode(uint8Array[i]);
|
|
860
|
+
}
|
|
861
|
+
return btoa(byteString);
|
|
862
|
+
}
|
|
863
|
+
return image;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Generates a response from a text prompt.
|
|
867
|
+
* @param request {GenerateRequest} - The request object.
|
|
868
|
+
* @returns {Promise<GenerateResponse | AbortableAsyncIterator<GenerateResponse>>} - The response object or
|
|
869
|
+
* an AbortableAsyncIterator that yields response messages.
|
|
870
|
+
*/
|
|
871
|
+
async generate(request) {
|
|
872
|
+
if (request.images) {
|
|
873
|
+
request.images = await Promise.all(request.images.map(this.encodeImage.bind(this)));
|
|
874
|
+
}
|
|
875
|
+
return this.processStreamableRequest("generate", request);
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Chats with the model. The request object can contain messages with images that are either
|
|
879
|
+
* Uint8Arrays or base64 encoded strings. The images will be base64 encoded before sending the
|
|
880
|
+
* request.
|
|
881
|
+
* @param request {ChatRequest} - The request object.
|
|
882
|
+
* @returns {Promise<ChatResponse | AbortableAsyncIterator<ChatResponse>>} - The response object or an
|
|
883
|
+
* AbortableAsyncIterator that yields response messages.
|
|
884
|
+
*/
|
|
885
|
+
async chat(request) {
|
|
886
|
+
if (request.messages) {
|
|
887
|
+
for (const message of request.messages) {
|
|
888
|
+
if (message.images) {
|
|
889
|
+
message.images = await Promise.all(
|
|
890
|
+
message.images.map(this.encodeImage.bind(this))
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return this.processStreamableRequest("chat", request);
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Creates a new model from a stream of data.
|
|
899
|
+
* @param request {CreateRequest} - The request object.
|
|
900
|
+
* @returns {Promise<ProgressResponse | AbortableAsyncIterator<ProgressResponse>>} - The response object or a stream of progress responses.
|
|
901
|
+
*/
|
|
902
|
+
async create(request) {
|
|
903
|
+
return this.processStreamableRequest("create", {
|
|
904
|
+
...request
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Pulls a model from the Ollama registry. The request object can contain a stream flag to indicate if the
|
|
909
|
+
* response should be streamed.
|
|
910
|
+
* @param request {PullRequest} - The request object.
|
|
911
|
+
* @returns {Promise<ProgressResponse | AbortableAsyncIterator<ProgressResponse>>} - The response object or
|
|
912
|
+
* an AbortableAsyncIterator that yields response messages.
|
|
913
|
+
*/
|
|
914
|
+
async pull(request) {
|
|
915
|
+
return this.processStreamableRequest("pull", {
|
|
916
|
+
name: request.model,
|
|
917
|
+
stream: request.stream,
|
|
918
|
+
insecure: request.insecure
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Pushes a model to the Ollama registry. The request object can contain a stream flag to indicate if the
|
|
923
|
+
* response should be streamed.
|
|
924
|
+
* @param request {PushRequest} - The request object.
|
|
925
|
+
* @returns {Promise<ProgressResponse | AbortableAsyncIterator<ProgressResponse>>} - The response object or
|
|
926
|
+
* an AbortableAsyncIterator that yields response messages.
|
|
927
|
+
*/
|
|
928
|
+
async push(request) {
|
|
929
|
+
return this.processStreamableRequest("push", {
|
|
930
|
+
name: request.model,
|
|
931
|
+
stream: request.stream,
|
|
932
|
+
insecure: request.insecure
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Deletes a model from the server. The request object should contain the name of the model to
|
|
937
|
+
* delete.
|
|
938
|
+
* @param request {DeleteRequest} - The request object.
|
|
939
|
+
* @returns {Promise<StatusResponse>} - The response object.
|
|
940
|
+
*/
|
|
941
|
+
async delete(request) {
|
|
942
|
+
await del(
|
|
943
|
+
this.fetch,
|
|
944
|
+
`${this.config.host}/api/delete`,
|
|
945
|
+
{ name: request.model },
|
|
946
|
+
{ headers: this.config.headers }
|
|
947
|
+
);
|
|
948
|
+
return { status: "success" };
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Copies a model from one name to another. The request object should contain the name of the
|
|
952
|
+
* model to copy and the new name.
|
|
953
|
+
* @param request {CopyRequest} - The request object.
|
|
954
|
+
* @returns {Promise<StatusResponse>} - The response object.
|
|
955
|
+
*/
|
|
956
|
+
async copy(request) {
|
|
957
|
+
await post(this.fetch, `${this.config.host}/api/copy`, { ...request }, {
|
|
958
|
+
headers: this.config.headers
|
|
959
|
+
});
|
|
960
|
+
return { status: "success" };
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Lists the models on the server.
|
|
964
|
+
* @returns {Promise<ListResponse>} - The response object.
|
|
965
|
+
* @throws {Error} - If the response body is missing.
|
|
966
|
+
*/
|
|
967
|
+
async list() {
|
|
968
|
+
const response = await get(this.fetch, `${this.config.host}/api/tags`, {
|
|
969
|
+
headers: this.config.headers
|
|
970
|
+
});
|
|
971
|
+
return await response.json();
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Shows the metadata of a model. The request object should contain the name of the model.
|
|
975
|
+
* @param request {ShowRequest} - The request object.
|
|
976
|
+
* @returns {Promise<ShowResponse>} - The response object.
|
|
977
|
+
*/
|
|
978
|
+
async show(request) {
|
|
979
|
+
const response = await post(this.fetch, `${this.config.host}/api/show`, {
|
|
980
|
+
...request
|
|
981
|
+
}, {
|
|
982
|
+
headers: this.config.headers
|
|
983
|
+
});
|
|
984
|
+
return await response.json();
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Embeds text input into vectors.
|
|
988
|
+
* @param request {EmbedRequest} - The request object.
|
|
989
|
+
* @returns {Promise<EmbedResponse>} - The response object.
|
|
990
|
+
*/
|
|
991
|
+
async embed(request) {
|
|
992
|
+
const response = await post(this.fetch, `${this.config.host}/api/embed`, {
|
|
993
|
+
...request
|
|
994
|
+
}, {
|
|
995
|
+
headers: this.config.headers
|
|
996
|
+
});
|
|
997
|
+
return await response.json();
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Embeds a text prompt into a vector.
|
|
1001
|
+
* @param request {EmbeddingsRequest} - The request object.
|
|
1002
|
+
* @returns {Promise<EmbeddingsResponse>} - The response object.
|
|
1003
|
+
*/
|
|
1004
|
+
async embeddings(request) {
|
|
1005
|
+
const response = await post(this.fetch, `${this.config.host}/api/embeddings`, {
|
|
1006
|
+
...request
|
|
1007
|
+
}, {
|
|
1008
|
+
headers: this.config.headers
|
|
1009
|
+
});
|
|
1010
|
+
return await response.json();
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Lists the running models on the server
|
|
1014
|
+
* @returns {Promise<ListResponse>} - The response object.
|
|
1015
|
+
* @throws {Error} - If the response body is missing.
|
|
1016
|
+
*/
|
|
1017
|
+
async ps() {
|
|
1018
|
+
const response = await get(this.fetch, `${this.config.host}/api/ps`, {
|
|
1019
|
+
headers: this.config.headers
|
|
1020
|
+
});
|
|
1021
|
+
return await response.json();
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Returns the Ollama server version.
|
|
1025
|
+
* @returns {Promise<VersionResponse>} - The server version object.
|
|
1026
|
+
*/
|
|
1027
|
+
async version() {
|
|
1028
|
+
const response = await get(this.fetch, `${this.config.host}/api/version`, {
|
|
1029
|
+
headers: this.config.headers
|
|
1030
|
+
});
|
|
1031
|
+
return await response.json();
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Performs web search using the Ollama web search API
|
|
1035
|
+
* @param request {WebSearchRequest} - The search request containing query and options
|
|
1036
|
+
* @returns {Promise<WebSearchResponse>} - The search results
|
|
1037
|
+
* @throws {Error} - If the request is invalid or the server returns an error
|
|
1038
|
+
*/
|
|
1039
|
+
async webSearch(request) {
|
|
1040
|
+
if (!request.query || request.query.length === 0) {
|
|
1041
|
+
throw new Error("Query is required");
|
|
1042
|
+
}
|
|
1043
|
+
const response = await post(this.fetch, `https://ollama.com/api/web_search`, { ...request }, {
|
|
1044
|
+
headers: this.config.headers
|
|
1045
|
+
});
|
|
1046
|
+
return await response.json();
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Fetches a single page using the Ollama web fetch API
|
|
1050
|
+
* @param request {WebFetchRequest} - The fetch request containing a URL
|
|
1051
|
+
* @returns {Promise<WebFetchResponse>} - The fetch result
|
|
1052
|
+
* @throws {Error} - If the request is invalid or the server returns an error
|
|
1053
|
+
*/
|
|
1054
|
+
async webFetch(request) {
|
|
1055
|
+
if (!request.url || request.url.length === 0) {
|
|
1056
|
+
throw new Error("URL is required");
|
|
1057
|
+
}
|
|
1058
|
+
const response = await post(this.fetch, `https://ollama.com/api/web_fetch`, { ...request }, { headers: this.config.headers });
|
|
1059
|
+
return await response.json();
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
browser = new Ollama$1();
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
// ../../node_modules/ollama/dist/index.mjs
|
|
1067
|
+
var dist_exports = {};
|
|
1068
|
+
__export(dist_exports, {
|
|
1069
|
+
Ollama: () => Ollama2,
|
|
1070
|
+
default: () => index
|
|
1071
|
+
});
|
|
1072
|
+
import fs, { promises } from "fs";
|
|
1073
|
+
import { resolve } from "path";
|
|
1074
|
+
var Ollama2, index;
|
|
1075
|
+
var init_dist = __esm({
|
|
1076
|
+
"../../node_modules/ollama/dist/index.mjs"() {
|
|
1077
|
+
"use strict";
|
|
1078
|
+
init_browser();
|
|
1079
|
+
init_fetch();
|
|
1080
|
+
Ollama2 = class extends Ollama$1 {
|
|
1081
|
+
async encodeImage(image) {
|
|
1082
|
+
if (typeof image !== "string") {
|
|
1083
|
+
return Buffer.from(image).toString("base64");
|
|
1084
|
+
}
|
|
1085
|
+
try {
|
|
1086
|
+
if (fs.existsSync(image)) {
|
|
1087
|
+
const fileBuffer = await promises.readFile(resolve(image));
|
|
1088
|
+
return Buffer.from(fileBuffer).toString("base64");
|
|
1089
|
+
}
|
|
1090
|
+
} catch {
|
|
1091
|
+
}
|
|
1092
|
+
return image;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* checks if a file exists
|
|
1096
|
+
* @param path {string} - The path to the file
|
|
1097
|
+
* @private @internal
|
|
1098
|
+
* @returns {Promise<boolean>} - Whether the file exists or not
|
|
1099
|
+
*/
|
|
1100
|
+
async fileExists(path) {
|
|
1101
|
+
try {
|
|
1102
|
+
await promises.access(path);
|
|
1103
|
+
return true;
|
|
1104
|
+
} catch {
|
|
1105
|
+
return false;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
async create(request) {
|
|
1109
|
+
if (request.from && await this.fileExists(resolve(request.from))) {
|
|
1110
|
+
throw Error("Creating with a local path is not currently supported from ollama-js");
|
|
1111
|
+
}
|
|
1112
|
+
if (request.stream) {
|
|
1113
|
+
return super.create(request);
|
|
1114
|
+
} else {
|
|
1115
|
+
return super.create(request);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
index = new Ollama2();
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
7
1122
|
|
|
8
1123
|
// src/types.ts
|
|
9
1124
|
import { Schema } from "effect";
|
|
@@ -192,28 +1307,26 @@ var LLMService = class extends Context.Tag("LLMService")() {
|
|
|
192
1307
|
import { Context as Context2, Layer } from "effect";
|
|
193
1308
|
var LLMConfig = class extends Context2.Tag("LLMConfig")() {
|
|
194
1309
|
};
|
|
195
|
-
var
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
})
|
|
216
|
-
);
|
|
1310
|
+
var llmConfigFromEnv = LLMConfig.of({
|
|
1311
|
+
defaultProvider: "anthropic",
|
|
1312
|
+
defaultModel: process.env.LLM_DEFAULT_MODEL ?? "claude-sonnet-4-20250514",
|
|
1313
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
1314
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
1315
|
+
googleApiKey: process.env.GOOGLE_API_KEY,
|
|
1316
|
+
ollamaEndpoint: process.env.OLLAMA_ENDPOINT ?? "http://localhost:11434",
|
|
1317
|
+
embeddingConfig: {
|
|
1318
|
+
model: process.env.EMBEDDING_MODEL ?? "text-embedding-3-small",
|
|
1319
|
+
dimensions: Number(process.env.EMBEDDING_DIMENSIONS ?? 1536),
|
|
1320
|
+
provider: process.env.EMBEDDING_PROVIDER ?? "openai",
|
|
1321
|
+
batchSize: 100
|
|
1322
|
+
},
|
|
1323
|
+
supportsPromptCaching: (process.env.LLM_DEFAULT_MODEL ?? "claude-sonnet-4-20250514").startsWith("claude"),
|
|
1324
|
+
maxRetries: Number(process.env.LLM_MAX_RETRIES ?? 3),
|
|
1325
|
+
timeoutMs: Number(process.env.LLM_TIMEOUT_MS ?? 3e4),
|
|
1326
|
+
defaultMaxTokens: 4096,
|
|
1327
|
+
defaultTemperature: Number(process.env.LLM_DEFAULT_TEMPERATURE ?? 0.7)
|
|
1328
|
+
});
|
|
1329
|
+
var LLMConfigFromEnv = Layer.succeed(LLMConfig, llmConfigFromEnv);
|
|
217
1330
|
|
|
218
1331
|
// src/prompt-manager.ts
|
|
219
1332
|
import { Effect as Effect3, Context as Context3, Layer as Layer2 } from "effect";
|
|
@@ -669,6 +1782,14 @@ var toEffectError2 = (error, provider) => {
|
|
|
669
1782
|
cause: error
|
|
670
1783
|
});
|
|
671
1784
|
};
|
|
1785
|
+
var toOpenAITool = (tool) => ({
|
|
1786
|
+
type: "function",
|
|
1787
|
+
function: {
|
|
1788
|
+
name: tool.name,
|
|
1789
|
+
description: tool.description,
|
|
1790
|
+
parameters: tool.inputSchema
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
672
1793
|
var OpenAIProviderLive = Layer4.effect(
|
|
673
1794
|
LLMService,
|
|
674
1795
|
Effect5.gen(function* () {
|
|
@@ -687,14 +1808,22 @@ var OpenAIProviderLive = Layer4.effect(
|
|
|
687
1808
|
complete: (request) => Effect5.gen(function* () {
|
|
688
1809
|
const client = getClient();
|
|
689
1810
|
const model = typeof request.model === "string" ? request.model : request.model?.model ?? defaultModel;
|
|
1811
|
+
const messages = toOpenAIMessages(request.messages);
|
|
1812
|
+
if (request.systemPrompt) {
|
|
1813
|
+
messages.unshift({ role: "system", content: request.systemPrompt });
|
|
1814
|
+
}
|
|
1815
|
+
const requestBody = {
|
|
1816
|
+
model,
|
|
1817
|
+
max_tokens: request.maxTokens ?? config.defaultMaxTokens,
|
|
1818
|
+
temperature: request.temperature ?? config.defaultTemperature,
|
|
1819
|
+
messages,
|
|
1820
|
+
stop: request.stopSequences ? [...request.stopSequences] : void 0
|
|
1821
|
+
};
|
|
1822
|
+
if (request.tools && request.tools.length > 0) {
|
|
1823
|
+
requestBody.tools = request.tools.map(toOpenAITool);
|
|
1824
|
+
}
|
|
690
1825
|
const response = yield* Effect5.tryPromise({
|
|
691
|
-
try: () => client.chat.completions.create(
|
|
692
|
-
model,
|
|
693
|
-
max_tokens: request.maxTokens ?? config.defaultMaxTokens,
|
|
694
|
-
temperature: request.temperature ?? config.defaultTemperature,
|
|
695
|
-
messages: toOpenAIMessages(request.messages),
|
|
696
|
-
stop: request.stopSequences ? [...request.stopSequences] : void 0
|
|
697
|
-
}),
|
|
1826
|
+
try: () => client.chat.completions.create(requestBody),
|
|
698
1827
|
catch: (error) => toEffectError2(error, "openai")
|
|
699
1828
|
});
|
|
700
1829
|
return mapOpenAIResponse(response, model);
|
|
@@ -722,7 +1851,13 @@ var OpenAIProviderLive = Layer4.effect(
|
|
|
722
1851
|
model,
|
|
723
1852
|
max_tokens: request.maxTokens ?? config.defaultMaxTokens,
|
|
724
1853
|
temperature: request.temperature ?? config.defaultTemperature,
|
|
725
|
-
messages:
|
|
1854
|
+
messages: (() => {
|
|
1855
|
+
const msgs = toOpenAIMessages(request.messages);
|
|
1856
|
+
if (request.systemPrompt) {
|
|
1857
|
+
msgs.unshift({ role: "system", content: request.systemPrompt });
|
|
1858
|
+
}
|
|
1859
|
+
return msgs;
|
|
1860
|
+
})(),
|
|
726
1861
|
stream: true
|
|
727
1862
|
});
|
|
728
1863
|
let fullContent = "";
|
|
@@ -873,8 +2008,24 @@ No markdown, no code fences, just raw JSON.`
|
|
|
873
2008
|
})
|
|
874
2009
|
);
|
|
875
2010
|
var mapOpenAIResponse = (response, model) => {
|
|
876
|
-
const
|
|
877
|
-
const
|
|
2011
|
+
const message = response.choices[0]?.message;
|
|
2012
|
+
const content = message?.content ?? "";
|
|
2013
|
+
const rawToolCalls = message?.tool_calls;
|
|
2014
|
+
const hasToolCalls = rawToolCalls && rawToolCalls.length > 0;
|
|
2015
|
+
const stopReason = response.choices[0]?.finish_reason === "tool_calls" || hasToolCalls ? "tool_use" : response.choices[0]?.finish_reason === "stop" ? "end_turn" : response.choices[0]?.finish_reason === "length" ? "max_tokens" : "end_turn";
|
|
2016
|
+
const toolCalls = hasToolCalls ? rawToolCalls.map((tc) => {
|
|
2017
|
+
let input;
|
|
2018
|
+
try {
|
|
2019
|
+
input = JSON.parse(tc.function.arguments);
|
|
2020
|
+
} catch {
|
|
2021
|
+
input = { raw: tc.function.arguments };
|
|
2022
|
+
}
|
|
2023
|
+
return {
|
|
2024
|
+
id: tc.id,
|
|
2025
|
+
name: tc.function.name,
|
|
2026
|
+
input
|
|
2027
|
+
};
|
|
2028
|
+
}) : void 0;
|
|
878
2029
|
return {
|
|
879
2030
|
content,
|
|
880
2031
|
stopReason,
|
|
@@ -888,7 +2039,8 @@ var mapOpenAIResponse = (response, model) => {
|
|
|
888
2039
|
model
|
|
889
2040
|
)
|
|
890
2041
|
},
|
|
891
|
-
model: response.model ?? model
|
|
2042
|
+
model: response.model ?? model,
|
|
2043
|
+
toolCalls
|
|
892
2044
|
};
|
|
893
2045
|
};
|
|
894
2046
|
|
|
@@ -900,37 +2052,57 @@ var toOllamaMessages = (messages) => messages.map((m) => ({
|
|
|
900
2052
|
(b) => b.type === "text"
|
|
901
2053
|
).map((b) => b.text).join("")
|
|
902
2054
|
}));
|
|
2055
|
+
var toOllamaTools = (tools) => {
|
|
2056
|
+
if (!tools || tools.length === 0) return void 0;
|
|
2057
|
+
return tools.map((t) => ({
|
|
2058
|
+
type: "function",
|
|
2059
|
+
function: {
|
|
2060
|
+
name: t.name,
|
|
2061
|
+
description: t.description,
|
|
2062
|
+
parameters: t.inputSchema
|
|
2063
|
+
}
|
|
2064
|
+
}));
|
|
2065
|
+
};
|
|
2066
|
+
var parseToolCalls = (toolCalls) => {
|
|
2067
|
+
if (!toolCalls || toolCalls.length === 0) return void 0;
|
|
2068
|
+
return toolCalls.map((tc, i) => ({
|
|
2069
|
+
id: `ollama-tc-${Date.now()}-${i}`,
|
|
2070
|
+
name: tc.function.name,
|
|
2071
|
+
input: tc.function.arguments
|
|
2072
|
+
}));
|
|
2073
|
+
};
|
|
903
2074
|
var LocalProviderLive = Layer5.effect(
|
|
904
2075
|
LLMService,
|
|
905
2076
|
Effect6.gen(function* () {
|
|
906
2077
|
const config = yield* LLMConfig;
|
|
907
2078
|
const endpoint = config.ollamaEndpoint ?? "http://localhost:11434";
|
|
908
2079
|
const defaultModel = config.defaultModel.startsWith("claude") || config.defaultModel.startsWith("gpt") ? "llama3" : config.defaultModel;
|
|
2080
|
+
const getClient = async () => {
|
|
2081
|
+
const { Ollama: Ollama3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
2082
|
+
return new Ollama3({ host: endpoint });
|
|
2083
|
+
};
|
|
909
2084
|
return LLMService.of({
|
|
910
2085
|
complete: (request) => Effect6.gen(function* () {
|
|
911
2086
|
const model = typeof request.model === "string" ? request.model : request.model?.model ?? defaultModel;
|
|
912
2087
|
const response = yield* Effect6.tryPromise({
|
|
913
2088
|
try: async () => {
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
model,
|
|
919
|
-
messages: toOllamaMessages(request.messages),
|
|
920
|
-
stream: false,
|
|
921
|
-
options: {
|
|
922
|
-
temperature: request.temperature ?? config.defaultTemperature,
|
|
923
|
-
num_predict: request.maxTokens ?? config.defaultMaxTokens,
|
|
924
|
-
stop: request.stopSequences ? [...request.stopSequences] : void 0
|
|
925
|
-
}
|
|
926
|
-
})
|
|
927
|
-
});
|
|
928
|
-
if (!res.ok) {
|
|
929
|
-
throw new Error(
|
|
930
|
-
`Ollama request failed: ${res.status} ${res.statusText}`
|
|
931
|
-
);
|
|
2089
|
+
const client = await getClient();
|
|
2090
|
+
const msgs = toOllamaMessages(request.messages);
|
|
2091
|
+
if (request.systemPrompt) {
|
|
2092
|
+
msgs.unshift({ role: "system", content: request.systemPrompt });
|
|
932
2093
|
}
|
|
933
|
-
return
|
|
2094
|
+
return client.chat({
|
|
2095
|
+
model,
|
|
2096
|
+
messages: msgs,
|
|
2097
|
+
tools: toOllamaTools(request.tools),
|
|
2098
|
+
stream: false,
|
|
2099
|
+
keep_alive: "5m",
|
|
2100
|
+
options: {
|
|
2101
|
+
temperature: request.temperature ?? config.defaultTemperature,
|
|
2102
|
+
num_predict: request.maxTokens ?? config.defaultMaxTokens,
|
|
2103
|
+
stop: request.stopSequences ? [...request.stopSequences] : void 0
|
|
2104
|
+
}
|
|
2105
|
+
});
|
|
934
2106
|
},
|
|
935
2107
|
catch: (error) => new LLMError({
|
|
936
2108
|
message: `Ollama request failed: ${error}`,
|
|
@@ -941,9 +2113,13 @@ var LocalProviderLive = Layer5.effect(
|
|
|
941
2113
|
const content = response.message?.content ?? "";
|
|
942
2114
|
const inputTokens = response.prompt_eval_count ?? 0;
|
|
943
2115
|
const outputTokens = response.eval_count ?? 0;
|
|
2116
|
+
const toolCalls = parseToolCalls(
|
|
2117
|
+
response.message?.tool_calls
|
|
2118
|
+
);
|
|
2119
|
+
const hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
944
2120
|
return {
|
|
945
2121
|
content,
|
|
946
|
-
stopReason: response.done_reason === "stop" ? "end_turn" : response.done_reason === "length" ? "max_tokens" : "end_turn",
|
|
2122
|
+
stopReason: hasToolCalls ? "tool_use" : response.done_reason === "stop" ? "end_turn" : response.done_reason === "length" ? "max_tokens" : "end_turn",
|
|
947
2123
|
usage: {
|
|
948
2124
|
inputTokens,
|
|
949
2125
|
outputTokens,
|
|
@@ -951,18 +2127,19 @@ var LocalProviderLive = Layer5.effect(
|
|
|
951
2127
|
estimatedCost: 0
|
|
952
2128
|
// Local models are free
|
|
953
2129
|
},
|
|
954
|
-
model: response.model ?? model
|
|
2130
|
+
model: response.model ?? model,
|
|
2131
|
+
toolCalls
|
|
955
2132
|
};
|
|
956
2133
|
}).pipe(
|
|
957
2134
|
Effect6.retry(retryPolicy),
|
|
958
|
-
Effect6.timeout("
|
|
2135
|
+
Effect6.timeout("120 seconds"),
|
|
959
2136
|
Effect6.catchTag(
|
|
960
2137
|
"TimeoutException",
|
|
961
2138
|
() => Effect6.fail(
|
|
962
2139
|
new LLMTimeoutError({
|
|
963
2140
|
message: "Local LLM request timed out",
|
|
964
2141
|
provider: "ollama",
|
|
965
|
-
timeoutMs:
|
|
2142
|
+
timeoutMs: 12e4
|
|
966
2143
|
})
|
|
967
2144
|
)
|
|
968
2145
|
)
|
|
@@ -972,54 +2149,46 @@ var LocalProviderLive = Layer5.effect(
|
|
|
972
2149
|
return Stream3.async((emit) => {
|
|
973
2150
|
const doStream = async () => {
|
|
974
2151
|
try {
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
model,
|
|
980
|
-
messages: toOllamaMessages(request.messages),
|
|
981
|
-
stream: true,
|
|
982
|
-
options: {
|
|
983
|
-
temperature: request.temperature ?? config.defaultTemperature,
|
|
984
|
-
num_predict: request.maxTokens ?? config.defaultMaxTokens
|
|
985
|
-
}
|
|
986
|
-
})
|
|
987
|
-
});
|
|
988
|
-
if (!res.ok || !res.body) {
|
|
989
|
-
throw new Error(`Ollama stream failed: ${res.status}`);
|
|
2152
|
+
const client = await getClient();
|
|
2153
|
+
const msgs = toOllamaMessages(request.messages);
|
|
2154
|
+
if (request.systemPrompt) {
|
|
2155
|
+
msgs.unshift({ role: "system", content: request.systemPrompt });
|
|
990
2156
|
}
|
|
991
|
-
const
|
|
992
|
-
|
|
2157
|
+
const stream = await client.chat({
|
|
2158
|
+
model,
|
|
2159
|
+
messages: msgs,
|
|
2160
|
+
tools: toOllamaTools(request.tools),
|
|
2161
|
+
stream: true,
|
|
2162
|
+
keep_alive: "5m",
|
|
2163
|
+
options: {
|
|
2164
|
+
temperature: request.temperature ?? config.defaultTemperature,
|
|
2165
|
+
num_predict: request.maxTokens ?? config.defaultMaxTokens
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
993
2168
|
let fullContent = "";
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
totalTokens: (parsed.prompt_eval_count ?? 0) + (parsed.eval_count ?? 0),
|
|
1018
|
-
estimatedCost: 0
|
|
1019
|
-
}
|
|
1020
|
-
});
|
|
1021
|
-
emit.end();
|
|
1022
|
-
}
|
|
2169
|
+
for await (const chunk of stream) {
|
|
2170
|
+
if (chunk.message?.content) {
|
|
2171
|
+
fullContent += chunk.message.content;
|
|
2172
|
+
emit.single({
|
|
2173
|
+
type: "text_delta",
|
|
2174
|
+
text: chunk.message.content
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2177
|
+
if (chunk.done) {
|
|
2178
|
+
emit.single({
|
|
2179
|
+
type: "content_complete",
|
|
2180
|
+
content: fullContent
|
|
2181
|
+
});
|
|
2182
|
+
emit.single({
|
|
2183
|
+
type: "usage",
|
|
2184
|
+
usage: {
|
|
2185
|
+
inputTokens: chunk.prompt_eval_count ?? 0,
|
|
2186
|
+
outputTokens: chunk.eval_count ?? 0,
|
|
2187
|
+
totalTokens: (chunk.prompt_eval_count ?? 0) + (chunk.eval_count ?? 0),
|
|
2188
|
+
estimatedCost: 0
|
|
2189
|
+
}
|
|
2190
|
+
});
|
|
2191
|
+
emit.end();
|
|
1023
2192
|
}
|
|
1024
2193
|
}
|
|
1025
2194
|
} catch (error) {
|
|
@@ -1042,79 +2211,68 @@ var LocalProviderLive = Layer5.effect(
|
|
|
1042
2211
|
null,
|
|
1043
2212
|
2
|
|
1044
2213
|
);
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
2214
|
+
const model = typeof request.model === "string" ? request.model : request.model?.model ?? defaultModel;
|
|
2215
|
+
let lastError = null;
|
|
2216
|
+
const maxRetries = request.maxParseRetries ?? 2;
|
|
2217
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
2218
|
+
const msgs = toOllamaMessages(
|
|
2219
|
+
attempt === 0 ? [
|
|
2220
|
+
...request.messages,
|
|
2221
|
+
{
|
|
2222
|
+
role: "user",
|
|
2223
|
+
content: `
|
|
2224
|
+
Respond with ONLY valid JSON matching this schema:
|
|
2225
|
+
${schemaStr}
|
|
2226
|
+
|
|
2227
|
+
No markdown, no code fences, just raw JSON.`
|
|
2228
|
+
}
|
|
2229
|
+
] : [
|
|
2230
|
+
...request.messages,
|
|
2231
|
+
{
|
|
2232
|
+
role: "user",
|
|
2233
|
+
content: `
|
|
1050
2234
|
Respond with ONLY valid JSON matching this schema:
|
|
1051
2235
|
${schemaStr}
|
|
1052
2236
|
|
|
1053
2237
|
No markdown, no code fences, just raw JSON.`
|
|
1054
|
-
}
|
|
1055
|
-
];
|
|
1056
|
-
let lastError = null;
|
|
1057
|
-
const maxRetries = request.maxParseRetries ?? 2;
|
|
1058
|
-
const llm = {
|
|
1059
|
-
complete: (req) => Effect6.gen(function* () {
|
|
1060
|
-
const model = req.model?.model ?? defaultModel;
|
|
1061
|
-
const res = yield* Effect6.tryPromise({
|
|
1062
|
-
try: async () => {
|
|
1063
|
-
const resp = await fetch(`${endpoint}/api/chat`, {
|
|
1064
|
-
method: "POST",
|
|
1065
|
-
headers: { "Content-Type": "application/json" },
|
|
1066
|
-
body: JSON.stringify({
|
|
1067
|
-
model,
|
|
1068
|
-
messages: toOllamaMessages(req.messages),
|
|
1069
|
-
stream: false,
|
|
1070
|
-
options: {
|
|
1071
|
-
temperature: req.temperature ?? config.defaultTemperature,
|
|
1072
|
-
num_predict: req.maxTokens ?? config.defaultMaxTokens
|
|
1073
|
-
}
|
|
1074
|
-
})
|
|
1075
|
-
});
|
|
1076
|
-
return await resp.json();
|
|
1077
2238
|
},
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
cause: error
|
|
1082
|
-
})
|
|
1083
|
-
});
|
|
1084
|
-
const content = res.message?.content ?? "";
|
|
1085
|
-
const inputTokens = res.prompt_eval_count ?? 0;
|
|
1086
|
-
const outputTokens = res.eval_count ?? 0;
|
|
1087
|
-
return {
|
|
1088
|
-
content,
|
|
1089
|
-
stopReason: "end_turn",
|
|
1090
|
-
usage: {
|
|
1091
|
-
inputTokens,
|
|
1092
|
-
outputTokens,
|
|
1093
|
-
totalTokens: inputTokens + outputTokens,
|
|
1094
|
-
estimatedCost: 0
|
|
2239
|
+
{
|
|
2240
|
+
role: "assistant",
|
|
2241
|
+
content: String(lastError)
|
|
1095
2242
|
},
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
{
|
|
1104
|
-
|
|
1105
|
-
|
|
2243
|
+
{
|
|
2244
|
+
role: "user",
|
|
2245
|
+
content: `That response was not valid JSON. The parse error was: ${String(lastError)}. Please try again with valid JSON only.`
|
|
2246
|
+
}
|
|
2247
|
+
]
|
|
2248
|
+
);
|
|
2249
|
+
if (request.systemPrompt) {
|
|
2250
|
+
msgs.unshift({ role: "system", content: request.systemPrompt });
|
|
2251
|
+
}
|
|
2252
|
+
const response = yield* Effect6.tryPromise({
|
|
2253
|
+
try: async () => {
|
|
2254
|
+
const client = await getClient();
|
|
2255
|
+
return client.chat({
|
|
2256
|
+
model,
|
|
2257
|
+
messages: msgs,
|
|
2258
|
+
stream: false,
|
|
2259
|
+
format: "json",
|
|
2260
|
+
keep_alive: "5m",
|
|
2261
|
+
options: {
|
|
2262
|
+
temperature: request.temperature ?? config.defaultTemperature,
|
|
2263
|
+
num_predict: request.maxTokens ?? config.defaultMaxTokens
|
|
2264
|
+
}
|
|
2265
|
+
});
|
|
1106
2266
|
},
|
|
1107
|
-
{
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
const response = yield* llm.complete({
|
|
1113
|
-
...request,
|
|
1114
|
-
messages: msgs
|
|
2267
|
+
catch: (error) => new LLMError({
|
|
2268
|
+
message: `Ollama request failed: ${error}`,
|
|
2269
|
+
provider: "ollama",
|
|
2270
|
+
cause: error
|
|
2271
|
+
})
|
|
1115
2272
|
});
|
|
2273
|
+
const content = response.message?.content ?? "";
|
|
1116
2274
|
try {
|
|
1117
|
-
const parsed = JSON.parse(
|
|
2275
|
+
const parsed = JSON.parse(content);
|
|
1118
2276
|
const decoded = Schema4.decodeUnknownEither(
|
|
1119
2277
|
request.outputSchema
|
|
1120
2278
|
)(parsed);
|
|
@@ -1136,21 +2294,13 @@ No markdown, no code fences, just raw JSON.`
|
|
|
1136
2294
|
}),
|
|
1137
2295
|
embed: (texts, model) => Effect6.tryPromise({
|
|
1138
2296
|
try: async () => {
|
|
2297
|
+
const client = await getClient();
|
|
1139
2298
|
const embeddingModel = model ?? config.embeddingConfig.model ?? "nomic-embed-text";
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
body: JSON.stringify({
|
|
1146
|
-
model: embeddingModel,
|
|
1147
|
-
input: text
|
|
1148
|
-
})
|
|
1149
|
-
});
|
|
1150
|
-
const data = await res.json();
|
|
1151
|
-
return data.embeddings[0];
|
|
1152
|
-
})
|
|
1153
|
-
);
|
|
2299
|
+
const response = await client.embed({
|
|
2300
|
+
model: embeddingModel,
|
|
2301
|
+
input: [...texts]
|
|
2302
|
+
});
|
|
2303
|
+
return response.embeddings;
|
|
1154
2304
|
},
|
|
1155
2305
|
catch: (error) => new LLMError({
|
|
1156
2306
|
message: `Embedding failed: ${error}`,
|
|
@@ -1622,14 +2772,14 @@ var ComplexityAnalysisSchema = Schema7.Struct({
|
|
|
1622
2772
|
|
|
1623
2773
|
// src/runtime.ts
|
|
1624
2774
|
import { Layer as Layer8 } from "effect";
|
|
1625
|
-
var createLLMProviderLayer = (provider = "anthropic", testResponses) => {
|
|
2775
|
+
var createLLMProviderLayer = (provider = "anthropic", testResponses, model) => {
|
|
1626
2776
|
if (provider === "test") {
|
|
1627
2777
|
return Layer8.mergeAll(
|
|
1628
2778
|
TestLLMServiceLayer(testResponses ?? {}),
|
|
1629
2779
|
PromptManagerLive
|
|
1630
2780
|
);
|
|
1631
2781
|
}
|
|
1632
|
-
const configLayer = LLMConfigFromEnv;
|
|
2782
|
+
const configLayer = model ? Layer8.succeed(LLMConfig, LLMConfig.of({ ...llmConfigFromEnv, defaultModel: model })) : LLMConfigFromEnv;
|
|
1633
2783
|
const providerLayer = provider === "anthropic" ? AnthropicProviderLive : provider === "openai" ? OpenAIProviderLive : provider === "gemini" ? GeminiProviderLive : LocalProviderLive;
|
|
1634
2784
|
return Layer8.mergeAll(
|
|
1635
2785
|
providerLayer.pipe(Layer8.provide(configLayer)),
|
|
@@ -1687,6 +2837,7 @@ export {
|
|
|
1687
2837
|
createLLMProviderLayer,
|
|
1688
2838
|
createLLMProviderLayerWithConfig,
|
|
1689
2839
|
estimateTokenCount,
|
|
2840
|
+
llmConfigFromEnv,
|
|
1690
2841
|
makeCacheable,
|
|
1691
2842
|
retryPolicy
|
|
1692
2843
|
};
|