@octocodeai/freellama-mcp-server 0.1.0 → 0.5.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/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +18 -0
- package/README.md +203 -33
- package/adapters/agent_context.py +216 -29
- package/adapters/agent_transport.py +131 -0
- package/adapters/bash_agent.py +67 -92
- package/adapters/octocode_agent.py +63 -53
- package/adapters/shell_sandbox.py +487 -0
- package/assets/logo.jpg +0 -0
- package/dist/index.js +1287 -412
- package/docs/ARCHITECTURE.md +169 -26
- package/docs/CLI.md +107 -17
- package/docs/CPU_GPU_ROUTING.md +65 -20
- package/docs/ECONOMICS.md +20 -15
- package/docs/INDEX.md +8 -2
- package/docs/MODEL_METADATA.md +106 -0
- package/docs/MODEL_SELECTION.md +15 -2
- package/docs/MONITORING.md +285 -0
- package/docs/OLLAMA_SIDECAR.md +8 -6
- package/docs/PRODUCTION.md +49 -18
- package/docs/PRODUCT_POSITIONING.md +86 -256
- package/docs/README.md +40 -0
- package/docs/SCOPES_AND_WARMING.md +226 -0
- package/docs/TESTING.md +118 -1
- package/docs/dev/FINDINGS_AND_POSITIONING.md +290 -0
- package/docs/dev/LOCAL_PERFORMANCE_TESTING.md +298 -0
- package/docs/{OLLAMA_SYSTEM_OPTIMIZATION.md → dev/OLLAMA_SYSTEM_OPTIMIZATION.md} +19 -18
- package/native/index.d.ts +31 -0
- package/package.json +13 -10
- /package/docs/{ADR_RESOURCE_AWARE_BACKEND_ROUTING.md → dev/ADR_RESOURCE_AWARE_BACKEND_ROUTING.md} +0 -0
package/dist/index.js
CHANGED
|
@@ -3109,6 +3109,7 @@ var require_utils = __commonJS({
|
|
|
3109
3109
|
"use strict";
|
|
3110
3110
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3111
3111
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3112
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3112
3113
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3113
3114
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3114
3115
|
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
@@ -3261,8 +3262,8 @@ var require_utils = __commonJS({
|
|
|
3261
3262
|
}
|
|
3262
3263
|
return ind;
|
|
3263
3264
|
}
|
|
3264
|
-
function removeDotSegments(
|
|
3265
|
-
let input =
|
|
3265
|
+
function removeDotSegments(path6) {
|
|
3266
|
+
let input = path6;
|
|
3266
3267
|
const output = [];
|
|
3267
3268
|
let nextSlash = -1;
|
|
3268
3269
|
let len = 0;
|
|
@@ -3574,8 +3575,12 @@ var require_utils = __commonJS({
|
|
|
3574
3575
|
uriTokens.push(host);
|
|
3575
3576
|
}
|
|
3576
3577
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3578
|
+
const port = String(component.port);
|
|
3579
|
+
if (!isPort(port)) {
|
|
3580
|
+
throw new TypeError("URI port is malformed.");
|
|
3581
|
+
}
|
|
3577
3582
|
uriTokens.push(":");
|
|
3578
|
-
uriTokens.push(
|
|
3583
|
+
uriTokens.push(port);
|
|
3579
3584
|
}
|
|
3580
3585
|
return uriTokens.length ? uriTokens.join("") : void 0;
|
|
3581
3586
|
}
|
|
@@ -3667,8 +3672,8 @@ var require_schemes = __commonJS({
|
|
|
3667
3672
|
}
|
|
3668
3673
|
if (wsComponent.resourceName) {
|
|
3669
3674
|
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3670
|
-
const
|
|
3671
|
-
wsComponent.path =
|
|
3675
|
+
const path6 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3676
|
+
wsComponent.path = path6 && path6 !== "/" ? path6 : void 0;
|
|
3672
3677
|
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3673
3678
|
wsComponent.resourceName = void 0;
|
|
3674
3679
|
}
|
|
@@ -4018,12 +4023,15 @@ var require_fast_uri = __commonJS({
|
|
|
4018
4023
|
}
|
|
4019
4024
|
return false;
|
|
4020
4025
|
}
|
|
4026
|
+
function isIPLiteral(host) {
|
|
4027
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
4028
|
+
}
|
|
4021
4029
|
function hasMalformedComponentPercentEncoding(matches) {
|
|
4022
4030
|
const host = matches[4];
|
|
4023
|
-
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host
|
|
4031
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4024
4032
|
}
|
|
4025
4033
|
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
4026
|
-
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host
|
|
4034
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
4027
4035
|
try {
|
|
4028
4036
|
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4029
4037
|
} catch (e) {
|
|
@@ -4110,10 +4118,11 @@ var require_fast_uri = __commonJS({
|
|
|
4110
4118
|
if (parsed.host) {
|
|
4111
4119
|
const ipv4result = isIPv4(parsed.host);
|
|
4112
4120
|
if (ipv4result === false) {
|
|
4113
|
-
const bracketedIPLiteral = parsed.host
|
|
4121
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4122
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
4114
4123
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
4115
4124
|
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4116
|
-
malformedIPLiteral =
|
|
4125
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4117
4126
|
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4118
4127
|
if (malformedIPLiteral) {
|
|
4119
4128
|
parsed.error = parsed.error || "URI host is malformed.";
|
|
@@ -4136,14 +4145,17 @@ var require_fast_uri = __commonJS({
|
|
|
4136
4145
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
4137
4146
|
}
|
|
4138
4147
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4148
|
+
if (!malformedIPLiteral) {
|
|
4149
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
4150
|
+
}
|
|
4151
|
+
if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4152
|
+
let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4153
|
+
if (!isIP) {
|
|
4154
|
+
host = normalizePercentEncoding(host.toLowerCase());
|
|
4146
4155
|
}
|
|
4156
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
4157
|
+
}
|
|
4158
|
+
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
4147
4159
|
if (parsed.path) {
|
|
4148
4160
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
4149
4161
|
}
|
|
@@ -7189,12 +7201,12 @@ var require_dist = __commonJS({
|
|
|
7189
7201
|
|
|
7190
7202
|
// src/index.ts
|
|
7191
7203
|
import { execFile } from "node:child_process";
|
|
7192
|
-
import { existsSync as
|
|
7204
|
+
import { existsSync as existsSync5, readdirSync } from "node:fs";
|
|
7193
7205
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
7194
7206
|
import { createHash } from "node:crypto";
|
|
7195
7207
|
import { tmpdir } from "node:os";
|
|
7196
|
-
import
|
|
7197
|
-
import { fileURLToPath as
|
|
7208
|
+
import path5 from "node:path";
|
|
7209
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
7198
7210
|
import { promisify } from "node:util";
|
|
7199
7211
|
|
|
7200
7212
|
// ../../node_modules/zod/v3/external.js
|
|
@@ -7675,8 +7687,8 @@ function getErrorMap() {
|
|
|
7675
7687
|
|
|
7676
7688
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
7677
7689
|
var makeIssue = (params) => {
|
|
7678
|
-
const { data, path:
|
|
7679
|
-
const fullPath = [...
|
|
7690
|
+
const { data, path: path6, errorMaps, issueData } = params;
|
|
7691
|
+
const fullPath = [...path6, ...issueData.path || []];
|
|
7680
7692
|
const fullIssue = {
|
|
7681
7693
|
...issueData,
|
|
7682
7694
|
path: fullPath
|
|
@@ -7731,18 +7743,18 @@ var ParseStatus = class _ParseStatus {
|
|
|
7731
7743
|
if (this.value !== "aborted")
|
|
7732
7744
|
this.value = "aborted";
|
|
7733
7745
|
}
|
|
7734
|
-
static mergeArray(
|
|
7746
|
+
static mergeArray(status2, results) {
|
|
7735
7747
|
const arrayValue = [];
|
|
7736
7748
|
for (const s of results) {
|
|
7737
7749
|
if (s.status === "aborted")
|
|
7738
7750
|
return INVALID;
|
|
7739
7751
|
if (s.status === "dirty")
|
|
7740
|
-
|
|
7752
|
+
status2.dirty();
|
|
7741
7753
|
arrayValue.push(s.value);
|
|
7742
7754
|
}
|
|
7743
|
-
return { status:
|
|
7755
|
+
return { status: status2.value, value: arrayValue };
|
|
7744
7756
|
}
|
|
7745
|
-
static async mergeObjectAsync(
|
|
7757
|
+
static async mergeObjectAsync(status2, pairs) {
|
|
7746
7758
|
const syncPairs = [];
|
|
7747
7759
|
for (const pair of pairs) {
|
|
7748
7760
|
const key = await pair.key;
|
|
@@ -7752,9 +7764,9 @@ var ParseStatus = class _ParseStatus {
|
|
|
7752
7764
|
value
|
|
7753
7765
|
});
|
|
7754
7766
|
}
|
|
7755
|
-
return _ParseStatus.mergeObjectSync(
|
|
7767
|
+
return _ParseStatus.mergeObjectSync(status2, syncPairs);
|
|
7756
7768
|
}
|
|
7757
|
-
static mergeObjectSync(
|
|
7769
|
+
static mergeObjectSync(status2, pairs) {
|
|
7758
7770
|
const finalObject = {};
|
|
7759
7771
|
for (const pair of pairs) {
|
|
7760
7772
|
const { key, value } = pair;
|
|
@@ -7763,14 +7775,14 @@ var ParseStatus = class _ParseStatus {
|
|
|
7763
7775
|
if (value.status === "aborted")
|
|
7764
7776
|
return INVALID;
|
|
7765
7777
|
if (key.status === "dirty")
|
|
7766
|
-
|
|
7778
|
+
status2.dirty();
|
|
7767
7779
|
if (value.status === "dirty")
|
|
7768
|
-
|
|
7780
|
+
status2.dirty();
|
|
7769
7781
|
if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
|
|
7770
7782
|
finalObject[key.value] = value.value;
|
|
7771
7783
|
}
|
|
7772
7784
|
}
|
|
7773
|
-
return { status:
|
|
7785
|
+
return { status: status2.value, value: finalObject };
|
|
7774
7786
|
}
|
|
7775
7787
|
};
|
|
7776
7788
|
var INVALID = Object.freeze({
|
|
@@ -7792,11 +7804,11 @@ var errorUtil;
|
|
|
7792
7804
|
|
|
7793
7805
|
// ../../node_modules/zod/v3/types.js
|
|
7794
7806
|
var ParseInputLazyPath = class {
|
|
7795
|
-
constructor(parent, value,
|
|
7807
|
+
constructor(parent, value, path6, key) {
|
|
7796
7808
|
this._cachedPath = [];
|
|
7797
7809
|
this.parent = parent;
|
|
7798
7810
|
this.data = value;
|
|
7799
|
-
this._path =
|
|
7811
|
+
this._path = path6;
|
|
7800
7812
|
this._key = key;
|
|
7801
7813
|
}
|
|
7802
7814
|
get path() {
|
|
@@ -8230,7 +8242,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8230
8242
|
});
|
|
8231
8243
|
return INVALID;
|
|
8232
8244
|
}
|
|
8233
|
-
const
|
|
8245
|
+
const status2 = new ParseStatus();
|
|
8234
8246
|
let ctx = void 0;
|
|
8235
8247
|
for (const check2 of this._def.checks) {
|
|
8236
8248
|
if (check2.kind === "min") {
|
|
@@ -8244,7 +8256,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8244
8256
|
exact: false,
|
|
8245
8257
|
message: check2.message
|
|
8246
8258
|
});
|
|
8247
|
-
|
|
8259
|
+
status2.dirty();
|
|
8248
8260
|
}
|
|
8249
8261
|
} else if (check2.kind === "max") {
|
|
8250
8262
|
if (input.data.length > check2.value) {
|
|
@@ -8257,7 +8269,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8257
8269
|
exact: false,
|
|
8258
8270
|
message: check2.message
|
|
8259
8271
|
});
|
|
8260
|
-
|
|
8272
|
+
status2.dirty();
|
|
8261
8273
|
}
|
|
8262
8274
|
} else if (check2.kind === "length") {
|
|
8263
8275
|
const tooBig = input.data.length > check2.value;
|
|
@@ -8283,7 +8295,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8283
8295
|
message: check2.message
|
|
8284
8296
|
});
|
|
8285
8297
|
}
|
|
8286
|
-
|
|
8298
|
+
status2.dirty();
|
|
8287
8299
|
}
|
|
8288
8300
|
} else if (check2.kind === "email") {
|
|
8289
8301
|
if (!emailRegex.test(input.data)) {
|
|
@@ -8293,7 +8305,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8293
8305
|
code: ZodIssueCode.invalid_string,
|
|
8294
8306
|
message: check2.message
|
|
8295
8307
|
});
|
|
8296
|
-
|
|
8308
|
+
status2.dirty();
|
|
8297
8309
|
}
|
|
8298
8310
|
} else if (check2.kind === "emoji") {
|
|
8299
8311
|
if (!emojiRegex) {
|
|
@@ -8306,7 +8318,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8306
8318
|
code: ZodIssueCode.invalid_string,
|
|
8307
8319
|
message: check2.message
|
|
8308
8320
|
});
|
|
8309
|
-
|
|
8321
|
+
status2.dirty();
|
|
8310
8322
|
}
|
|
8311
8323
|
} else if (check2.kind === "uuid") {
|
|
8312
8324
|
if (!uuidRegex.test(input.data)) {
|
|
@@ -8316,7 +8328,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8316
8328
|
code: ZodIssueCode.invalid_string,
|
|
8317
8329
|
message: check2.message
|
|
8318
8330
|
});
|
|
8319
|
-
|
|
8331
|
+
status2.dirty();
|
|
8320
8332
|
}
|
|
8321
8333
|
} else if (check2.kind === "nanoid") {
|
|
8322
8334
|
if (!nanoidRegex.test(input.data)) {
|
|
@@ -8326,7 +8338,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8326
8338
|
code: ZodIssueCode.invalid_string,
|
|
8327
8339
|
message: check2.message
|
|
8328
8340
|
});
|
|
8329
|
-
|
|
8341
|
+
status2.dirty();
|
|
8330
8342
|
}
|
|
8331
8343
|
} else if (check2.kind === "cuid") {
|
|
8332
8344
|
if (!cuidRegex.test(input.data)) {
|
|
@@ -8336,7 +8348,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8336
8348
|
code: ZodIssueCode.invalid_string,
|
|
8337
8349
|
message: check2.message
|
|
8338
8350
|
});
|
|
8339
|
-
|
|
8351
|
+
status2.dirty();
|
|
8340
8352
|
}
|
|
8341
8353
|
} else if (check2.kind === "cuid2") {
|
|
8342
8354
|
if (!cuid2Regex.test(input.data)) {
|
|
@@ -8346,7 +8358,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8346
8358
|
code: ZodIssueCode.invalid_string,
|
|
8347
8359
|
message: check2.message
|
|
8348
8360
|
});
|
|
8349
|
-
|
|
8361
|
+
status2.dirty();
|
|
8350
8362
|
}
|
|
8351
8363
|
} else if (check2.kind === "ulid") {
|
|
8352
8364
|
if (!ulidRegex.test(input.data)) {
|
|
@@ -8356,7 +8368,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8356
8368
|
code: ZodIssueCode.invalid_string,
|
|
8357
8369
|
message: check2.message
|
|
8358
8370
|
});
|
|
8359
|
-
|
|
8371
|
+
status2.dirty();
|
|
8360
8372
|
}
|
|
8361
8373
|
} else if (check2.kind === "url") {
|
|
8362
8374
|
try {
|
|
@@ -8368,7 +8380,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8368
8380
|
code: ZodIssueCode.invalid_string,
|
|
8369
8381
|
message: check2.message
|
|
8370
8382
|
});
|
|
8371
|
-
|
|
8383
|
+
status2.dirty();
|
|
8372
8384
|
}
|
|
8373
8385
|
} else if (check2.kind === "regex") {
|
|
8374
8386
|
check2.regex.lastIndex = 0;
|
|
@@ -8380,7 +8392,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8380
8392
|
code: ZodIssueCode.invalid_string,
|
|
8381
8393
|
message: check2.message
|
|
8382
8394
|
});
|
|
8383
|
-
|
|
8395
|
+
status2.dirty();
|
|
8384
8396
|
}
|
|
8385
8397
|
} else if (check2.kind === "trim") {
|
|
8386
8398
|
input.data = input.data.trim();
|
|
@@ -8392,7 +8404,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8392
8404
|
validation: { includes: check2.value, position: check2.position },
|
|
8393
8405
|
message: check2.message
|
|
8394
8406
|
});
|
|
8395
|
-
|
|
8407
|
+
status2.dirty();
|
|
8396
8408
|
}
|
|
8397
8409
|
} else if (check2.kind === "toLowerCase") {
|
|
8398
8410
|
input.data = input.data.toLowerCase();
|
|
@@ -8406,7 +8418,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8406
8418
|
validation: { startsWith: check2.value },
|
|
8407
8419
|
message: check2.message
|
|
8408
8420
|
});
|
|
8409
|
-
|
|
8421
|
+
status2.dirty();
|
|
8410
8422
|
}
|
|
8411
8423
|
} else if (check2.kind === "endsWith") {
|
|
8412
8424
|
if (!input.data.endsWith(check2.value)) {
|
|
@@ -8416,7 +8428,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8416
8428
|
validation: { endsWith: check2.value },
|
|
8417
8429
|
message: check2.message
|
|
8418
8430
|
});
|
|
8419
|
-
|
|
8431
|
+
status2.dirty();
|
|
8420
8432
|
}
|
|
8421
8433
|
} else if (check2.kind === "datetime") {
|
|
8422
8434
|
const regex = datetimeRegex(check2);
|
|
@@ -8427,7 +8439,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8427
8439
|
validation: "datetime",
|
|
8428
8440
|
message: check2.message
|
|
8429
8441
|
});
|
|
8430
|
-
|
|
8442
|
+
status2.dirty();
|
|
8431
8443
|
}
|
|
8432
8444
|
} else if (check2.kind === "date") {
|
|
8433
8445
|
const regex = dateRegex;
|
|
@@ -8438,7 +8450,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8438
8450
|
validation: "date",
|
|
8439
8451
|
message: check2.message
|
|
8440
8452
|
});
|
|
8441
|
-
|
|
8453
|
+
status2.dirty();
|
|
8442
8454
|
}
|
|
8443
8455
|
} else if (check2.kind === "time") {
|
|
8444
8456
|
const regex = timeRegex(check2);
|
|
@@ -8449,7 +8461,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8449
8461
|
validation: "time",
|
|
8450
8462
|
message: check2.message
|
|
8451
8463
|
});
|
|
8452
|
-
|
|
8464
|
+
status2.dirty();
|
|
8453
8465
|
}
|
|
8454
8466
|
} else if (check2.kind === "duration") {
|
|
8455
8467
|
if (!durationRegex.test(input.data)) {
|
|
@@ -8459,7 +8471,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8459
8471
|
code: ZodIssueCode.invalid_string,
|
|
8460
8472
|
message: check2.message
|
|
8461
8473
|
});
|
|
8462
|
-
|
|
8474
|
+
status2.dirty();
|
|
8463
8475
|
}
|
|
8464
8476
|
} else if (check2.kind === "ip") {
|
|
8465
8477
|
if (!isValidIP(input.data, check2.version)) {
|
|
@@ -8469,7 +8481,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8469
8481
|
code: ZodIssueCode.invalid_string,
|
|
8470
8482
|
message: check2.message
|
|
8471
8483
|
});
|
|
8472
|
-
|
|
8484
|
+
status2.dirty();
|
|
8473
8485
|
}
|
|
8474
8486
|
} else if (check2.kind === "jwt") {
|
|
8475
8487
|
if (!isValidJWT(input.data, check2.alg)) {
|
|
@@ -8479,7 +8491,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8479
8491
|
code: ZodIssueCode.invalid_string,
|
|
8480
8492
|
message: check2.message
|
|
8481
8493
|
});
|
|
8482
|
-
|
|
8494
|
+
status2.dirty();
|
|
8483
8495
|
}
|
|
8484
8496
|
} else if (check2.kind === "cidr") {
|
|
8485
8497
|
if (!isValidCidr(input.data, check2.version)) {
|
|
@@ -8489,7 +8501,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8489
8501
|
code: ZodIssueCode.invalid_string,
|
|
8490
8502
|
message: check2.message
|
|
8491
8503
|
});
|
|
8492
|
-
|
|
8504
|
+
status2.dirty();
|
|
8493
8505
|
}
|
|
8494
8506
|
} else if (check2.kind === "base64") {
|
|
8495
8507
|
if (!base64Regex.test(input.data)) {
|
|
@@ -8499,7 +8511,7 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8499
8511
|
code: ZodIssueCode.invalid_string,
|
|
8500
8512
|
message: check2.message
|
|
8501
8513
|
});
|
|
8502
|
-
|
|
8514
|
+
status2.dirty();
|
|
8503
8515
|
}
|
|
8504
8516
|
} else if (check2.kind === "base64url") {
|
|
8505
8517
|
if (!base64urlRegex.test(input.data)) {
|
|
@@ -8509,13 +8521,13 @@ var ZodString = class _ZodString2 extends ZodType {
|
|
|
8509
8521
|
code: ZodIssueCode.invalid_string,
|
|
8510
8522
|
message: check2.message
|
|
8511
8523
|
});
|
|
8512
|
-
|
|
8524
|
+
status2.dirty();
|
|
8513
8525
|
}
|
|
8514
8526
|
} else {
|
|
8515
8527
|
util.assertNever(check2);
|
|
8516
8528
|
}
|
|
8517
8529
|
}
|
|
8518
|
-
return { status:
|
|
8530
|
+
return { status: status2.value, value: input.data };
|
|
8519
8531
|
}
|
|
8520
8532
|
_regex(regex, validation, message) {
|
|
8521
8533
|
return this.refinement((data) => regex.test(data), {
|
|
@@ -8791,7 +8803,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8791
8803
|
return INVALID;
|
|
8792
8804
|
}
|
|
8793
8805
|
let ctx = void 0;
|
|
8794
|
-
const
|
|
8806
|
+
const status2 = new ParseStatus();
|
|
8795
8807
|
for (const check2 of this._def.checks) {
|
|
8796
8808
|
if (check2.kind === "int") {
|
|
8797
8809
|
if (!util.isInteger(input.data)) {
|
|
@@ -8802,7 +8814,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8802
8814
|
received: "float",
|
|
8803
8815
|
message: check2.message
|
|
8804
8816
|
});
|
|
8805
|
-
|
|
8817
|
+
status2.dirty();
|
|
8806
8818
|
}
|
|
8807
8819
|
} else if (check2.kind === "min") {
|
|
8808
8820
|
const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
|
|
@@ -8816,7 +8828,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8816
8828
|
exact: false,
|
|
8817
8829
|
message: check2.message
|
|
8818
8830
|
});
|
|
8819
|
-
|
|
8831
|
+
status2.dirty();
|
|
8820
8832
|
}
|
|
8821
8833
|
} else if (check2.kind === "max") {
|
|
8822
8834
|
const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
|
|
@@ -8830,7 +8842,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8830
8842
|
exact: false,
|
|
8831
8843
|
message: check2.message
|
|
8832
8844
|
});
|
|
8833
|
-
|
|
8845
|
+
status2.dirty();
|
|
8834
8846
|
}
|
|
8835
8847
|
} else if (check2.kind === "multipleOf") {
|
|
8836
8848
|
if (floatSafeRemainder(input.data, check2.value) !== 0) {
|
|
@@ -8840,7 +8852,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8840
8852
|
multipleOf: check2.value,
|
|
8841
8853
|
message: check2.message
|
|
8842
8854
|
});
|
|
8843
|
-
|
|
8855
|
+
status2.dirty();
|
|
8844
8856
|
}
|
|
8845
8857
|
} else if (check2.kind === "finite") {
|
|
8846
8858
|
if (!Number.isFinite(input.data)) {
|
|
@@ -8849,13 +8861,13 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
8849
8861
|
code: ZodIssueCode.not_finite,
|
|
8850
8862
|
message: check2.message
|
|
8851
8863
|
});
|
|
8852
|
-
|
|
8864
|
+
status2.dirty();
|
|
8853
8865
|
}
|
|
8854
8866
|
} else {
|
|
8855
8867
|
util.assertNever(check2);
|
|
8856
8868
|
}
|
|
8857
8869
|
}
|
|
8858
|
-
return { status:
|
|
8870
|
+
return { status: status2.value, value: input.data };
|
|
8859
8871
|
}
|
|
8860
8872
|
gte(value, message) {
|
|
8861
8873
|
return this.setLimit("min", value, true, errorUtil.toString(message));
|
|
@@ -9020,7 +9032,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
9020
9032
|
return this._getInvalidInput(input);
|
|
9021
9033
|
}
|
|
9022
9034
|
let ctx = void 0;
|
|
9023
|
-
const
|
|
9035
|
+
const status2 = new ParseStatus();
|
|
9024
9036
|
for (const check2 of this._def.checks) {
|
|
9025
9037
|
if (check2.kind === "min") {
|
|
9026
9038
|
const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
|
|
@@ -9033,7 +9045,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
9033
9045
|
inclusive: check2.inclusive,
|
|
9034
9046
|
message: check2.message
|
|
9035
9047
|
});
|
|
9036
|
-
|
|
9048
|
+
status2.dirty();
|
|
9037
9049
|
}
|
|
9038
9050
|
} else if (check2.kind === "max") {
|
|
9039
9051
|
const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
|
|
@@ -9046,7 +9058,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
9046
9058
|
inclusive: check2.inclusive,
|
|
9047
9059
|
message: check2.message
|
|
9048
9060
|
});
|
|
9049
|
-
|
|
9061
|
+
status2.dirty();
|
|
9050
9062
|
}
|
|
9051
9063
|
} else if (check2.kind === "multipleOf") {
|
|
9052
9064
|
if (input.data % check2.value !== BigInt(0)) {
|
|
@@ -9056,13 +9068,13 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
9056
9068
|
multipleOf: check2.value,
|
|
9057
9069
|
message: check2.message
|
|
9058
9070
|
});
|
|
9059
|
-
|
|
9071
|
+
status2.dirty();
|
|
9060
9072
|
}
|
|
9061
9073
|
} else {
|
|
9062
9074
|
util.assertNever(check2);
|
|
9063
9075
|
}
|
|
9064
9076
|
}
|
|
9065
|
-
return { status:
|
|
9077
|
+
return { status: status2.value, value: input.data };
|
|
9066
9078
|
}
|
|
9067
9079
|
_getInvalidInput(input) {
|
|
9068
9080
|
const ctx = this._getOrReturnCtx(input);
|
|
@@ -9220,7 +9232,7 @@ var ZodDate = class _ZodDate extends ZodType {
|
|
|
9220
9232
|
});
|
|
9221
9233
|
return INVALID;
|
|
9222
9234
|
}
|
|
9223
|
-
const
|
|
9235
|
+
const status2 = new ParseStatus();
|
|
9224
9236
|
let ctx = void 0;
|
|
9225
9237
|
for (const check2 of this._def.checks) {
|
|
9226
9238
|
if (check2.kind === "min") {
|
|
@@ -9234,7 +9246,7 @@ var ZodDate = class _ZodDate extends ZodType {
|
|
|
9234
9246
|
minimum: check2.value,
|
|
9235
9247
|
type: "date"
|
|
9236
9248
|
});
|
|
9237
|
-
|
|
9249
|
+
status2.dirty();
|
|
9238
9250
|
}
|
|
9239
9251
|
} else if (check2.kind === "max") {
|
|
9240
9252
|
if (input.data.getTime() > check2.value) {
|
|
@@ -9247,14 +9259,14 @@ var ZodDate = class _ZodDate extends ZodType {
|
|
|
9247
9259
|
maximum: check2.value,
|
|
9248
9260
|
type: "date"
|
|
9249
9261
|
});
|
|
9250
|
-
|
|
9262
|
+
status2.dirty();
|
|
9251
9263
|
}
|
|
9252
9264
|
} else {
|
|
9253
9265
|
util.assertNever(check2);
|
|
9254
9266
|
}
|
|
9255
9267
|
}
|
|
9256
9268
|
return {
|
|
9257
|
-
status:
|
|
9269
|
+
status: status2.value,
|
|
9258
9270
|
value: new Date(input.data.getTime())
|
|
9259
9271
|
};
|
|
9260
9272
|
}
|
|
@@ -9440,7 +9452,7 @@ ZodVoid.create = (params) => {
|
|
|
9440
9452
|
};
|
|
9441
9453
|
var ZodArray = class _ZodArray extends ZodType {
|
|
9442
9454
|
_parse(input) {
|
|
9443
|
-
const { ctx, status } = this._processInputParams(input);
|
|
9455
|
+
const { ctx, status: status2 } = this._processInputParams(input);
|
|
9444
9456
|
const def = this._def;
|
|
9445
9457
|
if (ctx.parsedType !== ZodParsedType.array) {
|
|
9446
9458
|
addIssueToContext(ctx, {
|
|
@@ -9463,7 +9475,7 @@ var ZodArray = class _ZodArray extends ZodType {
|
|
|
9463
9475
|
exact: true,
|
|
9464
9476
|
message: def.exactLength.message
|
|
9465
9477
|
});
|
|
9466
|
-
|
|
9478
|
+
status2.dirty();
|
|
9467
9479
|
}
|
|
9468
9480
|
}
|
|
9469
9481
|
if (def.minLength !== null) {
|
|
@@ -9476,7 +9488,7 @@ var ZodArray = class _ZodArray extends ZodType {
|
|
|
9476
9488
|
exact: false,
|
|
9477
9489
|
message: def.minLength.message
|
|
9478
9490
|
});
|
|
9479
|
-
|
|
9491
|
+
status2.dirty();
|
|
9480
9492
|
}
|
|
9481
9493
|
}
|
|
9482
9494
|
if (def.maxLength !== null) {
|
|
@@ -9489,20 +9501,20 @@ var ZodArray = class _ZodArray extends ZodType {
|
|
|
9489
9501
|
exact: false,
|
|
9490
9502
|
message: def.maxLength.message
|
|
9491
9503
|
});
|
|
9492
|
-
|
|
9504
|
+
status2.dirty();
|
|
9493
9505
|
}
|
|
9494
9506
|
}
|
|
9495
9507
|
if (ctx.common.async) {
|
|
9496
9508
|
return Promise.all([...ctx.data].map((item, i) => {
|
|
9497
9509
|
return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i));
|
|
9498
9510
|
})).then((result2) => {
|
|
9499
|
-
return ParseStatus.mergeArray(
|
|
9511
|
+
return ParseStatus.mergeArray(status2, result2);
|
|
9500
9512
|
});
|
|
9501
9513
|
}
|
|
9502
9514
|
const result = [...ctx.data].map((item, i) => {
|
|
9503
9515
|
return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i));
|
|
9504
9516
|
});
|
|
9505
|
-
return ParseStatus.mergeArray(
|
|
9517
|
+
return ParseStatus.mergeArray(status2, result);
|
|
9506
9518
|
}
|
|
9507
9519
|
get element() {
|
|
9508
9520
|
return this._def.type;
|
|
@@ -9591,7 +9603,7 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
9591
9603
|
});
|
|
9592
9604
|
return INVALID;
|
|
9593
9605
|
}
|
|
9594
|
-
const { status, ctx } = this._processInputParams(input);
|
|
9606
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
9595
9607
|
const { shape, keys: shapeKeys } = this._getCached();
|
|
9596
9608
|
const extraKeys = [];
|
|
9597
9609
|
if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) {
|
|
@@ -9626,7 +9638,7 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
9626
9638
|
code: ZodIssueCode.unrecognized_keys,
|
|
9627
9639
|
keys: extraKeys
|
|
9628
9640
|
});
|
|
9629
|
-
|
|
9641
|
+
status2.dirty();
|
|
9630
9642
|
}
|
|
9631
9643
|
} else if (unknownKeys === "strip") {
|
|
9632
9644
|
} else {
|
|
@@ -9660,10 +9672,10 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
9660
9672
|
}
|
|
9661
9673
|
return syncPairs;
|
|
9662
9674
|
}).then((syncPairs) => {
|
|
9663
|
-
return ParseStatus.mergeObjectSync(
|
|
9675
|
+
return ParseStatus.mergeObjectSync(status2, syncPairs);
|
|
9664
9676
|
});
|
|
9665
9677
|
} else {
|
|
9666
|
-
return ParseStatus.mergeObjectSync(
|
|
9678
|
+
return ParseStatus.mergeObjectSync(status2, pairs);
|
|
9667
9679
|
}
|
|
9668
9680
|
}
|
|
9669
9681
|
get shape() {
|
|
@@ -10141,7 +10153,7 @@ function mergeValues(a, b) {
|
|
|
10141
10153
|
}
|
|
10142
10154
|
var ZodIntersection = class extends ZodType {
|
|
10143
10155
|
_parse(input) {
|
|
10144
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10156
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10145
10157
|
const handleParsed = (parsedLeft, parsedRight) => {
|
|
10146
10158
|
if (isAborted(parsedLeft) || isAborted(parsedRight)) {
|
|
10147
10159
|
return INVALID;
|
|
@@ -10154,9 +10166,9 @@ var ZodIntersection = class extends ZodType {
|
|
|
10154
10166
|
return INVALID;
|
|
10155
10167
|
}
|
|
10156
10168
|
if (isDirty(parsedLeft) || isDirty(parsedRight)) {
|
|
10157
|
-
|
|
10169
|
+
status2.dirty();
|
|
10158
10170
|
}
|
|
10159
|
-
return { status:
|
|
10171
|
+
return { status: status2.value, value: merged.data };
|
|
10160
10172
|
};
|
|
10161
10173
|
if (ctx.common.async) {
|
|
10162
10174
|
return Promise.all([
|
|
@@ -10194,7 +10206,7 @@ ZodIntersection.create = (left, right, params) => {
|
|
|
10194
10206
|
};
|
|
10195
10207
|
var ZodTuple = class _ZodTuple extends ZodType {
|
|
10196
10208
|
_parse(input) {
|
|
10197
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10209
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10198
10210
|
if (ctx.parsedType !== ZodParsedType.array) {
|
|
10199
10211
|
addIssueToContext(ctx, {
|
|
10200
10212
|
code: ZodIssueCode.invalid_type,
|
|
@@ -10222,7 +10234,7 @@ var ZodTuple = class _ZodTuple extends ZodType {
|
|
|
10222
10234
|
exact: false,
|
|
10223
10235
|
type: "array"
|
|
10224
10236
|
});
|
|
10225
|
-
|
|
10237
|
+
status2.dirty();
|
|
10226
10238
|
}
|
|
10227
10239
|
const items = [...ctx.data].map((item, itemIndex) => {
|
|
10228
10240
|
const schema = this._def.items[itemIndex] || this._def.rest;
|
|
@@ -10232,10 +10244,10 @@ var ZodTuple = class _ZodTuple extends ZodType {
|
|
|
10232
10244
|
}).filter((x) => !!x);
|
|
10233
10245
|
if (ctx.common.async) {
|
|
10234
10246
|
return Promise.all(items).then((results) => {
|
|
10235
|
-
return ParseStatus.mergeArray(
|
|
10247
|
+
return ParseStatus.mergeArray(status2, results);
|
|
10236
10248
|
});
|
|
10237
10249
|
} else {
|
|
10238
|
-
return ParseStatus.mergeArray(
|
|
10250
|
+
return ParseStatus.mergeArray(status2, items);
|
|
10239
10251
|
}
|
|
10240
10252
|
}
|
|
10241
10253
|
get items() {
|
|
@@ -10267,7 +10279,7 @@ var ZodRecord = class _ZodRecord extends ZodType {
|
|
|
10267
10279
|
return this._def.valueType;
|
|
10268
10280
|
}
|
|
10269
10281
|
_parse(input) {
|
|
10270
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10282
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10271
10283
|
if (ctx.parsedType !== ZodParsedType.object) {
|
|
10272
10284
|
addIssueToContext(ctx, {
|
|
10273
10285
|
code: ZodIssueCode.invalid_type,
|
|
@@ -10287,9 +10299,9 @@ var ZodRecord = class _ZodRecord extends ZodType {
|
|
|
10287
10299
|
});
|
|
10288
10300
|
}
|
|
10289
10301
|
if (ctx.common.async) {
|
|
10290
|
-
return ParseStatus.mergeObjectAsync(
|
|
10302
|
+
return ParseStatus.mergeObjectAsync(status2, pairs);
|
|
10291
10303
|
} else {
|
|
10292
|
-
return ParseStatus.mergeObjectSync(
|
|
10304
|
+
return ParseStatus.mergeObjectSync(status2, pairs);
|
|
10293
10305
|
}
|
|
10294
10306
|
}
|
|
10295
10307
|
get element() {
|
|
@@ -10320,7 +10332,7 @@ var ZodMap = class extends ZodType {
|
|
|
10320
10332
|
return this._def.valueType;
|
|
10321
10333
|
}
|
|
10322
10334
|
_parse(input) {
|
|
10323
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10335
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10324
10336
|
if (ctx.parsedType !== ZodParsedType.map) {
|
|
10325
10337
|
addIssueToContext(ctx, {
|
|
10326
10338
|
code: ZodIssueCode.invalid_type,
|
|
@@ -10347,11 +10359,11 @@ var ZodMap = class extends ZodType {
|
|
|
10347
10359
|
return INVALID;
|
|
10348
10360
|
}
|
|
10349
10361
|
if (key.status === "dirty" || value.status === "dirty") {
|
|
10350
|
-
|
|
10362
|
+
status2.dirty();
|
|
10351
10363
|
}
|
|
10352
10364
|
finalMap.set(key.value, value.value);
|
|
10353
10365
|
}
|
|
10354
|
-
return { status:
|
|
10366
|
+
return { status: status2.value, value: finalMap };
|
|
10355
10367
|
});
|
|
10356
10368
|
} else {
|
|
10357
10369
|
const finalMap = /* @__PURE__ */ new Map();
|
|
@@ -10362,11 +10374,11 @@ var ZodMap = class extends ZodType {
|
|
|
10362
10374
|
return INVALID;
|
|
10363
10375
|
}
|
|
10364
10376
|
if (key.status === "dirty" || value.status === "dirty") {
|
|
10365
|
-
|
|
10377
|
+
status2.dirty();
|
|
10366
10378
|
}
|
|
10367
10379
|
finalMap.set(key.value, value.value);
|
|
10368
10380
|
}
|
|
10369
|
-
return { status:
|
|
10381
|
+
return { status: status2.value, value: finalMap };
|
|
10370
10382
|
}
|
|
10371
10383
|
}
|
|
10372
10384
|
};
|
|
@@ -10380,7 +10392,7 @@ ZodMap.create = (keyType, valueType, params) => {
|
|
|
10380
10392
|
};
|
|
10381
10393
|
var ZodSet = class _ZodSet extends ZodType {
|
|
10382
10394
|
_parse(input) {
|
|
10383
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10395
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10384
10396
|
if (ctx.parsedType !== ZodParsedType.set) {
|
|
10385
10397
|
addIssueToContext(ctx, {
|
|
10386
10398
|
code: ZodIssueCode.invalid_type,
|
|
@@ -10400,7 +10412,7 @@ var ZodSet = class _ZodSet extends ZodType {
|
|
|
10400
10412
|
exact: false,
|
|
10401
10413
|
message: def.minSize.message
|
|
10402
10414
|
});
|
|
10403
|
-
|
|
10415
|
+
status2.dirty();
|
|
10404
10416
|
}
|
|
10405
10417
|
}
|
|
10406
10418
|
if (def.maxSize !== null) {
|
|
@@ -10413,7 +10425,7 @@ var ZodSet = class _ZodSet extends ZodType {
|
|
|
10413
10425
|
exact: false,
|
|
10414
10426
|
message: def.maxSize.message
|
|
10415
10427
|
});
|
|
10416
|
-
|
|
10428
|
+
status2.dirty();
|
|
10417
10429
|
}
|
|
10418
10430
|
}
|
|
10419
10431
|
const valueType = this._def.valueType;
|
|
@@ -10423,10 +10435,10 @@ var ZodSet = class _ZodSet extends ZodType {
|
|
|
10423
10435
|
if (element.status === "aborted")
|
|
10424
10436
|
return INVALID;
|
|
10425
10437
|
if (element.status === "dirty")
|
|
10426
|
-
|
|
10438
|
+
status2.dirty();
|
|
10427
10439
|
parsedSet.add(element.value);
|
|
10428
10440
|
}
|
|
10429
|
-
return { status:
|
|
10441
|
+
return { status: status2.value, value: parsedSet };
|
|
10430
10442
|
}
|
|
10431
10443
|
const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i)));
|
|
10432
10444
|
if (ctx.common.async) {
|
|
@@ -10757,15 +10769,15 @@ var ZodEffects = class extends ZodType {
|
|
|
10757
10769
|
return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects ? this._def.schema.sourceType() : this._def.schema;
|
|
10758
10770
|
}
|
|
10759
10771
|
_parse(input) {
|
|
10760
|
-
const { status, ctx } = this._processInputParams(input);
|
|
10772
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
10761
10773
|
const effect = this._def.effect || null;
|
|
10762
10774
|
const checkCtx = {
|
|
10763
10775
|
addIssue: (arg) => {
|
|
10764
10776
|
addIssueToContext(ctx, arg);
|
|
10765
10777
|
if (arg.fatal) {
|
|
10766
|
-
|
|
10778
|
+
status2.abort();
|
|
10767
10779
|
} else {
|
|
10768
|
-
|
|
10780
|
+
status2.dirty();
|
|
10769
10781
|
}
|
|
10770
10782
|
},
|
|
10771
10783
|
get path() {
|
|
@@ -10777,7 +10789,7 @@ var ZodEffects = class extends ZodType {
|
|
|
10777
10789
|
const processed = effect.transform(ctx.data, checkCtx);
|
|
10778
10790
|
if (ctx.common.async) {
|
|
10779
10791
|
return Promise.resolve(processed).then(async (processed2) => {
|
|
10780
|
-
if (
|
|
10792
|
+
if (status2.value === "aborted")
|
|
10781
10793
|
return INVALID;
|
|
10782
10794
|
const result = await this._def.schema._parseAsync({
|
|
10783
10795
|
data: processed2,
|
|
@@ -10788,12 +10800,12 @@ var ZodEffects = class extends ZodType {
|
|
|
10788
10800
|
return INVALID;
|
|
10789
10801
|
if (result.status === "dirty")
|
|
10790
10802
|
return DIRTY(result.value);
|
|
10791
|
-
if (
|
|
10803
|
+
if (status2.value === "dirty")
|
|
10792
10804
|
return DIRTY(result.value);
|
|
10793
10805
|
return result;
|
|
10794
10806
|
});
|
|
10795
10807
|
} else {
|
|
10796
|
-
if (
|
|
10808
|
+
if (status2.value === "aborted")
|
|
10797
10809
|
return INVALID;
|
|
10798
10810
|
const result = this._def.schema._parseSync({
|
|
10799
10811
|
data: processed,
|
|
@@ -10804,7 +10816,7 @@ var ZodEffects = class extends ZodType {
|
|
|
10804
10816
|
return INVALID;
|
|
10805
10817
|
if (result.status === "dirty")
|
|
10806
10818
|
return DIRTY(result.value);
|
|
10807
|
-
if (
|
|
10819
|
+
if (status2.value === "dirty")
|
|
10808
10820
|
return DIRTY(result.value);
|
|
10809
10821
|
return result;
|
|
10810
10822
|
}
|
|
@@ -10829,17 +10841,17 @@ var ZodEffects = class extends ZodType {
|
|
|
10829
10841
|
if (inner.status === "aborted")
|
|
10830
10842
|
return INVALID;
|
|
10831
10843
|
if (inner.status === "dirty")
|
|
10832
|
-
|
|
10844
|
+
status2.dirty();
|
|
10833
10845
|
executeRefinement(inner.value);
|
|
10834
|
-
return { status:
|
|
10846
|
+
return { status: status2.value, value: inner.value };
|
|
10835
10847
|
} else {
|
|
10836
10848
|
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
|
|
10837
10849
|
if (inner.status === "aborted")
|
|
10838
10850
|
return INVALID;
|
|
10839
10851
|
if (inner.status === "dirty")
|
|
10840
|
-
|
|
10852
|
+
status2.dirty();
|
|
10841
10853
|
return executeRefinement(inner.value).then(() => {
|
|
10842
|
-
return { status:
|
|
10854
|
+
return { status: status2.value, value: inner.value };
|
|
10843
10855
|
});
|
|
10844
10856
|
});
|
|
10845
10857
|
}
|
|
@@ -10857,13 +10869,13 @@ var ZodEffects = class extends ZodType {
|
|
|
10857
10869
|
if (result instanceof Promise) {
|
|
10858
10870
|
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
10859
10871
|
}
|
|
10860
|
-
return { status:
|
|
10872
|
+
return { status: status2.value, value: result };
|
|
10861
10873
|
} else {
|
|
10862
10874
|
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
|
|
10863
10875
|
if (!isValid(base))
|
|
10864
10876
|
return INVALID;
|
|
10865
10877
|
return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
|
|
10866
|
-
status:
|
|
10878
|
+
status: status2.value,
|
|
10867
10879
|
value: result
|
|
10868
10880
|
}));
|
|
10869
10881
|
});
|
|
@@ -11042,7 +11054,7 @@ var ZodBranded = class extends ZodType {
|
|
|
11042
11054
|
};
|
|
11043
11055
|
var ZodPipeline = class _ZodPipeline extends ZodType {
|
|
11044
11056
|
_parse(input) {
|
|
11045
|
-
const { status, ctx } = this._processInputParams(input);
|
|
11057
|
+
const { status: status2, ctx } = this._processInputParams(input);
|
|
11046
11058
|
if (ctx.common.async) {
|
|
11047
11059
|
const handleAsync = async () => {
|
|
11048
11060
|
const inResult = await this._def.in._parseAsync({
|
|
@@ -11053,7 +11065,7 @@ var ZodPipeline = class _ZodPipeline extends ZodType {
|
|
|
11053
11065
|
if (inResult.status === "aborted")
|
|
11054
11066
|
return INVALID;
|
|
11055
11067
|
if (inResult.status === "dirty") {
|
|
11056
|
-
|
|
11068
|
+
status2.dirty();
|
|
11057
11069
|
return DIRTY(inResult.value);
|
|
11058
11070
|
} else {
|
|
11059
11071
|
return this._def.out._parseAsync({
|
|
@@ -11073,7 +11085,7 @@ var ZodPipeline = class _ZodPipeline extends ZodType {
|
|
|
11073
11085
|
if (inResult.status === "aborted")
|
|
11074
11086
|
return INVALID;
|
|
11075
11087
|
if (inResult.status === "dirty") {
|
|
11076
|
-
|
|
11088
|
+
status2.dirty();
|
|
11077
11089
|
return {
|
|
11078
11090
|
status: "dirty",
|
|
11079
11091
|
value: inResult.value
|
|
@@ -11433,10 +11445,10 @@ function assignProp(target, prop, value) {
|
|
|
11433
11445
|
configurable: true
|
|
11434
11446
|
});
|
|
11435
11447
|
}
|
|
11436
|
-
function getElementAtPath(obj,
|
|
11437
|
-
if (!
|
|
11448
|
+
function getElementAtPath(obj, path6) {
|
|
11449
|
+
if (!path6)
|
|
11438
11450
|
return obj;
|
|
11439
|
-
return
|
|
11451
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
11440
11452
|
}
|
|
11441
11453
|
function promiseAllObject(promisesObj) {
|
|
11442
11454
|
const keys = Object.keys(promisesObj);
|
|
@@ -11756,11 +11768,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11756
11768
|
}
|
|
11757
11769
|
return false;
|
|
11758
11770
|
}
|
|
11759
|
-
function prefixIssues(
|
|
11771
|
+
function prefixIssues(path6, issues) {
|
|
11760
11772
|
return issues.map((iss) => {
|
|
11761
11773
|
var _a;
|
|
11762
11774
|
(_a = iss).path ?? (_a.path = []);
|
|
11763
|
-
iss.path.unshift(
|
|
11775
|
+
iss.path.unshift(path6);
|
|
11764
11776
|
return iss;
|
|
11765
11777
|
});
|
|
11766
11778
|
}
|
|
@@ -15171,11 +15183,11 @@ function normalizeObjectSchema(schema) {
|
|
|
15171
15183
|
}
|
|
15172
15184
|
return void 0;
|
|
15173
15185
|
}
|
|
15174
|
-
function getDotPath(
|
|
15175
|
-
if (
|
|
15186
|
+
function getDotPath(path6) {
|
|
15187
|
+
if (path6.length === 0) {
|
|
15176
15188
|
return "object root";
|
|
15177
15189
|
}
|
|
15178
|
-
return
|
|
15190
|
+
return path6.reduce((acc, seg, index) => {
|
|
15179
15191
|
if (index === 0) {
|
|
15180
15192
|
return String(seg);
|
|
15181
15193
|
}
|
|
@@ -17474,8 +17486,8 @@ var UrlElicitationRequiredError = class extends McpError {
|
|
|
17474
17486
|
};
|
|
17475
17487
|
|
|
17476
17488
|
// ../../node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
17477
|
-
function isTerminal(
|
|
17478
|
-
return
|
|
17489
|
+
function isTerminal(status2) {
|
|
17490
|
+
return status2 === "completed" || status2 === "failed" || status2 === "cancelled";
|
|
17479
17491
|
}
|
|
17480
17492
|
|
|
17481
17493
|
// ../../node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
@@ -19694,8 +19706,8 @@ var Protocol = class {
|
|
|
19694
19706
|
}
|
|
19695
19707
|
return task;
|
|
19696
19708
|
},
|
|
19697
|
-
storeTaskResult: async (taskId,
|
|
19698
|
-
await taskStore.storeTaskResult(taskId,
|
|
19709
|
+
storeTaskResult: async (taskId, status2, result) => {
|
|
19710
|
+
await taskStore.storeTaskResult(taskId, status2, result, sessionId);
|
|
19699
19711
|
const task = await taskStore.getTask(taskId, sessionId);
|
|
19700
19712
|
if (task) {
|
|
19701
19713
|
const notification = TaskStatusNotificationSchema.parse({
|
|
@@ -19711,15 +19723,15 @@ var Protocol = class {
|
|
|
19711
19723
|
getTaskResult: (taskId) => {
|
|
19712
19724
|
return taskStore.getTaskResult(taskId, sessionId);
|
|
19713
19725
|
},
|
|
19714
|
-
updateTaskStatus: async (taskId,
|
|
19726
|
+
updateTaskStatus: async (taskId, status2, statusMessage) => {
|
|
19715
19727
|
const task = await taskStore.getTask(taskId, sessionId);
|
|
19716
19728
|
if (!task) {
|
|
19717
19729
|
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
19718
19730
|
}
|
|
19719
19731
|
if (isTerminal(task.status)) {
|
|
19720
|
-
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${
|
|
19732
|
+
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status2}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
19721
19733
|
}
|
|
19722
|
-
await taskStore.updateTaskStatus(taskId,
|
|
19734
|
+
await taskStore.updateTaskStatus(taskId, status2, statusMessage, sessionId);
|
|
19723
19735
|
const updatedTask = await taskStore.getTask(taskId, sessionId);
|
|
19724
19736
|
if (updatedTask) {
|
|
19725
19737
|
const notification = TaskStatusNotificationSchema.parse({
|
|
@@ -21438,9 +21450,10 @@ import path from "node:path";
|
|
|
21438
21450
|
import { fileURLToPath } from "node:url";
|
|
21439
21451
|
import { homedir } from "node:os";
|
|
21440
21452
|
function findRepoRoot() {
|
|
21453
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
21441
21454
|
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
21442
21455
|
for (let depth = 0; depth < 10; depth += 1) {
|
|
21443
|
-
if (existsSync(path.join(dir, "Cargo.toml"))) return dir;
|
|
21456
|
+
if (existsSync(path.join(dir, "Cargo.toml")) && path.join(dir, "packages", "mcp") === packageRoot) return dir;
|
|
21444
21457
|
const parent = path.dirname(dir);
|
|
21445
21458
|
if (parent === dir) break;
|
|
21446
21459
|
dir = parent;
|
|
@@ -21467,7 +21480,7 @@ function envInt(name, fallback) {
|
|
|
21467
21480
|
}
|
|
21468
21481
|
var DEFAULT_OLLAMA_ENDPOINT = process.env.FREELLAMA_OLLAMA_ENDPOINT ?? "http://127.0.0.1:11434";
|
|
21469
21482
|
var DEFAULT_SERVE_ENDPOINT = process.env.FREELLAMA_SERVE_ENDPOINT ?? "http://127.0.0.1:11435";
|
|
21470
|
-
var DEFAULT_DELEGATE_MODEL = process.env.FREELLAMA_MCP_DEFAULT_MODEL
|
|
21483
|
+
var DEFAULT_DELEGATE_MODEL = process.env.FREELLAMA_MCP_DEFAULT_MODEL?.trim() || void 0;
|
|
21471
21484
|
var DEFAULT_DELEGATE_MAX_TURNS = envInt("FREELLAMA_MCP_MAX_TURNS", 8);
|
|
21472
21485
|
var DEFAULT_DELEGATE_TIMEOUT_SECONDS = envInt("FREELLAMA_MCP_DELEGATE_TIMEOUT_SECONDS", 180);
|
|
21473
21486
|
var DEFAULT_PULL_TIMEOUT_SECONDS = envInt("FREELLAMA_MCP_PULL_TIMEOUT_SECONDS", 1200);
|
|
@@ -21521,16 +21534,159 @@ async function assertAllowedWorkspace(workspacePath) {
|
|
|
21521
21534
|
}
|
|
21522
21535
|
return resolved;
|
|
21523
21536
|
}
|
|
21537
|
+
var DELEGATE_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
21538
|
+
"PATH",
|
|
21539
|
+
"HOME",
|
|
21540
|
+
"USER",
|
|
21541
|
+
"LOGNAME",
|
|
21542
|
+
"LANG",
|
|
21543
|
+
"LC_ALL",
|
|
21544
|
+
"LC_CTYPE",
|
|
21545
|
+
"TZ",
|
|
21546
|
+
"TMPDIR",
|
|
21547
|
+
"TEMP",
|
|
21548
|
+
"TMP",
|
|
21549
|
+
"SYSTEMROOT",
|
|
21550
|
+
"SYSTEMDRIVE",
|
|
21551
|
+
"WINDIR",
|
|
21552
|
+
"COMSPEC",
|
|
21553
|
+
"PATHEXT",
|
|
21554
|
+
"APPDATA",
|
|
21555
|
+
"LOCALAPPDATA",
|
|
21556
|
+
"USERPROFILE",
|
|
21557
|
+
"HTTP_PROXY",
|
|
21558
|
+
"HTTPS_PROXY",
|
|
21559
|
+
"NO_PROXY",
|
|
21560
|
+
"http_proxy",
|
|
21561
|
+
"https_proxy",
|
|
21562
|
+
"no_proxy",
|
|
21563
|
+
"NODE_EXTRA_CA_CERTS",
|
|
21564
|
+
"SSL_CERT_FILE",
|
|
21565
|
+
"SSL_CERT_DIR",
|
|
21566
|
+
"REQUESTS_CA_BUNDLE",
|
|
21567
|
+
"XDG_CACHE_HOME",
|
|
21568
|
+
"XDG_DATA_HOME",
|
|
21569
|
+
"npm_config_cache",
|
|
21570
|
+
"PYTHONPATH"
|
|
21571
|
+
]);
|
|
21572
|
+
function delegateEnvironment(source = process.env) {
|
|
21573
|
+
const env = {};
|
|
21574
|
+
for (const [key, value] of Object.entries(source)) {
|
|
21575
|
+
if (value !== void 0 && (DELEGATE_ENV_ALLOWLIST.has(key) || key.startsWith("FREELLAMA_"))) env[key] = value;
|
|
21576
|
+
}
|
|
21577
|
+
return env;
|
|
21578
|
+
}
|
|
21524
21579
|
|
|
21525
21580
|
// src/native.ts
|
|
21526
21581
|
import { createRequire } from "node:module";
|
|
21527
21582
|
import native from "../native/index.js";
|
|
21528
|
-
var { doctor, machine, health, createSession, deleteSession, listModels, route, runTask, runTaskRequest, runTaskBatchRequest } = native;
|
|
21583
|
+
var { createScope, getScope, forkScope, deleteScope, warmModelRequest, doctor, machine, health, status, usage, createSession, deleteSession, killSession, listModels, route, runTask, runTaskRequest, runTaskBatchRequest, listTaskJobs, getTaskJob, cancelTaskJob, removeTaskJob } = native;
|
|
21529
21584
|
var { version: SERVER_VERSION } = createRequire(import.meta.url)("../package.json");
|
|
21530
21585
|
|
|
21531
|
-
// src/
|
|
21532
|
-
import {
|
|
21586
|
+
// src/serve.ts
|
|
21587
|
+
import { spawn } from "node:child_process";
|
|
21588
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
21589
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
21533
21590
|
import path2 from "node:path";
|
|
21591
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
21592
|
+
var HEALTH_PATH = "/_freellama/v1/health";
|
|
21593
|
+
var STARTUP_TIMEOUT_MS = 15e3;
|
|
21594
|
+
var child = null;
|
|
21595
|
+
var starting = null;
|
|
21596
|
+
function withServe(call) {
|
|
21597
|
+
return async (endpoint, ...args) => {
|
|
21598
|
+
await ensureServe(endpoint ?? void 0);
|
|
21599
|
+
return call(endpoint, ...args);
|
|
21600
|
+
};
|
|
21601
|
+
}
|
|
21602
|
+
function autostartEnabled() {
|
|
21603
|
+
return process.env.FREELLAMA_MCP_AUTOSTART_SERVE !== "0";
|
|
21604
|
+
}
|
|
21605
|
+
function loopbackListen(endpoint) {
|
|
21606
|
+
try {
|
|
21607
|
+
const url = new URL(endpoint);
|
|
21608
|
+
if (!["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)) return null;
|
|
21609
|
+
return `${url.hostname === "localhost" ? "127.0.0.1" : url.hostname}:${url.port || "80"}`;
|
|
21610
|
+
} catch {
|
|
21611
|
+
return null;
|
|
21612
|
+
}
|
|
21613
|
+
}
|
|
21614
|
+
async function answers(endpoint, timeoutMs) {
|
|
21615
|
+
try {
|
|
21616
|
+
await fetch(`${endpoint.replace(/\/$/, "")}${HEALTH_PATH}`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
21617
|
+
return true;
|
|
21618
|
+
} catch {
|
|
21619
|
+
return false;
|
|
21620
|
+
}
|
|
21621
|
+
}
|
|
21622
|
+
function serveBinaryCandidates() {
|
|
21623
|
+
const exe = process.platform === "win32" ? "freellama.exe" : "freellama";
|
|
21624
|
+
const candidates = [
|
|
21625
|
+
path2.join(REPO_ROOT, "target", "release", exe),
|
|
21626
|
+
path2.join(REPO_ROOT, "target", "debug", exe)
|
|
21627
|
+
];
|
|
21628
|
+
const requireFromHere = createRequire2(fileURLToPath2(import.meta.url));
|
|
21629
|
+
const suffixes = process.platform === "linux" ? ["-gnu", "-musl"] : process.platform === "win32" ? ["-msvc"] : [""];
|
|
21630
|
+
for (const suffix of suffixes) {
|
|
21631
|
+
try {
|
|
21632
|
+
const manifest = requireFromHere.resolve(`@octocodeai/freellama-native-${process.platform}-${process.arch}${suffix}/package.json`);
|
|
21633
|
+
candidates.push(path2.join(path2.dirname(manifest), exe));
|
|
21634
|
+
} catch {
|
|
21635
|
+
}
|
|
21636
|
+
}
|
|
21637
|
+
if (process.env.FREELLAMA_SERVE_BINARY) candidates.unshift(process.env.FREELLAMA_SERVE_BINARY);
|
|
21638
|
+
return candidates;
|
|
21639
|
+
}
|
|
21640
|
+
function stopAutostartedServe() {
|
|
21641
|
+
if (child && child.exitCode === null) child.kill("SIGTERM");
|
|
21642
|
+
child = null;
|
|
21643
|
+
}
|
|
21644
|
+
async function ensureServe(endpoint) {
|
|
21645
|
+
const target = endpoint ?? DEFAULT_SERVE_ENDPOINT;
|
|
21646
|
+
if (!autostartEnabled() || target !== DEFAULT_SERVE_ENDPOINT) return;
|
|
21647
|
+
const listen = loopbackListen(target);
|
|
21648
|
+
if (!listen) return;
|
|
21649
|
+
if (child && child.exitCode === null && await answers(target, 1e3)) return;
|
|
21650
|
+
starting ??= (async () => {
|
|
21651
|
+
try {
|
|
21652
|
+
if (await answers(target, 1e3)) return;
|
|
21653
|
+
const binary = serveBinaryCandidates().find((candidate) => existsSync2(candidate));
|
|
21654
|
+
if (!binary) return;
|
|
21655
|
+
const spawned = spawn(binary, ["serve", "--listen", listen, "--upstream", DEFAULT_OLLAMA_ENDPOINT], {
|
|
21656
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
21657
|
+
});
|
|
21658
|
+
child = spawned;
|
|
21659
|
+
spawned.stderr?.on("data", (chunk) => process.stderr.write(`[freellama serve] ${chunk}`));
|
|
21660
|
+
spawned.once("exit", () => {
|
|
21661
|
+
if (child === spawned) child = null;
|
|
21662
|
+
});
|
|
21663
|
+
await new Promise((resolve, reject) => {
|
|
21664
|
+
spawned.once("spawn", resolve);
|
|
21665
|
+
spawned.once("error", (error2) => {
|
|
21666
|
+
if (child === spawned) child = null;
|
|
21667
|
+
reject(new Error(`Could not start freellama serve at ${target}: ${error2.message}`));
|
|
21668
|
+
});
|
|
21669
|
+
});
|
|
21670
|
+
const deadline = Date.now() + STARTUP_TIMEOUT_MS;
|
|
21671
|
+
while (Date.now() < deadline && child === spawned) {
|
|
21672
|
+
if (await answers(target, 500)) return;
|
|
21673
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
21674
|
+
}
|
|
21675
|
+
if (child === spawned) {
|
|
21676
|
+
stopAutostartedServe();
|
|
21677
|
+
throw new Error(`freellama serve did not become ready at ${target} within ${STARTUP_TIMEOUT_MS}ms.`);
|
|
21678
|
+
}
|
|
21679
|
+
throw new Error(`freellama serve exited before becoming ready at ${target} (exit ${spawned.exitCode}, signal ${spawned.signalCode}).`);
|
|
21680
|
+
} finally {
|
|
21681
|
+
starting = null;
|
|
21682
|
+
}
|
|
21683
|
+
})();
|
|
21684
|
+
await starting;
|
|
21685
|
+
}
|
|
21686
|
+
|
|
21687
|
+
// src/helpers.ts
|
|
21688
|
+
import { existsSync as existsSync3, realpathSync, statSync } from "node:fs";
|
|
21689
|
+
import path3 from "node:path";
|
|
21534
21690
|
function extractExistingWorkspacePath(command, workspace) {
|
|
21535
21691
|
let root;
|
|
21536
21692
|
try {
|
|
@@ -21545,35 +21701,36 @@ function extractExistingWorkspacePath(command, workspace) {
|
|
|
21545
21701
|
if (index > 0 && patternFlags.has(tokens[index - 1] ?? "")) continue;
|
|
21546
21702
|
const token = raw.replace(/^["']|["']$/g, "").replace(/[|;&)]+$/g, "").replace(/:\d+(?::\d+)?$/, "");
|
|
21547
21703
|
if (!token || token.startsWith("-") || /[*?$`]/.test(token)) continue;
|
|
21548
|
-
const candidate =
|
|
21549
|
-
if (!
|
|
21704
|
+
const candidate = path3.isAbsolute(token) ? token : path3.resolve(root, token);
|
|
21705
|
+
if (!existsSync3(candidate)) continue;
|
|
21550
21706
|
try {
|
|
21551
21707
|
const resolved = realpathSync(candidate);
|
|
21552
|
-
const relative =
|
|
21553
|
-
const withinRoot = relative && relative !== ".." && !relative.startsWith(`..${
|
|
21708
|
+
const relative = path3.relative(root, resolved);
|
|
21709
|
+
const withinRoot = relative && relative !== ".." && !relative.startsWith(`..${path3.sep}`);
|
|
21554
21710
|
if (withinRoot && statSync(resolved).isFile()) return relative;
|
|
21555
21711
|
} catch {
|
|
21556
21712
|
}
|
|
21557
21713
|
}
|
|
21558
21714
|
return null;
|
|
21559
21715
|
}
|
|
21560
|
-
async function ollamaFetch(endpoint,
|
|
21716
|
+
async function ollamaFetch(endpoint, path6, init = {}) {
|
|
21561
21717
|
const base = (endpoint ?? DEFAULT_OLLAMA_ENDPOINT).replace(/\/$/, "");
|
|
21562
21718
|
const controller = new AbortController();
|
|
21563
21719
|
const timeout = setTimeout(
|
|
21564
21720
|
() => controller.abort(),
|
|
21565
21721
|
init.timeoutMs ?? DEFAULT_OLLAMA_FETCH_TIMEOUT_SECONDS * 1e3
|
|
21566
21722
|
);
|
|
21723
|
+
const signal = init.signal ? AbortSignal.any([controller.signal, init.signal]) : controller.signal;
|
|
21567
21724
|
try {
|
|
21568
|
-
const response = await fetch(`${base}${
|
|
21725
|
+
const response = await fetch(`${base}${path6}`, {
|
|
21569
21726
|
method: init.method ?? "GET",
|
|
21570
21727
|
headers: init.body ? { "content-type": "application/json" } : void 0,
|
|
21571
21728
|
body: init.body ? JSON.stringify(init.body) : void 0,
|
|
21572
|
-
signal
|
|
21729
|
+
signal
|
|
21573
21730
|
});
|
|
21574
|
-
const text = await response.text();
|
|
21731
|
+
const text = init.onLine && response.ok && response.body ? await readNdjson(response.body, init.onLine) : await response.text();
|
|
21575
21732
|
if (!response.ok) {
|
|
21576
|
-
throw new Error(`Ollama ${init.method ?? "GET"} ${
|
|
21733
|
+
throw new Error(`Ollama ${init.method ?? "GET"} ${path6} -> HTTP ${response.status}: ${text}`);
|
|
21577
21734
|
}
|
|
21578
21735
|
if (!text) return {};
|
|
21579
21736
|
if (init.parse === "ndjson") return text;
|
|
@@ -21582,6 +21739,26 @@ async function ollamaFetch(endpoint, path5, init = {}) {
|
|
|
21582
21739
|
clearTimeout(timeout);
|
|
21583
21740
|
}
|
|
21584
21741
|
}
|
|
21742
|
+
async function readNdjson(body, onLine) {
|
|
21743
|
+
const decoder = new TextDecoder();
|
|
21744
|
+
let text = "";
|
|
21745
|
+
let pending = "";
|
|
21746
|
+
for await (const chunk of body) {
|
|
21747
|
+
const piece = decoder.decode(chunk, { stream: true });
|
|
21748
|
+
text += piece;
|
|
21749
|
+
pending += piece;
|
|
21750
|
+
const lines = pending.split("\n");
|
|
21751
|
+
pending = lines.pop() ?? "";
|
|
21752
|
+
for (const line of lines) {
|
|
21753
|
+
try {
|
|
21754
|
+
const parsed = JSON.parse(line);
|
|
21755
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) onLine(parsed);
|
|
21756
|
+
} catch {
|
|
21757
|
+
}
|
|
21758
|
+
}
|
|
21759
|
+
}
|
|
21760
|
+
return text + decoder.decode();
|
|
21761
|
+
}
|
|
21585
21762
|
function summarizeOllamaPullStream(text) {
|
|
21586
21763
|
const events = [];
|
|
21587
21764
|
for (const line of text.split(/\r?\n/)) {
|
|
@@ -21612,10 +21789,10 @@ function summarizeOllamaPullStream(text) {
|
|
|
21612
21789
|
const completed = typeof withBytes?.completed === "number" ? withBytes.completed : null;
|
|
21613
21790
|
const total = typeof withBytes?.total === "number" ? withBytes.total : null;
|
|
21614
21791
|
const percent = completed != null && total != null && total > 0 ? Math.round(completed / total * 1e3) / 10 : null;
|
|
21615
|
-
const
|
|
21792
|
+
const status2 = typeof last.error === "string" && last.error ? "error" : last.status;
|
|
21616
21793
|
return {
|
|
21617
21794
|
...last,
|
|
21618
|
-
...
|
|
21795
|
+
...status2 === void 0 ? {} : { status: status2 },
|
|
21619
21796
|
progress: {
|
|
21620
21797
|
events: events.length,
|
|
21621
21798
|
completed,
|
|
@@ -21625,19 +21802,21 @@ function summarizeOllamaPullStream(text) {
|
|
|
21625
21802
|
}
|
|
21626
21803
|
};
|
|
21627
21804
|
}
|
|
21628
|
-
async function ollamaPull(endpoint, model, timeoutSeconds) {
|
|
21805
|
+
async function ollamaPull(endpoint, model, timeoutSeconds, options = {}) {
|
|
21629
21806
|
const raw = await ollamaFetch(endpoint, "/api/pull", {
|
|
21630
21807
|
method: "POST",
|
|
21631
|
-
body: {
|
|
21808
|
+
body: { model, stream: true },
|
|
21632
21809
|
timeoutMs: (timeoutSeconds ?? DEFAULT_PULL_TIMEOUT_SECONDS) * 1e3,
|
|
21633
|
-
parse: "ndjson"
|
|
21810
|
+
parse: "ndjson",
|
|
21811
|
+
signal: options.signal,
|
|
21812
|
+
onLine: options.onProgress
|
|
21634
21813
|
});
|
|
21635
21814
|
if (typeof raw === "string") return summarizeOllamaPullStream(raw);
|
|
21636
21815
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) return raw;
|
|
21637
21816
|
return { status: "empty" };
|
|
21638
21817
|
}
|
|
21639
|
-
var endpointParam = external_exports.string().min(1).optional()
|
|
21640
|
-
var ollamaEndpointParam = external_exports.string().min(1).optional()
|
|
21818
|
+
var endpointParam = external_exports.string().min(1).optional();
|
|
21819
|
+
var ollamaEndpointParam = external_exports.string().min(1).optional();
|
|
21641
21820
|
var TASK_KINDS = [
|
|
21642
21821
|
"completion",
|
|
21643
21822
|
"coding",
|
|
@@ -21649,17 +21828,15 @@ var TASK_KINDS = [
|
|
|
21649
21828
|
"long_context"
|
|
21650
21829
|
];
|
|
21651
21830
|
var MCP_TASK_KINDS = [...TASK_KINDS, "code_review"];
|
|
21652
|
-
var taskParam = external_exports.enum(MCP_TASK_KINDS).describe("
|
|
21831
|
+
var taskParam = external_exports.enum(MCP_TASK_KINDS).default("completion").describe("caller owns prompts and output format.");
|
|
21653
21832
|
function canonicalTaskKind(task) {
|
|
21654
21833
|
return task === "code_review" ? "coding" : task;
|
|
21655
21834
|
}
|
|
21656
|
-
var objectiveParam = external_exports.enum(["fastest", "balanced", "quality"]).optional()
|
|
21657
|
-
var executionPreferenceParam = external_exports.enum(["auto", "prefer_cpu", "prefer_gpu"]).optional()
|
|
21658
|
-
|
|
21659
|
-
);
|
|
21660
|
-
var minPlacementEvidenceParam = external_exports.enum(["configured", "observed"]).optional().describe('"observed" fails closed unless Ollama /api/ps confirms the selected processor');
|
|
21835
|
+
var objectiveParam = external_exports.enum(["fastest", "balanced", "quality"]).optional();
|
|
21836
|
+
var executionPreferenceParam = external_exports.enum(["auto", "prefer_cpu", "prefer_gpu"]).optional();
|
|
21837
|
+
var minPlacementEvidenceParam = external_exports.enum(["configured", "observed"]).optional();
|
|
21661
21838
|
var CONFIDENCE_RANK = { low: 1, medium: 2 };
|
|
21662
|
-
var minConfidenceParam = external_exports.enum(["low", "medium"]).optional()
|
|
21839
|
+
var minConfidenceParam = external_exports.enum(["low", "medium"]).optional();
|
|
21663
21840
|
function belowConfidence(decision, minConfidence) {
|
|
21664
21841
|
if (!minConfidence) return null;
|
|
21665
21842
|
const actual = typeof decision.confidence === "string" ? decision.confidence : "low";
|
|
@@ -21679,22 +21856,49 @@ var REQUIRED_CAPABILITIES = [
|
|
|
21679
21856
|
"thinking",
|
|
21680
21857
|
"embedding"
|
|
21681
21858
|
];
|
|
21682
|
-
var requiredCapabilitiesParam = external_exports.array(external_exports.enum(REQUIRED_CAPABILITIES)).max(REQUIRED_CAPABILITIES.length).optional()
|
|
21859
|
+
var requiredCapabilitiesParam = external_exports.array(external_exports.enum(REQUIRED_CAPABILITIES)).max(REQUIRED_CAPABILITIES.length).optional();
|
|
21860
|
+
var systemPromptParam = external_exports.string().optional().describe("Local model instructions; verbatim.");
|
|
21861
|
+
var messagesParam = external_exports.array(external_exports.object({
|
|
21862
|
+
role: external_exports.enum(["system", "user", "assistant", "tool"]),
|
|
21863
|
+
content: external_exports.string().optional()
|
|
21864
|
+
}).passthrough()).min(1).optional();
|
|
21865
|
+
var localToolsParam = external_exports.array(external_exports.object({
|
|
21866
|
+
type: external_exports.literal("function"),
|
|
21867
|
+
function: external_exports.object({
|
|
21868
|
+
name: external_exports.string().min(1),
|
|
21869
|
+
description: external_exports.string().optional(),
|
|
21870
|
+
parameters: external_exports.record(external_exports.unknown()).optional()
|
|
21871
|
+
}).passthrough()
|
|
21872
|
+
}).passthrough()).min(1).optional();
|
|
21873
|
+
function taskMessages({ systemPrompt, messages, prompt, images }) {
|
|
21874
|
+
if (systemPrompt === void 0) return messages ?? [];
|
|
21875
|
+
const conversation = messages ?? (prompt === void 0 ? [] : [{
|
|
21876
|
+
role: "user",
|
|
21877
|
+
content: prompt,
|
|
21878
|
+
...images === void 0 ? {} : { images }
|
|
21879
|
+
}]);
|
|
21880
|
+
return [{ role: "system", content: systemPrompt }, ...conversation];
|
|
21881
|
+
}
|
|
21683
21882
|
var batchTaskParam = external_exports.object({
|
|
21684
|
-
task: taskParam,
|
|
21883
|
+
task: taskParam.removeDefault().optional().describe("caller owns prompts and output format."),
|
|
21685
21884
|
objective: objectiveParam,
|
|
21686
21885
|
model: external_exports.string().min(1).optional(),
|
|
21687
21886
|
sessionId: external_exports.string().uuid().optional(),
|
|
21887
|
+
scopeId: external_exports.string().uuid().optional(),
|
|
21888
|
+
scopeRevision: external_exports.number().int().nonnegative().optional(),
|
|
21688
21889
|
contextTokens: external_exports.number().int().positive().optional(),
|
|
21689
21890
|
executionPreference: executionPreferenceParam,
|
|
21690
21891
|
minPlacementEvidence: minPlacementEvidenceParam,
|
|
21691
21892
|
requiredCapabilities: requiredCapabilitiesParam,
|
|
21692
21893
|
priority: external_exports.enum(["interactive", "normal", "background"]).optional(),
|
|
21894
|
+
maxWaitSeconds: external_exports.number().int().positive().optional(),
|
|
21895
|
+
timeoutSeconds: external_exports.number().int().positive().optional(),
|
|
21693
21896
|
prompt: external_exports.string().min(1).optional(),
|
|
21694
|
-
|
|
21897
|
+
systemPrompt: systemPromptParam,
|
|
21898
|
+
messages: messagesParam,
|
|
21695
21899
|
images: external_exports.array(external_exports.string().min(1)).min(1).optional(),
|
|
21696
21900
|
input: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).min(1)]).optional(),
|
|
21697
|
-
tools:
|
|
21901
|
+
tools: localToolsParam,
|
|
21698
21902
|
keepAlive: external_exports.string().min(1).optional(),
|
|
21699
21903
|
format: external_exports.union([external_exports.literal("json"), external_exports.record(external_exports.unknown())]).optional(),
|
|
21700
21904
|
think: external_exports.union([external_exports.boolean(), external_exports.enum(["low", "medium", "high"])]).optional(),
|
|
@@ -21716,7 +21920,9 @@ var doctorResultSchema = external_exports.object({
|
|
|
21716
21920
|
}).passthrough();
|
|
21717
21921
|
var sessionResultSchema = external_exports.object({
|
|
21718
21922
|
session_id: external_exports.string().optional(),
|
|
21719
|
-
deleted: external_exports.boolean().optional()
|
|
21923
|
+
deleted: external_exports.boolean().optional(),
|
|
21924
|
+
killed: external_exports.boolean().optional(),
|
|
21925
|
+
runner_stop_confirmed: external_exports.boolean().optional()
|
|
21720
21926
|
}).passthrough();
|
|
21721
21927
|
var manageResultSchema = external_exports.object({
|
|
21722
21928
|
status: external_exports.string().optional(),
|
|
@@ -21728,7 +21934,9 @@ var deleteResultSchema = external_exports.object({
|
|
|
21728
21934
|
var modelsResultSchema = external_exports.object({
|
|
21729
21935
|
models: external_exports.array(external_exports.record(external_exports.unknown())).optional(),
|
|
21730
21936
|
tags: external_exports.array(external_exports.record(external_exports.unknown())).optional(),
|
|
21731
|
-
page: external_exports.unknown().optional()
|
|
21937
|
+
page: external_exports.unknown().optional(),
|
|
21938
|
+
knowledge: external_exports.unknown().optional(),
|
|
21939
|
+
library: external_exports.unknown().optional()
|
|
21732
21940
|
}).passthrough();
|
|
21733
21941
|
var taskResultSchema = external_exports.object({
|
|
21734
21942
|
selected_model: external_exports.string().optional(),
|
|
@@ -21763,22 +21971,22 @@ function configuredExternalCost(env = process.env) {
|
|
|
21763
21971
|
}
|
|
21764
21972
|
return { model, input, output };
|
|
21765
21973
|
}
|
|
21766
|
-
function costTelemetry(
|
|
21974
|
+
function costTelemetry(usage2, externalCost) {
|
|
21767
21975
|
const local = {
|
|
21768
|
-
inputTokens:
|
|
21769
|
-
outputTokens:
|
|
21770
|
-
totalTokens:
|
|
21771
|
-
totalDurationNs:
|
|
21976
|
+
inputTokens: usage2.inputTokens,
|
|
21977
|
+
outputTokens: usage2.outputTokens,
|
|
21978
|
+
totalTokens: usage2.inputTokens === null || usage2.outputTokens === null ? null : usage2.inputTokens + usage2.outputTokens,
|
|
21979
|
+
totalDurationNs: usage2.totalDurationNs ?? null
|
|
21772
21980
|
};
|
|
21773
|
-
if (!externalCost ||
|
|
21981
|
+
if (!externalCost || usage2.inputTokens === null || usage2.outputTokens === null) {
|
|
21774
21982
|
return {
|
|
21775
21983
|
local,
|
|
21776
21984
|
externalEquivalent: null,
|
|
21777
21985
|
note: externalCost ? "External equivalent unavailable because Ollama did not report both input and output token counts." : "No external rate card supplied; local usage is observed, but avoided external cost is not estimated."
|
|
21778
21986
|
};
|
|
21779
21987
|
}
|
|
21780
|
-
const inputUsd =
|
|
21781
|
-
const outputUsd =
|
|
21988
|
+
const inputUsd = usage2.inputTokens * externalCost.input / 1e6;
|
|
21989
|
+
const outputUsd = usage2.outputTokens * externalCost.output / 1e6;
|
|
21782
21990
|
return {
|
|
21783
21991
|
local,
|
|
21784
21992
|
externalEquivalent: {
|
|
@@ -21816,9 +22024,52 @@ function resultSummary(value) {
|
|
|
21816
22024
|
const keys = Object.keys(value);
|
|
21817
22025
|
return `Structured result available (${keys.slice(0, 8).join(", ") || "empty object"}).`;
|
|
21818
22026
|
}
|
|
22027
|
+
var ANSWER_TEXT_MAX_CHARS = 8 * 1024;
|
|
22028
|
+
function record2(value) {
|
|
22029
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
22030
|
+
}
|
|
22031
|
+
function taskAnswerText(payload) {
|
|
22032
|
+
const response = record2(payload.response);
|
|
22033
|
+
if (!response) return void 0;
|
|
22034
|
+
const model = record2(payload.route)?.selected_model ?? payload.selected_model ?? response.model;
|
|
22035
|
+
const header = typeof model === "string" && model ? `[${model}] ` : "";
|
|
22036
|
+
const message = record2(response.message);
|
|
22037
|
+
if (message) {
|
|
22038
|
+
const parts = [];
|
|
22039
|
+
if (typeof message.content === "string" && message.content.trim()) parts.push(message.content.trim());
|
|
22040
|
+
if (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) {
|
|
22041
|
+
parts.push(`tool_calls: ${JSON.stringify(message.tool_calls)}`);
|
|
22042
|
+
}
|
|
22043
|
+
if (parts.length === 0) parts.push("(empty response)");
|
|
22044
|
+
return clipText(header + parts.join("\n"), ANSWER_TEXT_MAX_CHARS);
|
|
22045
|
+
}
|
|
22046
|
+
if (typeof response.response === "string") return clipText(header + response.response.trim(), ANSWER_TEXT_MAX_CHARS);
|
|
22047
|
+
const omitted = record2(response.embeddings_omitted);
|
|
22048
|
+
if (Array.isArray(response.embeddings) || omitted) {
|
|
22049
|
+
const count = Array.isArray(response.embeddings) ? response.embeddings.length : omitted?.count;
|
|
22050
|
+
const where = omitted ? "vectors withheld; pass returnEmbeddings:true" : "vectors are in structuredContent";
|
|
22051
|
+
return `${header}embedding complete (${String(count ?? "?")} vectors); ${where}.`;
|
|
22052
|
+
}
|
|
22053
|
+
return void 0;
|
|
22054
|
+
}
|
|
22055
|
+
function batchAnswerText(payload) {
|
|
22056
|
+
if (!Array.isArray(payload.results)) return void 0;
|
|
22057
|
+
const perItem = Math.max(512, Math.floor(ANSWER_TEXT_MAX_CHARS / Math.max(payload.results.length, 1)));
|
|
22058
|
+
const lines = payload.results.map((row) => {
|
|
22059
|
+
const item = record2(row) ?? {};
|
|
22060
|
+
const id = String(item.id ?? "?");
|
|
22061
|
+
if (item.ok !== true) return `## ${id} (failed)
|
|
22062
|
+
${clipText(JSON.stringify(item.error ?? item), perItem)}`;
|
|
22063
|
+
const answer = taskAnswerText(record2(item.response) ?? {}) ?? "(no answer)";
|
|
22064
|
+
return `## ${id}
|
|
22065
|
+
${clipText(answer, perItem)}`;
|
|
22066
|
+
});
|
|
22067
|
+
return lines.join("\n\n");
|
|
22068
|
+
}
|
|
21819
22069
|
function structuredResult(value, options = {}) {
|
|
22070
|
+
const text = options.text ?? (options.legacyJson ? serialize(value) : resultSummary(value));
|
|
21820
22071
|
return {
|
|
21821
|
-
content: [{ type: "text", text
|
|
22072
|
+
content: [{ type: "text", text }],
|
|
21822
22073
|
structuredContent: value
|
|
21823
22074
|
};
|
|
21824
22075
|
}
|
|
@@ -21839,13 +22090,31 @@ ${clipText(raw, 2e3)}`
|
|
|
21839
22090
|
}
|
|
21840
22091
|
return structuredResult(value);
|
|
21841
22092
|
}
|
|
22093
|
+
function isStructuredSuccess(result) {
|
|
22094
|
+
return !("isError" in result && result.isError) && "structuredContent" in result && result.structuredContent !== void 0;
|
|
22095
|
+
}
|
|
21842
22096
|
function errorResult(error2) {
|
|
21843
22097
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
22098
|
+
let receipt;
|
|
22099
|
+
try {
|
|
22100
|
+
const parsed = JSON.parse(message);
|
|
22101
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && typeof parsed.error === "string") {
|
|
22102
|
+
receipt = parsed;
|
|
22103
|
+
}
|
|
22104
|
+
} catch {
|
|
22105
|
+
}
|
|
21844
22106
|
const managedServeUnavailable = /(?:connection refused|connect error|failed to connect|error sending request)/i.test(message) && /(?:_freellama|127\.0\.0\.1:11435|localhost:11435)/i.test(message);
|
|
22107
|
+
const ollamaUnavailable = !managedServeUnavailable && /(?:connection refused|connect error|failed to connect|error sending request)/i.test(message) && /\/api\/(?:tags|ps|chat|generate|embed|show)/.test(message);
|
|
21845
22108
|
const actionableMessage = managedServeUnavailable ? `${message}
|
|
21846
22109
|
|
|
21847
|
-
FreeLlama managed serve is unreachable. Start it with \`freellama serve\`, or set \`FREELLAMA_SERVE_ENDPOINT\` to a running managed endpoint; then retry. Run \`doctor\` to inspect the configured endpoint.` : message
|
|
21848
|
-
|
|
22110
|
+
FreeLlama managed serve is unreachable. Start it with \`freellama serve\`, or set \`FREELLAMA_SERVE_ENDPOINT\` to a running managed endpoint; then retry. Run \`doctor\` to inspect the configured endpoint.` : ollamaUnavailable ? `${message}
|
|
22111
|
+
|
|
22112
|
+
Ollama is not running at that address. Ask the user to start Ollama (the app, or \`ollama serve\`); retrying before that cannot succeed.` : message;
|
|
22113
|
+
return {
|
|
22114
|
+
content: [{ type: "text", text: actionableMessage }],
|
|
22115
|
+
isError: true,
|
|
22116
|
+
...receipt ? { structuredContent: receipt } : {}
|
|
22117
|
+
};
|
|
21849
22118
|
}
|
|
21850
22119
|
var adapterCallSchema = external_exports.object({
|
|
21851
22120
|
raw_name: external_exports.string().optional(),
|
|
@@ -21900,11 +22169,64 @@ function summarizeEmbeddings(payload) {
|
|
|
21900
22169
|
}
|
|
21901
22170
|
|
|
21902
22171
|
// src/model-search.ts
|
|
22172
|
+
function decodeHtml(text) {
|
|
22173
|
+
const entities = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " ", middot: "\xB7", bull: "\u2022" };
|
|
22174
|
+
return text.replace(/&(#x[\da-f]+|#\d+|[a-z]+);/gi, (raw, entity) => {
|
|
22175
|
+
if (!entity.startsWith("#")) return entities[entity.toLowerCase()] ?? raw;
|
|
22176
|
+
const code = entity[1].toLowerCase() === "x" ? Number.parseInt(entity.slice(2), 16) : Number(entity.slice(1));
|
|
22177
|
+
return code > 0 && code <= 1114111 && !(code >= 55296 && code <= 57343) ? String.fromCodePoint(code) : raw;
|
|
22178
|
+
});
|
|
22179
|
+
}
|
|
22180
|
+
function attribute(tag, name) {
|
|
22181
|
+
return tag.match(new RegExp(`(?:^|\\s)${name}\\s*=\\s*(["'])([\\s\\S]*?)\\1`, "i"))?.[2];
|
|
22182
|
+
}
|
|
22183
|
+
function htmlText(html) {
|
|
22184
|
+
return decodeHtml(html.replace(/<(script|style|svg)\b[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<\/(?:p|li|div|h[1-6]|pre|tr)>|<br\s*\/?\s*>/gi, "\n").replace(/<[^>]*>/g, " ")).split("\n").map((line) => line.replace(/\s+/g, " ").trim()).filter(Boolean).join("\n");
|
|
22185
|
+
}
|
|
22186
|
+
function divContent(html, id) {
|
|
22187
|
+
const tags = /<\/?div\b[^>]*>/gi;
|
|
22188
|
+
let start;
|
|
22189
|
+
let depth = 0;
|
|
22190
|
+
for (const match of html.matchAll(tags)) {
|
|
22191
|
+
if (start === void 0) {
|
|
22192
|
+
if (attribute(match[0], "id") !== id) continue;
|
|
22193
|
+
start = match.index + match[0].length;
|
|
22194
|
+
depth = 1;
|
|
22195
|
+
} else {
|
|
22196
|
+
depth += /^<\//.test(match[0]) ? -1 : 1;
|
|
22197
|
+
if (depth === 0) return html.slice(start, match.index);
|
|
22198
|
+
}
|
|
22199
|
+
}
|
|
22200
|
+
return void 0;
|
|
22201
|
+
}
|
|
22202
|
+
function parseModelCard(html) {
|
|
22203
|
+
const meta = [...html.matchAll(/<meta\b[^>]*>/gi)].find((m) => attribute(m[0], "name") === "description");
|
|
22204
|
+
const description = decodeHtml(meta ? attribute(meta[0], "content") ?? "" : "").trim();
|
|
22205
|
+
const editor = [...html.matchAll(/<textarea\b([^>]*)>([\s\S]*?)<\/textarea>/gi)].find((m) => attribute(m[1], "id") === "editor");
|
|
22206
|
+
const rendered = divContent(html, "display");
|
|
22207
|
+
const readme = editor ? decodeHtml(editor[2]).trim() : rendered === void 0 ? "" : htmlText(rendered);
|
|
22208
|
+
if (!description && !editor && rendered === void 0) throw new Error("Ollama library markup was not recognized.");
|
|
22209
|
+
const header = html.split(/<div[^>]*\bid=["']readme["']/i)[0];
|
|
22210
|
+
const capabilities = [...new Set([...header.matchAll(/<span\b[^>]*class=["'][^"']*text-(?:indigo-600|cyan-500)[^"']*["'][^>]*>\s*([a-z]+)\s*<\/span>/g)].map((m) => m[1]))];
|
|
22211
|
+
return { description, readme, readmeFormat: editor ? "markdown" : "text", capabilities };
|
|
22212
|
+
}
|
|
22213
|
+
function libraryTrialCandidate(tag, embedding) {
|
|
22214
|
+
return {
|
|
22215
|
+
tag,
|
|
22216
|
+
evidence: "download_size_preflight_only",
|
|
22217
|
+
taskQuality: "unmeasured",
|
|
22218
|
+
why: embedding ? "Smallest listed download inside the conservative host-memory budget. This is a trial candidate; smaller size does not establish better embedding quality." : "Largest listed download inside the conservative host-memory budget. This is a trial candidate; download size establishes neither accelerator fit nor task quality.",
|
|
22219
|
+
configure: 'Set contextTokens and output limits for the workload, then inspect preview and execution receipts. Ollama defaults depend on its configuration and hardware. Use keepAlive:"0" for one-off work; keep related repeated work warm when resources permit.',
|
|
22220
|
+
caution: "Measure this exact tag on representative tasks before choosing it. Include resident runners, context/KV caches and OS headroom in memory fit. Discovery does not authorize a pull."
|
|
22221
|
+
};
|
|
22222
|
+
}
|
|
21903
22223
|
function parseModelSearch(html) {
|
|
21904
22224
|
const results = [];
|
|
21905
22225
|
for (const block of html.split(/<li\s/).slice(1)) {
|
|
21906
|
-
const
|
|
22226
|
+
const link = block.match(/href="\/(?:library\/([\w.-]+)|([\w.-]+\/[\w.-]+))"/);
|
|
22227
|
+
const name = link?.[1] ?? link?.[2];
|
|
21907
22228
|
if (!name) continue;
|
|
22229
|
+
if (!/<p\b[^>]*class="max-w-lg/.test(block)) continue;
|
|
21908
22230
|
const description = block.match(/<p class="max-w-lg[^"]*">([\s\S]*?)<\/p>/)?.[1]?.replace(/<[^>]+>/g, "").replace(/'/g, "'").replace(/&/g, "&").replace(/"/g, '"').replace(/\s+/g, " ").trim() ?? "";
|
|
21909
22231
|
const capabilities = [...block.matchAll(/text-(?:indigo-600|cyan-500)[^>]*>([a-z]+)<\/span>/g)].map(
|
|
21910
22232
|
(m) => m[1]
|
|
@@ -21918,7 +22240,8 @@ function parseModelSearch(html) {
|
|
|
21918
22240
|
capabilities,
|
|
21919
22241
|
pulls: stat("Pulls"),
|
|
21920
22242
|
tags: stat("Tag"),
|
|
21921
|
-
|
|
22243
|
+
cloudAvailable: capabilities.includes("cloud"),
|
|
22244
|
+
cloudOnly: null
|
|
21922
22245
|
});
|
|
21923
22246
|
}
|
|
21924
22247
|
return results;
|
|
@@ -21926,38 +22249,330 @@ function parseModelSearch(html) {
|
|
|
21926
22249
|
function parseModelTags(html, family) {
|
|
21927
22250
|
const tags = [];
|
|
21928
22251
|
const seen = /* @__PURE__ */ new Set();
|
|
21929
|
-
const row = /<a
|
|
22252
|
+
const row = /<a\b([^>]*)>([\s\S]*?)<\/a>/gi;
|
|
21930
22253
|
for (const m of html.matchAll(row)) {
|
|
21931
|
-
|
|
22254
|
+
let tag;
|
|
22255
|
+
try {
|
|
22256
|
+
tag = decodeURIComponent(attribute(m[1], "href") ?? "").replace(/^\/(?:library\/)?/, "");
|
|
22257
|
+
} catch {
|
|
22258
|
+
continue;
|
|
22259
|
+
}
|
|
22260
|
+
if (!tag.startsWith(`${family}:`)) continue;
|
|
22261
|
+
const text = htmlText(m[2]).replace(/\n/g, " ");
|
|
22262
|
+
if (!/context window|[\d.]\s*[MG]B\b|\bcloud\b/i.test(text)) continue;
|
|
21932
22263
|
if (seen.has(tag)) continue;
|
|
21933
22264
|
seen.add(tag);
|
|
21934
|
-
const meta =
|
|
22265
|
+
const meta = text.split(/[·•]/).map((x) => x.trim());
|
|
21935
22266
|
const sizeText = meta.find((x) => /^[\d.]+\s?[MG]B$/i.test(x)) ?? null;
|
|
21936
22267
|
const bytes = sizeText ? Number.parseFloat(sizeText) * (/GB/i.test(sizeText) ? 1e9 : 1e6) : null;
|
|
21937
22268
|
tags.push({
|
|
21938
22269
|
tag,
|
|
22270
|
+
digest: text.replace(tag, "").match(/\b[\da-f]{12,64}\b/i)?.[0]?.toLowerCase() ?? null,
|
|
22271
|
+
cloud: /-cloud$/i.test(tag) || meta.some((part) => /^cloud$/i.test(part)),
|
|
21939
22272
|
size: sizeText,
|
|
21940
22273
|
sizeBytes: bytes,
|
|
21941
22274
|
context: meta.find((x) => /context window/i.test(x))?.replace(/\s*context window\s*/i, "") ?? null,
|
|
21942
|
-
modalities: meta.find((x) => /^(Text|Image|Audio)/i.test(x)) ?? null,
|
|
22275
|
+
modalities: meta.find((x) => /^(Text|Image|Audio)/i.test(x))?.replace(/\s+input.*$/i, "") ?? null,
|
|
21943
22276
|
updated: meta.at(-1) ?? null
|
|
21944
22277
|
});
|
|
21945
22278
|
}
|
|
21946
22279
|
return { family, tags };
|
|
21947
22280
|
}
|
|
21948
22281
|
|
|
22282
|
+
// src/model-knowledge.ts
|
|
22283
|
+
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
22284
|
+
var FAILURE_TTL_MS = 60 * 1e3;
|
|
22285
|
+
var MAX_PAGE_BYTES = 2 * 1024 * 1024;
|
|
22286
|
+
var MAX_README_CHARS = 64 * 1024;
|
|
22287
|
+
function libraryReference(model) {
|
|
22288
|
+
const match = model.match(/^(?:library\/)?([a-zA-Z0-9][\w.-]*(?:\/[a-zA-Z0-9][\w.-]*)?)(?::([\w.-]+))?$/);
|
|
22289
|
+
if (!match || match[1].split("/").some((part) => part === "." || part === "..")) return null;
|
|
22290
|
+
const family = match[1];
|
|
22291
|
+
const pathname = family.includes("/") ? family : `library/${family}`;
|
|
22292
|
+
return { family, tag: `${family}:${match[2] ?? "latest"}`, url: `https://ollama.com/${pathname}` };
|
|
22293
|
+
}
|
|
22294
|
+
var LibraryFetchError = class extends Error {
|
|
22295
|
+
constructor(status2, message) {
|
|
22296
|
+
super(message);
|
|
22297
|
+
this.status = status2;
|
|
22298
|
+
}
|
|
22299
|
+
status;
|
|
22300
|
+
};
|
|
22301
|
+
var OllamaLibraryClient = class {
|
|
22302
|
+
constructor(options = {}) {
|
|
22303
|
+
this.options = options;
|
|
22304
|
+
}
|
|
22305
|
+
options;
|
|
22306
|
+
cache = /* @__PURE__ */ new Map();
|
|
22307
|
+
pending = /* @__PURE__ */ new Map();
|
|
22308
|
+
async search(params) {
|
|
22309
|
+
const url = `https://ollama.com/search?${params.toString()}`;
|
|
22310
|
+
const models = parseModelSearch(await this.page(url));
|
|
22311
|
+
return { url, models, fetchedAt: new Date((this.options.now ?? Date.now)()).toISOString() };
|
|
22312
|
+
}
|
|
22313
|
+
async lookup(model) {
|
|
22314
|
+
const ref = libraryReference(model);
|
|
22315
|
+
if (!ref) return {
|
|
22316
|
+
status: "unmatched",
|
|
22317
|
+
sourceUrl: null,
|
|
22318
|
+
tagsSourceUrl: null,
|
|
22319
|
+
fetchedAt: null,
|
|
22320
|
+
expiresAt: null,
|
|
22321
|
+
cached: false,
|
|
22322
|
+
message: "No exact Ollama public name could be resolved. Base-model provenance is unknown."
|
|
22323
|
+
};
|
|
22324
|
+
const now = this.options.now ?? Date.now;
|
|
22325
|
+
const cached2 = this.cache.get(ref.family);
|
|
22326
|
+
if (cached2 && Date.parse(cached2.expiresAt) > now()) {
|
|
22327
|
+
this.cache.delete(ref.family);
|
|
22328
|
+
this.cache.set(ref.family, cached2);
|
|
22329
|
+
return { ...cached2, cached: true };
|
|
22330
|
+
}
|
|
22331
|
+
const pending = this.pending.get(ref.family);
|
|
22332
|
+
if (pending) return { ...await pending, cached: true };
|
|
22333
|
+
const work = this.load(ref).then((record3) => {
|
|
22334
|
+
this.cache.delete(ref.family);
|
|
22335
|
+
this.cache.set(ref.family, record3);
|
|
22336
|
+
while (this.cache.size > (this.options.maxEntries ?? 128)) this.cache.delete(this.cache.keys().next().value);
|
|
22337
|
+
return record3;
|
|
22338
|
+
});
|
|
22339
|
+
this.pending.set(ref.family, work);
|
|
22340
|
+
try {
|
|
22341
|
+
return await work;
|
|
22342
|
+
} finally {
|
|
22343
|
+
this.pending.delete(ref.family);
|
|
22344
|
+
}
|
|
22345
|
+
}
|
|
22346
|
+
async page(url) {
|
|
22347
|
+
const response = await (this.options.fetch ?? fetch)(url, {
|
|
22348
|
+
method: "GET",
|
|
22349
|
+
redirect: "error",
|
|
22350
|
+
headers: { accept: "text/html" },
|
|
22351
|
+
signal: AbortSignal.timeout(this.options.timeoutMs ?? Math.min(DEFAULT_OLLAMA_FETCH_TIMEOUT_SECONDS * 1e3, 1e4))
|
|
22352
|
+
});
|
|
22353
|
+
if (!response.ok) {
|
|
22354
|
+
await response.body?.cancel();
|
|
22355
|
+
throw new LibraryFetchError(response.status === 404 ? "not_found" : "unavailable", `Ollama library returned HTTP ${response.status}.`);
|
|
22356
|
+
}
|
|
22357
|
+
if (!(response.headers.get("content-type") ?? "").includes("text/html")) {
|
|
22358
|
+
await response.body?.cancel();
|
|
22359
|
+
throw new LibraryFetchError("parse_error", "Ollama library did not return HTML.");
|
|
22360
|
+
}
|
|
22361
|
+
if (Number(response.headers.get("content-length")) > MAX_PAGE_BYTES) {
|
|
22362
|
+
await response.body?.cancel();
|
|
22363
|
+
throw new LibraryFetchError("unavailable", "Ollama library page exceeds the 2 MiB limit.");
|
|
22364
|
+
}
|
|
22365
|
+
const reader = response.body?.getReader();
|
|
22366
|
+
if (!reader) throw new LibraryFetchError("parse_error", "Ollama library returned an empty body.");
|
|
22367
|
+
const chunks = [];
|
|
22368
|
+
let bytes = 0;
|
|
22369
|
+
try {
|
|
22370
|
+
while (true) {
|
|
22371
|
+
const { done, value } = await reader.read();
|
|
22372
|
+
if (done) break;
|
|
22373
|
+
bytes += value.byteLength;
|
|
22374
|
+
if (bytes > MAX_PAGE_BYTES) throw new LibraryFetchError("unavailable", "Ollama library page exceeds the 2 MiB limit.");
|
|
22375
|
+
chunks.push(value);
|
|
22376
|
+
}
|
|
22377
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
22378
|
+
} finally {
|
|
22379
|
+
await reader.cancel();
|
|
22380
|
+
}
|
|
22381
|
+
}
|
|
22382
|
+
async load(ref) {
|
|
22383
|
+
let result;
|
|
22384
|
+
try {
|
|
22385
|
+
const pages = await Promise.allSettled([this.page(ref.url), this.page(`${ref.url}/tags`)]);
|
|
22386
|
+
if (pages[0].status === "rejected") throw pages[0].reason;
|
|
22387
|
+
if (pages[1].status === "rejected") throw pages[1].reason;
|
|
22388
|
+
let card;
|
|
22389
|
+
try {
|
|
22390
|
+
card = parseModelCard(pages[0].value);
|
|
22391
|
+
} catch {
|
|
22392
|
+
throw new LibraryFetchError("parse_error", "Ollama model-card markup was not recognized.");
|
|
22393
|
+
}
|
|
22394
|
+
const { tags } = parseModelTags(pages[1].value, ref.family);
|
|
22395
|
+
if (tags.length === 0) throw new LibraryFetchError("parse_error", "No tag rows were recognized; check the source page before concluding a model is absent.");
|
|
22396
|
+
result = {
|
|
22397
|
+
status: "available",
|
|
22398
|
+
tags,
|
|
22399
|
+
readmeTruncated: card.readme.length > MAX_README_CHARS,
|
|
22400
|
+
card: { ...card, readme: card.readme.slice(0, MAX_README_CHARS) }
|
|
22401
|
+
};
|
|
22402
|
+
} catch (error2) {
|
|
22403
|
+
result = {
|
|
22404
|
+
status: error2 instanceof LibraryFetchError ? error2.status : "unavailable",
|
|
22405
|
+
message: error2 instanceof LibraryFetchError ? error2.message : "Ollama library lookup failed or timed out. Local metadata remains available."
|
|
22406
|
+
};
|
|
22407
|
+
}
|
|
22408
|
+
const now = (this.options.now ?? Date.now)();
|
|
22409
|
+
return {
|
|
22410
|
+
...result,
|
|
22411
|
+
sourceUrl: ref.url,
|
|
22412
|
+
tagsSourceUrl: `${ref.url}/tags`,
|
|
22413
|
+
fetchedAt: new Date(now).toISOString(),
|
|
22414
|
+
expiresAt: new Date(now + (result.status === "available" ? CACHE_TTL_MS : FAILURE_TTL_MS)).toISOString(),
|
|
22415
|
+
cached: false
|
|
22416
|
+
};
|
|
22417
|
+
}
|
|
22418
|
+
};
|
|
22419
|
+
var supportedUses = {
|
|
22420
|
+
completion: { use: "text_generation", reason: "Ollama advertises completion support; task accuracy still needs evaluation." },
|
|
22421
|
+
tools: { use: "tool_calling", reason: "Ollama advertises tool-call support; this does not establish reliable agent execution." },
|
|
22422
|
+
vision: { use: "image_understanding", reason: "Ollama advertises image-input support; OCR and visual accuracy are unmeasured here." },
|
|
22423
|
+
audio: { use: "audio_input", reason: "Ollama advertises audio support; inspect the model instructions for the supported audio workflow." },
|
|
22424
|
+
embedding: { use: "embeddings", reason: "Ollama advertises embedding support for retrieval and similarity; retrieval quality needs evaluation." },
|
|
22425
|
+
thinking: { use: "thinking", reason: "Ollama advertises a thinking mode; it does not establish reasoning accuracy." },
|
|
22426
|
+
insert: { use: "fill_in_middle", reason: "Ollama advertises suffix-based insertion support." },
|
|
22427
|
+
image: { use: "image_generation", reason: "Ollama advertises image-generation support." }
|
|
22428
|
+
};
|
|
22429
|
+
var advertisedUses = [
|
|
22430
|
+
{ task: "coding", pattern: /\b(coding|code generation|software engineering)\b/i, requires: "completion" },
|
|
22431
|
+
{ task: "tool_calling", pattern: /\b(tool (?:use|calling)|function calling)\b/i, requires: "tools" },
|
|
22432
|
+
{ task: "image_understanding", pattern: /\b(vision|image understanding|processing text and images|multimodal|OCR|optical character recognition)\b/i, requires: "vision" },
|
|
22433
|
+
{ task: "reasoning", pattern: /\b(reasoning|mathematical|math tasks)\b/i, requires: "completion" },
|
|
22434
|
+
{ task: "embeddings", pattern: /\b(embedding|embeddings|text encoder)\b/i, requires: "embedding" },
|
|
22435
|
+
{ task: "summarization", pattern: /\b(summarization|summarisation|summarize|summarise)\b/i, requires: "completion" },
|
|
22436
|
+
{ task: "question_answering", pattern: /\b(question answering|question-answering)\b/i, requires: "completion" },
|
|
22437
|
+
{ task: "translation", pattern: /\b(translation|translate)\b/i, requires: "completion" },
|
|
22438
|
+
{ task: "long_context", pattern: /\b(long[- ]context|repository[- ]scale understanding)\b/i, requires: "completion" }
|
|
22439
|
+
];
|
|
22440
|
+
function prose(card) {
|
|
22441
|
+
return `${card.description}
|
|
22442
|
+
${card.readme}`.replace(/```[\s\S]*?```|~~~[\s\S]*?~~~/g, "").replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").split(/\n|(?<=[.!?])\s+/).map((line) => line.replace(/^[\s#>*-]+/, "").trim()).filter(Boolean);
|
|
22443
|
+
}
|
|
22444
|
+
function publicModelGuidance(record3, capabilities, includeReadme = false) {
|
|
22445
|
+
const card = record3.card;
|
|
22446
|
+
if (!card) return { advertisedUseCases: [], usageNotes: [] };
|
|
22447
|
+
const sentences = prose(card);
|
|
22448
|
+
const advertisedUseCases = advertisedUses.flatMap(({ task, pattern, requires }) => {
|
|
22449
|
+
if (capabilities && !capabilities.includes(requires)) return [];
|
|
22450
|
+
const sentence = sentences.find((sentence2) => pattern.test(sentence2) && !/\b(not|never|cannot|unsupported|without)\b|doesn['’]t/i.test(sentence2));
|
|
22451
|
+
const start = sentence ? Math.max(0, sentence.search(pattern) - 120) : 0;
|
|
22452
|
+
return sentence ? [{
|
|
22453
|
+
task,
|
|
22454
|
+
basis: "advertised",
|
|
22455
|
+
scope: "family",
|
|
22456
|
+
quality: "unmeasured",
|
|
22457
|
+
evidence: { excerpt: sentence.slice(start, start + 320), sourceUrl: record3.sourceUrl, fetchedAt: record3.fetchedAt }
|
|
22458
|
+
}] : [];
|
|
22459
|
+
});
|
|
22460
|
+
const usageNotes = sentences.filter((sentence) => /\b(requires?|only|cannot|limitations?|must|memory|languages?|prefix)\b|not support|context (window|length)/i.test(sentence)).slice(0, 8).map((text) => ({ text: text.slice(0, 400), scope: "family", sourceUrl: record3.sourceUrl }));
|
|
22461
|
+
return {
|
|
22462
|
+
description: card.description,
|
|
22463
|
+
advertisedFamilyCapabilities: card.capabilities,
|
|
22464
|
+
advertisedUseCases,
|
|
22465
|
+
usageNotes,
|
|
22466
|
+
readmeAvailable: card.readme.length > 0,
|
|
22467
|
+
...includeReadme ? { readme: { text: card.readme, format: card.readmeFormat, truncated: record3.readmeTruncated ?? false } } : {}
|
|
22468
|
+
};
|
|
22469
|
+
}
|
|
22470
|
+
function provenance(record3) {
|
|
22471
|
+
const { card: _card, tags: _tags, readmeTruncated: _truncated, ...source } = record3;
|
|
22472
|
+
return source;
|
|
22473
|
+
}
|
|
22474
|
+
function modelKnowledge(model, data, record3, includeReadme = false, supportedFeaturesSource = "ollama_api") {
|
|
22475
|
+
const capabilities = Array.isArray(data.capabilities) ? data.capabilities.filter((item) => typeof item === "string") : [];
|
|
22476
|
+
const supportedUseCases = capabilities.flatMap((capability) => Object.hasOwn(supportedUses, capability) ? [{ capability, ...supportedUses[capability], basis: "supported_feature" }] : []);
|
|
22477
|
+
const local = {
|
|
22478
|
+
supportedFeatures: capabilities,
|
|
22479
|
+
supportedFeaturesSource,
|
|
22480
|
+
supportedUseCases,
|
|
22481
|
+
quality: "metadata_only",
|
|
22482
|
+
note: "Supported features and advertised uses do not establish task quality. Keep exact-model benchmark and policy evidence separate."
|
|
22483
|
+
};
|
|
22484
|
+
if (data.remote_host || data.remote_model || /-cloud$/i.test(model)) {
|
|
22485
|
+
return { ...local, localModel: false, library: { status: "remote_model", message: "This Ollama entry points to a remote model." } };
|
|
22486
|
+
}
|
|
22487
|
+
if (!record3) return { ...local, localModel: true, library: { status: "not_requested" } };
|
|
22488
|
+
if (record3.status !== "available") return { ...local, localModel: true, library: provenance(record3) };
|
|
22489
|
+
const ref = libraryReference(model);
|
|
22490
|
+
const tag = record3.tags?.find((tag2) => tag2.tag === ref.tag);
|
|
22491
|
+
const digest = typeof data.digest === "string" ? data.digest.replace(/^sha256:/, "").toLowerCase() : null;
|
|
22492
|
+
const validDigest = digest && /^[\da-f]{64}$/.test(digest);
|
|
22493
|
+
const matched = validDigest && tag?.digest && digest.startsWith(tag.digest);
|
|
22494
|
+
const status2 = !tag ? "tag_not_found" : !validDigest || !tag.digest ? "unverified" : matched ? "matched" : "digest_mismatch";
|
|
22495
|
+
if (!matched || tag?.cloud) return { ...local, localModel: true, library: {
|
|
22496
|
+
...provenance(record3),
|
|
22497
|
+
status: tag?.cloud ? "remote_tag" : status2,
|
|
22498
|
+
message: "Public guidance was withheld because an exact local tag and digest match could not be verified.",
|
|
22499
|
+
tag: tag ?? null
|
|
22500
|
+
} };
|
|
22501
|
+
return { ...local, localModel: true, library: {
|
|
22502
|
+
...provenance(record3),
|
|
22503
|
+
status: status2,
|
|
22504
|
+
tag,
|
|
22505
|
+
...publicModelGuidance(record3, capabilities, includeReadme)
|
|
22506
|
+
} };
|
|
22507
|
+
}
|
|
22508
|
+
async function enrichInstalledModels(models, client, includeLibrary, loadTags) {
|
|
22509
|
+
const results = new Array(models.length);
|
|
22510
|
+
const inventories = /* @__PURE__ */ new Map();
|
|
22511
|
+
let next = 0;
|
|
22512
|
+
await Promise.all(Array.from({ length: Math.min(4, models.length) }, async () => {
|
|
22513
|
+
while (next < models.length) {
|
|
22514
|
+
const index = next++;
|
|
22515
|
+
const model = models[index];
|
|
22516
|
+
const name = String(model.name ?? model.model ?? "");
|
|
22517
|
+
let local = model;
|
|
22518
|
+
let featureSource = "freellama_catalog";
|
|
22519
|
+
let localError;
|
|
22520
|
+
if (includeLibrary && loadTags) {
|
|
22521
|
+
const upstream = model.execution?.upstream;
|
|
22522
|
+
let inventory = inventories.get(upstream);
|
|
22523
|
+
if (!inventory) {
|
|
22524
|
+
inventory = loadTags(upstream);
|
|
22525
|
+
inventories.set(upstream, inventory);
|
|
22526
|
+
}
|
|
22527
|
+
try {
|
|
22528
|
+
const entry = (await inventory).find((entry2) => String(entry2.name ?? entry2.model) === name);
|
|
22529
|
+
if (!entry || entry.digest !== model.digest) localError = "Local inventory changed; inspect models again before matching public guidance.";
|
|
22530
|
+
else {
|
|
22531
|
+
local = { ...model, ...entry };
|
|
22532
|
+
if (Array.isArray(entry.capabilities)) featureSource = "ollama_api";
|
|
22533
|
+
}
|
|
22534
|
+
} catch {
|
|
22535
|
+
localError = "The selected Ollama backend's inventory could not be verified; public guidance was withheld.";
|
|
22536
|
+
}
|
|
22537
|
+
}
|
|
22538
|
+
const record3 = includeLibrary && !localError && !local.remote_host && !local.remote_model && !/-cloud$/i.test(name) ? await client.lookup(name) : void 0;
|
|
22539
|
+
const knowledge = modelKnowledge(name, local, record3, false, featureSource);
|
|
22540
|
+
results[index] = { ...model, knowledge: localError ? { ...knowledge, library: { status: "unverified", message: localError } } : knowledge };
|
|
22541
|
+
}
|
|
22542
|
+
}));
|
|
22543
|
+
return results;
|
|
22544
|
+
}
|
|
22545
|
+
|
|
21949
22546
|
// src/delegate.ts
|
|
21950
|
-
import { existsSync as
|
|
21951
|
-
import
|
|
22547
|
+
import { existsSync as existsSync4, readFileSync } from "node:fs";
|
|
22548
|
+
import path4 from "node:path";
|
|
22549
|
+
function researchErrorResult(error2, diagnostic) {
|
|
22550
|
+
const result = errorResult(error2);
|
|
22551
|
+
const summary = diagnostic ?? result.content[0].text;
|
|
22552
|
+
return {
|
|
22553
|
+
...result,
|
|
22554
|
+
content: [{ type: "text", text: summary }],
|
|
22555
|
+
structuredContent: {
|
|
22556
|
+
...result.structuredContent ?? { error: summary },
|
|
22557
|
+
answer: "",
|
|
22558
|
+
summary,
|
|
22559
|
+
verification: {
|
|
22560
|
+
recommendation: "escalate",
|
|
22561
|
+
grounded: false,
|
|
22562
|
+
why: "The research request failed; no usable answer was produced."
|
|
22563
|
+
}
|
|
22564
|
+
}
|
|
22565
|
+
};
|
|
22566
|
+
}
|
|
21952
22567
|
var MODEL_EVIDENCE = (() => {
|
|
21953
22568
|
const configured = process.env.FREELLAMA_MCP_MODEL_EVIDENCE;
|
|
21954
22569
|
const candidates = [
|
|
21955
22570
|
configured,
|
|
21956
|
-
|
|
22571
|
+
path4.join(REPO_ROOT, "benchmark/evidence/model-evidence.json")
|
|
21957
22572
|
].filter((x) => Boolean(x));
|
|
21958
22573
|
for (const file of candidates) {
|
|
21959
22574
|
try {
|
|
21960
|
-
if (!
|
|
22575
|
+
if (!existsSync4(file)) continue;
|
|
21961
22576
|
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
21962
22577
|
return parsed.models ?? {};
|
|
21963
22578
|
} catch {
|
|
@@ -22025,11 +22640,135 @@ function assessDelegatedAnswer(question, evidenceCount, model) {
|
|
|
22025
22640
|
};
|
|
22026
22641
|
}
|
|
22027
22642
|
|
|
22643
|
+
// src/context-tools.ts
|
|
22644
|
+
var routeDefaults = external_exports.object({
|
|
22645
|
+
task: taskParam.removeDefault().optional(),
|
|
22646
|
+
objective: objectiveParam,
|
|
22647
|
+
model: external_exports.string().min(1).optional(),
|
|
22648
|
+
contextTokens: external_exports.number().int().positive().optional(),
|
|
22649
|
+
executionPreference: executionPreferenceParam,
|
|
22650
|
+
minPlacementEvidence: minPlacementEvidenceParam,
|
|
22651
|
+
minConfidence: minConfidenceParam,
|
|
22652
|
+
requiredCapabilities: requiredCapabilitiesParam
|
|
22653
|
+
}).strict();
|
|
22654
|
+
var limits = external_exports.object({
|
|
22655
|
+
maxMessages: external_exports.number().int().positive().optional(),
|
|
22656
|
+
maxBytes: external_exports.number().int().positive().optional(),
|
|
22657
|
+
maxEstimatedTokens: external_exports.number().int().positive().optional(),
|
|
22658
|
+
ttlSeconds: external_exports.number().int().positive().optional()
|
|
22659
|
+
}).strict();
|
|
22660
|
+
function scopeBody(messages, defaults, bounds) {
|
|
22661
|
+
return {
|
|
22662
|
+
messages,
|
|
22663
|
+
route_defaults: defaults === void 0 ? void 0 : {
|
|
22664
|
+
task: defaults.task === void 0 ? void 0 : canonicalTaskKind(defaults.task),
|
|
22665
|
+
objective: defaults.objective,
|
|
22666
|
+
model: defaults.model,
|
|
22667
|
+
context_tokens: defaults.contextTokens,
|
|
22668
|
+
execution_preference: defaults.executionPreference,
|
|
22669
|
+
min_placement_evidence: defaults.minPlacementEvidence,
|
|
22670
|
+
min_confidence: defaults.minConfidence,
|
|
22671
|
+
required_capabilities: defaults.requiredCapabilities
|
|
22672
|
+
},
|
|
22673
|
+
limits: bounds === void 0 ? void 0 : {
|
|
22674
|
+
max_messages: bounds.maxMessages,
|
|
22675
|
+
max_bytes: bounds.maxBytes,
|
|
22676
|
+
max_estimated_tokens: bounds.maxEstimatedTokens,
|
|
22677
|
+
ttl_seconds: bounds.ttlSeconds
|
|
22678
|
+
}
|
|
22679
|
+
};
|
|
22680
|
+
}
|
|
22681
|
+
function registerContextTools(server2) {
|
|
22682
|
+
const createScope2 = withServe(createScope);
|
|
22683
|
+
const getScope2 = withServe(getScope);
|
|
22684
|
+
const forkScope2 = withServe(forkScope);
|
|
22685
|
+
const deleteScope2 = withServe(deleteScope);
|
|
22686
|
+
const warmModel = withServe(warmModelRequest);
|
|
22687
|
+
server2.registerTool("scope", {
|
|
22688
|
+
description: "Use when: saved history. Do not use when: KV control. Returns: process-local scope metadata; history is opt-in.",
|
|
22689
|
+
inputSchema: external_exports.object({
|
|
22690
|
+
action: external_exports.enum(["create", "get", "fork", "delete"]),
|
|
22691
|
+
endpoint: endpointParam,
|
|
22692
|
+
scopeId: external_exports.string().uuid().optional(),
|
|
22693
|
+
revision: external_exports.number().int().nonnegative().optional(),
|
|
22694
|
+
messages: messagesParam.unwrap().min(0).optional(),
|
|
22695
|
+
routeDefaults: routeDefaults.optional(),
|
|
22696
|
+
limits: limits.optional(),
|
|
22697
|
+
includeMessages: external_exports.boolean().optional()
|
|
22698
|
+
}).strict(),
|
|
22699
|
+
outputSchema: objectResultSchema,
|
|
22700
|
+
annotations: { destructiveHint: true }
|
|
22701
|
+
}, async ({ action, endpoint, scopeId, revision, messages, routeDefaults: defaults, limits: bounds, includeMessages }) => {
|
|
22702
|
+
try {
|
|
22703
|
+
if (action === "create" !== (scopeId === void 0)) throw new Error("scopeId is required for get/fork/delete, forbidden for create.");
|
|
22704
|
+
if (action === "fork" !== (revision !== void 0)) throw new Error("revision is required only for fork.");
|
|
22705
|
+
if (includeMessages !== void 0 && action !== "get") throw new Error("includeMessages is valid only for get.");
|
|
22706
|
+
if (messages !== void 0 && action !== "create") throw new Error("messages is valid only for create.");
|
|
22707
|
+
if ((defaults !== void 0 || bounds !== void 0) && action !== "create" && action !== "fork") throw new Error("routeDefaults and limits are valid only for create/fork.");
|
|
22708
|
+
if (action === "delete") {
|
|
22709
|
+
await deleteScope2(endpoint, scopeId);
|
|
22710
|
+
return structuredResult({ deleted: true, scope_id: scopeId });
|
|
22711
|
+
}
|
|
22712
|
+
return parsedResult(action === "create" ? await createScope2(endpoint, scopeBody(messages, defaults, bounds)) : action === "fork" ? await forkScope2(endpoint, scopeId, { ...scopeBody(void 0, defaults, bounds), revision }) : await getScope2(endpoint, scopeId, includeMessages));
|
|
22713
|
+
} catch (error2) {
|
|
22714
|
+
return errorResult(error2);
|
|
22715
|
+
}
|
|
22716
|
+
});
|
|
22717
|
+
server2.registerTool("warm_model", {
|
|
22718
|
+
description: "Use when: preload an installed model. Do not use when: generation or pull. Returns: managed residency receipt or job ID.",
|
|
22719
|
+
inputSchema: external_exports.object({
|
|
22720
|
+
endpoint: endpointParam,
|
|
22721
|
+
model: external_exports.string().min(1),
|
|
22722
|
+
task: taskParam.removeDefault().optional(),
|
|
22723
|
+
contextTokens: external_exports.number().int().positive().optional(),
|
|
22724
|
+
executionPreference: executionPreferenceParam,
|
|
22725
|
+
minPlacementEvidence: minPlacementEvidenceParam,
|
|
22726
|
+
priority: external_exports.enum(["interactive", "normal", "background"]).optional(),
|
|
22727
|
+
keepAlive: external_exports.string().min(1).optional().describe("Omitted = adaptive finite TTL."),
|
|
22728
|
+
maxWaitSeconds: external_exports.number().int().positive().optional(),
|
|
22729
|
+
timeoutSeconds: external_exports.number().int().positive().optional(),
|
|
22730
|
+
defer: external_exports.boolean().optional()
|
|
22731
|
+
}).strict(),
|
|
22732
|
+
outputSchema: objectResultSchema,
|
|
22733
|
+
annotations: { destructiveHint: false }
|
|
22734
|
+
}, async ({ endpoint, model, task, contextTokens, executionPreference, minPlacementEvidence, priority, keepAlive, maxWaitSeconds, timeoutSeconds, defer }) => {
|
|
22735
|
+
try {
|
|
22736
|
+
if (task === "embedding") throw new Error("warm_model supports chat models; embedding warming is unsupported.");
|
|
22737
|
+
return parsedResult(await warmModel(endpoint, {
|
|
22738
|
+
model,
|
|
22739
|
+
task: task === void 0 ? void 0 : canonicalTaskKind(task),
|
|
22740
|
+
context_tokens: contextTokens,
|
|
22741
|
+
execution_preference: executionPreference,
|
|
22742
|
+
min_placement_evidence: minPlacementEvidence,
|
|
22743
|
+
priority,
|
|
22744
|
+
keep_alive: keepAlive,
|
|
22745
|
+
max_wait_seconds: maxWaitSeconds,
|
|
22746
|
+
timeout_seconds: timeoutSeconds,
|
|
22747
|
+
defer
|
|
22748
|
+
}));
|
|
22749
|
+
} catch (error2) {
|
|
22750
|
+
return errorResult(error2);
|
|
22751
|
+
}
|
|
22752
|
+
});
|
|
22753
|
+
}
|
|
22754
|
+
|
|
22028
22755
|
// src/index.ts
|
|
22029
22756
|
var execFileAsync = promisify(execFile);
|
|
22757
|
+
var createSession2 = withServe(createSession);
|
|
22758
|
+
var deleteSession2 = withServe(deleteSession);
|
|
22759
|
+
var killSession2 = withServe(killSession);
|
|
22760
|
+
var listModels2 = withServe(listModels);
|
|
22761
|
+
var ollamaLibrary = new OllamaLibraryClient();
|
|
22762
|
+
var route2 = withServe(route);
|
|
22763
|
+
var runTaskRequest2 = withServe(runTaskRequest);
|
|
22764
|
+
var runTaskBatchRequest2 = withServe(runTaskBatchRequest);
|
|
22765
|
+
var listTaskJobs2 = withServe(listTaskJobs);
|
|
22766
|
+
var getTaskJob2 = withServe(getTaskJob);
|
|
22767
|
+
var cancelTaskJob2 = withServe(cancelTaskJob);
|
|
22768
|
+
var removeTaskJob2 = withServe(removeTaskJob);
|
|
22030
22769
|
var EXTERNAL_COST = configuredExternalCost();
|
|
22031
22770
|
function withTaskTelemetry(result) {
|
|
22032
|
-
if (!(
|
|
22771
|
+
if (!isStructuredSuccess(result)) return result;
|
|
22033
22772
|
const payload = result.structuredContent;
|
|
22034
22773
|
const metrics = payload.metrics;
|
|
22035
22774
|
return structuredResult({
|
|
@@ -22039,10 +22778,10 @@ function withTaskTelemetry(result) {
|
|
|
22039
22778
|
outputTokens: typeof metrics?.output_tokens === "number" ? metrics.output_tokens : null,
|
|
22040
22779
|
totalDurationNs: typeof metrics?.total_duration_ns === "number" ? metrics.total_duration_ns : null
|
|
22041
22780
|
}, EXTERNAL_COST)
|
|
22042
|
-
});
|
|
22781
|
+
}, { text: taskAnswerText(payload) });
|
|
22043
22782
|
}
|
|
22044
22783
|
function withBatchTelemetry(result) {
|
|
22045
|
-
if (!(
|
|
22784
|
+
if (!isStructuredSuccess(result)) return result;
|
|
22046
22785
|
const payload = result.structuredContent;
|
|
22047
22786
|
const rows = Array.isArray(payload.results) ? payload.results : [];
|
|
22048
22787
|
let inputTokens = 0;
|
|
@@ -22067,7 +22806,7 @@ function withBatchTelemetry(result) {
|
|
|
22067
22806
|
...payload,
|
|
22068
22807
|
results,
|
|
22069
22808
|
telemetry: complete === rows.filter((row) => row?.ok === true).length ? costTelemetry({ inputTokens, outputTokens }, EXTERNAL_COST) : { local: null, externalEquivalent: null, note: "Batch aggregate unavailable because one or more successful items omitted token counts." }
|
|
22070
|
-
});
|
|
22809
|
+
}, { text: batchAnswerText(payload) });
|
|
22071
22810
|
}
|
|
22072
22811
|
function pageLiveList(items, limit, cursor, identity) {
|
|
22073
22812
|
const pageSize = limit ?? 20;
|
|
@@ -22095,9 +22834,9 @@ function pageLiveList(items, limit, cursor, identity) {
|
|
|
22095
22834
|
}
|
|
22096
22835
|
var liveDelegates = /* @__PURE__ */ new Set();
|
|
22097
22836
|
function killLiveDelegates() {
|
|
22098
|
-
for (const
|
|
22837
|
+
for (const child2 of liveDelegates) {
|
|
22099
22838
|
try {
|
|
22100
|
-
|
|
22839
|
+
child2.kill("SIGKILL");
|
|
22101
22840
|
} catch {
|
|
22102
22841
|
}
|
|
22103
22842
|
}
|
|
@@ -22109,63 +22848,107 @@ for (const stream of [process.stdout, process.stderr]) {
|
|
|
22109
22848
|
throw error2;
|
|
22110
22849
|
});
|
|
22111
22850
|
}
|
|
22112
|
-
process.on("exit",
|
|
22851
|
+
process.on("exit", () => {
|
|
22852
|
+
killLiveDelegates();
|
|
22853
|
+
stopAutostartedServe();
|
|
22854
|
+
});
|
|
22855
|
+
process.stdin.on("close", () => {
|
|
22856
|
+
killLiveDelegates();
|
|
22857
|
+
stopAutostartedServe();
|
|
22858
|
+
process.exit(0);
|
|
22859
|
+
});
|
|
22860
|
+
function pullProgressReporter(extra) {
|
|
22861
|
+
const token = extra._meta?.progressToken;
|
|
22862
|
+
if (token === void 0) return void 0;
|
|
22863
|
+
let lastSent = 0;
|
|
22864
|
+
let step = 0;
|
|
22865
|
+
return (event) => {
|
|
22866
|
+
const now = Date.now();
|
|
22867
|
+
if (now - lastSent < 500 && event.status !== "success") return;
|
|
22868
|
+
lastSent = now;
|
|
22869
|
+
step += 1;
|
|
22870
|
+
const completed = typeof event.completed === "number" ? event.completed : void 0;
|
|
22871
|
+
const total = typeof event.total === "number" ? event.total : void 0;
|
|
22872
|
+
void extra.sendNotification({
|
|
22873
|
+
method: "notifications/progress",
|
|
22874
|
+
params: {
|
|
22875
|
+
progressToken: token,
|
|
22876
|
+
progress: completed ?? step,
|
|
22877
|
+
...completed !== void 0 && total !== void 0 ? { total } : {},
|
|
22878
|
+
message: String(event.status ?? "pulling")
|
|
22879
|
+
}
|
|
22880
|
+
}).catch(() => void 0);
|
|
22881
|
+
};
|
|
22882
|
+
}
|
|
22113
22883
|
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
22114
22884
|
process.on(signal, () => {
|
|
22115
22885
|
killLiveDelegates();
|
|
22116
22886
|
process.exit(0);
|
|
22117
22887
|
});
|
|
22118
22888
|
}
|
|
22119
|
-
var INSTRUCTIONS = `
|
|
22120
|
-
|
|
22121
|
-
|
|
22122
|
-
|
|
22123
|
-
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
Docs: freellama://docs/index.`;
|
|
22889
|
+
var INSTRUCTIONS = `models{view:"installed"}; models{view:"resident"} for residency.
|
|
22890
|
+
run_task preview never executes; code_review aliases coding. Preview routing only; requiredCapabilities:["tools"] previews tools; omit preview and supply the payload. Caller executes tools.
|
|
22891
|
+
quality needs policy/model; medium needs policy+benchmark; observed needs /api/ps proof.
|
|
22892
|
+
Scoped run_task needs scopeId+scopeRevision. Scopes store history; sessions affinity, not messages/KV. defer:true: job.id\u2192task_jobs.jobId unchanged. Restart loses scopes/sessions/jobs.
|
|
22893
|
+
Check isError first; prefer structuredContent, else content[].text. page.next_cursor\u2192cursor unchanged.
|
|
22894
|
+
caller owns task decomposition/prompts/format/verification; findings are candidates, not accepted defects. operator owns endpoints, exact --cpu-model assignments/lifecycle. Ollama plus the OS/driver run physical CPU/GPU.
|
|
22895
|
+
ask approval for one exact tag and reported size before ollama_manage pull; search or recommendation is never download permission. Stop/delete need exact-tag approval.
|
|
22896
|
+
serve :11435; default-endpoint autostart optional. Docs: freellama://docs/index.`;
|
|
22127
22897
|
var server = new McpServer(
|
|
22128
22898
|
{ name: "freellama", version: SERVER_VERSION },
|
|
22129
22899
|
{ instructions: INSTRUCTIONS }
|
|
22130
22900
|
);
|
|
22131
|
-
var PACKAGED_DOCS_DIR =
|
|
22132
|
-
if (!
|
|
22901
|
+
var PACKAGED_DOCS_DIR = path5.resolve(path5.dirname(fileURLToPath3(import.meta.url)), "..", "docs");
|
|
22902
|
+
if (!existsSync5(PACKAGED_DOCS_DIR)) {
|
|
22133
22903
|
throw new Error(`FreeLlama MCP documentation is missing at ${PACKAGED_DOCS_DIR}; run the package build.`);
|
|
22134
22904
|
}
|
|
22135
|
-
var
|
|
22905
|
+
var PACKAGED_DEV_DOCS_DIR = path5.join(PACKAGED_DOCS_DIR, "dev");
|
|
22906
|
+
var packagedDocs = [
|
|
22907
|
+
...readdirSync(PACKAGED_DOCS_DIR).filter((name) => name.endsWith(".md")).sort(),
|
|
22908
|
+
...existsSync5(PACKAGED_DEV_DOCS_DIR) ? readdirSync(PACKAGED_DEV_DOCS_DIR).filter((name) => name.endsWith(".md")).sort().map((name) => `dev/${name}`) : []
|
|
22909
|
+
];
|
|
22910
|
+
var packagedDocNames = packagedDocs.map((name) => path5.basename(name));
|
|
22911
|
+
if (new Set(packagedDocNames).size !== packagedDocNames.length) {
|
|
22912
|
+
throw new Error(`FreeLlama MCP documentation has duplicate names across docs/ and docs/dev/: ${packagedDocs.join(", ")}`);
|
|
22913
|
+
}
|
|
22136
22914
|
if (!packagedDocs.includes("INDEX.md")) {
|
|
22137
22915
|
throw new Error(`FreeLlama MCP documentation index is missing at ${PACKAGED_DOCS_DIR}/INDEX.md; run the package build.`);
|
|
22138
22916
|
}
|
|
22139
22917
|
for (const name of packagedDocs) {
|
|
22140
|
-
const
|
|
22918
|
+
const base = path5.basename(name);
|
|
22919
|
+
const uri = `freellama://docs/${base === "INDEX.md" ? "index" : base.replace(/\.md$/, "")}`;
|
|
22141
22920
|
server.registerResource(
|
|
22142
|
-
`freellama-docs-${
|
|
22921
|
+
`freellama-docs-${base.toLowerCase().replace(/\.md$/, "")}`,
|
|
22143
22922
|
uri,
|
|
22144
22923
|
{
|
|
22145
22924
|
mimeType: "text/markdown",
|
|
22146
22925
|
description: name === "INDEX.md" ? "Index of packaged FreeLlama operator and agent documentation. Read this first, then fetch one relevant document." : `Packaged FreeLlama documentation: ${name}.`
|
|
22147
22926
|
},
|
|
22148
22927
|
async () => ({
|
|
22149
|
-
contents: [{ uri, mimeType: "text/markdown", text: await readFile(
|
|
22928
|
+
contents: [{ uri, mimeType: "text/markdown", text: await readFile(path5.join(PACKAGED_DOCS_DIR, name), "utf8") }]
|
|
22150
22929
|
})
|
|
22151
22930
|
);
|
|
22152
22931
|
}
|
|
22153
22932
|
server.registerTool(
|
|
22154
22933
|
"doctor",
|
|
22155
22934
|
{
|
|
22156
|
-
description: "Use when:
|
|
22157
|
-
inputSchema: {
|
|
22935
|
+
description: "Use when: diagnosis/status/usage. Do not use when: choosing models. Returns: summary; opt into detail.",
|
|
22936
|
+
inputSchema: external_exports.object({
|
|
22158
22937
|
endpoint: ollamaEndpointParam,
|
|
22159
22938
|
serveEndpoint: endpointParam,
|
|
22160
|
-
view: external_exports.enum(["summary", "scheduler", "config", "full"]).optional()
|
|
22161
|
-
|
|
22939
|
+
view: external_exports.enum(["summary", "scheduler", "config", "full", "status", "usage"]).optional(),
|
|
22940
|
+
days: external_exports.number().int().min(1).max(366).optional()
|
|
22941
|
+
}).strict(),
|
|
22162
22942
|
outputSchema: doctorResultSchema,
|
|
22163
22943
|
annotations: { readOnlyHint: true }
|
|
22164
22944
|
},
|
|
22165
|
-
async ({ endpoint, serveEndpoint, view }) => {
|
|
22945
|
+
async ({ endpoint, serveEndpoint, view, days }) => {
|
|
22166
22946
|
try {
|
|
22947
|
+
if (days !== void 0 && view !== "usage") return errorResult(new Error("days is only valid with view: usage."));
|
|
22948
|
+
if (view === "status") return parsedResult(await status(serveEndpoint));
|
|
22949
|
+
if (view === "usage") return parsedResult(await usage(serveEndpoint, days));
|
|
22167
22950
|
const report = parsedResult(await doctor(endpoint));
|
|
22168
|
-
if (!(
|
|
22951
|
+
if (!isStructuredSuccess(report)) return report;
|
|
22169
22952
|
try {
|
|
22170
22953
|
report.structuredContent.machine = JSON.parse(await machine(serveEndpoint));
|
|
22171
22954
|
delete report.structuredContent.machine_unavailable;
|
|
@@ -22224,23 +23007,24 @@ server.registerTool(
|
|
|
22224
23007
|
server.registerTool(
|
|
22225
23008
|
"session",
|
|
22226
23009
|
{
|
|
22227
|
-
description: "Use when:
|
|
22228
|
-
inputSchema: {
|
|
22229
|
-
action: external_exports.enum(["create", "delete"
|
|
22230
|
-
sessionId: external_exports.string().uuid().optional()
|
|
23010
|
+
description: "Use when: affinity/session kill. Do not use when: job cancel/history/unload. Returns: receipt.",
|
|
23011
|
+
inputSchema: external_exports.object({
|
|
23012
|
+
action: external_exports.enum(["create", "delete", "kill"]),
|
|
23013
|
+
sessionId: external_exports.string().uuid().optional(),
|
|
22231
23014
|
endpoint: endpointParam
|
|
22232
|
-
},
|
|
23015
|
+
}).strict(),
|
|
22233
23016
|
outputSchema: sessionResultSchema,
|
|
22234
|
-
annotations: { destructiveHint:
|
|
23017
|
+
annotations: { destructiveHint: true }
|
|
22235
23018
|
},
|
|
22236
23019
|
async ({ action, sessionId, endpoint }) => {
|
|
22237
23020
|
try {
|
|
22238
23021
|
if (action === "create") {
|
|
22239
|
-
if (sessionId !== void 0) return errorResult(new Error("sessionId is only valid for action: delete."));
|
|
22240
|
-
return structuredResult(JSON.parse(await
|
|
23022
|
+
if (sessionId !== void 0) return errorResult(new Error("sessionId is only valid for action: delete or kill."));
|
|
23023
|
+
return structuredResult(JSON.parse(await createSession2(endpoint)));
|
|
22241
23024
|
}
|
|
22242
|
-
if (sessionId === void 0) return errorResult(new Error(
|
|
22243
|
-
await
|
|
23025
|
+
if (sessionId === void 0) return errorResult(new Error(`action: ${action} requires sessionId.`));
|
|
23026
|
+
if (action === "kill") return parsedResult(await killSession2(endpoint, sessionId));
|
|
23027
|
+
await deleteSession2(endpoint, sessionId);
|
|
22244
23028
|
return structuredResult({ session_id: sessionId, deleted: true });
|
|
22245
23029
|
} catch (error2) {
|
|
22246
23030
|
return errorResult(error2);
|
|
@@ -22250,25 +23034,33 @@ server.registerTool(
|
|
|
22250
23034
|
server.registerTool(
|
|
22251
23035
|
"models",
|
|
22252
23036
|
{
|
|
22253
|
-
description:
|
|
22254
|
-
inputSchema: {
|
|
22255
|
-
view: external_exports.enum(["installed", "resident", "detail", "raw", "library"]).optional()
|
|
22256
|
-
model: external_exports.string().min(1).optional()
|
|
22257
|
-
includeVerbose: external_exports.boolean().optional()
|
|
22258
|
-
|
|
22259
|
-
|
|
22260
|
-
|
|
22261
|
-
|
|
22262
|
-
|
|
23037
|
+
description: "Use when: inventory/library. Do not use when: execution/mutation. Returns: models; library finds families, then one family's tags.",
|
|
23038
|
+
inputSchema: external_exports.object({
|
|
23039
|
+
view: external_exports.enum(["installed", "resident", "detail", "raw", "library"]).optional(),
|
|
23040
|
+
model: external_exports.string().min(1).optional(),
|
|
23041
|
+
includeVerbose: external_exports.boolean().optional(),
|
|
23042
|
+
includeLibrary: external_exports.boolean().optional(),
|
|
23043
|
+
includeReadme: external_exports.boolean().optional(),
|
|
23044
|
+
query: external_exports.string().min(1).optional(),
|
|
23045
|
+
capabilities: external_exports.array(external_exports.enum(["vision", "tools", "thinking", "embedding", "cloud"])).min(1).max(5).optional(),
|
|
23046
|
+
order: external_exports.enum(["popular", "newest"]).optional(),
|
|
23047
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
23048
|
+
cursor: external_exports.string().min(1).optional(),
|
|
22263
23049
|
endpoint: endpointParam,
|
|
22264
23050
|
ollamaEndpoint: ollamaEndpointParam
|
|
22265
|
-
},
|
|
23051
|
+
}).strict(),
|
|
22266
23052
|
outputSchema: modelsResultSchema,
|
|
22267
23053
|
annotations: { readOnlyHint: true }
|
|
22268
23054
|
},
|
|
22269
|
-
async ({ view, model, includeVerbose, query, capabilities, order, limit, cursor, endpoint, ollamaEndpoint }) => {
|
|
23055
|
+
async ({ view, model, includeVerbose, includeLibrary, includeReadme, query, capabilities, order, limit, cursor, endpoint, ollamaEndpoint }) => {
|
|
22270
23056
|
try {
|
|
22271
23057
|
const selectedView = view ?? "installed";
|
|
23058
|
+
if (includeLibrary !== void 0 && selectedView !== "installed" && selectedView !== "detail") {
|
|
23059
|
+
return errorResult(new Error('`includeLibrary` is valid only for views "installed" and "detail".'));
|
|
23060
|
+
}
|
|
23061
|
+
if (includeReadme !== void 0 && !(selectedView === "library" && model || selectedView === "detail" && includeLibrary === true)) {
|
|
23062
|
+
return errorResult(new Error('`includeReadme` needs library step 2, or view "detail" with `includeLibrary:true`.'));
|
|
23063
|
+
}
|
|
22272
23064
|
if (selectedView !== "library" && [query, capabilities, order].some((value) => value !== void 0)) {
|
|
22273
23065
|
return errorResult(new Error(`view "${selectedView}" does not accept library search fields.`));
|
|
22274
23066
|
}
|
|
@@ -22294,11 +23086,11 @@ server.registerTool(
|
|
|
22294
23086
|
return structuredResult({ ...raw, models: page.items, page: { returned: page.returned, total: page.total, next_cursor: page.next_cursor } });
|
|
22295
23087
|
}
|
|
22296
23088
|
case "resident": {
|
|
22297
|
-
const managed = parsedResult(await
|
|
22298
|
-
if (!(
|
|
23089
|
+
const managed = parsedResult(await listModels2(endpoint));
|
|
23090
|
+
if (!isStructuredSuccess(managed)) return managed;
|
|
22299
23091
|
const data = managed.structuredContent;
|
|
22300
23092
|
const models = (data.models ?? []).filter((entry) => entry.resident === true).map((entry) => {
|
|
22301
|
-
const size = typeof entry.
|
|
23093
|
+
const size = typeof entry.resident_size === "number" ? entry.resident_size : null;
|
|
22302
23094
|
const vram = typeof entry.resident_vram === "number" ? entry.resident_vram : null;
|
|
22303
23095
|
if (size === null || vram === null || size === 0) return entry;
|
|
22304
23096
|
const gpuPercent = Math.round(vram / size * 100);
|
|
@@ -22331,6 +23123,17 @@ server.registerTool(
|
|
|
22331
23123
|
method: "POST",
|
|
22332
23124
|
body: { model }
|
|
22333
23125
|
});
|
|
23126
|
+
let local = data;
|
|
23127
|
+
if (includeLibrary && !data.remote_host && !data.remote_model && !/-cloud$/i.test(model)) {
|
|
23128
|
+
try {
|
|
23129
|
+
const inventory = await ollamaFetch(ollamaEndpoint, "/api/tags");
|
|
23130
|
+
const canonical = libraryReference(model)?.tag;
|
|
23131
|
+
const entry = canonical && inventory.models?.find((entry2) => libraryReference(String(entry2.name ?? entry2.model))?.tag === canonical);
|
|
23132
|
+
if (entry) local = { ...entry, ...data, digest: entry.digest };
|
|
23133
|
+
} catch {
|
|
23134
|
+
}
|
|
23135
|
+
}
|
|
23136
|
+
const library = includeLibrary && !local.remote_host && !local.remote_model && !/-cloud$/i.test(model) ? await ollamaLibrary.lookup(model) : void 0;
|
|
22334
23137
|
const { license, modelfile, ...rest } = data;
|
|
22335
23138
|
const modelInfo = rest.model_info ?? {};
|
|
22336
23139
|
const contextEntry = Object.entries(modelInfo).find(
|
|
@@ -22339,13 +23142,23 @@ server.registerTool(
|
|
|
22339
23142
|
return structuredResult({
|
|
22340
23143
|
...rest,
|
|
22341
23144
|
max_context_length: contextEntry?.[1] ?? null,
|
|
23145
|
+
knowledge: modelKnowledge(model, local, library, includeReadme),
|
|
22342
23146
|
...includeVerbose ? { license, modelfile } : {}
|
|
22343
23147
|
});
|
|
22344
23148
|
}
|
|
22345
23149
|
case "library":
|
|
22346
|
-
return await libraryLookup({ model, query, capabilities, order, limit, cursor, endpoint, ollamaEndpoint });
|
|
22347
|
-
default:
|
|
22348
|
-
|
|
23150
|
+
return await libraryLookup({ model, query, capabilities, order, limit, cursor, includeReadme, endpoint, ollamaEndpoint });
|
|
23151
|
+
default: {
|
|
23152
|
+
const result = parsedResult(await listModels2(endpoint));
|
|
23153
|
+
if (!isStructuredSuccess(result)) return result;
|
|
23154
|
+
const data = result.structuredContent;
|
|
23155
|
+
return structuredResult({ ...data, models: await enrichInstalledModels(
|
|
23156
|
+
data.models ?? [],
|
|
23157
|
+
ollamaLibrary,
|
|
23158
|
+
includeLibrary ?? false,
|
|
23159
|
+
async (upstream) => (await ollamaFetch(upstream ?? ollamaEndpoint, "/api/tags")).models ?? []
|
|
23160
|
+
) });
|
|
23161
|
+
}
|
|
22349
23162
|
}
|
|
22350
23163
|
} catch (error2) {
|
|
22351
23164
|
return errorResult(error2);
|
|
@@ -22359,20 +23172,10 @@ async function libraryLookup({
|
|
|
22359
23172
|
order,
|
|
22360
23173
|
limit,
|
|
22361
23174
|
cursor,
|
|
23175
|
+
includeReadme,
|
|
22362
23176
|
endpoint,
|
|
22363
23177
|
ollamaEndpoint
|
|
22364
23178
|
}) {
|
|
22365
|
-
const fetchPage = async (url) => {
|
|
22366
|
-
const controller = new AbortController();
|
|
22367
|
-
const timer = setTimeout(() => controller.abort(), DEFAULT_OLLAMA_FETCH_TIMEOUT_SECONDS * 1e3);
|
|
22368
|
-
try {
|
|
22369
|
-
const response = await fetch(url, { signal: controller.signal });
|
|
22370
|
-
if (!response.ok) throw new Error(`ollama.com returned HTTP ${response.status}`);
|
|
22371
|
-
return await response.text();
|
|
22372
|
-
} finally {
|
|
22373
|
-
clearTimeout(timer);
|
|
22374
|
-
}
|
|
22375
|
-
};
|
|
22376
23179
|
const localState = async () => {
|
|
22377
23180
|
let installed = /* @__PURE__ */ new Set();
|
|
22378
23181
|
let memoryBytes = null;
|
|
@@ -22390,9 +23193,19 @@ async function libraryLookup({
|
|
|
22390
23193
|
};
|
|
22391
23194
|
try {
|
|
22392
23195
|
if (model) {
|
|
22393
|
-
const
|
|
22394
|
-
|
|
22395
|
-
const {
|
|
23196
|
+
const ref = libraryReference(model);
|
|
23197
|
+
if (!ref) throw new Error("Use an exact Ollama family or namespace/model name, not a URL or path.");
|
|
23198
|
+
const { family } = ref;
|
|
23199
|
+
const library = await ollamaLibrary.lookup(model);
|
|
23200
|
+
if (library.status !== "available") return structuredResult({
|
|
23201
|
+
family,
|
|
23202
|
+
sourcePage: ref.url,
|
|
23203
|
+
tags: [],
|
|
23204
|
+
tagsUnavailable: library.message,
|
|
23205
|
+
library,
|
|
23206
|
+
recommendation: null
|
|
23207
|
+
});
|
|
23208
|
+
const tags = library.tags;
|
|
22396
23209
|
const { installed: installed2, memoryBytes } = await localState();
|
|
22397
23210
|
const budget = memoryBytes ? memoryBytes * 0.6 : null;
|
|
22398
23211
|
const annotated = tags.map((t) => ({
|
|
@@ -22401,15 +23214,23 @@ async function libraryLookup({
|
|
|
22401
23214
|
fitsInMemory: budget && t.sizeBytes ? t.sizeBytes <= budget : null,
|
|
22402
23215
|
fitScope: "host_memory_budget_only"
|
|
22403
23216
|
}));
|
|
22404
|
-
const runnable = annotated.filter((t) => t.fitsInMemory === true &&
|
|
22405
|
-
const
|
|
22406
|
-
const isEmbeddingFamily = embeddingMentions >= 3 || /embed/i.test(family);
|
|
23217
|
+
const runnable = annotated.filter((t) => t.fitsInMemory === true && !t.cloud);
|
|
23218
|
+
const isEmbeddingFamily = library.card.capabilities.includes("embedding");
|
|
22407
23219
|
const sized = runnable.filter((t) => t.sizeBytes);
|
|
22408
23220
|
const best = budget ? isEmbeddingFamily ? sized.sort((a, b) => (a.sizeBytes ?? 0) - (b.sizeBytes ?? 0))[0] : sized.sort((a, b) => (b.sizeBytes ?? 0) - (a.sizeBytes ?? 0))[0] : void 0;
|
|
22409
23221
|
const tagPage = pageLiveList(annotated, limit, cursor, (tag) => tag.tag);
|
|
22410
23222
|
return structuredResult({
|
|
22411
23223
|
family,
|
|
22412
|
-
sourcePage:
|
|
23224
|
+
sourcePage: ref.url,
|
|
23225
|
+
library: {
|
|
23226
|
+
status: library.status,
|
|
23227
|
+
sourceUrl: library.sourceUrl,
|
|
23228
|
+
tagsSourceUrl: library.tagsSourceUrl,
|
|
23229
|
+
fetchedAt: library.fetchedAt,
|
|
23230
|
+
expiresAt: library.expiresAt,
|
|
23231
|
+
cached: library.cached,
|
|
23232
|
+
...publicModelGuidance(library, void 0, includeReadme)
|
|
23233
|
+
},
|
|
22413
23234
|
...tags.length === 0 ? {
|
|
22414
23235
|
tagsUnavailable: `No pullable tags found for "${family}". Either it is cloud-only (no local download), the family name is wrong, or ollama.com changed its markup. Open the page above to check before concluding the model does not exist.`
|
|
22415
23236
|
} : {},
|
|
@@ -22418,29 +23239,22 @@ async function libraryLookup({
|
|
|
22418
23239
|
tags: tagPage.items,
|
|
22419
23240
|
page: { returned: tagPage.returned, total: tagPage.total, next_cursor: tagPage.next_cursor },
|
|
22420
23241
|
recommendationUnavailable: budget ? void 0 : "No machine profile (freellama serve unreachable), so memory fit could not be checked and no tag is recommended. Start serve, or read the sizes yourself.",
|
|
22421
|
-
recommendation: best ? isEmbeddingFamily
|
|
22422
|
-
tag: best.tag,
|
|
22423
|
-
why: "Smallest tag that fits \u2014 this is an embedding family, where bigger is NOT better. Measured on real retrieval over this repo: nomic-embed-text (274MB) scored 5/6 recall@3 in 4.2s, while qwen3-embedding:0.6b (2.3x the size) scored 4/6 at 3.5x the indexing cost. Embeddings do no sampling, so there is no accuracy cliff for size to buy you past.",
|
|
22424
|
-
configure: 'Batch your inputs in one `run_task` call and use keepAlive:"0" \u2014 an embedding model has no reason to hold memory after the vectors are computed. Leave returnEmbeddings off unless you are storing the vectors yourself.',
|
|
22425
|
-
caution: "Index once, query many times, and own the staleness: FreeLlama stores no vectors, and a stale index fails silently by returning confidently wrong files. Also, if you know the keyword, grep beat embedding search here on accuracy, latency and cost at the same time \u2014 reach for embeddings when there is no keyword to search for."
|
|
22426
|
-
} : {
|
|
22427
|
-
tag: best.tag,
|
|
22428
|
-
why: `Largest tag inside the conservative ~60% host-memory preflight${memoryBytes ? ` of ${Math.round(memoryBytes / 1e9)}GB` : ""}. This proves neither accelerator fit nor task quality; preview and benchmark before pulling.`,
|
|
22429
|
-
configure: `Send an explicit num_ctx rather than inheriting Ollama's default, which is 4096 tokens by default unless the Ollama service or request sets num_ctx. Use keepAlive:"0" for one-off calls so it does not hold memory after.`,
|
|
22430
|
-
caution: 'Do not co-resident large models until their combined runner sizes, contexts, KV caches, and OS headroom fit this host. Check `models{view:"resident"}` and accelerator telemetry first; benchmark packaging rather than inferring quality or speed from a model suffix.'
|
|
22431
|
-
} : null
|
|
23242
|
+
recommendation: best ? libraryTrialCandidate(best.tag, isEmbeddingFamily) : null
|
|
22432
23243
|
});
|
|
22433
23244
|
}
|
|
22434
23245
|
const params = new URLSearchParams();
|
|
22435
23246
|
for (const c of capabilities ?? []) params.append("c", c);
|
|
22436
23247
|
if (query) params.set("q", query);
|
|
22437
23248
|
if (order === "newest") params.set("o", "newest");
|
|
22438
|
-
const
|
|
22439
|
-
const
|
|
23249
|
+
const search = await ollamaLibrary.search(params);
|
|
23250
|
+
const url = search.url;
|
|
23251
|
+
const parsed = search.models.slice(0, limit ?? 10);
|
|
22440
23252
|
const { installed } = await localState();
|
|
22441
23253
|
const installedFamilies = new Set([...installed].map((n) => n.split(":")[0]));
|
|
22442
23254
|
return structuredResult({
|
|
22443
23255
|
query: url,
|
|
23256
|
+
fetchedAt: search.fetchedAt,
|
|
23257
|
+
...parsed.length === 0 ? { searchUnavailable: "No result cards were recognized. The query may have no matches or Ollama's markup may have changed; inspect the source URL." } : {},
|
|
22444
23258
|
order: order ?? "popular",
|
|
22445
23259
|
count: parsed.length,
|
|
22446
23260
|
nextStep: 'Not pullable yet. Call again with view:"library", model:"<name>" to get tags, sizes and memory fit.',
|
|
@@ -22450,42 +23264,47 @@ async function libraryLookup({
|
|
|
22450
23264
|
return errorResult(error2);
|
|
22451
23265
|
}
|
|
22452
23266
|
}
|
|
23267
|
+
registerContextTools(server);
|
|
22453
23268
|
server.registerTool(
|
|
22454
23269
|
"run_task",
|
|
22455
23270
|
{
|
|
22456
|
-
description: "Use when:
|
|
22457
|
-
inputSchema: {
|
|
23271
|
+
description: "Use when: supplied chat/tools/embeddings. Do not use when: files. Returns: response/receipts.",
|
|
23272
|
+
inputSchema: external_exports.object({
|
|
22458
23273
|
endpoint: endpointParam,
|
|
22459
|
-
task: taskParam,
|
|
23274
|
+
task: taskParam.removeDefault().optional().describe("caller owns prompts and output format."),
|
|
22460
23275
|
objective: objectiveParam,
|
|
22461
|
-
model: external_exports.string().min(1).optional()
|
|
22462
|
-
sessionId: external_exports.string().
|
|
22463
|
-
|
|
23276
|
+
model: external_exports.string().min(1).optional(),
|
|
23277
|
+
sessionId: external_exports.string().uuid().optional(),
|
|
23278
|
+
scopeId: external_exports.string().uuid().optional(),
|
|
23279
|
+
scopeRevision: external_exports.number().int().nonnegative().optional(),
|
|
23280
|
+
contextTokens: external_exports.number().int().positive().optional().describe("Total input + output window (num_ctx)."),
|
|
22464
23281
|
executionPreference: executionPreferenceParam,
|
|
22465
23282
|
minPlacementEvidence: minPlacementEvidenceParam,
|
|
22466
23283
|
requiredCapabilities: requiredCapabilitiesParam,
|
|
22467
|
-
prompt: external_exports.string().min(1).optional()
|
|
23284
|
+
prompt: external_exports.string().min(1).optional(),
|
|
23285
|
+
systemPrompt: systemPromptParam,
|
|
22468
23286
|
images: external_exports.array(external_exports.string().min(1)).min(1).optional().describe("base64, no data-URI prefix; prompt mode only; requires an explicit tested vision model"),
|
|
22469
|
-
messages:
|
|
22470
|
-
|
|
22471
|
-
).min(1).optional().describe(
|
|
22472
|
-
"wins over prompt; preserves Ollama images, thinking, tool_calls, tool_name, and other message fields"
|
|
23287
|
+
messages: messagesParam.describe(
|
|
23288
|
+
"Caller system prompts; no injected task instructions. Overrides prompt; extra fields preserved."
|
|
22473
23289
|
),
|
|
22474
|
-
input: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).min(1)]).optional()
|
|
22475
|
-
tools:
|
|
22476
|
-
keepAlive: external_exports.string().min(1).optional().describe('"0" unloads now, "-1" pins
|
|
22477
|
-
format: external_exports.union([external_exports.literal("json"), external_exports.record(external_exports.unknown())]).optional()
|
|
22478
|
-
think: external_exports.union([external_exports.boolean(), external_exports.enum(["low", "medium", "high"])]).optional()
|
|
22479
|
-
options: external_exports.record(external_exports.unknown()).optional().describe("
|
|
23290
|
+
input: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).min(1)]).optional(),
|
|
23291
|
+
tools: localToolsParam,
|
|
23292
|
+
keepAlive: external_exports.string().min(1).optional().describe('"0" unloads now, "-1" pins; omitted = adaptive finite TTL'),
|
|
23293
|
+
format: external_exports.union([external_exports.literal("json"), external_exports.record(external_exports.unknown())]).optional(),
|
|
23294
|
+
think: external_exports.union([external_exports.boolean(), external_exports.enum(["low", "medium", "high"])]).optional(),
|
|
23295
|
+
options: external_exports.record(external_exports.unknown()).optional().describe("num_ctx/contextTokens and num_gpu/placement are routing-owned; num_predict caps output."),
|
|
22480
23296
|
logprobs: external_exports.boolean().optional(),
|
|
22481
|
-
topLogprobs: external_exports.number().int().nonnegative().optional()
|
|
23297
|
+
topLogprobs: external_exports.number().int().nonnegative().optional(),
|
|
22482
23298
|
minConfidence: minConfidenceParam,
|
|
22483
|
-
priority: external_exports.enum(["interactive", "normal", "background"]).optional()
|
|
22484
|
-
|
|
23299
|
+
priority: external_exports.enum(["interactive", "normal", "background"]).optional(),
|
|
23300
|
+
maxWaitSeconds: external_exports.number().int().positive().optional(),
|
|
23301
|
+
timeoutSeconds: external_exports.number().int().positive().optional(),
|
|
23302
|
+
defer: external_exports.boolean().optional(),
|
|
23303
|
+
returnEmbeddings: external_exports.boolean().optional(),
|
|
22485
23304
|
preview: external_exports.boolean().optional().describe(
|
|
22486
23305
|
"true = routing fields only; rejects payloads and runtime controls; never executes"
|
|
22487
23306
|
)
|
|
22488
|
-
},
|
|
23307
|
+
}).strict(),
|
|
22489
23308
|
outputSchema: taskResultSchema,
|
|
22490
23309
|
annotations: { destructiveHint: false }
|
|
22491
23310
|
},
|
|
@@ -22495,11 +23314,14 @@ server.registerTool(
|
|
|
22495
23314
|
objective,
|
|
22496
23315
|
model,
|
|
22497
23316
|
sessionId,
|
|
23317
|
+
scopeId,
|
|
23318
|
+
scopeRevision,
|
|
22498
23319
|
contextTokens,
|
|
22499
23320
|
executionPreference,
|
|
22500
23321
|
minPlacementEvidence,
|
|
22501
23322
|
requiredCapabilities,
|
|
22502
23323
|
prompt,
|
|
23324
|
+
systemPrompt,
|
|
22503
23325
|
images,
|
|
22504
23326
|
messages,
|
|
22505
23327
|
input,
|
|
@@ -22512,14 +23334,23 @@ server.registerTool(
|
|
|
22512
23334
|
topLogprobs,
|
|
22513
23335
|
minConfidence,
|
|
22514
23336
|
priority,
|
|
23337
|
+
maxWaitSeconds,
|
|
23338
|
+
timeoutSeconds,
|
|
23339
|
+
defer,
|
|
22515
23340
|
returnEmbeddings,
|
|
22516
23341
|
preview
|
|
22517
23342
|
}) => {
|
|
22518
23343
|
try {
|
|
22519
|
-
const canonicalTask = canonicalTaskKind(task);
|
|
23344
|
+
const canonicalTask = canonicalTaskKind(task ?? "completion");
|
|
23345
|
+
if (scopeId === void 0 !== (scopeRevision === void 0)) {
|
|
23346
|
+
return errorResult(new Error("scopeId and scopeRevision must be supplied together."));
|
|
23347
|
+
}
|
|
22520
23348
|
if (preview) {
|
|
22521
23349
|
const executionOnlyFields = [
|
|
23350
|
+
["scopeId", scopeId],
|
|
23351
|
+
["scopeRevision", scopeRevision],
|
|
22522
23352
|
["prompt", prompt],
|
|
23353
|
+
["systemPrompt", systemPrompt],
|
|
22523
23354
|
["images", images],
|
|
22524
23355
|
["messages", messages],
|
|
22525
23356
|
["input", input],
|
|
@@ -22530,7 +23361,11 @@ server.registerTool(
|
|
|
22530
23361
|
["options", options],
|
|
22531
23362
|
["logprobs", logprobs],
|
|
22532
23363
|
["topLogprobs", topLogprobs],
|
|
22533
|
-
["returnEmbeddings", returnEmbeddings]
|
|
23364
|
+
["returnEmbeddings", returnEmbeddings],
|
|
23365
|
+
["maxWaitSeconds", maxWaitSeconds],
|
|
23366
|
+
["priority", priority],
|
|
23367
|
+
["timeoutSeconds", timeoutSeconds],
|
|
23368
|
+
["defer", defer]
|
|
22534
23369
|
].filter(([, value]) => value !== void 0).map(([name]) => `\`${name}\``);
|
|
22535
23370
|
if (executionOnlyFields.length > 0) {
|
|
22536
23371
|
return errorResult(
|
|
@@ -22546,7 +23381,7 @@ server.registerTool(
|
|
|
22546
23381
|
}
|
|
22547
23382
|
if (!preview && task === "embedding") {
|
|
22548
23383
|
if (input === void 0) return errorResult(new Error('task "embedding" requires `input`.'));
|
|
22549
|
-
if ([prompt, images, messages, tools, format, think, logprobs, topLogprobs].some(
|
|
23384
|
+
if ([prompt, systemPrompt, images, messages, tools, format, think, logprobs, topLogprobs].some(
|
|
22550
23385
|
(value) => value !== void 0
|
|
22551
23386
|
)) {
|
|
22552
23387
|
return errorResult(
|
|
@@ -22558,10 +23393,10 @@ server.registerTool(
|
|
|
22558
23393
|
if (input !== void 0 || returnEmbeddings !== void 0) {
|
|
22559
23394
|
return errorResult(new Error('`input` and `returnEmbeddings` are valid only for task "embedding".'));
|
|
22560
23395
|
}
|
|
22561
|
-
if (prompt === void 0 && (messages === void 0 || messages.length === 0)) {
|
|
22562
|
-
return errorResult(new Error(`task "${task}" requires \`prompt\` or \`messages\`.`));
|
|
23396
|
+
if (prompt === void 0 && systemPrompt === void 0 && (messages === void 0 || messages.length === 0)) {
|
|
23397
|
+
return errorResult(new Error(`task "${task}" requires \`prompt\`, \`systemPrompt\`, or \`messages\`.`));
|
|
22563
23398
|
}
|
|
22564
|
-
if (images !== void 0 && messages !== void 0) {
|
|
23399
|
+
if (images !== void 0 && (messages !== void 0 || prompt === void 0)) {
|
|
22565
23400
|
return errorResult(
|
|
22566
23401
|
new Error("Top-level `images` is valid only with `prompt`; put images inside messages instead.")
|
|
22567
23402
|
);
|
|
@@ -22572,44 +23407,48 @@ server.registerTool(
|
|
|
22572
23407
|
}
|
|
22573
23408
|
if (preview) {
|
|
22574
23409
|
const result2 = parsedResult(
|
|
22575
|
-
await
|
|
23410
|
+
await route2(endpoint, canonicalTask, objective, model, sessionId, contextTokens, effectiveRequiredCapabilities, minConfidence, executionPreference, minPlacementEvidence)
|
|
22576
23411
|
);
|
|
22577
|
-
if (
|
|
23412
|
+
if (isStructuredSuccess(result2)) {
|
|
22578
23413
|
const refusal = belowConfidence(result2.structuredContent, minConfidence);
|
|
22579
23414
|
if (refusal) return refusal;
|
|
22580
23415
|
}
|
|
22581
23416
|
return result2;
|
|
22582
23417
|
}
|
|
22583
|
-
if (minConfidence) {
|
|
23418
|
+
if (minConfidence && scopeId === void 0) {
|
|
22584
23419
|
const decision = parsedResult(
|
|
22585
23420
|
// minConfidence is forwarded so the CORE gate refuses, with its actionable message naming
|
|
22586
23421
|
// the two commands that raise the grade. The belowConfidence() check below stays only as a
|
|
22587
23422
|
// fallback for servers older than the core gate.
|
|
22588
|
-
await
|
|
23423
|
+
await route2(endpoint, canonicalTask, objective, model, sessionId, contextTokens, effectiveRequiredCapabilities, minConfidence, executionPreference, minPlacementEvidence)
|
|
22589
23424
|
);
|
|
22590
|
-
if (
|
|
22591
|
-
|
|
22592
|
-
|
|
22593
|
-
}
|
|
23425
|
+
if (!isStructuredSuccess(decision)) return decision;
|
|
23426
|
+
const refusal = belowConfidence(decision.structuredContent, minConfidence);
|
|
23427
|
+
if (refusal) return refusal;
|
|
22594
23428
|
}
|
|
22595
23429
|
const result = parsedResult(
|
|
22596
|
-
await
|
|
22597
|
-
task: canonicalTask,
|
|
22598
|
-
objective: objective ?? "balanced",
|
|
23430
|
+
await runTaskRequest2(endpoint ?? DEFAULT_SERVE_ENDPOINT, {
|
|
23431
|
+
task: scopeId !== void 0 && task === void 0 ? void 0 : canonicalTask,
|
|
23432
|
+
objective: objective ?? (scopeId === void 0 ? "balanced" : void 0),
|
|
22599
23433
|
model,
|
|
22600
23434
|
session_id: sessionId,
|
|
23435
|
+
scope_id: scopeId,
|
|
23436
|
+
scope_revision: scopeRevision,
|
|
22601
23437
|
context_tokens: contextTokens,
|
|
22602
|
-
required_capabilities: effectiveRequiredCapabilities
|
|
23438
|
+
required_capabilities: effectiveRequiredCapabilities,
|
|
22603
23439
|
prompt,
|
|
22604
23440
|
images,
|
|
22605
|
-
messages: messages
|
|
23441
|
+
messages: taskMessages({ systemPrompt, messages, prompt, images }),
|
|
22606
23442
|
input,
|
|
22607
23443
|
tools,
|
|
22608
23444
|
keep_alive: keepAlive,
|
|
22609
23445
|
min_confidence: minConfidence,
|
|
22610
23446
|
priority: priority ?? "normal",
|
|
22611
|
-
|
|
22612
|
-
|
|
23447
|
+
max_wait_seconds: maxWaitSeconds,
|
|
23448
|
+
timeout_seconds: timeoutSeconds,
|
|
23449
|
+
defer: defer ?? false,
|
|
23450
|
+
execution_preference: executionPreference,
|
|
23451
|
+
min_placement_evidence: minPlacementEvidence,
|
|
22613
23452
|
request_options: {
|
|
22614
23453
|
format,
|
|
22615
23454
|
think,
|
|
@@ -22619,7 +23458,8 @@ server.registerTool(
|
|
|
22619
23458
|
}
|
|
22620
23459
|
})
|
|
22621
23460
|
);
|
|
22622
|
-
if (
|
|
23461
|
+
if (isStructuredSuccess(result) && result.structuredContent.deferred === true) return result;
|
|
23462
|
+
if (!returnEmbeddings && isStructuredSuccess(result)) {
|
|
22623
23463
|
const trimmed = summarizeEmbeddings(result.structuredContent);
|
|
22624
23464
|
if (trimmed) return withTaskTelemetry(structuredResult(trimmed));
|
|
22625
23465
|
}
|
|
@@ -22629,15 +23469,50 @@ server.registerTool(
|
|
|
22629
23469
|
}
|
|
22630
23470
|
}
|
|
22631
23471
|
);
|
|
23472
|
+
server.registerTool(
|
|
23473
|
+
"task_jobs",
|
|
23474
|
+
{
|
|
23475
|
+
description: "Use when: task jobs. Do not use when: new work/session kill. Returns: status/result; remove cancels first.",
|
|
23476
|
+
inputSchema: external_exports.object({
|
|
23477
|
+
endpoint: endpointParam,
|
|
23478
|
+
action: external_exports.enum(["list", "get", "cancel", "remove"]),
|
|
23479
|
+
jobId: external_exports.string().uuid().optional(),
|
|
23480
|
+
returnEmbeddings: external_exports.boolean().optional()
|
|
23481
|
+
}).strict(),
|
|
23482
|
+
outputSchema: objectResultSchema,
|
|
23483
|
+
annotations: { destructiveHint: true }
|
|
23484
|
+
},
|
|
23485
|
+
async ({ endpoint, action, jobId, returnEmbeddings }) => {
|
|
23486
|
+
try {
|
|
23487
|
+
if (action === "list" ? jobId !== void 0 : jobId === void 0) {
|
|
23488
|
+
return errorResult(new Error("Use jobId only with get/cancel/remove; all require a jobId."));
|
|
23489
|
+
}
|
|
23490
|
+
if (returnEmbeddings !== void 0 && action !== "get") {
|
|
23491
|
+
return errorResult(new Error("returnEmbeddings is valid only with get."));
|
|
23492
|
+
}
|
|
23493
|
+
const result = parsedResult(action === "list" ? await listTaskJobs2(endpoint) : action === "get" ? await getTaskJob2(endpoint, jobId) : action === "cancel" ? await cancelTaskJob2(endpoint, jobId) : await removeTaskJob2(endpoint, jobId));
|
|
23494
|
+
if (!returnEmbeddings && isStructuredSuccess(result)) {
|
|
23495
|
+
const job = result.structuredContent.job;
|
|
23496
|
+
if (job?.result && typeof job.result === "object") {
|
|
23497
|
+
const trimmed = summarizeEmbeddings(job.result);
|
|
23498
|
+
if (trimmed) return structuredResult({ ...result.structuredContent, job: { ...job, result: trimmed } });
|
|
23499
|
+
}
|
|
23500
|
+
}
|
|
23501
|
+
return result;
|
|
23502
|
+
} catch (error2) {
|
|
23503
|
+
return errorResult(error2);
|
|
23504
|
+
}
|
|
23505
|
+
}
|
|
23506
|
+
);
|
|
22632
23507
|
server.registerTool(
|
|
22633
23508
|
"run_task_batch",
|
|
22634
23509
|
{
|
|
22635
|
-
description: "Use when: independent work. Do not use when: dependencies.
|
|
22636
|
-
inputSchema: {
|
|
23510
|
+
description: "Use when: independent:true work. Do not use when: dependencies. Returns: ordered receipts; maxParallelism caps dispatch.",
|
|
23511
|
+
inputSchema: external_exports.object({
|
|
22637
23512
|
tasks: external_exports.array(batchItemParam).min(1).max(64),
|
|
22638
23513
|
maxParallelism: external_exports.number().int().positive().max(64).optional(),
|
|
22639
23514
|
endpoint: endpointParam
|
|
22640
|
-
},
|
|
23515
|
+
}).strict(),
|
|
22641
23516
|
outputSchema: batchResultSchema,
|
|
22642
23517
|
annotations: { destructiveHint: false }
|
|
22643
23518
|
},
|
|
@@ -22645,36 +23520,46 @@ server.registerTool(
|
|
|
22645
23520
|
try {
|
|
22646
23521
|
for (const item of tasks) {
|
|
22647
23522
|
const task = item.task;
|
|
23523
|
+
if (task.scopeId === void 0 !== (task.scopeRevision === void 0)) {
|
|
23524
|
+
return errorResult(new Error(`batch item ${item.id}: scopeId and scopeRevision must be supplied together.`));
|
|
23525
|
+
}
|
|
22648
23526
|
if (task.task === "embedding") {
|
|
22649
|
-
if (task.input === void 0 || task.prompt !== void 0 || task.messages !== void 0 || task.tools !== void 0) {
|
|
23527
|
+
if (task.input === void 0 || task.prompt !== void 0 || task.systemPrompt !== void 0 || task.messages !== void 0 || task.tools !== void 0) {
|
|
22650
23528
|
return errorResult(new Error(`batch item ${item.id}: embedding requires input and accepts no chat payload.`));
|
|
22651
23529
|
}
|
|
22652
|
-
} else if (task.input !== void 0 || task.prompt === void 0 && task.messages === void 0) {
|
|
22653
|
-
return errorResult(new Error(`batch item ${item.id}: chat work requires prompt or messages and accepts no input.`));
|
|
23530
|
+
} else if (task.input !== void 0 || task.prompt === void 0 && task.systemPrompt === void 0 && task.messages === void 0) {
|
|
23531
|
+
return errorResult(new Error(`batch item ${item.id}: chat work requires prompt, systemPrompt, or messages and accepts no input.`));
|
|
23532
|
+
}
|
|
23533
|
+
if (task.images !== void 0 && (task.messages !== void 0 || task.prompt === void 0)) {
|
|
23534
|
+
return errorResult(new Error(`batch item ${item.id}: top-level images requires prompt without messages; put images inside messages instead.`));
|
|
22654
23535
|
}
|
|
22655
23536
|
if (task.images !== void 0 && task.model === void 0) {
|
|
22656
23537
|
return errorResult(new Error(`batch item ${item.id}: images require an explicit tested vision model.`));
|
|
22657
23538
|
}
|
|
22658
23539
|
}
|
|
22659
|
-
return withBatchTelemetry(parsedResult(await
|
|
23540
|
+
return withBatchTelemetry(parsedResult(await runTaskBatchRequest2(endpoint ?? DEFAULT_SERVE_ENDPOINT, {
|
|
22660
23541
|
tasks: tasks.map((item) => {
|
|
22661
23542
|
const task = item.task;
|
|
22662
23543
|
return {
|
|
22663
23544
|
id: item.id,
|
|
22664
23545
|
independent: item.independent,
|
|
22665
23546
|
task: {
|
|
22666
|
-
task: task.task === "code_review" ? "coding" : task.task,
|
|
22667
|
-
objective: task.objective ?? "balanced",
|
|
23547
|
+
task: task.task === "code_review" ? "coding" : task.task ?? (task.scopeId === void 0 ? "completion" : void 0),
|
|
23548
|
+
objective: task.objective ?? (task.scopeId === void 0 ? "balanced" : void 0),
|
|
22668
23549
|
model: task.model,
|
|
22669
23550
|
session_id: task.sessionId,
|
|
23551
|
+
scope_id: task.scopeId,
|
|
23552
|
+
scope_revision: task.scopeRevision,
|
|
22670
23553
|
context_tokens: task.contextTokens,
|
|
22671
|
-
execution_preference: task.executionPreference
|
|
22672
|
-
min_placement_evidence: task.minPlacementEvidence
|
|
22673
|
-
required_capabilities: task.requiredCapabilities
|
|
23554
|
+
execution_preference: task.executionPreference,
|
|
23555
|
+
min_placement_evidence: task.minPlacementEvidence,
|
|
23556
|
+
required_capabilities: task.requiredCapabilities,
|
|
22674
23557
|
priority: task.priority ?? "normal",
|
|
23558
|
+
max_wait_seconds: task.maxWaitSeconds,
|
|
23559
|
+
timeout_seconds: task.timeoutSeconds,
|
|
22675
23560
|
prompt: task.prompt,
|
|
22676
23561
|
images: task.images,
|
|
22677
|
-
messages: task
|
|
23562
|
+
messages: taskMessages(task),
|
|
22678
23563
|
input: task.input,
|
|
22679
23564
|
tools: task.tools,
|
|
22680
23565
|
keep_alive: task.keepAlive,
|
|
@@ -22699,24 +23584,28 @@ server.registerTool(
|
|
|
22699
23584
|
server.registerTool(
|
|
22700
23585
|
"ollama_manage",
|
|
22701
23586
|
{
|
|
22702
|
-
description: "Use when:
|
|
22703
|
-
inputSchema: {
|
|
22704
|
-
action: external_exports.enum(["pull", "stop"])
|
|
23587
|
+
description: "Use when: approved pull/stop. Do not use when: delete/discovery. Returns: receipt; timeoutSeconds is pull-only.",
|
|
23588
|
+
inputSchema: external_exports.object({
|
|
23589
|
+
action: external_exports.enum(["pull", "stop"]),
|
|
22705
23590
|
model: external_exports.string().min(1),
|
|
22706
23591
|
ollamaEndpoint: ollamaEndpointParam,
|
|
22707
|
-
timeoutSeconds: external_exports.number().int().positive().optional()
|
|
22708
|
-
},
|
|
23592
|
+
timeoutSeconds: external_exports.number().int().positive().optional()
|
|
23593
|
+
}).strict(),
|
|
22709
23594
|
outputSchema: manageResultSchema,
|
|
22710
23595
|
annotations: { destructiveHint: false }
|
|
22711
23596
|
},
|
|
22712
|
-
async ({ action, model, ollamaEndpoint, timeoutSeconds }) => {
|
|
23597
|
+
async ({ action, model, ollamaEndpoint, timeoutSeconds }, extra) => {
|
|
22713
23598
|
try {
|
|
22714
23599
|
if (action === "stop" && timeoutSeconds !== void 0) {
|
|
22715
23600
|
return errorResult(new Error('`timeoutSeconds` is valid only for action "pull".'));
|
|
22716
23601
|
}
|
|
22717
|
-
const data = action === "pull" ? await ollamaPull(ollamaEndpoint, model, timeoutSeconds
|
|
23602
|
+
const data = action === "pull" ? await ollamaPull(ollamaEndpoint, model, timeoutSeconds, {
|
|
23603
|
+
signal: extra.signal,
|
|
23604
|
+
onProgress: pullProgressReporter(extra)
|
|
23605
|
+
}) : await ollamaFetch(ollamaEndpoint, "/api/generate", {
|
|
22718
23606
|
method: "POST",
|
|
22719
|
-
body: { model, keep_alive: 0 }
|
|
23607
|
+
body: { model, keep_alive: 0 },
|
|
23608
|
+
signal: extra.signal
|
|
22720
23609
|
});
|
|
22721
23610
|
const payload = data;
|
|
22722
23611
|
if (typeof payload.error === "string" && payload.error) {
|
|
@@ -22731,11 +23620,11 @@ server.registerTool(
|
|
|
22731
23620
|
server.registerTool(
|
|
22732
23621
|
"ollama_delete",
|
|
22733
23622
|
{
|
|
22734
|
-
description: "DESTRUCTIVE AND IRREVERSIBLE. Use when:
|
|
22735
|
-
inputSchema: {
|
|
23623
|
+
description: "DESTRUCTIVE AND IRREVERSIBLE. Use when: human names exact tag. Do not use when: inferred cleanup. Returns: deleted tag.",
|
|
23624
|
+
inputSchema: external_exports.object({
|
|
22736
23625
|
model: external_exports.string().min(1),
|
|
22737
23626
|
ollamaEndpoint: ollamaEndpointParam
|
|
22738
|
-
},
|
|
23627
|
+
}).strict(),
|
|
22739
23628
|
outputSchema: deleteResultSchema,
|
|
22740
23629
|
annotations: { destructiveHint: true }
|
|
22741
23630
|
},
|
|
@@ -22743,7 +23632,7 @@ server.registerTool(
|
|
|
22743
23632
|
try {
|
|
22744
23633
|
await ollamaFetch(ollamaEndpoint, "/api/delete", {
|
|
22745
23634
|
method: "DELETE",
|
|
22746
|
-
body: {
|
|
23635
|
+
body: { model }
|
|
22747
23636
|
});
|
|
22748
23637
|
return structuredResult({ deleted: model });
|
|
22749
23638
|
} catch (error2) {
|
|
@@ -22751,57 +23640,54 @@ server.registerTool(
|
|
|
22751
23640
|
}
|
|
22752
23641
|
}
|
|
22753
23642
|
);
|
|
23643
|
+
async function routedResearchModel(endpoint, executionPreference, minPlacementEvidence) {
|
|
23644
|
+
const decision = JSON.parse(
|
|
23645
|
+
await route2(endpoint, "coding", "balanced", void 0, void 0, void 0, [], void 0, executionPreference, minPlacementEvidence)
|
|
23646
|
+
);
|
|
23647
|
+
if (typeof decision.selected_model !== "string" || !decision.selected_model) {
|
|
23648
|
+
throw new Error(
|
|
23649
|
+
"No research model: pass `model`, set FREELLAMA_MCP_DEFAULT_MODEL, or install a coding model (models{view:'installed'} shows what routing can use)."
|
|
23650
|
+
);
|
|
23651
|
+
}
|
|
23652
|
+
return decision.selected_model;
|
|
23653
|
+
}
|
|
22754
23654
|
server.registerTool(
|
|
22755
23655
|
"delegate_research",
|
|
22756
23656
|
{
|
|
22757
|
-
description: "Use when:
|
|
22758
|
-
inputSchema: {
|
|
22759
|
-
question: external_exports.string().min(1)
|
|
22760
|
-
workspacePath: external_exports.string().min(1)
|
|
22761
|
-
adapter: external_exports.enum(["bash", "octocode"]).optional()
|
|
22762
|
-
model: external_exports.string().min(1).optional()
|
|
23657
|
+
description: "Use when: workspace lookup. Do not use when: mutation/external facts. Returns: citations/answer; discard verification.recommendation=escalate, otherwise verify citations.",
|
|
23658
|
+
inputSchema: external_exports.object({
|
|
23659
|
+
question: external_exports.string().min(1),
|
|
23660
|
+
workspacePath: external_exports.string().min(1),
|
|
23661
|
+
adapter: external_exports.enum(["bash", "octocode"]).optional(),
|
|
23662
|
+
model: external_exports.string().min(1).optional(),
|
|
22763
23663
|
endpoint: endpointParam,
|
|
22764
23664
|
executionPreference: executionPreferenceParam,
|
|
22765
23665
|
minPlacementEvidence: minPlacementEvidenceParam,
|
|
22766
|
-
legacyText: external_exports.boolean().optional()
|
|
23666
|
+
legacyText: external_exports.boolean().optional(),
|
|
22767
23667
|
agent: external_exports.object({
|
|
22768
23668
|
maxTurns: external_exports.number().int().positive().optional(),
|
|
22769
|
-
contextTokens: external_exports.number().int().positive().optional()
|
|
22770
|
-
outputTokens: external_exports.number().int().positive().optional()
|
|
23669
|
+
contextTokens: external_exports.number().int().positive().optional(),
|
|
23670
|
+
outputTokens: external_exports.number().int().positive().optional(),
|
|
22771
23671
|
temperature: external_exports.number().nonnegative().optional(),
|
|
22772
23672
|
seed: external_exports.number().int().nonnegative().optional(),
|
|
22773
23673
|
think: external_exports.boolean().optional(),
|
|
22774
|
-
keepAlive: external_exports.string().min(1).optional()
|
|
23674
|
+
keepAlive: external_exports.string().min(1).optional(),
|
|
22775
23675
|
requestTimeoutSeconds: external_exports.number().positive().optional(),
|
|
22776
|
-
toolTimeoutSeconds: external_exports.number().positive().optional()
|
|
22777
|
-
|
|
22778
|
-
|
|
22779
|
-
maxParseRepairs: external_exports.number().int().nonnegative().optional(),
|
|
22780
|
-
parseRepairEchoChars: external_exports.number().int().positive().optional(),
|
|
22781
|
-
context: external_exports.object({
|
|
22782
|
-
charsPerToken: external_exports.number().positive().optional(),
|
|
22783
|
-
safetyMarginTokens: external_exports.number().int().nonnegative().optional(),
|
|
22784
|
-
imageTokenEstimate: external_exports.number().int().nonnegative().optional(),
|
|
22785
|
-
keepRecent: external_exports.number().int().nonnegative().optional(),
|
|
22786
|
-
compactPreviewChars: external_exports.number().int().positive().optional(),
|
|
22787
|
-
compactRetainRatio: external_exports.number().positive().lt(1).optional(),
|
|
22788
|
-
clipHeadRatio: external_exports.number().positive().lt(1).optional(),
|
|
22789
|
-
observationPageChars: external_exports.number().int().positive().optional(),
|
|
22790
|
-
pinnedOverflow: external_exports.enum(["error", "clip"]).optional()
|
|
22791
|
-
}).optional()
|
|
22792
|
-
}).optional().describe("Per-call agent budget, recovery, and compaction controls.")
|
|
22793
|
-
},
|
|
23676
|
+
toolTimeoutSeconds: external_exports.number().positive().optional()
|
|
23677
|
+
}).strict().optional()
|
|
23678
|
+
}).strict(),
|
|
22794
23679
|
outputSchema: researchResultSchema,
|
|
22795
23680
|
annotations: { destructiveHint: false }
|
|
22796
23681
|
},
|
|
22797
|
-
async ({ question, workspacePath, adapter, model, endpoint, executionPreference, minPlacementEvidence, legacyText, agent }) => {
|
|
23682
|
+
async ({ question, workspacePath, adapter, model, endpoint, executionPreference, minPlacementEvidence, legacyText, agent }, extra) => {
|
|
22798
23683
|
const chosenAdapter = adapter ?? DEFAULT_RESEARCH_ADAPTER;
|
|
22799
|
-
const chosenModel = model ?? DEFAULT_DELEGATE_MODEL;
|
|
22800
23684
|
let resolvedWorkspace;
|
|
23685
|
+
let chosenModel;
|
|
22801
23686
|
try {
|
|
22802
23687
|
resolvedWorkspace = await assertAllowedWorkspace(workspacePath);
|
|
23688
|
+
chosenModel = model ?? DEFAULT_DELEGATE_MODEL ?? await routedResearchModel(endpoint, executionPreference, minPlacementEvidence);
|
|
22803
23689
|
} catch (error2) {
|
|
22804
|
-
return
|
|
23690
|
+
return researchErrorResult(error2);
|
|
22805
23691
|
}
|
|
22806
23692
|
const known = MODEL_EVIDENCE[chosenModel];
|
|
22807
23693
|
if (known?.grade === "unusable") {
|
|
@@ -22816,23 +23702,24 @@ server.registerTool(
|
|
|
22816
23702
|
summary: `Refused before running: ${chosenModel} is measured unusable for research here (${known.note}). Re-run with a ~27B model (see README), or answer it yourself.`
|
|
22817
23703
|
});
|
|
22818
23704
|
}
|
|
22819
|
-
const dir = await mkdtemp(
|
|
22820
|
-
const promptFile =
|
|
22821
|
-
const resultFile =
|
|
23705
|
+
const dir = await mkdtemp(path5.join(tmpdir(), "freellama-delegate-"));
|
|
23706
|
+
const promptFile = path5.join(dir, "prompt.md");
|
|
23707
|
+
const resultFile = path5.join(dir, "result.json");
|
|
22822
23708
|
try {
|
|
22823
23709
|
await writeFile(promptFile, `${question}
|
|
22824
23710
|
`, "utf8");
|
|
22825
23711
|
const adapter2 = RESEARCH_ADAPTERS[chosenAdapter];
|
|
22826
|
-
if (!
|
|
22827
|
-
return
|
|
23712
|
+
if (!existsSync5(adapter2)) {
|
|
23713
|
+
return researchErrorResult(
|
|
22828
23714
|
new Error(
|
|
22829
23715
|
`research adapter not found at ${adapter2}. In a published install it should be bundled under <package>/adapters; in-repo it comes from benchmark/local/scripts. Reinstall, or run \`npm run build\` from packages/mcp/ to re-copy it.`
|
|
22830
23716
|
)
|
|
22831
23717
|
);
|
|
22832
23718
|
}
|
|
22833
23719
|
const running = execFileAsync("python3", [adapter2], {
|
|
23720
|
+
signal: extra.signal,
|
|
22834
23721
|
env: {
|
|
22835
|
-
...
|
|
23722
|
+
...delegateEnvironment(),
|
|
22836
23723
|
FREELLAMA_TARGET_MODEL: chosenModel,
|
|
22837
23724
|
FREELLAMA_AGENT_MANAGED_ENDPOINT: endpoint ?? DEFAULT_SERVE_ENDPOINT,
|
|
22838
23725
|
FREELLAMA_AGENT_EXECUTION_PREFERENCE: executionPreference ?? "auto",
|
|
@@ -22849,20 +23736,7 @@ server.registerTool(
|
|
|
22849
23736
|
...agent?.think !== void 0 ? { FREELLAMA_AGENT_THINK: String(agent.think) } : {},
|
|
22850
23737
|
...agent?.keepAlive !== void 0 ? { FREELLAMA_AGENT_KEEP_ALIVE: agent.keepAlive } : {},
|
|
22851
23738
|
...agent?.requestTimeoutSeconds !== void 0 ? { FREELLAMA_AGENT_REQUEST_TIMEOUT_SECONDS: String(agent.requestTimeoutSeconds) } : {},
|
|
22852
|
-
...agent?.toolTimeoutSeconds !== void 0 ? { FREELLAMA_AGENT_TOOL_TIMEOUT_SECONDS: String(agent.toolTimeoutSeconds) } : {}
|
|
22853
|
-
...agent?.retryAttempts !== void 0 ? { FREELLAMA_AGENT_RETRY_ATTEMPTS: String(agent.retryAttempts) } : {},
|
|
22854
|
-
...agent?.retryBackoffSeconds !== void 0 ? { FREELLAMA_AGENT_RETRY_BACKOFF_SECONDS: String(agent.retryBackoffSeconds) } : {},
|
|
22855
|
-
...agent?.maxParseRepairs !== void 0 ? { FREELLAMA_AGENT_MAX_PARSE_REPAIRS: String(agent.maxParseRepairs) } : {},
|
|
22856
|
-
...agent?.parseRepairEchoChars !== void 0 ? { FREELLAMA_AGENT_PARSE_REPAIR_ECHO_CHARS: String(agent.parseRepairEchoChars) } : {},
|
|
22857
|
-
...agent?.context?.charsPerToken !== void 0 ? { FREELLAMA_AGENT_CHARS_PER_TOKEN: String(agent.context.charsPerToken) } : {},
|
|
22858
|
-
...agent?.context?.safetyMarginTokens !== void 0 ? { FREELLAMA_AGENT_SAFETY_MARGIN_TOKENS: String(agent.context.safetyMarginTokens) } : {},
|
|
22859
|
-
...agent?.context?.imageTokenEstimate !== void 0 ? { FREELLAMA_AGENT_IMAGE_TOKEN_ESTIMATE: String(agent.context.imageTokenEstimate) } : {},
|
|
22860
|
-
...agent?.context?.keepRecent !== void 0 ? { FREELLAMA_AGENT_KEEP_RECENT: String(agent.context.keepRecent) } : {},
|
|
22861
|
-
...agent?.context?.compactPreviewChars !== void 0 ? { FREELLAMA_AGENT_COMPACT_PREVIEW_CHARS: String(agent.context.compactPreviewChars) } : {},
|
|
22862
|
-
...agent?.context?.compactRetainRatio !== void 0 ? { FREELLAMA_AGENT_COMPACT_RETAIN_RATIO: String(agent.context.compactRetainRatio) } : {},
|
|
22863
|
-
...agent?.context?.clipHeadRatio !== void 0 ? { FREELLAMA_AGENT_CLIP_HEAD_RATIO: String(agent.context.clipHeadRatio) } : {},
|
|
22864
|
-
...agent?.context?.observationPageChars !== void 0 ? { FREELLAMA_AGENT_OBSERVATION_PAGE_CHARS: String(agent.context.observationPageChars) } : {},
|
|
22865
|
-
...agent?.context?.pinnedOverflow !== void 0 ? { FREELLAMA_AGENT_PINNED_OVERFLOW: agent.context.pinnedOverflow } : {}
|
|
23739
|
+
...agent?.toolTimeoutSeconds !== void 0 ? { FREELLAMA_AGENT_TOOL_TIMEOUT_SECONDS: String(agent.toolTimeoutSeconds) } : {}
|
|
22866
23740
|
},
|
|
22867
23741
|
timeout: DEFAULT_DELEGATE_TIMEOUT_SECONDS * 1e3,
|
|
22868
23742
|
// The answer is read from `resultFile`, never from stdout — but execFile's default 1 MB
|
|
@@ -22888,7 +23762,7 @@ server.registerTool(
|
|
|
22888
23762
|
try {
|
|
22889
23763
|
result = parseAdapterResult(await readFile(resultFile, "utf8"));
|
|
22890
23764
|
} catch {
|
|
22891
|
-
return
|
|
23765
|
+
return researchErrorResult(
|
|
22892
23766
|
adapterError ?? new Error(
|
|
22893
23767
|
`research adapter exited without writing a readable result file \u2014 it was killed before it could report. Check that the model is loadable and that ${DEFAULT_DELEGATE_TIMEOUT_SECONDS}s is enough for this question.`
|
|
22894
23768
|
)
|
|
@@ -22905,7 +23779,7 @@ server.registerTool(
|
|
|
22905
23779
|
// lets a reader tell a run that read three files from one that failed three commands —
|
|
22906
23780
|
// indistinguishable in the trail before, and graded identically.
|
|
22907
23781
|
status: call.status ?? "ok",
|
|
22908
|
-
path: target ?
|
|
23782
|
+
path: target ? path5.relative(resolvedWorkspace, target) : detail ? extractExistingWorkspacePath(detail, resolvedWorkspace) : null,
|
|
22909
23783
|
detail,
|
|
22910
23784
|
detail_truncated: rawDetail !== detail
|
|
22911
23785
|
};
|
|
@@ -22915,21 +23789,16 @@ server.registerTool(
|
|
|
22915
23789
|
const evidenceText = evidence.map(
|
|
22916
23790
|
(step) => ` ${step.step}. ${step.tool}${step.status === "ok" ? "" : ` [${step.status}]`}${step.path ? ` -> ${step.path}` : ""}${step.detail ? `: ${clipText(step.detail, 400)}` : ""}`
|
|
22917
23791
|
).join("\n");
|
|
22918
|
-
const citations = succeeded.map((step) => ({
|
|
22919
|
-
step: step.step,
|
|
22920
|
-
tool: step.tool,
|
|
22921
|
-
path: step.path,
|
|
22922
|
-
command: step.detail,
|
|
22923
|
-
command_truncated: step.detail_truncated
|
|
22924
|
-
}));
|
|
23792
|
+
const citations = succeeded.map((step) => ({ step: step.step, tool: step.tool, path: step.path }));
|
|
22925
23793
|
if (adapterError) {
|
|
22926
|
-
|
|
22927
|
-
new Error(
|
|
22928
|
-
`research adapter failed: ${result.final_answer}` + (evidenceText ? `
|
|
23794
|
+
const diagnostic = `research adapter failed: ${result.final_answer}` + (evidenceText ? `
|
|
22929
23795
|
Evidence collected before the failure:
|
|
22930
|
-
${evidenceText}` : "")
|
|
22931
|
-
|
|
22932
|
-
)
|
|
23796
|
+
${evidenceText}` : "");
|
|
23797
|
+
const refusal = external_exports.object({ receipt: external_exports.object({ error: external_exports.string() }).passthrough() }).safeParse(result.model_metadata?.transport_error);
|
|
23798
|
+
if (refusal.success) {
|
|
23799
|
+
return researchErrorResult(new Error(JSON.stringify(refusal.data.receipt)), diagnostic);
|
|
23800
|
+
}
|
|
23801
|
+
return researchErrorResult(new Error(diagnostic));
|
|
22933
23802
|
}
|
|
22934
23803
|
const verification = assessDelegatedAnswer(question, succeeded.length, chosenModel);
|
|
22935
23804
|
const summary = `Delegated answer ready: ${result.tool_calls.length} tool call(s)` + (failed > 0 ? `, ${failed} of which did not succeed` : "") + `; ${result.usage.input_tokens ?? "?"} input / ${result.usage.output_tokens ?? "?"} output local tokens; verification=${verification.recommendation}. Read structuredContent.answer and citations.`;
|
|
@@ -22959,9 +23828,15 @@ ${evidenceText}` : "")
|
|
|
22959
23828
|
evidence,
|
|
22960
23829
|
summary
|
|
22961
23830
|
};
|
|
22962
|
-
|
|
23831
|
+
const cited = [...new Set(citations.map((citation) => citation.path).filter(Boolean))];
|
|
23832
|
+
const answerText = `${clipText(result.final_answer, ANSWER_TEXT_MAX_CHARS)}
|
|
23833
|
+
|
|
23834
|
+
verification: ${verification.recommendation}` + (cited.length ? `
|
|
23835
|
+
cited: ${cited.slice(0, 20).join(", ")}` : "") + `
|
|
23836
|
+
(${chosenModel}, ${result.tool_calls.length} tool call(s))`;
|
|
23837
|
+
return structuredResult(payload, legacyText === true ? { legacyJson: true } : { text: answerText });
|
|
22963
23838
|
} catch (error2) {
|
|
22964
|
-
return
|
|
23839
|
+
return researchErrorResult(error2);
|
|
22965
23840
|
} finally {
|
|
22966
23841
|
await rm(dir, { recursive: true, force: true });
|
|
22967
23842
|
}
|