@nemesis-oss/ollama-sdk 1.0.0 → 1.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/CHANGELOG.md +154 -0
- package/README.md +402 -11
- package/dist/{compose-DC11aDJn.d.cts → compose-CDWq8oxJ.d.cts} +80 -4
- package/dist/{compose-DC11aDJn.d.ts → compose-CDWq8oxJ.d.ts} +80 -4
- package/dist/index.cjs +504 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +448 -13
- package/dist/index.d.ts +448 -13
- package/dist/index.js +498 -71
- package/dist/index.js.map +1 -1
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +2 -2
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
// src/config.ts
|
|
4
4
|
var DEFAULT_BASE_URL = "http://localhost:11434";
|
|
5
5
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
6
|
+
var OLLAMA_CLOUD_BASE_URL = "https://ollama.com";
|
|
6
7
|
function readEnv(name) {
|
|
7
8
|
return typeof process !== "undefined" && process.env ? process.env[name] : void 0;
|
|
8
9
|
}
|
|
@@ -12,6 +13,34 @@ function resolveBaseUrl(configBaseUrl) {
|
|
|
12
13
|
function resolveApiKey(configApiKey) {
|
|
13
14
|
return configApiKey ?? readEnv("OLLAMA_API_KEY");
|
|
14
15
|
}
|
|
16
|
+
function resolveCredentialEndpoints(config) {
|
|
17
|
+
if (config.credentials === void 0) return [];
|
|
18
|
+
const modelsByCredential = /* @__PURE__ */ new Map();
|
|
19
|
+
for (const [model, bound] of Object.entries(config.modelBindings ?? {})) {
|
|
20
|
+
for (const id of typeof bound === "string" ? [bound] : bound) {
|
|
21
|
+
if (!(id in config.credentials)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`modelBindings["${model}"] references unknown credential "${id}" \u2014 it isn't in \`credentials\`. Known credentials: ${Object.keys(config.credentials).join(", ") || "(none)"}.`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const list = modelsByCredential.get(id) ?? [];
|
|
27
|
+
list.push(model);
|
|
28
|
+
modelsByCredential.set(id, list);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Object.entries(config.credentials).map(([id, credential]) => {
|
|
32
|
+
const isDefault = id === config.defaultCredential;
|
|
33
|
+
const boundModels = isDefault ? void 0 : modelsByCredential.get(id);
|
|
34
|
+
return {
|
|
35
|
+
name: `credential:${id}`,
|
|
36
|
+
baseUrl: resolveBaseUrl(credential.baseUrl ?? config.baseUrl),
|
|
37
|
+
apiKey: credential.apiKey,
|
|
38
|
+
...credential.headers !== void 0 ? { headers: credential.headers } : {},
|
|
39
|
+
...boundModels !== void 0 ? { models: boundModels } : {},
|
|
40
|
+
priority: isDefault ? -1 : 0
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
15
44
|
var DEFAULT_FAILOVER_CODES = [
|
|
16
45
|
"network_error",
|
|
17
46
|
"timeout",
|
|
@@ -70,6 +99,15 @@ var OllamaRateLimitError = class extends OllamaClientError {
|
|
|
70
99
|
this.retryAfterMs = options?.retryAfterMs;
|
|
71
100
|
}
|
|
72
101
|
};
|
|
102
|
+
var OllamaQuotaExceededError = class extends OllamaClientError {
|
|
103
|
+
windowId;
|
|
104
|
+
resetAt;
|
|
105
|
+
constructor(message, options) {
|
|
106
|
+
super(message, { ...options, code: "quota_exceeded", retryable: false });
|
|
107
|
+
this.windowId = options.windowId;
|
|
108
|
+
this.resetAt = options.resetAt;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
73
111
|
var OllamaServerError = class extends OllamaClientError {
|
|
74
112
|
constructor(message, options) {
|
|
75
113
|
super(message, { ...options, code: "server_error", retryable: true });
|
|
@@ -105,6 +143,15 @@ var OllamaUnsupportedCapabilityError = class extends OllamaClientError {
|
|
|
105
143
|
this.capability = options.capability;
|
|
106
144
|
}
|
|
107
145
|
};
|
|
146
|
+
var OllamaModelRoutingError = class extends OllamaClientError {
|
|
147
|
+
model;
|
|
148
|
+
availableModels;
|
|
149
|
+
constructor(message, options) {
|
|
150
|
+
super(message, { ...options, code: "model_routing_error", retryable: false });
|
|
151
|
+
this.model = options.model;
|
|
152
|
+
this.availableModels = options.availableModels;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
108
155
|
var OllamaAgentMaxIterationsError = class extends OllamaClientError {
|
|
109
156
|
maxIterations;
|
|
110
157
|
constructor(message, options) {
|
|
@@ -216,17 +263,143 @@ var EndpointRegistry = class {
|
|
|
216
263
|
failureThreshold;
|
|
217
264
|
cooldownMs;
|
|
218
265
|
now;
|
|
266
|
+
strategy;
|
|
267
|
+
roundRobinCounter = 0;
|
|
268
|
+
activeCounts = /* @__PURE__ */ new Map();
|
|
269
|
+
maxConcurrentPerEndpoint;
|
|
270
|
+
waiters = [];
|
|
219
271
|
constructor(endpoints, options = {}) {
|
|
220
272
|
this.endpoints = endpoints.length > 0 ? endpoints : [{ name: "default", baseUrl: "http://localhost:11434" }];
|
|
221
273
|
this.failureThreshold = options.failureThreshold ?? 3;
|
|
222
274
|
this.cooldownMs = options.cooldownMs ?? 3e4;
|
|
223
275
|
this.now = options.now ?? Date.now;
|
|
276
|
+
this.strategy = options.strategy ?? "priority";
|
|
277
|
+
this.maxConcurrentPerEndpoint = options.maxConcurrentPerEndpoint;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Marks one more request as in-flight against `name`. Callers (`OllamaClient`) must
|
|
281
|
+
* pair every `acquire` with a `release` once that attempt finishes, success or not —
|
|
282
|
+
* see `OllamaClient.executeWithFailover`. Only affects candidate ordering when
|
|
283
|
+
* `strategy` is `'least-connections'`; harmless (just bookkeeping) otherwise, and
|
|
284
|
+
* always reflected in `status()`'s `activeRequests`.
|
|
285
|
+
*/
|
|
286
|
+
acquire(name) {
|
|
287
|
+
this.activeCounts.set(name, (this.activeCounts.get(name) ?? 0) + 1);
|
|
288
|
+
}
|
|
289
|
+
/** Releases one in-flight request marked via `acquire`, waking one waiter for `name` if any. */
|
|
290
|
+
release(name) {
|
|
291
|
+
const next = (this.activeCounts.get(name) ?? 0) - 1;
|
|
292
|
+
if (next <= 0) {
|
|
293
|
+
this.activeCounts.delete(name);
|
|
294
|
+
} else {
|
|
295
|
+
this.activeCounts.set(name, next);
|
|
296
|
+
}
|
|
297
|
+
const idx = this.waiters.findIndex((w) => w.names.includes(name));
|
|
298
|
+
if (idx !== -1) {
|
|
299
|
+
const [waiter] = this.waiters.splice(idx, 1);
|
|
300
|
+
waiter?.cleanup();
|
|
301
|
+
waiter?.resolve();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* `candidates` filtered down to those currently under `maxConcurrentPerEndpoint` (all
|
|
306
|
+
* of them, unchanged, if that option is unset).
|
|
307
|
+
*/
|
|
308
|
+
filterWithCapacity(candidates) {
|
|
309
|
+
const cap = this.maxConcurrentPerEndpoint;
|
|
310
|
+
if (cap === void 0) return [...candidates];
|
|
311
|
+
return candidates.filter((ep) => (this.activeCounts.get(ep.name) ?? 0) < cap);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Resolves once any endpoint named in `names` has spare capacity under
|
|
315
|
+
* `maxConcurrentPerEndpoint` (a no-op resolve if that option is unset, or if one
|
|
316
|
+
* already does). Otherwise queues (FIFO per name) until a matching `release()` frees a
|
|
317
|
+
* slot, or rejects if `signal` aborts first — mirroring whatever aborted it
|
|
318
|
+
* (`OllamaTimeoutError`/the caller's own abort reason) so callers see the same error
|
|
319
|
+
* shape as any other in-flight request that times out or is cancelled. FIFO order is
|
|
320
|
+
* best-effort (a newly-arriving request can still win a race for a slot that just
|
|
321
|
+
* freed) — the capacity cap itself, not fairness, is the guarantee this exists for.
|
|
322
|
+
*/
|
|
323
|
+
waitForCapacity(names, signal) {
|
|
324
|
+
const cap = this.maxConcurrentPerEndpoint;
|
|
325
|
+
if (cap === void 0) return Promise.resolve();
|
|
326
|
+
if (names.some((n) => (this.activeCounts.get(n) ?? 0) < cap)) return Promise.resolve();
|
|
327
|
+
return new Promise((resolve, reject) => {
|
|
328
|
+
const waiter = { names, resolve, cleanup: () => void 0 };
|
|
329
|
+
const onAbort = () => {
|
|
330
|
+
const idx = this.waiters.indexOf(waiter);
|
|
331
|
+
if (idx !== -1) this.waiters.splice(idx, 1);
|
|
332
|
+
reject(
|
|
333
|
+
signal?.reason instanceof Error ? signal.reason : new OllamaAbortError("Aborted while waiting for endpoint capacity")
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
if (signal !== void 0) {
|
|
337
|
+
if (signal.aborted) {
|
|
338
|
+
onAbort();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
342
|
+
waiter.cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
343
|
+
}
|
|
344
|
+
this.waiters.push(waiter);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Rotates each same-`priority` group in `sorted` (already sorted highest-priority-first)
|
|
349
|
+
* by one position further per call, wrapping around within the group. Priority tiers
|
|
350
|
+
* themselves are never reordered — only candidates that were already tied.
|
|
351
|
+
*/
|
|
352
|
+
applyRoundRobin(sorted) {
|
|
353
|
+
const offset = this.roundRobinCounter++;
|
|
354
|
+
const result = [];
|
|
355
|
+
let i = 0;
|
|
356
|
+
while (i < sorted.length) {
|
|
357
|
+
const priority = sorted[i]?.priority ?? 0;
|
|
358
|
+
let j = i + 1;
|
|
359
|
+
while (j < sorted.length && (sorted[j]?.priority ?? 0) === priority) j++;
|
|
360
|
+
const tier = sorted.slice(i, j);
|
|
361
|
+
const rotation = offset % tier.length;
|
|
362
|
+
result.push(...tier.slice(rotation), ...tier.slice(0, rotation));
|
|
363
|
+
i = j;
|
|
364
|
+
}
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Reorders each same-`priority` group in `sorted` by ascending in-flight request count
|
|
369
|
+
* (from `acquire`/`release`); a stable sort, so candidates tied on active count keep
|
|
370
|
+
* their relative (priority-then-registration) order. Priority tiers themselves are
|
|
371
|
+
* never reordered.
|
|
372
|
+
*/
|
|
373
|
+
applyLeastConnections(sorted) {
|
|
374
|
+
const result = [];
|
|
375
|
+
let i = 0;
|
|
376
|
+
while (i < sorted.length) {
|
|
377
|
+
const priority = sorted[i]?.priority ?? 0;
|
|
378
|
+
let j = i + 1;
|
|
379
|
+
while (j < sorted.length && (sorted[j]?.priority ?? 0) === priority) j++;
|
|
380
|
+
const tier = [...sorted.slice(i, j)].sort(
|
|
381
|
+
(a, b) => (this.activeCounts.get(a.name) ?? 0) - (this.activeCounts.get(b.name) ?? 0)
|
|
382
|
+
);
|
|
383
|
+
result.push(...tier);
|
|
384
|
+
i = j;
|
|
385
|
+
}
|
|
386
|
+
return result;
|
|
224
387
|
}
|
|
225
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Endpoints eligible for `model`, sorted healthy-first-by-priority (falling back to
|
|
390
|
+
* soonest-to-recover if every eligible endpoint is cooling down); same-priority
|
|
391
|
+
* candidates are further reordered per `options.strategy` (see
|
|
392
|
+
* `EndpointRegistryOptions.strategy`). When `model` is given, endpoints whose `models`
|
|
393
|
+
* allow-list doesn't include it are excluded entirely — see `OllamaEndpoint.models`.
|
|
394
|
+
* Omit `model` to consider every configured endpoint, regardless of any `models`
|
|
395
|
+
* restriction (used for non-model-scoped operations).
|
|
396
|
+
*/
|
|
397
|
+
candidates(model) {
|
|
226
398
|
const currentTime = this.now();
|
|
399
|
+
const scoped = model === void 0 ? this.endpoints : this.endpoints.filter((ep) => ep.models === void 0 || ep.models.includes(model));
|
|
227
400
|
const healthy = [];
|
|
228
401
|
const coolingDown = [];
|
|
229
|
-
for (const ep of
|
|
402
|
+
for (const ep of scoped) {
|
|
230
403
|
const failures = this.failureCounts.get(ep.name) ?? 0;
|
|
231
404
|
const lastFail = this.lastFailures.get(ep.name) ?? 0;
|
|
232
405
|
const isCooling = failures >= this.failureThreshold && currentTime - lastFail < this.cooldownMs;
|
|
@@ -237,7 +410,10 @@ var EndpointRegistry = class {
|
|
|
237
410
|
}
|
|
238
411
|
}
|
|
239
412
|
if (healthy.length > 0) {
|
|
240
|
-
|
|
413
|
+
const sorted = healthy.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
414
|
+
if (this.strategy === "round-robin") return this.applyRoundRobin(sorted);
|
|
415
|
+
if (this.strategy === "least-connections") return this.applyLeastConnections(sorted);
|
|
416
|
+
return sorted;
|
|
241
417
|
}
|
|
242
418
|
return coolingDown.sort((a, b) => a.recoveredAt - b.recoveredAt).map((c) => c.endpoint);
|
|
243
419
|
}
|
|
@@ -253,6 +429,10 @@ var EndpointRegistry = class {
|
|
|
253
429
|
list() {
|
|
254
430
|
return this.endpoints;
|
|
255
431
|
}
|
|
432
|
+
/** True if any configured endpoint restricts itself to a `models` allow-list. */
|
|
433
|
+
hasModelScopedEndpoints() {
|
|
434
|
+
return this.endpoints.some((ep) => ep.models !== void 0);
|
|
435
|
+
}
|
|
256
436
|
status() {
|
|
257
437
|
const currentTime = this.now();
|
|
258
438
|
return this.endpoints.map((ep) => {
|
|
@@ -263,7 +443,8 @@ var EndpointRegistry = class {
|
|
|
263
443
|
endpoint: ep,
|
|
264
444
|
failureCount: failures,
|
|
265
445
|
...lastFail !== void 0 ? { lastFailureTimestamp: lastFail } : {},
|
|
266
|
-
isCoolingDown
|
|
446
|
+
isCoolingDown,
|
|
447
|
+
activeRequests: this.activeCounts.get(ep.name) ?? 0
|
|
267
448
|
};
|
|
268
449
|
});
|
|
269
450
|
}
|
|
@@ -820,6 +1001,7 @@ function aggregateChat(accumulated, chunk) {
|
|
|
820
1001
|
},
|
|
821
1002
|
model: chunk.model,
|
|
822
1003
|
done: chunk.done,
|
|
1004
|
+
doneReason: chunk.done ? chunk.done_reason : accumulated.doneReason,
|
|
823
1005
|
totalDurationMs: chunk.done && chunk.total_duration !== void 0 ? chunk.total_duration / NANOS_PER_MS : accumulated.totalDurationMs,
|
|
824
1006
|
usage: chunk.done ? extractUsage(chunk) : accumulated.usage,
|
|
825
1007
|
raw: chunk
|
|
@@ -869,6 +1051,7 @@ function aggregateGenerate(accumulated, chunk) {
|
|
|
869
1051
|
response: accumulated.response + (chunk.response ?? ""),
|
|
870
1052
|
model: chunk.model,
|
|
871
1053
|
done: chunk.done,
|
|
1054
|
+
doneReason: chunk.done ? chunk.done_reason : accumulated.doneReason,
|
|
872
1055
|
totalDurationMs: chunk.done && chunk.total_duration !== void 0 ? chunk.total_duration / NANOS_PER_MS : accumulated.totalDurationMs,
|
|
873
1056
|
usage: chunk.done ? extractUsage(chunk) : accumulated.usage,
|
|
874
1057
|
raw: chunk
|
|
@@ -1020,7 +1203,7 @@ var ModelsClient = class {
|
|
|
1020
1203
|
});
|
|
1021
1204
|
return normalizeProgressStream(stream);
|
|
1022
1205
|
},
|
|
1023
|
-
{ ...request, singleEndpoint: true }
|
|
1206
|
+
{ ...request, singleEndpoint: true, holdUntil: (stream) => stream.finalResult }
|
|
1024
1207
|
);
|
|
1025
1208
|
}
|
|
1026
1209
|
return this.runner(
|
|
@@ -1043,7 +1226,7 @@ var ModelsClient = class {
|
|
|
1043
1226
|
});
|
|
1044
1227
|
return normalizeProgressStream(stream);
|
|
1045
1228
|
},
|
|
1046
|
-
{ ...request, singleEndpoint: true }
|
|
1229
|
+
{ ...request, singleEndpoint: true, holdUntil: (stream) => stream.finalResult }
|
|
1047
1230
|
);
|
|
1048
1231
|
}
|
|
1049
1232
|
return this.runner(
|
|
@@ -1066,7 +1249,7 @@ var ModelsClient = class {
|
|
|
1066
1249
|
});
|
|
1067
1250
|
return normalizeProgressStream(stream);
|
|
1068
1251
|
},
|
|
1069
|
-
{ ...request, singleEndpoint: true }
|
|
1252
|
+
{ ...request, singleEndpoint: true, holdUntil: (stream) => stream.finalResult }
|
|
1070
1253
|
);
|
|
1071
1254
|
}
|
|
1072
1255
|
return this.runner(
|
|
@@ -1157,6 +1340,16 @@ var OpenAICompatClient = class {
|
|
|
1157
1340
|
signal
|
|
1158
1341
|
});
|
|
1159
1342
|
}
|
|
1343
|
+
async createResponses(request, signal) {
|
|
1344
|
+
return this.http.request({
|
|
1345
|
+
path: "/v1/responses",
|
|
1346
|
+
body: request,
|
|
1347
|
+
signal
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
async responses(request, signal) {
|
|
1351
|
+
return this.createResponses(request, signal);
|
|
1352
|
+
}
|
|
1160
1353
|
};
|
|
1161
1354
|
|
|
1162
1355
|
// src/integrations/anthropic.ts
|
|
@@ -1177,6 +1370,32 @@ var AnthropicCompatClient = class {
|
|
|
1177
1370
|
}
|
|
1178
1371
|
};
|
|
1179
1372
|
|
|
1373
|
+
// src/utils.ts
|
|
1374
|
+
async function encodeImage(image) {
|
|
1375
|
+
if (typeof image === "string") return image;
|
|
1376
|
+
const bufferCtor = globalThis.Buffer;
|
|
1377
|
+
if (bufferCtor !== void 0) return bufferCtor.from(image).toString("base64");
|
|
1378
|
+
const CHUNK_SIZE = 32768;
|
|
1379
|
+
let binary = "";
|
|
1380
|
+
for (let i = 0; i < image.length; i += CHUNK_SIZE) {
|
|
1381
|
+
binary += String.fromCharCode(...image.subarray(i, i + CHUNK_SIZE));
|
|
1382
|
+
}
|
|
1383
|
+
return btoa(binary);
|
|
1384
|
+
}
|
|
1385
|
+
async function encodeImages(images) {
|
|
1386
|
+
if (images === void 0) return void 0;
|
|
1387
|
+
return Promise.all(images.map((image) => encodeImage(image)));
|
|
1388
|
+
}
|
|
1389
|
+
async function withEncodedImages(req) {
|
|
1390
|
+
if (!req.images?.some((image) => image instanceof Uint8Array)) return req;
|
|
1391
|
+
return { ...req, images: await encodeImages(req.images) };
|
|
1392
|
+
}
|
|
1393
|
+
async function withEncodedMessageImages(messages) {
|
|
1394
|
+
if (!messages.some((message) => message.images?.some((image) => image instanceof Uint8Array)))
|
|
1395
|
+
return messages;
|
|
1396
|
+
return Promise.all(messages.map((message) => withEncodedImages(message)));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1180
1399
|
// src/client.ts
|
|
1181
1400
|
var OllamaClient = class {
|
|
1182
1401
|
registry;
|
|
@@ -1186,17 +1405,27 @@ var OllamaClient = class {
|
|
|
1186
1405
|
failoverCodes;
|
|
1187
1406
|
fetchImpl;
|
|
1188
1407
|
logger;
|
|
1408
|
+
/**
|
|
1409
|
+
* API key for Ollama's hosted web tools (`webSearch`/`webFetch`), which always target
|
|
1410
|
+
* `OLLAMA_CLOUD_BASE_URL` regardless of `config.endpoints` — an Ollama account API key
|
|
1411
|
+
* is inherently a single global credential, not tied to any one inference endpoint.
|
|
1412
|
+
* Resolved the same way as a single-endpoint `apiKey` (`config.apiKey` falling back to
|
|
1413
|
+
* `OLLAMA_API_KEY`), independent of whether `config.endpoints` was used instead.
|
|
1414
|
+
*/
|
|
1415
|
+
cloudApiKey;
|
|
1189
1416
|
constructor(config = {}) {
|
|
1190
1417
|
const resolvedApiKey = resolveApiKey(config.apiKey);
|
|
1191
|
-
|
|
1418
|
+
this.cloudApiKey = resolvedApiKey;
|
|
1419
|
+
const credentialEndpoints = resolveCredentialEndpoints(config);
|
|
1420
|
+
const endpoints = config.endpoints ?? (credentialEndpoints.length > 0 ? [] : [
|
|
1192
1421
|
{
|
|
1193
1422
|
name: "default",
|
|
1194
1423
|
baseUrl: resolveBaseUrl(config.baseUrl),
|
|
1195
1424
|
...resolvedApiKey !== void 0 ? { apiKey: resolvedApiKey } : {},
|
|
1196
1425
|
...config.headers !== void 0 ? { headers: config.headers } : {}
|
|
1197
1426
|
}
|
|
1198
|
-
];
|
|
1199
|
-
this.registry = new EndpointRegistry(endpoints, config.endpointHealth);
|
|
1427
|
+
]);
|
|
1428
|
+
this.registry = new EndpointRegistry([...endpoints, ...credentialEndpoints], config.endpointHealth);
|
|
1200
1429
|
this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1201
1430
|
this.failoverCodes = new Set(config.failoverOn ?? DEFAULT_FAILOVER_CODES);
|
|
1202
1431
|
this.fetchImpl = config.fetch ?? globalThis.fetch;
|
|
@@ -1225,53 +1454,92 @@ var OllamaClient = class {
|
|
|
1225
1454
|
async executeWithFailover(operation, options) {
|
|
1226
1455
|
const timeout = createTimeoutSignal(options?.timeoutMs ?? this.timeoutMs, options?.signal);
|
|
1227
1456
|
try {
|
|
1228
|
-
const allCandidates = this.registry.candidates();
|
|
1229
|
-
const candidates = options?.singleEndpoint ? allCandidates.slice(0, 1) : allCandidates;
|
|
1230
1457
|
let lastError;
|
|
1231
|
-
for (
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
});
|
|
1239
|
-
try {
|
|
1240
|
-
const result = await withSpan(
|
|
1241
|
-
"ollama.endpoint.attempt",
|
|
1242
|
-
{
|
|
1243
|
-
[ATTR_OLLAMA_ENDPOINT_NAME]: endpoint.name,
|
|
1244
|
-
[ATTR_OLLAMA_ENDPOINT_ATTEMPT]: attemptIndex
|
|
1245
|
-
},
|
|
1246
|
-
() => withRetry(() => operation(http, timeout.signal), this.retryConfig)
|
|
1458
|
+
for (; ; ) {
|
|
1459
|
+
const allCandidates = this.registry.candidates(options?.model);
|
|
1460
|
+
if (allCandidates.length === 0 && options?.model !== void 0 && this.registry.hasModelScopedEndpoints()) {
|
|
1461
|
+
const configured = this.registry.list().flatMap((ep) => ep.models ?? []).filter((m, i, arr) => arr.indexOf(m) === i);
|
|
1462
|
+
throw new OllamaModelRoutingError(
|
|
1463
|
+
`No configured endpoint is authorized for model "${options.model}". ` + (configured.length > 0 ? `Endpoints are scoped to: ${configured.join(", ")}.` : "No endpoint declares a `models` allow-list that includes it.") + " Add or widen an `OllamaEndpoint.models` entry to route this model.",
|
|
1464
|
+
{ model: options.model, availableModels: configured }
|
|
1247
1465
|
);
|
|
1248
|
-
this.registry.reportSuccess(endpoint.name);
|
|
1249
|
-
return result;
|
|
1250
|
-
} catch (err) {
|
|
1251
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1252
|
-
lastError = error;
|
|
1253
|
-
this.registry.reportFailure(endpoint.name);
|
|
1254
|
-
this.logger.warn(`Failed on "${endpoint.name}": ${error.message}`);
|
|
1255
|
-
if (!(error instanceof OllamaClientError && this.failoverCodes.has(error.code)))
|
|
1256
|
-
throw error;
|
|
1257
1466
|
}
|
|
1467
|
+
const candidates = options?.singleEndpoint ? allCandidates.slice(0, 1) : allCandidates;
|
|
1468
|
+
const runnable = this.registry.filterWithCapacity(candidates);
|
|
1469
|
+
if (runnable.length === 0 && candidates.length > 0) {
|
|
1470
|
+
await this.registry.waitForCapacity(
|
|
1471
|
+
candidates.map((c) => c.name),
|
|
1472
|
+
timeout.signal
|
|
1473
|
+
);
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
for (const [attemptIndex, endpoint] of runnable.entries()) {
|
|
1477
|
+
this.logger.debug(`Executing on endpoint "${endpoint.name}" (${endpoint.baseUrl})`);
|
|
1478
|
+
const http = new HttpClient({
|
|
1479
|
+
baseUrl: endpoint.baseUrl,
|
|
1480
|
+
...endpoint.apiKey !== void 0 ? { apiKey: endpoint.apiKey } : {},
|
|
1481
|
+
...endpoint.headers !== void 0 ? { headers: endpoint.headers } : {},
|
|
1482
|
+
fetch: this.fetchImpl
|
|
1483
|
+
});
|
|
1484
|
+
this.registry.acquire(endpoint.name);
|
|
1485
|
+
let holdPromise;
|
|
1486
|
+
try {
|
|
1487
|
+
const result = await withSpan(
|
|
1488
|
+
"ollama.endpoint.attempt",
|
|
1489
|
+
{
|
|
1490
|
+
[ATTR_OLLAMA_ENDPOINT_NAME]: endpoint.name,
|
|
1491
|
+
[ATTR_OLLAMA_ENDPOINT_ATTEMPT]: attemptIndex
|
|
1492
|
+
},
|
|
1493
|
+
() => withRetry(() => operation(http, timeout.signal), this.retryConfig)
|
|
1494
|
+
);
|
|
1495
|
+
this.registry.reportSuccess(endpoint.name);
|
|
1496
|
+
if (options?.holdUntil) holdPromise = options.holdUntil(result);
|
|
1497
|
+
return result;
|
|
1498
|
+
} catch (err) {
|
|
1499
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1500
|
+
lastError = error;
|
|
1501
|
+
this.registry.reportFailure(endpoint.name);
|
|
1502
|
+
this.logger.warn(`Failed on "${endpoint.name}": ${error.message}`);
|
|
1503
|
+
if (!(error instanceof OllamaClientError && this.failoverCodes.has(error.code)))
|
|
1504
|
+
throw error;
|
|
1505
|
+
} finally {
|
|
1506
|
+
if (holdPromise) {
|
|
1507
|
+
void holdPromise.catch(() => void 0).finally(() => this.registry.release(endpoint.name));
|
|
1508
|
+
} else {
|
|
1509
|
+
this.registry.release(endpoint.name);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
throw lastError ?? new Error("No healthy Ollama endpoints available");
|
|
1258
1514
|
}
|
|
1259
|
-
throw lastError ?? new Error("No healthy Ollama endpoints available");
|
|
1260
1515
|
} finally {
|
|
1261
1516
|
timeout.cancel();
|
|
1262
1517
|
}
|
|
1263
1518
|
}
|
|
1264
1519
|
async chat(req) {
|
|
1520
|
+
const messages = await withEncodedMessageImages(req.messages);
|
|
1265
1521
|
if (req.stream) {
|
|
1266
|
-
return this.executeWithFailover(
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1522
|
+
return this.executeWithFailover(
|
|
1523
|
+
async (http, signal) => {
|
|
1524
|
+
if (req.format !== void 0)
|
|
1525
|
+
this.assertStructuredOutputSupported(http.baseUrl, req.model);
|
|
1526
|
+
const stream = await http.requestStream({
|
|
1527
|
+
path: "/api/chat",
|
|
1528
|
+
body: { ...req, messages, stream: true },
|
|
1529
|
+
signal
|
|
1530
|
+
});
|
|
1531
|
+
return normalizeChatStream(stream);
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
signal: req.signal,
|
|
1535
|
+
timeoutMs: req.timeoutMs,
|
|
1536
|
+
model: req.model,
|
|
1537
|
+
// The endpoint's concurrency slot must stay held for as long as the stream is
|
|
1538
|
+
// actually being consumed, not just until the initial response/headers arrive
|
|
1539
|
+
// — see `executeWithFailover`'s `holdUntil` doc.
|
|
1540
|
+
holdUntil: (stream) => stream.finalResult
|
|
1541
|
+
}
|
|
1542
|
+
);
|
|
1275
1543
|
}
|
|
1276
1544
|
return withSpan(
|
|
1277
1545
|
`chat ${req.model}`,
|
|
@@ -1286,7 +1554,7 @@ var OllamaClient = class {
|
|
|
1286
1554
|
this.assertStructuredOutputSupported(http.baseUrl, req.model);
|
|
1287
1555
|
return http.request({
|
|
1288
1556
|
path: "/api/chat",
|
|
1289
|
-
body: { ...req, stream: false },
|
|
1557
|
+
body: { ...req, messages, stream: false },
|
|
1290
1558
|
signal
|
|
1291
1559
|
});
|
|
1292
1560
|
}, req);
|
|
@@ -1313,34 +1581,44 @@ var OllamaClient = class {
|
|
|
1313
1581
|
return parseStructuredOutput(res.message.content, schema);
|
|
1314
1582
|
}
|
|
1315
1583
|
async generate(req) {
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1584
|
+
const encodedReq = await withEncodedImages(req);
|
|
1585
|
+
if (encodedReq.stream) {
|
|
1586
|
+
return this.executeWithFailover(
|
|
1587
|
+
async (http, signal) => {
|
|
1588
|
+
if (encodedReq.format !== void 0)
|
|
1589
|
+
this.assertStructuredOutputSupported(http.baseUrl, encodedReq.model);
|
|
1590
|
+
const stream = await http.requestStream({
|
|
1591
|
+
path: "/api/generate",
|
|
1592
|
+
body: { ...encodedReq, stream: true },
|
|
1593
|
+
signal
|
|
1594
|
+
});
|
|
1595
|
+
return normalizeGenerateStream(stream);
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
signal: encodedReq.signal,
|
|
1599
|
+
timeoutMs: encodedReq.timeoutMs,
|
|
1600
|
+
model: encodedReq.model,
|
|
1601
|
+
holdUntil: (stream) => stream.finalResult
|
|
1602
|
+
}
|
|
1603
|
+
);
|
|
1326
1604
|
}
|
|
1327
1605
|
return withSpan(
|
|
1328
|
-
`text_completion ${
|
|
1606
|
+
`text_completion ${encodedReq.model}`,
|
|
1329
1607
|
{
|
|
1330
1608
|
[ATTR_GEN_AI_SYSTEM]: GEN_AI_SYSTEM_OLLAMA,
|
|
1331
1609
|
[ATTR_GEN_AI_OPERATION_NAME]: "text_completion",
|
|
1332
|
-
[ATTR_GEN_AI_REQUEST_MODEL]:
|
|
1610
|
+
[ATTR_GEN_AI_REQUEST_MODEL]: encodedReq.model
|
|
1333
1611
|
},
|
|
1334
1612
|
async (span) => {
|
|
1335
1613
|
const res = await this.executeWithFailover((http, signal) => {
|
|
1336
|
-
if (
|
|
1337
|
-
this.assertStructuredOutputSupported(http.baseUrl,
|
|
1614
|
+
if (encodedReq.format !== void 0)
|
|
1615
|
+
this.assertStructuredOutputSupported(http.baseUrl, encodedReq.model);
|
|
1338
1616
|
return http.request({
|
|
1339
1617
|
path: "/api/generate",
|
|
1340
|
-
body: { ...
|
|
1618
|
+
body: { ...encodedReq, stream: false },
|
|
1341
1619
|
signal
|
|
1342
1620
|
});
|
|
1343
|
-
},
|
|
1621
|
+
}, encodedReq);
|
|
1344
1622
|
span?.setAttributes({
|
|
1345
1623
|
[ATTR_GEN_AI_RESPONSE_MODEL]: res.model,
|
|
1346
1624
|
...res.prompt_eval_count !== void 0 ? { [ATTR_GEN_AI_USAGE_INPUT_TOKENS]: res.prompt_eval_count } : {},
|
|
@@ -1396,22 +1674,60 @@ var OllamaClient = class {
|
|
|
1396
1674
|
createBlob = (digest, data) => this.models.createBlob(digest, data);
|
|
1397
1675
|
checkBlob = (digest) => this.models.checkBlob(digest);
|
|
1398
1676
|
// --- Web Endpoints ---
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1677
|
+
/**
|
|
1678
|
+
* Ollama's hosted web search tool (`POST https://ollama.com/api/web_search`) — a fixed
|
|
1679
|
+
* Ollama Cloud service, unrelated to `config.endpoints`/`baseUrl` and not proxied
|
|
1680
|
+
* through a local server. Requires an Ollama account API key: pass `apiKey` to the
|
|
1681
|
+
* client constructor or set `OLLAMA_API_KEY`. Applies the same default `timeoutMs` and
|
|
1682
|
+
* retry policy as inference calls, but never cross-endpoint-fails-over — there is only
|
|
1683
|
+
* ever the one cloud endpoint to call.
|
|
1684
|
+
*/
|
|
1685
|
+
async webSearch(req) {
|
|
1686
|
+
const { count, max_results, ...rest } = req;
|
|
1687
|
+
const res = await this.executeCloudRequest(
|
|
1688
|
+
(http, signal) => http.request({
|
|
1689
|
+
path: "/api/web_search",
|
|
1690
|
+
body: { ...rest, max_results: max_results ?? count },
|
|
1691
|
+
signal
|
|
1692
|
+
}),
|
|
1402
1693
|
req
|
|
1403
1694
|
);
|
|
1695
|
+
return { results: res.results.map((r) => ({ ...r, snippet: r.content })) };
|
|
1404
1696
|
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Ollama's hosted web fetch tool (`POST https://ollama.com/api/web_fetch`) — see
|
|
1699
|
+
* {@link OllamaClient.webSearch} for the cloud-endpoint/auth/timeout/retry behavior,
|
|
1700
|
+
* which applies identically here.
|
|
1701
|
+
*/
|
|
1405
1702
|
webFetch(req) {
|
|
1406
|
-
return this.
|
|
1407
|
-
(http, signal) => http.request({ path: "/api/
|
|
1703
|
+
return this.executeCloudRequest(
|
|
1704
|
+
(http, signal) => http.request({ path: "/api/web_fetch", body: req, signal }),
|
|
1408
1705
|
req
|
|
1409
1706
|
);
|
|
1410
1707
|
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Runs `operation` against the fixed Ollama Cloud host with this client's default
|
|
1710
|
+
* timeout and retry policy — the same primitives `executeWithFailover` uses, minus the
|
|
1711
|
+
* multi-candidate loop, since `webSearch`/`webFetch` only ever have the one endpoint.
|
|
1712
|
+
*/
|
|
1713
|
+
async executeCloudRequest(operation, options) {
|
|
1714
|
+
const timeout = createTimeoutSignal(options.timeoutMs ?? this.timeoutMs, options.signal);
|
|
1715
|
+
try {
|
|
1716
|
+
const http = new HttpClient({
|
|
1717
|
+
baseUrl: OLLAMA_CLOUD_BASE_URL,
|
|
1718
|
+
apiKey: this.cloudApiKey,
|
|
1719
|
+
fetch: this.fetchImpl
|
|
1720
|
+
});
|
|
1721
|
+
return await withRetry(() => operation(http, timeout.signal), this.retryConfig);
|
|
1722
|
+
} finally {
|
|
1723
|
+
timeout.cancel();
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1411
1726
|
// --- Capabilities & Health ---
|
|
1412
1727
|
capabilities(model) {
|
|
1413
1728
|
return this.executeWithFailover((http) => detectModelCapabilities(http, model), {
|
|
1414
|
-
singleEndpoint: true
|
|
1729
|
+
singleEndpoint: true,
|
|
1730
|
+
model
|
|
1415
1731
|
});
|
|
1416
1732
|
}
|
|
1417
1733
|
runtimeMode() {
|
|
@@ -1529,6 +1845,117 @@ function toResponse(stream, init = {}) {
|
|
|
1529
1845
|
return new Response(body, { ...init, headers });
|
|
1530
1846
|
}
|
|
1531
1847
|
|
|
1848
|
+
// src/quota.ts
|
|
1849
|
+
var QuotaManager = class {
|
|
1850
|
+
now;
|
|
1851
|
+
windows;
|
|
1852
|
+
constructor(options) {
|
|
1853
|
+
if (options.windows.length === 0) {
|
|
1854
|
+
throw new Error("QuotaManager requires at least one window configuration.");
|
|
1855
|
+
}
|
|
1856
|
+
this.now = options.now ?? Date.now;
|
|
1857
|
+
this.windows = options.windows.map((config) => ({
|
|
1858
|
+
config,
|
|
1859
|
+
tokensUsed: 0,
|
|
1860
|
+
requestsMade: 0,
|
|
1861
|
+
windowStartedAt: this.now()
|
|
1862
|
+
}));
|
|
1863
|
+
}
|
|
1864
|
+
rollover(state) {
|
|
1865
|
+
if (this.now() - state.windowStartedAt >= state.config.windowMs) {
|
|
1866
|
+
state.tokensUsed = 0;
|
|
1867
|
+
state.requestsMade = 0;
|
|
1868
|
+
state.windowStartedAt = this.now();
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
/** Current usage, budgets, and reset time for every configured window. */
|
|
1872
|
+
status() {
|
|
1873
|
+
return this.windows.map((state) => {
|
|
1874
|
+
this.rollover(state);
|
|
1875
|
+
const { config } = state;
|
|
1876
|
+
return {
|
|
1877
|
+
...config,
|
|
1878
|
+
tokensUsed: state.tokensUsed,
|
|
1879
|
+
requestsMade: state.requestsMade,
|
|
1880
|
+
windowStartedAt: state.windowStartedAt,
|
|
1881
|
+
windowResetAt: state.windowStartedAt + config.windowMs,
|
|
1882
|
+
...config.maxTokens !== void 0 ? { remainingTokens: Math.max(0, config.maxTokens - state.tokensUsed) } : {},
|
|
1883
|
+
...config.maxRequests !== void 0 ? { remainingRequests: Math.max(0, config.maxRequests - state.requestsMade) } : {}
|
|
1884
|
+
};
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* True if one more request — optionally estimated at `estimatedTokens` — would stay
|
|
1889
|
+
* within every configured window's budget. Read-only; does not record usage.
|
|
1890
|
+
*/
|
|
1891
|
+
canProceed(estimatedTokens = 0) {
|
|
1892
|
+
return this.windows.every((state) => {
|
|
1893
|
+
this.rollover(state);
|
|
1894
|
+
const { config } = state;
|
|
1895
|
+
if (config.maxRequests !== void 0 && state.requestsMade + 1 > config.maxRequests) {
|
|
1896
|
+
return false;
|
|
1897
|
+
}
|
|
1898
|
+
return !(config.maxTokens !== void 0 && state.tokensUsed + estimatedTokens > config.maxTokens);
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* Throws `OllamaQuotaExceededError` for the first window that `canProceed(estimatedTokens)`
|
|
1903
|
+
* would fail on; otherwise a no-op. Call before issuing a request.
|
|
1904
|
+
*/
|
|
1905
|
+
assertCanProceed(estimatedTokens = 0) {
|
|
1906
|
+
for (const state of this.windows) {
|
|
1907
|
+
this.rollover(state);
|
|
1908
|
+
const { config } = state;
|
|
1909
|
+
if (config.maxRequests !== void 0 && state.requestsMade + 1 > config.maxRequests) {
|
|
1910
|
+
throw new OllamaQuotaExceededError(
|
|
1911
|
+
`Client-side quota window "${config.id}" would exceed its request budget (${state.requestsMade}/${config.maxRequests} requests used).`,
|
|
1912
|
+
{ windowId: config.id, resetAt: state.windowStartedAt + config.windowMs }
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1915
|
+
if (config.maxTokens !== void 0 && state.tokensUsed + estimatedTokens > config.maxTokens) {
|
|
1916
|
+
throw new OllamaQuotaExceededError(
|
|
1917
|
+
`Client-side quota window "${config.id}" would exceed its token budget (${state.tokensUsed}/${config.maxTokens} tokens used).`,
|
|
1918
|
+
{ windowId: config.id, resetAt: state.windowStartedAt + config.windowMs }
|
|
1919
|
+
);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
/** Records one request's actual usage — a raw API response or a pre-normalized `TokenUsage` — against every window. */
|
|
1924
|
+
recordUsage(usage) {
|
|
1925
|
+
const normalized = "totalTokens" in usage ? usage : extractUsage(usage);
|
|
1926
|
+
for (const state of this.windows) {
|
|
1927
|
+
this.rollover(state);
|
|
1928
|
+
state.tokensUsed += normalized.totalTokens;
|
|
1929
|
+
state.requestsMade += 1;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
/** Resets one window (by `id`) or, if omitted, all windows — zeroing usage and restarting their clocks. */
|
|
1933
|
+
reset(windowId) {
|
|
1934
|
+
for (const state of this.windows) {
|
|
1935
|
+
if (windowId === void 0 || state.config.id === windowId) {
|
|
1936
|
+
state.tokensUsed = 0;
|
|
1937
|
+
state.requestsMade = 0;
|
|
1938
|
+
state.windowStartedAt = this.now();
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
function createOllamaCloudFreeTierQuota(budgets) {
|
|
1944
|
+
const windows = [];
|
|
1945
|
+
if (budgets.session !== void 0) {
|
|
1946
|
+
windows.push({ id: "session", windowMs: 5 * 60 * 60 * 1e3, ...budgets.session });
|
|
1947
|
+
}
|
|
1948
|
+
if (budgets.weekly !== void 0) {
|
|
1949
|
+
windows.push({ id: "weekly", windowMs: 7 * 24 * 60 * 60 * 1e3, ...budgets.weekly });
|
|
1950
|
+
}
|
|
1951
|
+
if (windows.length === 0) {
|
|
1952
|
+
throw new Error(
|
|
1953
|
+
"createOllamaCloudFreeTierQuota requires at least a `session` or `weekly` budget."
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
return new QuotaManager({ windows, ...budgets.now !== void 0 ? { now: budgets.now } : {} });
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1532
1959
|
// src/tools/define-tool.ts
|
|
1533
1960
|
function defineTool(options) {
|
|
1534
1961
|
const jsonSchema = zodToJsonSchema(options.schema);
|
|
@@ -1964,6 +2391,6 @@ var Agent = class {
|
|
|
1964
2391
|
}
|
|
1965
2392
|
};
|
|
1966
2393
|
|
|
1967
|
-
export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, Agent, AnthropicCompatClient, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_FAILOVER_CODES, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, EndpointRegistry, GEN_AI_SYSTEM_OLLAMA, HttpClient, ModelsClient, NANOS_PER_MS, NANOS_PER_SECOND, NOOP_LOGGER, OllamaAbortError, OllamaAgentMaxIterationsError, OllamaAuthError, OllamaClient, OllamaClientError, OllamaGenericClientError, OllamaMcpError, OllamaNetworkError, OllamaNotFoundError, OllamaRateLimitError, OllamaServerError, OllamaSkillInvalidError, OllamaSkillNotFoundError, OllamaStream, OllamaTimeoutError, OllamaToolTimeoutError, OllamaToolValidationError, OllamaUnsupportedCapabilityError, OpenAICompatClient, ToolRegistry, addSpanEvent, applySkill, calculateBackoff, checkEndpointHealth, composeMiddleware, createConsoleLogger, createTimeoutSignal, defineTool, detectModelCapabilities, extractUsage, inferRuntimeMode, listAvailableModels, loadMcpTools, mapError, normalizeChatStream, normalizeGenerateStream, normalizeProgressStream, parseFrontmatter, parseNdjsonStream, parseStructuredOutput, registerMcpTools, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
|
|
2394
|
+
export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, Agent, AnthropicCompatClient, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_FAILOVER_CODES, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, EndpointRegistry, GEN_AI_SYSTEM_OLLAMA, HttpClient, ModelsClient, NANOS_PER_MS, NANOS_PER_SECOND, NOOP_LOGGER, OLLAMA_CLOUD_BASE_URL, OllamaAbortError, OllamaAgentMaxIterationsError, OllamaAuthError, OllamaClient, OllamaClientError, OllamaGenericClientError, OllamaMcpError, OllamaModelRoutingError, OllamaNetworkError, OllamaNotFoundError, OllamaQuotaExceededError, OllamaRateLimitError, OllamaServerError, OllamaSkillInvalidError, OllamaSkillNotFoundError, OllamaStream, OllamaTimeoutError, OllamaToolTimeoutError, OllamaToolValidationError, OllamaUnsupportedCapabilityError, OpenAICompatClient, QuotaManager, ToolRegistry, addSpanEvent, applySkill, calculateBackoff, checkEndpointHealth, composeMiddleware, createConsoleLogger, createOllamaCloudFreeTierQuota, createTimeoutSignal, defineTool, detectModelCapabilities, encodeImage, extractUsage, inferRuntimeMode, listAvailableModels, loadMcpTools, mapError, normalizeChatStream, normalizeGenerateStream, normalizeProgressStream, parseFrontmatter, parseNdjsonStream, parseStructuredOutput, registerMcpTools, resolveCredentialEndpoints, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
|
|
1968
2395
|
//# sourceMappingURL=index.js.map
|
|
1969
2396
|
//# sourceMappingURL=index.js.map
|