crosscheck-mcp 0.1.0 → 0.1.2
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 +386 -69
- 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 +386 -69
- 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(
|
|
@@ -5485,11 +5717,43 @@ Synthesize the node outputs into a single coherent deliverable. Preserve any [MI
|
|
|
5485
5717
|
{ role: "system", content: "You are the orchestrator. Combine node outputs into the final result." },
|
|
5486
5718
|
{ role: "user", content: recombinePrompt }
|
|
5487
5719
|
];
|
|
5488
|
-
|
|
5720
|
+
let synthProvider = moderator;
|
|
5721
|
+
let synthModel = null;
|
|
5722
|
+
if (cheapMode && opts.pricing) {
|
|
5723
|
+
const pick = selectForDifficulty({
|
|
5724
|
+
pricing: opts.pricing,
|
|
5725
|
+
tier: "med",
|
|
5726
|
+
availableProviders: cheapAvailable,
|
|
5727
|
+
providerWeights: cheapWeights,
|
|
5728
|
+
...cheapAllowOnly ? { allowOnly: cheapAllowOnly } : {}
|
|
5729
|
+
});
|
|
5730
|
+
for (const c of pick.scored) {
|
|
5731
|
+
if (isModelDead(c.provider, c.model)) continue;
|
|
5732
|
+
const base = opts.providers[c.provider];
|
|
5733
|
+
if (base) {
|
|
5734
|
+
synthProvider = retargetProvider(base, c.model);
|
|
5735
|
+
synthModel = `${c.provider}/${c.model}`;
|
|
5736
|
+
break;
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
let synthAns = await askOne(synthProvider, recMsgs, {
|
|
5489
5741
|
maxTokens,
|
|
5490
5742
|
temperature: 0.4,
|
|
5491
5743
|
purpose: "synth"
|
|
5492
5744
|
});
|
|
5745
|
+
if (synthAns.error !== void 0 && synthProvider !== moderator) {
|
|
5746
|
+
if (isDeadModelError(synthAns) && synthModel) {
|
|
5747
|
+
const [prov, mdl] = synthModel.split("/");
|
|
5748
|
+
if (prov && mdl) recordDeadModel(prov, mdl, synthAns.error ?? "");
|
|
5749
|
+
}
|
|
5750
|
+
synthAns = await askOne(moderator, recMsgs, {
|
|
5751
|
+
maxTokens,
|
|
5752
|
+
temperature: 0.4,
|
|
5753
|
+
purpose: "synth"
|
|
5754
|
+
});
|
|
5755
|
+
synthModel = null;
|
|
5756
|
+
}
|
|
5493
5757
|
const finalText = synthAns.error !== void 0 ? "" : synthAns.response ?? "";
|
|
5494
5758
|
const synthErr = synthAns.error;
|
|
5495
5759
|
const publicNodes = Object.keys(nodesById).map(
|
|
@@ -5513,6 +5777,7 @@ Synthesize the node outputs into a single coherent deliverable. Preserve any [MI
|
|
|
5513
5777
|
fail_fast: failFast,
|
|
5514
5778
|
cheap_mode: cheapMode
|
|
5515
5779
|
};
|
|
5780
|
+
if (synthModel) result["synth_model"] = synthModel;
|
|
5516
5781
|
if (synthErr) result["synth_error"] = synthErr;
|
|
5517
5782
|
if (plannerErrors.length > 0) result["planner_errors"] = plannerErrors;
|
|
5518
5783
|
if (unknownNames.length > 0) result["skipped_unknown_providers"] = unknownNames;
|
|
@@ -6084,6 +6349,16 @@ function errorPayload(code, message, hint, kind = "client") {
|
|
|
6084
6349
|
};
|
|
6085
6350
|
}
|
|
6086
6351
|
|
|
6352
|
+
// src/core/call-context.ts
|
|
6353
|
+
function buildCallContext(args) {
|
|
6354
|
+
const ctx = {
|
|
6355
|
+
cheap_mode: args.cheapMode,
|
|
6356
|
+
session_id: args.sessionId
|
|
6357
|
+
};
|
|
6358
|
+
if (args.purpose) ctx.purpose = args.purpose;
|
|
6359
|
+
return ctx;
|
|
6360
|
+
}
|
|
6361
|
+
|
|
6087
6362
|
// src/tools/create.ts
|
|
6088
6363
|
var CREATE_DOC_MAX_BYTES = 32 * 1024;
|
|
6089
6364
|
var CREATE_AUDIT_THRESHOLD = 0.7;
|
|
@@ -6112,6 +6387,10 @@ async function runCreate(args, opts) {
|
|
|
6112
6387
|
const dryRun = boolArg3(args["dry_run"], false);
|
|
6113
6388
|
const planOnly = boolArg3(args["plan_only"], false);
|
|
6114
6389
|
const moderator = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
|
|
6390
|
+
const ctx = opts.ctx ?? buildCallContext({
|
|
6391
|
+
cheapMode,
|
|
6392
|
+
sessionId
|
|
6393
|
+
});
|
|
6115
6394
|
const descriptors = await ingestDocuments(documents, sessionId, opts);
|
|
6116
6395
|
const documentsPayload = formatDocumentsPayload(descriptors);
|
|
6117
6396
|
const okCount = descriptors.filter((d) => d.status === "ok").length;
|
|
@@ -6129,7 +6408,8 @@ ${documentsPayload}`;
|
|
|
6129
6408
|
}, {
|
|
6130
6409
|
providers: opts.providers,
|
|
6131
6410
|
allowlist: opts.allowlist ?? null,
|
|
6132
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6411
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6412
|
+
ctx
|
|
6133
6413
|
});
|
|
6134
6414
|
const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
|
|
6135
6415
|
${a["response"]}`).join("\n\n") : "";
|
|
@@ -6151,7 +6431,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6151
6431
|
providers: opts.providers,
|
|
6152
6432
|
allowlist: opts.allowlist ?? null,
|
|
6153
6433
|
moderator,
|
|
6154
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6434
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6435
|
+
ctx
|
|
6155
6436
|
});
|
|
6156
6437
|
let attempts = 1;
|
|
6157
6438
|
if (planOnly) {
|
|
@@ -6185,7 +6466,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6185
6466
|
}, {
|
|
6186
6467
|
providers: opts.providers,
|
|
6187
6468
|
allowlist: opts.allowlist ?? null,
|
|
6188
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6469
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6470
|
+
ctx
|
|
6189
6471
|
});
|
|
6190
6472
|
}
|
|
6191
6473
|
let auditEnvelope = null;
|
|
@@ -6207,7 +6489,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6207
6489
|
}, {
|
|
6208
6490
|
providers: opts.providers,
|
|
6209
6491
|
allowlist: opts.allowlist ?? null,
|
|
6210
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6492
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6493
|
+
ctx
|
|
6211
6494
|
});
|
|
6212
6495
|
let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6213
6496
|
if (overallF !== null && overallF < auditThreshold && !cheapMode && !boolArg3(args["_no_retry"], false)) {
|
|
@@ -6231,7 +6514,8 @@ ${documentsPayload}`
|
|
|
6231
6514
|
providers: opts.providers,
|
|
6232
6515
|
allowlist: opts.allowlist ?? null,
|
|
6233
6516
|
moderator,
|
|
6234
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6517
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6518
|
+
ctx
|
|
6235
6519
|
}
|
|
6236
6520
|
);
|
|
6237
6521
|
orchestration = retryOrchestration;
|
|
@@ -6250,7 +6534,8 @@ ${documentsPayload}`
|
|
|
6250
6534
|
}, {
|
|
6251
6535
|
providers: opts.providers,
|
|
6252
6536
|
allowlist: opts.allowlist ?? null,
|
|
6253
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6537
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6538
|
+
ctx
|
|
6254
6539
|
});
|
|
6255
6540
|
overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6256
6541
|
} else {
|
|
@@ -8101,7 +8386,7 @@ CRITERIA:
|
|
|
8101
8386
|
${criteriaBlock}`
|
|
8102
8387
|
}
|
|
8103
8388
|
];
|
|
8104
|
-
const maxTokens = opts.maxTokens ??
|
|
8389
|
+
const maxTokens = opts.maxTokens ?? 4096;
|
|
8105
8390
|
const scoresByProvider = {};
|
|
8106
8391
|
const answersCollected = [];
|
|
8107
8392
|
const scoringErrors = {};
|
|
@@ -8297,9 +8582,23 @@ function toArray(v) {
|
|
|
8297
8582
|
}
|
|
8298
8583
|
|
|
8299
8584
|
// src/tools/plan.ts
|
|
8585
|
+
var PLAN_MODE_PRESETS = {
|
|
8586
|
+
fast: { max_rounds: 2, early_stop: true, early_stop_threshold: 0.7 },
|
|
8587
|
+
thorough: { max_rounds: 5, early_stop: false, early_stop_threshold: 0.7 }
|
|
8588
|
+
};
|
|
8589
|
+
var DEFAULT_PLAN_MODE = "fast";
|
|
8300
8590
|
async function runPlan(args, opts) {
|
|
8301
8591
|
const goal = typeof args["goal"] === "string" ? args["goal"] : String(args["goal"] ?? "");
|
|
8302
8592
|
const constraints = typeof args["constraints"] === "string" ? args["constraints"] : "";
|
|
8593
|
+
const modeArg = args["mode"];
|
|
8594
|
+
const mode = modeArg === "fast" || modeArg === "thorough" ? modeArg : DEFAULT_PLAN_MODE;
|
|
8595
|
+
const preset = PLAN_MODE_PRESETS[mode];
|
|
8596
|
+
const maxRoundsRaw = args["max_rounds"];
|
|
8597
|
+
const earlyStopRaw = args["early_stop"];
|
|
8598
|
+
const earlyStopThresholdRaw = args["early_stop_threshold"];
|
|
8599
|
+
const maxRounds = typeof maxRoundsRaw === "number" && Number.isFinite(maxRoundsRaw) && maxRoundsRaw > 0 ? Math.trunc(maxRoundsRaw) : preset.max_rounds;
|
|
8600
|
+
const earlyStop = typeof earlyStopRaw === "boolean" ? earlyStopRaw : preset.early_stop;
|
|
8601
|
+
const earlyStopThreshold = typeof earlyStopThresholdRaw === "number" && Number.isFinite(earlyStopThresholdRaw) ? earlyStopThresholdRaw : preset.early_stop_threshold;
|
|
8303
8602
|
const merged = `We need a step-by-step plan to achieve this goal.
|
|
8304
8603
|
|
|
8305
8604
|
GOAL: ${goal}
|
|
@@ -8310,7 +8609,10 @@ Return: (1) the plan as numbered steps, (2) risks, (3) alternatives considered.`
|
|
|
8310
8609
|
const debateArgs = {
|
|
8311
8610
|
topic: merged,
|
|
8312
8611
|
context: typeof args["context"] === "string" ? args["context"] : "",
|
|
8313
|
-
structured: Boolean(args["structured"])
|
|
8612
|
+
structured: Boolean(args["structured"]),
|
|
8613
|
+
max_rounds: maxRounds,
|
|
8614
|
+
early_stop: earlyStop,
|
|
8615
|
+
early_stop_threshold: earlyStopThreshold
|
|
8314
8616
|
};
|
|
8315
8617
|
if (args["providers"] !== void 0) debateArgs["providers"] = args["providers"];
|
|
8316
8618
|
if (args["moderator"] !== void 0) debateArgs["moderator"] = args["moderator"];
|
|
@@ -10020,7 +10322,7 @@ function critiqueTool(providers, allowlist, bridge) {
|
|
|
10020
10322
|
function planTool(providers, allowlist, bridge) {
|
|
10021
10323
|
return {
|
|
10022
10324
|
name: "plan",
|
|
10023
|
-
description:
|
|
10325
|
+
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
10326
|
inputSchema: {
|
|
10025
10327
|
type: "object",
|
|
10026
10328
|
additionalProperties: true,
|
|
@@ -10031,7 +10333,11 @@ function planTool(providers, allowlist, bridge) {
|
|
|
10031
10333
|
providers: { type: "array", items: { type: "string" } },
|
|
10032
10334
|
moderator: { type: "string" },
|
|
10033
10335
|
session_id: { type: "string" },
|
|
10034
|
-
structured: { type: "boolean" }
|
|
10336
|
+
structured: { type: "boolean" },
|
|
10337
|
+
mode: { type: "string", enum: ["fast", "thorough"] },
|
|
10338
|
+
max_rounds: { type: "integer", minimum: 1 },
|
|
10339
|
+
early_stop: { type: "boolean" },
|
|
10340
|
+
early_stop_threshold: { type: "number", minimum: 0, maximum: 1 }
|
|
10035
10341
|
},
|
|
10036
10342
|
required: ["goal"]
|
|
10037
10343
|
},
|
|
@@ -10424,8 +10730,19 @@ async function main() {
|
|
|
10424
10730
|
);
|
|
10425
10731
|
}
|
|
10426
10732
|
installShutdownHandlers(bridge);
|
|
10427
|
-
const
|
|
10428
|
-
|
|
10733
|
+
const bundledPricing = (() => {
|
|
10734
|
+
try {
|
|
10735
|
+
return import_node_path11.default.join(import_node_path11.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
|
|
10736
|
+
} catch {
|
|
10737
|
+
return void 0;
|
|
10738
|
+
}
|
|
10739
|
+
})();
|
|
10740
|
+
const pricingPath = [
|
|
10741
|
+
process.env["CROSSCHECK_PRICING_PATH"],
|
|
10742
|
+
resolveRepoFile("config/pricing.json"),
|
|
10743
|
+
bundledPricing
|
|
10744
|
+
].find((p) => p && (0, import_node_fs11.existsSync)(p));
|
|
10745
|
+
const pricing = pricingPath ? loadPricing(pricingPath) : {};
|
|
10429
10746
|
const providers = buildProviders({ env: process.env, pricing });
|
|
10430
10747
|
if (Object.keys(providers).length > 0) {
|
|
10431
10748
|
process.stderr.write(
|