crosscheck-mcp 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node-stdio.cjs +352 -68
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.d.cts +10 -0
- package/dist/node-stdio.d.ts +10 -0
- package/dist/node-stdio.js +352 -68
- package/dist/node-stdio.js.map +1 -1
- package/dist/pricing.json +90 -0
- package/package.json +2 -1
package/dist/node-stdio.cjs
CHANGED
|
@@ -48,6 +48,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
48
48
|
// src/entrypoints/node-stdio.ts
|
|
49
49
|
var import_node_fs11 = require("fs");
|
|
50
50
|
var import_node_path11 = __toESM(require("path"), 1);
|
|
51
|
+
var import_node_url2 = require("url");
|
|
51
52
|
var import_stdio2 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
52
53
|
|
|
53
54
|
// src/adapters/storage/better-sqlite3.ts
|
|
@@ -1265,6 +1266,7 @@ function defaultTransient(kind) {
|
|
|
1265
1266
|
// src/providers/anthropic.ts
|
|
1266
1267
|
var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
1267
1268
|
var ANTHROPIC_VERSION_HEADER = "2023-06-01";
|
|
1269
|
+
var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
|
|
1268
1270
|
function buildAnthropicRequest(opts) {
|
|
1269
1271
|
let system;
|
|
1270
1272
|
const convo = [];
|
|
@@ -1289,6 +1291,17 @@ function buildAnthropicRequest(opts) {
|
|
|
1289
1291
|
if (system !== void 0) {
|
|
1290
1292
|
body.system = system;
|
|
1291
1293
|
}
|
|
1294
|
+
if (opts.jsonSchema) {
|
|
1295
|
+
body.tools = [{
|
|
1296
|
+
name: ANTHROPIC_STRUCTURED_TOOL_NAME,
|
|
1297
|
+
description: "Emit a single JSON object matching the requested schema.",
|
|
1298
|
+
input_schema: opts.jsonSchema
|
|
1299
|
+
}];
|
|
1300
|
+
body.tool_choice = {
|
|
1301
|
+
type: "tool",
|
|
1302
|
+
name: ANTHROPIC_STRUCTURED_TOOL_NAME
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1292
1305
|
const headers = {
|
|
1293
1306
|
"content-type": "application/json",
|
|
1294
1307
|
"x-api-key": opts.apiKey,
|
|
@@ -1299,6 +1312,7 @@ function buildAnthropicRequest(opts) {
|
|
|
1299
1312
|
function parseAnthropicResponse(opts) {
|
|
1300
1313
|
const r = opts.resp ?? {};
|
|
1301
1314
|
let text = "";
|
|
1315
|
+
let toolUseInput = void 0;
|
|
1302
1316
|
const content = r["content"];
|
|
1303
1317
|
if (!Array.isArray(content)) {
|
|
1304
1318
|
throw new ProviderError(
|
|
@@ -1308,10 +1322,19 @@ function parseAnthropicResponse(opts) {
|
|
|
1308
1322
|
}
|
|
1309
1323
|
for (const block of content) {
|
|
1310
1324
|
if (block && typeof block === "object") {
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1325
|
+
const b = block;
|
|
1326
|
+
const type = b["type"];
|
|
1327
|
+
if (type === "tool_use" && b["name"] === ANTHROPIC_STRUCTURED_TOOL_NAME) {
|
|
1328
|
+
toolUseInput = b["input"];
|
|
1329
|
+
} else {
|
|
1330
|
+
const t = b["text"];
|
|
1331
|
+
if (typeof t === "string") text += t;
|
|
1332
|
+
}
|
|
1313
1333
|
}
|
|
1314
1334
|
}
|
|
1335
|
+
if (toolUseInput !== void 0) {
|
|
1336
|
+
text = JSON.stringify(toolUseInput);
|
|
1337
|
+
}
|
|
1315
1338
|
const u = r["usage"] ?? {};
|
|
1316
1339
|
const prompt = Math.trunc(Number(u["input_tokens"] ?? 0)) || 0;
|
|
1317
1340
|
const cached = Math.trunc(Number(u["cache_read_input_tokens"] ?? 0)) || 0;
|
|
@@ -1356,7 +1379,8 @@ async function sendAnthropic(args) {
|
|
|
1356
1379
|
apiKey: args.apiKey,
|
|
1357
1380
|
messages: args.messages,
|
|
1358
1381
|
maxTokens: args.maxTokens,
|
|
1359
|
-
temperature: args.temperature
|
|
1382
|
+
temperature: args.temperature,
|
|
1383
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1360
1384
|
});
|
|
1361
1385
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1362
1386
|
const init = {
|
|
@@ -1401,6 +1425,45 @@ async function sendAnthropic(args) {
|
|
|
1401
1425
|
|
|
1402
1426
|
// src/providers/gemini.ts
|
|
1403
1427
|
var GEMINI_API_URL_BASE = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
1428
|
+
function jsonSchemaToGeminiSchema(schema) {
|
|
1429
|
+
const out = {};
|
|
1430
|
+
const type = schema["type"];
|
|
1431
|
+
if (typeof type === "string") {
|
|
1432
|
+
out["type"] = type.toUpperCase();
|
|
1433
|
+
} else if (Array.isArray(type)) {
|
|
1434
|
+
const nonNull = type.find((t) => typeof t === "string" && t !== "null");
|
|
1435
|
+
const hasNull = type.includes("null");
|
|
1436
|
+
if (typeof nonNull === "string") out["type"] = nonNull.toUpperCase();
|
|
1437
|
+
if (hasNull) out["nullable"] = true;
|
|
1438
|
+
}
|
|
1439
|
+
const passthrough = [
|
|
1440
|
+
"description",
|
|
1441
|
+
"enum",
|
|
1442
|
+
"format",
|
|
1443
|
+
"nullable",
|
|
1444
|
+
"required",
|
|
1445
|
+
"minItems",
|
|
1446
|
+
"maxItems",
|
|
1447
|
+
"minimum",
|
|
1448
|
+
"maximum"
|
|
1449
|
+
];
|
|
1450
|
+
for (const k of passthrough) {
|
|
1451
|
+
if (k in schema) out[k] = schema[k];
|
|
1452
|
+
}
|
|
1453
|
+
if (schema["properties"] && typeof schema["properties"] === "object") {
|
|
1454
|
+
const props = {};
|
|
1455
|
+
for (const [name, val] of Object.entries(schema["properties"])) {
|
|
1456
|
+
if (val && typeof val === "object") {
|
|
1457
|
+
props[name] = jsonSchemaToGeminiSchema(val);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
out["properties"] = props;
|
|
1461
|
+
}
|
|
1462
|
+
if (schema["items"] && typeof schema["items"] === "object" && !Array.isArray(schema["items"])) {
|
|
1463
|
+
out["items"] = jsonSchemaToGeminiSchema(schema["items"]);
|
|
1464
|
+
}
|
|
1465
|
+
return out;
|
|
1466
|
+
}
|
|
1404
1467
|
function buildGeminiRequest(opts) {
|
|
1405
1468
|
const contents = [];
|
|
1406
1469
|
let systemText = null;
|
|
@@ -1426,6 +1489,10 @@ function buildGeminiRequest(opts) {
|
|
|
1426
1489
|
if (systemText !== null && systemText !== "") {
|
|
1427
1490
|
body.systemInstruction = { parts: [{ text: systemText }] };
|
|
1428
1491
|
}
|
|
1492
|
+
if (opts.jsonSchema) {
|
|
1493
|
+
body.generationConfig.responseMimeType = "application/json";
|
|
1494
|
+
body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
|
|
1495
|
+
}
|
|
1429
1496
|
const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
|
|
1430
1497
|
return { url, headers: {}, body };
|
|
1431
1498
|
}
|
|
@@ -1494,7 +1561,8 @@ async function sendGemini(args) {
|
|
|
1494
1561
|
apiKey: args.apiKey,
|
|
1495
1562
|
messages: args.messages,
|
|
1496
1563
|
maxTokens: args.maxTokens,
|
|
1497
|
-
temperature: args.temperature
|
|
1564
|
+
temperature: args.temperature,
|
|
1565
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1498
1566
|
});
|
|
1499
1567
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1500
1568
|
const init = {
|
|
@@ -1545,6 +1613,17 @@ var OPENAI_COMPAT_DEFAULT_URLS = {
|
|
|
1545
1613
|
groq: "https://api.groq.com/openai/v1/chat/completions",
|
|
1546
1614
|
deepseek: "https://api.deepseek.com/v1/chat/completions"
|
|
1547
1615
|
};
|
|
1616
|
+
var OPENAI_COMPAT_NATIVE_STRUCTURED = /* @__PURE__ */ new Set([
|
|
1617
|
+
"openai"
|
|
1618
|
+
]);
|
|
1619
|
+
function supportsNativeJsonSchema(provider, model) {
|
|
1620
|
+
if (!OPENAI_COMPAT_NATIVE_STRUCTURED.has(provider.toLowerCase())) {
|
|
1621
|
+
return false;
|
|
1622
|
+
}
|
|
1623
|
+
const m = model.toLowerCase();
|
|
1624
|
+
if (/^o1(?:-|$)/.test(m)) return false;
|
|
1625
|
+
return true;
|
|
1626
|
+
}
|
|
1548
1627
|
function buildOpenAICompatibleRequest(opts) {
|
|
1549
1628
|
const msgs = opts.messages.map((m) => ({
|
|
1550
1629
|
role: m.role,
|
|
@@ -1560,6 +1639,16 @@ function buildOpenAICompatibleRequest(opts) {
|
|
|
1560
1639
|
} else {
|
|
1561
1640
|
body.max_completion_tokens = opts.maxTokens;
|
|
1562
1641
|
}
|
|
1642
|
+
if (opts.jsonSchema && supportsNativeJsonSchema(opts.provider, opts.model)) {
|
|
1643
|
+
body.response_format = {
|
|
1644
|
+
type: "json_schema",
|
|
1645
|
+
json_schema: {
|
|
1646
|
+
name: "structured_output",
|
|
1647
|
+
schema: opts.jsonSchema,
|
|
1648
|
+
strict: true
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1563
1652
|
const headers = {
|
|
1564
1653
|
"content-type": "application/json",
|
|
1565
1654
|
Authorization: `Bearer ${opts.apiKey}`
|
|
@@ -1631,7 +1720,8 @@ async function sendOpenAICompatible(args) {
|
|
|
1631
1720
|
url: args.url,
|
|
1632
1721
|
messages: args.messages,
|
|
1633
1722
|
maxTokens: args.maxTokens,
|
|
1634
|
-
temperature: args.temperature
|
|
1723
|
+
temperature: args.temperature,
|
|
1724
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1635
1725
|
});
|
|
1636
1726
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1637
1727
|
const init = {
|
|
@@ -2104,11 +2194,13 @@ ${schemaText}`;
|
|
|
2104
2194
|
content: "Your previous response failed validation:\n- " + lastErrs.slice(0, 5).join("\n- ") + "\nFix the issues and re-emit valid JSON only."
|
|
2105
2195
|
});
|
|
2106
2196
|
}
|
|
2197
|
+
const useNative = opts.useNativeStructured !== false;
|
|
2107
2198
|
const ans = await askOne(provider, msgs, {
|
|
2108
2199
|
maxTokens: opts.maxTokens,
|
|
2109
2200
|
temperature: temp,
|
|
2110
2201
|
purpose,
|
|
2111
|
-
...opts.signal ? { signal: opts.signal } : {}
|
|
2202
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
2203
|
+
...useNative ? { jsonSchema: schema } : {}
|
|
2112
2204
|
});
|
|
2113
2205
|
lastAnswer = ans;
|
|
2114
2206
|
if (ans.error !== void 0) {
|
|
@@ -2143,7 +2235,8 @@ async function askOne(provider, messages, opts) {
|
|
|
2143
2235
|
maxTokens: opts.maxTokens,
|
|
2144
2236
|
temperature: opts.temperature,
|
|
2145
2237
|
purpose: opts.purpose,
|
|
2146
|
-
...opts.signal ? { signal: opts.signal } : {}
|
|
2238
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
2239
|
+
...opts.jsonSchema ? { jsonSchema: opts.jsonSchema } : {}
|
|
2147
2240
|
});
|
|
2148
2241
|
const wallMs = Math.trunc(performance.now() - startedWall);
|
|
2149
2242
|
const cpu = process.cpuUsage(startedCpu);
|
|
@@ -2386,7 +2479,7 @@ async function runAudit(args, opts) {
|
|
|
2386
2479
|
const rubricOverride = args["rubric"];
|
|
2387
2480
|
const producing = toStringArray(args["producing_panelists"]).map((s) => s.toLowerCase());
|
|
2388
2481
|
const explicit = typeof args["auditor"] === "string" ? args["auditor"] : null;
|
|
2389
|
-
const cheapMode = boolArg(args["cheap_mode"], true);
|
|
2482
|
+
const cheapMode = boolArg(args["cheap_mode"], opts.ctx?.cheap_mode ?? true);
|
|
2390
2483
|
const allowSelf = boolArg(args["allow_self_audit"], false);
|
|
2391
2484
|
let coalesce = boolArg(args["coalesce"], false);
|
|
2392
2485
|
const strictMode = boolArg(args["strict_mode"], false);
|
|
@@ -3916,7 +4009,7 @@ async function runConfer(args, opts) {
|
|
|
3916
4009
|
};
|
|
3917
4010
|
}
|
|
3918
4011
|
}
|
|
3919
|
-
|
|
4012
|
+
let { selected, unknown: unknownNames, blocked } = resolveProviders(
|
|
3920
4013
|
resolvedProviders,
|
|
3921
4014
|
opts.providers,
|
|
3922
4015
|
opts.allowlist ?? null
|
|
@@ -3933,6 +4026,49 @@ async function runConfer(args, opts) {
|
|
|
3933
4026
|
}
|
|
3934
4027
|
return { tool: "confer", error: "no active providers have API keys in .env" };
|
|
3935
4028
|
}
|
|
4029
|
+
let cheapModePanelMeta = null;
|
|
4030
|
+
if (opts.ctx?.cheap_mode === true && !callerSuppliedProviders && selected.length > 1) {
|
|
4031
|
+
if (!opts.pricing) {
|
|
4032
|
+
cheapModePanelMeta = {
|
|
4033
|
+
before: selected.length,
|
|
4034
|
+
after: selected.length,
|
|
4035
|
+
picked: null,
|
|
4036
|
+
reason: "ctx.cheap_mode=true but no pricing doc wired; kept full panel"
|
|
4037
|
+
};
|
|
4038
|
+
} else {
|
|
4039
|
+
const availableSet = new Set(selected.map((p) => p.name.toLowerCase()));
|
|
4040
|
+
const cheapWeights = opts.storage ? await loadProviderWeights(opts.storage, selected.map((p) => p.name)) : {};
|
|
4041
|
+
const allowOnly = opts.allowlist && opts.allowlist.length > 0 ? opts.allowlist.map((s) => s.toLowerCase()) : void 0;
|
|
4042
|
+
const tierPick = selectForDifficulty({
|
|
4043
|
+
pricing: opts.pricing,
|
|
4044
|
+
tier: "low",
|
|
4045
|
+
availableProviders: availableSet,
|
|
4046
|
+
providerWeights: cheapWeights,
|
|
4047
|
+
...allowOnly !== void 0 ? { allowOnly } : {}
|
|
4048
|
+
});
|
|
4049
|
+
if (tierPick.pick) {
|
|
4050
|
+
const baseProvider = opts.providers[tierPick.pick.provider.toLowerCase()];
|
|
4051
|
+
if (baseProvider) {
|
|
4052
|
+
const beforeCount = selected.length;
|
|
4053
|
+
const retargeted = retargetProvider(baseProvider, tierPick.pick.model);
|
|
4054
|
+
selected = [retargeted];
|
|
4055
|
+
cheapModePanelMeta = {
|
|
4056
|
+
before: beforeCount,
|
|
4057
|
+
after: 1,
|
|
4058
|
+
picked: { provider: tierPick.pick.provider, model: tierPick.pick.model },
|
|
4059
|
+
reason: "ctx.cheap_mode=true; narrowed to cheapest low-tier candidate"
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
} else {
|
|
4063
|
+
cheapModePanelMeta = {
|
|
4064
|
+
before: selected.length,
|
|
4065
|
+
after: selected.length,
|
|
4066
|
+
picked: null,
|
|
4067
|
+
reason: `ctx.cheap_mode=true; ${tierPick.reason ?? "no candidate"}; kept full panel`
|
|
4068
|
+
};
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
3936
4072
|
const untrusted = Boolean(args["untrusted_input"]);
|
|
3937
4073
|
const canary = untrusted ? mintCanary() : null;
|
|
3938
4074
|
const baseSys = "You are part of a panel of LLMs consulted by an engineer working inside Claude Code. Answer directly, cite assumptions, and keep it crisp.";
|
|
@@ -4049,6 +4185,7 @@ ${ctxBody}` });
|
|
|
4049
4185
|
if (claimsBlock !== null) result["claims"] = claimsBlock;
|
|
4050
4186
|
if (leaks.length > 0) result["canary_leaks"] = leaks;
|
|
4051
4187
|
if (autoPanelMeta !== null) result["auto_panel"] = autoPanelMeta;
|
|
4188
|
+
if (cheapModePanelMeta !== null) result["cheap_mode_panel"] = cheapModePanelMeta;
|
|
4052
4189
|
if (requestedWorkerTools.length > 0) {
|
|
4053
4190
|
result["worker_tools"] = {
|
|
4054
4191
|
accepted: acceptedWorkerTools,
|
|
@@ -5220,6 +5357,40 @@ var import_node_path8 = __toESM(require("path"), 1);
|
|
|
5220
5357
|
|
|
5221
5358
|
// src/tools/orchestrate.ts
|
|
5222
5359
|
var import_node_perf_hooks2 = require("perf_hooks");
|
|
5360
|
+
|
|
5361
|
+
// src/core/dead-models.ts
|
|
5362
|
+
var DEAD_MODELS_TTL_MS = 5 * 60 * 1e3;
|
|
5363
|
+
var deadModels = /* @__PURE__ */ new Map();
|
|
5364
|
+
function makeKey(provider, model) {
|
|
5365
|
+
return `${provider.toLowerCase()}:${model.toLowerCase()}`;
|
|
5366
|
+
}
|
|
5367
|
+
function recordDeadModel(provider, model, reason, nowMs = Date.now()) {
|
|
5368
|
+
const key = makeKey(provider, model);
|
|
5369
|
+
deadModels.set(key, {
|
|
5370
|
+
provider: provider.toLowerCase(),
|
|
5371
|
+
model: model.toLowerCase(),
|
|
5372
|
+
reason: reason.slice(0, 200),
|
|
5373
|
+
expires: nowMs + DEAD_MODELS_TTL_MS
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
5376
|
+
function isModelDead(provider, model, nowMs = Date.now()) {
|
|
5377
|
+
const key = makeKey(provider, model);
|
|
5378
|
+
const entry = deadModels.get(key);
|
|
5379
|
+
if (!entry) return false;
|
|
5380
|
+
if (nowMs >= entry.expires) {
|
|
5381
|
+
deadModels.delete(key);
|
|
5382
|
+
return false;
|
|
5383
|
+
}
|
|
5384
|
+
return true;
|
|
5385
|
+
}
|
|
5386
|
+
function isDeadModelError(err) {
|
|
5387
|
+
if (typeof err.error !== "string") return false;
|
|
5388
|
+
if (err.error_kind !== "client") return false;
|
|
5389
|
+
return /HTTP\s*404|not\s*found|does not exist|deprecated|decommission/i.test(err.error);
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
// src/tools/orchestrate.ts
|
|
5393
|
+
var F1B_MAX_TIER_RETRIES = 2;
|
|
5223
5394
|
var DIFFICULTY_TIERS2 = ["low", "med", "high"];
|
|
5224
5395
|
var EST_TOKENS = {
|
|
5225
5396
|
low: [800, 400],
|
|
@@ -5270,7 +5441,7 @@ async function runOrchestrate(args, opts) {
|
|
|
5270
5441
|
const moderator = opts.providers[moderatorName.toLowerCase()] ?? selected[0];
|
|
5271
5442
|
const failFast = boolArg2(args["fail_fast"], false);
|
|
5272
5443
|
const planOnly = boolArg2(args["plan_only"], false);
|
|
5273
|
-
const cheapMode = boolArg2(args["cheap_mode"], false);
|
|
5444
|
+
const cheapMode = boolArg2(args["cheap_mode"], opts.ctx?.cheap_mode ?? false);
|
|
5274
5445
|
const maxTokens = opts.maxTokens ?? 4096;
|
|
5275
5446
|
const cheapAvailable = new Set(
|
|
5276
5447
|
selected.map((p) => p.name.toLowerCase())
|
|
@@ -5356,12 +5527,51 @@ async function runOrchestrate(args, opts) {
|
|
|
5356
5527
|
failedIds.add(nid);
|
|
5357
5528
|
continue;
|
|
5358
5529
|
}
|
|
5530
|
+
const depsRaw = Array.isArray(node["depends_on"]) ? node["depends_on"] : [];
|
|
5531
|
+
const upstreamBlocks = [];
|
|
5532
|
+
for (const d of depsRaw) {
|
|
5533
|
+
if (typeof d !== "string") continue;
|
|
5534
|
+
const ur = nodeResults[d];
|
|
5535
|
+
if (ur && ur.status === "ok") {
|
|
5536
|
+
upstreamBlocks.push(`[node ${d} output]
|
|
5537
|
+
${ur.output ?? ""}`);
|
|
5538
|
+
} else if (ur && ur.status === "failed") {
|
|
5539
|
+
upstreamBlocks.push(`[node ${d}] [MISSING: failed \u2014 ${ur.error ?? ""}]`);
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
const ctxBlock = upstreamBlocks.length > 0 ? upstreamBlocks.join("\n\n") : "(no upstream nodes)";
|
|
5543
|
+
const sysMsg = "You are a worker LLM in an orchestrated DAG. Complete the assigned task using outputs from upstream nodes when relevant. Be concise.";
|
|
5544
|
+
const role = typeof node["role"] === "string" ? node["role"] : "worker";
|
|
5545
|
+
const task = String(node["task"] ?? "");
|
|
5546
|
+
const difficulty = String(node["difficulty"] ?? "med");
|
|
5547
|
+
const msgs = [
|
|
5548
|
+
{ role: "system", content: sysMsg },
|
|
5549
|
+
{
|
|
5550
|
+
role: "user",
|
|
5551
|
+
content: `ROLE: ${role}
|
|
5552
|
+
DIFFICULTY: ${difficulty}
|
|
5553
|
+
|
|
5554
|
+
UPSTREAM:
|
|
5555
|
+
${ctxBlock}
|
|
5556
|
+
|
|
5557
|
+
TASK:
|
|
5558
|
+
${task}`
|
|
5559
|
+
}
|
|
5560
|
+
];
|
|
5359
5561
|
let chosen;
|
|
5562
|
+
let ans;
|
|
5360
5563
|
let cheapReason = null;
|
|
5564
|
+
const retryAttempts = [];
|
|
5361
5565
|
const pinnedName = typeof node["provider"] === "string" ? node["provider"].toLowerCase() : null;
|
|
5362
5566
|
const pinnedModel = typeof node["model"] === "string" ? node["model"] : null;
|
|
5567
|
+
const started = import_node_perf_hooks2.performance.now();
|
|
5363
5568
|
if (pinnedName && opts.providers[pinnedName]) {
|
|
5364
5569
|
chosen = opts.providers[pinnedName];
|
|
5570
|
+
ans = await askOne(chosen, msgs, {
|
|
5571
|
+
maxTokens,
|
|
5572
|
+
temperature: 0.4,
|
|
5573
|
+
purpose: "worker"
|
|
5574
|
+
});
|
|
5365
5575
|
} else if (cheapMode && !pinnedName && !pinnedModel && opts.pricing) {
|
|
5366
5576
|
const tier = String(node["difficulty"] ?? "med");
|
|
5367
5577
|
const pick = selectForDifficulty({
|
|
@@ -5371,21 +5581,78 @@ async function runOrchestrate(args, opts) {
|
|
|
5371
5581
|
providerWeights: cheapWeights,
|
|
5372
5582
|
...cheapAllowOnly ? { allowOnly: cheapAllowOnly } : {}
|
|
5373
5583
|
});
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5584
|
+
const aliveCandidates = pick.scored.filter(
|
|
5585
|
+
(c) => !isModelDead(c.provider, c.model)
|
|
5586
|
+
);
|
|
5587
|
+
if (aliveCandidates.length === 0) {
|
|
5588
|
+
cheapReason = pick.reason ?? "all tier candidates filtered by deadModels cache";
|
|
5377
5589
|
} else {
|
|
5378
|
-
|
|
5590
|
+
const tryLimit = Math.min(F1B_MAX_TIER_RETRIES, aliveCandidates.length);
|
|
5591
|
+
for (let i = 0; i < tryLimit; i++) {
|
|
5592
|
+
const c = aliveCandidates[i];
|
|
5593
|
+
const base = opts.providers[c.provider];
|
|
5594
|
+
if (!base) {
|
|
5595
|
+
retryAttempts.push({
|
|
5596
|
+
provider: c.provider,
|
|
5597
|
+
model: c.model,
|
|
5598
|
+
reason: "provider not in active registry"
|
|
5599
|
+
});
|
|
5600
|
+
continue;
|
|
5601
|
+
}
|
|
5602
|
+
const candidateProvider = retargetProvider(base, c.model);
|
|
5603
|
+
const candidateAns = await askOne(candidateProvider, msgs, {
|
|
5604
|
+
maxTokens,
|
|
5605
|
+
temperature: 0.4,
|
|
5606
|
+
purpose: "worker"
|
|
5607
|
+
});
|
|
5608
|
+
if (candidateAns.error === void 0) {
|
|
5609
|
+
chosen = candidateProvider;
|
|
5610
|
+
ans = candidateAns;
|
|
5611
|
+
if (retryAttempts.length > 0) {
|
|
5612
|
+
cheapReason = `recovered after ${retryAttempts.length} dead-model retry(s): ` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ");
|
|
5613
|
+
}
|
|
5614
|
+
break;
|
|
5615
|
+
}
|
|
5616
|
+
if (isDeadModelError(candidateAns)) {
|
|
5617
|
+
recordDeadModel(c.provider, c.model, candidateAns.error ?? "");
|
|
5618
|
+
retryAttempts.push({
|
|
5619
|
+
provider: c.provider,
|
|
5620
|
+
model: c.model,
|
|
5621
|
+
reason: (candidateAns.error ?? "dead").slice(0, 100)
|
|
5622
|
+
});
|
|
5623
|
+
continue;
|
|
5624
|
+
}
|
|
5625
|
+
chosen = candidateProvider;
|
|
5626
|
+
ans = candidateAns;
|
|
5627
|
+
if (retryAttempts.length > 0) {
|
|
5628
|
+
cheapReason = `${retryAttempts.length} dead-model retry(s) before non-dead failure: ` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ");
|
|
5629
|
+
}
|
|
5630
|
+
break;
|
|
5631
|
+
}
|
|
5379
5632
|
}
|
|
5380
5633
|
if (!chosen) {
|
|
5381
5634
|
const idx = djb2Hash(nid) % Math.max(1, selected.length);
|
|
5382
5635
|
chosen = selected[idx];
|
|
5636
|
+
ans = await askOne(chosen, msgs, {
|
|
5637
|
+
maxTokens,
|
|
5638
|
+
temperature: 0.4,
|
|
5639
|
+
purpose: "worker"
|
|
5640
|
+
});
|
|
5641
|
+
if (retryAttempts.length > 0) {
|
|
5642
|
+
cheapReason = `cheap-mode tier exhausted (` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ") + `); fell back to id-hash rotation`;
|
|
5643
|
+
}
|
|
5383
5644
|
}
|
|
5384
5645
|
} else {
|
|
5385
5646
|
const idx = djb2Hash(nid) % Math.max(1, selected.length);
|
|
5386
5647
|
chosen = selected[idx];
|
|
5648
|
+
ans = await askOne(chosen, msgs, {
|
|
5649
|
+
maxTokens,
|
|
5650
|
+
temperature: 0.4,
|
|
5651
|
+
purpose: "worker"
|
|
5652
|
+
});
|
|
5387
5653
|
}
|
|
5388
|
-
|
|
5654
|
+
const wallMs = Math.trunc(import_node_perf_hooks2.performance.now() - started);
|
|
5655
|
+
if (!chosen || !ans) {
|
|
5389
5656
|
nodeResults[nid] = {
|
|
5390
5657
|
id: nid,
|
|
5391
5658
|
status: "failed",
|
|
@@ -5393,49 +5660,12 @@ async function runOrchestrate(args, opts) {
|
|
|
5393
5660
|
model: null,
|
|
5394
5661
|
error: "no provider available",
|
|
5395
5662
|
wall_ms: 0,
|
|
5396
|
-
cpu_ms: 0
|
|
5663
|
+
cpu_ms: 0,
|
|
5664
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5397
5665
|
};
|
|
5398
5666
|
failedIds.add(nid);
|
|
5399
5667
|
continue;
|
|
5400
5668
|
}
|
|
5401
|
-
const depsRaw = Array.isArray(node["depends_on"]) ? node["depends_on"] : [];
|
|
5402
|
-
const upstreamBlocks = [];
|
|
5403
|
-
for (const d of depsRaw) {
|
|
5404
|
-
if (typeof d !== "string") continue;
|
|
5405
|
-
const ur = nodeResults[d];
|
|
5406
|
-
if (ur && ur.status === "ok") {
|
|
5407
|
-
upstreamBlocks.push(`[node ${d} output]
|
|
5408
|
-
${ur.output ?? ""}`);
|
|
5409
|
-
} else if (ur && ur.status === "failed") {
|
|
5410
|
-
upstreamBlocks.push(`[node ${d}] [MISSING: failed \u2014 ${ur.error ?? ""}]`);
|
|
5411
|
-
}
|
|
5412
|
-
}
|
|
5413
|
-
const ctxBlock = upstreamBlocks.length > 0 ? upstreamBlocks.join("\n\n") : "(no upstream nodes)";
|
|
5414
|
-
const sysMsg = "You are a worker LLM in an orchestrated DAG. Complete the assigned task using outputs from upstream nodes when relevant. Be concise.";
|
|
5415
|
-
const role = typeof node["role"] === "string" ? node["role"] : "worker";
|
|
5416
|
-
const task = String(node["task"] ?? "");
|
|
5417
|
-
const difficulty = String(node["difficulty"] ?? "med");
|
|
5418
|
-
const msgs = [
|
|
5419
|
-
{ role: "system", content: sysMsg },
|
|
5420
|
-
{
|
|
5421
|
-
role: "user",
|
|
5422
|
-
content: `ROLE: ${role}
|
|
5423
|
-
DIFFICULTY: ${difficulty}
|
|
5424
|
-
|
|
5425
|
-
UPSTREAM:
|
|
5426
|
-
${ctxBlock}
|
|
5427
|
-
|
|
5428
|
-
TASK:
|
|
5429
|
-
${task}`
|
|
5430
|
-
}
|
|
5431
|
-
];
|
|
5432
|
-
const started = import_node_perf_hooks2.performance.now();
|
|
5433
|
-
const ans = await askOne(chosen, msgs, {
|
|
5434
|
-
maxTokens,
|
|
5435
|
-
temperature: 0.4,
|
|
5436
|
-
purpose: "worker"
|
|
5437
|
-
});
|
|
5438
|
-
const wallMs = Math.trunc(import_node_perf_hooks2.performance.now() - started);
|
|
5439
5669
|
if (ans.error !== void 0) {
|
|
5440
5670
|
nodeResults[nid] = {
|
|
5441
5671
|
id: nid,
|
|
@@ -5445,7 +5675,8 @@ ${task}`
|
|
|
5445
5675
|
error: ans.error,
|
|
5446
5676
|
wall_ms: wallMs,
|
|
5447
5677
|
cpu_ms: ans.cpu_ms,
|
|
5448
|
-
...cheapReason ? { cheap_fallback_reason: cheapReason } : {}
|
|
5678
|
+
...cheapReason ? { cheap_fallback_reason: cheapReason } : {},
|
|
5679
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5449
5680
|
};
|
|
5450
5681
|
failedIds.add(nid);
|
|
5451
5682
|
continue;
|
|
@@ -5458,7 +5689,8 @@ ${task}`
|
|
|
5458
5689
|
output: ans.response ?? "",
|
|
5459
5690
|
wall_ms: wallMs,
|
|
5460
5691
|
cpu_ms: ans.cpu_ms,
|
|
5461
|
-
...cheapReason ? { cheap_fallback_reason: cheapReason } : {}
|
|
5692
|
+
...cheapReason ? { cheap_fallback_reason: cheapReason } : {},
|
|
5693
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5462
5694
|
};
|
|
5463
5695
|
}
|
|
5464
5696
|
const missing = Object.keys(nodesById).filter(
|
|
@@ -6084,6 +6316,16 @@ function errorPayload(code, message, hint, kind = "client") {
|
|
|
6084
6316
|
};
|
|
6085
6317
|
}
|
|
6086
6318
|
|
|
6319
|
+
// src/core/call-context.ts
|
|
6320
|
+
function buildCallContext(args) {
|
|
6321
|
+
const ctx = {
|
|
6322
|
+
cheap_mode: args.cheapMode,
|
|
6323
|
+
session_id: args.sessionId
|
|
6324
|
+
};
|
|
6325
|
+
if (args.purpose) ctx.purpose = args.purpose;
|
|
6326
|
+
return ctx;
|
|
6327
|
+
}
|
|
6328
|
+
|
|
6087
6329
|
// src/tools/create.ts
|
|
6088
6330
|
var CREATE_DOC_MAX_BYTES = 32 * 1024;
|
|
6089
6331
|
var CREATE_AUDIT_THRESHOLD = 0.7;
|
|
@@ -6112,6 +6354,10 @@ async function runCreate(args, opts) {
|
|
|
6112
6354
|
const dryRun = boolArg3(args["dry_run"], false);
|
|
6113
6355
|
const planOnly = boolArg3(args["plan_only"], false);
|
|
6114
6356
|
const moderator = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
|
|
6357
|
+
const ctx = opts.ctx ?? buildCallContext({
|
|
6358
|
+
cheapMode,
|
|
6359
|
+
sessionId
|
|
6360
|
+
});
|
|
6115
6361
|
const descriptors = await ingestDocuments(documents, sessionId, opts);
|
|
6116
6362
|
const documentsPayload = formatDocumentsPayload(descriptors);
|
|
6117
6363
|
const okCount = descriptors.filter((d) => d.status === "ok").length;
|
|
@@ -6129,7 +6375,8 @@ ${documentsPayload}`;
|
|
|
6129
6375
|
}, {
|
|
6130
6376
|
providers: opts.providers,
|
|
6131
6377
|
allowlist: opts.allowlist ?? null,
|
|
6132
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6378
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6379
|
+
ctx
|
|
6133
6380
|
});
|
|
6134
6381
|
const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
|
|
6135
6382
|
${a["response"]}`).join("\n\n") : "";
|
|
@@ -6151,7 +6398,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6151
6398
|
providers: opts.providers,
|
|
6152
6399
|
allowlist: opts.allowlist ?? null,
|
|
6153
6400
|
moderator,
|
|
6154
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6401
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6402
|
+
ctx
|
|
6155
6403
|
});
|
|
6156
6404
|
let attempts = 1;
|
|
6157
6405
|
if (planOnly) {
|
|
@@ -6185,7 +6433,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6185
6433
|
}, {
|
|
6186
6434
|
providers: opts.providers,
|
|
6187
6435
|
allowlist: opts.allowlist ?? null,
|
|
6188
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6436
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6437
|
+
ctx
|
|
6189
6438
|
});
|
|
6190
6439
|
}
|
|
6191
6440
|
let auditEnvelope = null;
|
|
@@ -6207,7 +6456,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6207
6456
|
}, {
|
|
6208
6457
|
providers: opts.providers,
|
|
6209
6458
|
allowlist: opts.allowlist ?? null,
|
|
6210
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6459
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6460
|
+
ctx
|
|
6211
6461
|
});
|
|
6212
6462
|
let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6213
6463
|
if (overallF !== null && overallF < auditThreshold && !cheapMode && !boolArg3(args["_no_retry"], false)) {
|
|
@@ -6231,7 +6481,8 @@ ${documentsPayload}`
|
|
|
6231
6481
|
providers: opts.providers,
|
|
6232
6482
|
allowlist: opts.allowlist ?? null,
|
|
6233
6483
|
moderator,
|
|
6234
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6484
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6485
|
+
ctx
|
|
6235
6486
|
}
|
|
6236
6487
|
);
|
|
6237
6488
|
orchestration = retryOrchestration;
|
|
@@ -6250,7 +6501,8 @@ ${documentsPayload}`
|
|
|
6250
6501
|
}, {
|
|
6251
6502
|
providers: opts.providers,
|
|
6252
6503
|
allowlist: opts.allowlist ?? null,
|
|
6253
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6504
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6505
|
+
ctx
|
|
6254
6506
|
});
|
|
6255
6507
|
overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6256
6508
|
} else {
|
|
@@ -8101,7 +8353,7 @@ CRITERIA:
|
|
|
8101
8353
|
${criteriaBlock}`
|
|
8102
8354
|
}
|
|
8103
8355
|
];
|
|
8104
|
-
const maxTokens = opts.maxTokens ??
|
|
8356
|
+
const maxTokens = opts.maxTokens ?? 4096;
|
|
8105
8357
|
const scoresByProvider = {};
|
|
8106
8358
|
const answersCollected = [];
|
|
8107
8359
|
const scoringErrors = {};
|
|
@@ -8297,9 +8549,23 @@ function toArray(v) {
|
|
|
8297
8549
|
}
|
|
8298
8550
|
|
|
8299
8551
|
// src/tools/plan.ts
|
|
8552
|
+
var PLAN_MODE_PRESETS = {
|
|
8553
|
+
fast: { max_rounds: 2, early_stop: true, early_stop_threshold: 0.7 },
|
|
8554
|
+
thorough: { max_rounds: 5, early_stop: false, early_stop_threshold: 0.7 }
|
|
8555
|
+
};
|
|
8556
|
+
var DEFAULT_PLAN_MODE = "fast";
|
|
8300
8557
|
async function runPlan(args, opts) {
|
|
8301
8558
|
const goal = typeof args["goal"] === "string" ? args["goal"] : String(args["goal"] ?? "");
|
|
8302
8559
|
const constraints = typeof args["constraints"] === "string" ? args["constraints"] : "";
|
|
8560
|
+
const modeArg = args["mode"];
|
|
8561
|
+
const mode = modeArg === "fast" || modeArg === "thorough" ? modeArg : DEFAULT_PLAN_MODE;
|
|
8562
|
+
const preset = PLAN_MODE_PRESETS[mode];
|
|
8563
|
+
const maxRoundsRaw = args["max_rounds"];
|
|
8564
|
+
const earlyStopRaw = args["early_stop"];
|
|
8565
|
+
const earlyStopThresholdRaw = args["early_stop_threshold"];
|
|
8566
|
+
const maxRounds = typeof maxRoundsRaw === "number" && Number.isFinite(maxRoundsRaw) && maxRoundsRaw > 0 ? Math.trunc(maxRoundsRaw) : preset.max_rounds;
|
|
8567
|
+
const earlyStop = typeof earlyStopRaw === "boolean" ? earlyStopRaw : preset.early_stop;
|
|
8568
|
+
const earlyStopThreshold = typeof earlyStopThresholdRaw === "number" && Number.isFinite(earlyStopThresholdRaw) ? earlyStopThresholdRaw : preset.early_stop_threshold;
|
|
8303
8569
|
const merged = `We need a step-by-step plan to achieve this goal.
|
|
8304
8570
|
|
|
8305
8571
|
GOAL: ${goal}
|
|
@@ -8310,7 +8576,10 @@ Return: (1) the plan as numbered steps, (2) risks, (3) alternatives considered.`
|
|
|
8310
8576
|
const debateArgs = {
|
|
8311
8577
|
topic: merged,
|
|
8312
8578
|
context: typeof args["context"] === "string" ? args["context"] : "",
|
|
8313
|
-
structured: Boolean(args["structured"])
|
|
8579
|
+
structured: Boolean(args["structured"]),
|
|
8580
|
+
max_rounds: maxRounds,
|
|
8581
|
+
early_stop: earlyStop,
|
|
8582
|
+
early_stop_threshold: earlyStopThreshold
|
|
8314
8583
|
};
|
|
8315
8584
|
if (args["providers"] !== void 0) debateArgs["providers"] = args["providers"];
|
|
8316
8585
|
if (args["moderator"] !== void 0) debateArgs["moderator"] = args["moderator"];
|
|
@@ -10020,7 +10289,7 @@ function critiqueTool(providers, allowlist, bridge) {
|
|
|
10020
10289
|
function planTool(providers, allowlist, bridge) {
|
|
10021
10290
|
return {
|
|
10022
10291
|
name: "plan",
|
|
10023
|
-
description:
|
|
10292
|
+
description: 'Have an LLM panel debate a step-by-step plan for the stated goal under the given constraints. Returns the debate envelope with a moderator-synthesised plan. Defaults to `mode: "fast"` (2 rounds + early_stop) \u2014 set `mode: "thorough"` for 5 rounds without early_stop. Explicit `max_rounds` / `early_stop` / `early_stop_threshold` always override the mode preset. Use `structured: true` for schema-validated synthesis.',
|
|
10024
10293
|
inputSchema: {
|
|
10025
10294
|
type: "object",
|
|
10026
10295
|
additionalProperties: true,
|
|
@@ -10031,7 +10300,11 @@ function planTool(providers, allowlist, bridge) {
|
|
|
10031
10300
|
providers: { type: "array", items: { type: "string" } },
|
|
10032
10301
|
moderator: { type: "string" },
|
|
10033
10302
|
session_id: { type: "string" },
|
|
10034
|
-
structured: { type: "boolean" }
|
|
10303
|
+
structured: { type: "boolean" },
|
|
10304
|
+
mode: { type: "string", enum: ["fast", "thorough"] },
|
|
10305
|
+
max_rounds: { type: "integer", minimum: 1 },
|
|
10306
|
+
early_stop: { type: "boolean" },
|
|
10307
|
+
early_stop_threshold: { type: "number", minimum: 0, maximum: 1 }
|
|
10035
10308
|
},
|
|
10036
10309
|
required: ["goal"]
|
|
10037
10310
|
},
|
|
@@ -10424,8 +10697,19 @@ async function main() {
|
|
|
10424
10697
|
);
|
|
10425
10698
|
}
|
|
10426
10699
|
installShutdownHandlers(bridge);
|
|
10427
|
-
const
|
|
10428
|
-
|
|
10700
|
+
const bundledPricing = (() => {
|
|
10701
|
+
try {
|
|
10702
|
+
return import_node_path11.default.join(import_node_path11.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
|
|
10703
|
+
} catch {
|
|
10704
|
+
return void 0;
|
|
10705
|
+
}
|
|
10706
|
+
})();
|
|
10707
|
+
const pricingPath = [
|
|
10708
|
+
process.env["CROSSCHECK_PRICING_PATH"],
|
|
10709
|
+
resolveRepoFile("config/pricing.json"),
|
|
10710
|
+
bundledPricing
|
|
10711
|
+
].find((p) => p && (0, import_node_fs11.existsSync)(p));
|
|
10712
|
+
const pricing = pricingPath ? loadPricing(pricingPath) : {};
|
|
10429
10713
|
const providers = buildProviders({ env: process.env, pricing });
|
|
10430
10714
|
if (Object.keys(providers).length > 0) {
|
|
10431
10715
|
process.stderr.write(
|