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.js
CHANGED
|
@@ -16,6 +16,7 @@ var __dirname = /* @__PURE__ */ getDirname();
|
|
|
16
16
|
// src/entrypoints/node-stdio.ts
|
|
17
17
|
import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
|
|
18
18
|
import path9 from "path";
|
|
19
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
19
20
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
21
|
|
|
21
22
|
// src/adapters/storage/better-sqlite3.ts
|
|
@@ -1233,6 +1234,7 @@ function defaultTransient(kind) {
|
|
|
1233
1234
|
// src/providers/anthropic.ts
|
|
1234
1235
|
var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
1235
1236
|
var ANTHROPIC_VERSION_HEADER = "2023-06-01";
|
|
1237
|
+
var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
|
|
1236
1238
|
function buildAnthropicRequest(opts) {
|
|
1237
1239
|
let system;
|
|
1238
1240
|
const convo = [];
|
|
@@ -1257,6 +1259,17 @@ function buildAnthropicRequest(opts) {
|
|
|
1257
1259
|
if (system !== void 0) {
|
|
1258
1260
|
body.system = system;
|
|
1259
1261
|
}
|
|
1262
|
+
if (opts.jsonSchema) {
|
|
1263
|
+
body.tools = [{
|
|
1264
|
+
name: ANTHROPIC_STRUCTURED_TOOL_NAME,
|
|
1265
|
+
description: "Emit a single JSON object matching the requested schema.",
|
|
1266
|
+
input_schema: opts.jsonSchema
|
|
1267
|
+
}];
|
|
1268
|
+
body.tool_choice = {
|
|
1269
|
+
type: "tool",
|
|
1270
|
+
name: ANTHROPIC_STRUCTURED_TOOL_NAME
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1260
1273
|
const headers = {
|
|
1261
1274
|
"content-type": "application/json",
|
|
1262
1275
|
"x-api-key": opts.apiKey,
|
|
@@ -1267,6 +1280,7 @@ function buildAnthropicRequest(opts) {
|
|
|
1267
1280
|
function parseAnthropicResponse(opts) {
|
|
1268
1281
|
const r = opts.resp ?? {};
|
|
1269
1282
|
let text = "";
|
|
1283
|
+
let toolUseInput = void 0;
|
|
1270
1284
|
const content = r["content"];
|
|
1271
1285
|
if (!Array.isArray(content)) {
|
|
1272
1286
|
throw new ProviderError(
|
|
@@ -1276,10 +1290,19 @@ function parseAnthropicResponse(opts) {
|
|
|
1276
1290
|
}
|
|
1277
1291
|
for (const block of content) {
|
|
1278
1292
|
if (block && typeof block === "object") {
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1293
|
+
const b = block;
|
|
1294
|
+
const type = b["type"];
|
|
1295
|
+
if (type === "tool_use" && b["name"] === ANTHROPIC_STRUCTURED_TOOL_NAME) {
|
|
1296
|
+
toolUseInput = b["input"];
|
|
1297
|
+
} else {
|
|
1298
|
+
const t = b["text"];
|
|
1299
|
+
if (typeof t === "string") text += t;
|
|
1300
|
+
}
|
|
1281
1301
|
}
|
|
1282
1302
|
}
|
|
1303
|
+
if (toolUseInput !== void 0) {
|
|
1304
|
+
text = JSON.stringify(toolUseInput);
|
|
1305
|
+
}
|
|
1283
1306
|
const u = r["usage"] ?? {};
|
|
1284
1307
|
const prompt = Math.trunc(Number(u["input_tokens"] ?? 0)) || 0;
|
|
1285
1308
|
const cached = Math.trunc(Number(u["cache_read_input_tokens"] ?? 0)) || 0;
|
|
@@ -1324,7 +1347,8 @@ async function sendAnthropic(args) {
|
|
|
1324
1347
|
apiKey: args.apiKey,
|
|
1325
1348
|
messages: args.messages,
|
|
1326
1349
|
maxTokens: args.maxTokens,
|
|
1327
|
-
temperature: args.temperature
|
|
1350
|
+
temperature: args.temperature,
|
|
1351
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1328
1352
|
});
|
|
1329
1353
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1330
1354
|
const init = {
|
|
@@ -1369,6 +1393,45 @@ async function sendAnthropic(args) {
|
|
|
1369
1393
|
|
|
1370
1394
|
// src/providers/gemini.ts
|
|
1371
1395
|
var GEMINI_API_URL_BASE = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
1396
|
+
function jsonSchemaToGeminiSchema(schema) {
|
|
1397
|
+
const out = {};
|
|
1398
|
+
const type = schema["type"];
|
|
1399
|
+
if (typeof type === "string") {
|
|
1400
|
+
out["type"] = type.toUpperCase();
|
|
1401
|
+
} else if (Array.isArray(type)) {
|
|
1402
|
+
const nonNull = type.find((t) => typeof t === "string" && t !== "null");
|
|
1403
|
+
const hasNull = type.includes("null");
|
|
1404
|
+
if (typeof nonNull === "string") out["type"] = nonNull.toUpperCase();
|
|
1405
|
+
if (hasNull) out["nullable"] = true;
|
|
1406
|
+
}
|
|
1407
|
+
const passthrough = [
|
|
1408
|
+
"description",
|
|
1409
|
+
"enum",
|
|
1410
|
+
"format",
|
|
1411
|
+
"nullable",
|
|
1412
|
+
"required",
|
|
1413
|
+
"minItems",
|
|
1414
|
+
"maxItems",
|
|
1415
|
+
"minimum",
|
|
1416
|
+
"maximum"
|
|
1417
|
+
];
|
|
1418
|
+
for (const k of passthrough) {
|
|
1419
|
+
if (k in schema) out[k] = schema[k];
|
|
1420
|
+
}
|
|
1421
|
+
if (schema["properties"] && typeof schema["properties"] === "object") {
|
|
1422
|
+
const props = {};
|
|
1423
|
+
for (const [name, val] of Object.entries(schema["properties"])) {
|
|
1424
|
+
if (val && typeof val === "object") {
|
|
1425
|
+
props[name] = jsonSchemaToGeminiSchema(val);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
out["properties"] = props;
|
|
1429
|
+
}
|
|
1430
|
+
if (schema["items"] && typeof schema["items"] === "object" && !Array.isArray(schema["items"])) {
|
|
1431
|
+
out["items"] = jsonSchemaToGeminiSchema(schema["items"]);
|
|
1432
|
+
}
|
|
1433
|
+
return out;
|
|
1434
|
+
}
|
|
1372
1435
|
function buildGeminiRequest(opts) {
|
|
1373
1436
|
const contents = [];
|
|
1374
1437
|
let systemText = null;
|
|
@@ -1394,6 +1457,10 @@ function buildGeminiRequest(opts) {
|
|
|
1394
1457
|
if (systemText !== null && systemText !== "") {
|
|
1395
1458
|
body.systemInstruction = { parts: [{ text: systemText }] };
|
|
1396
1459
|
}
|
|
1460
|
+
if (opts.jsonSchema) {
|
|
1461
|
+
body.generationConfig.responseMimeType = "application/json";
|
|
1462
|
+
body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
|
|
1463
|
+
}
|
|
1397
1464
|
const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
|
|
1398
1465
|
return { url, headers: {}, body };
|
|
1399
1466
|
}
|
|
@@ -1462,7 +1529,8 @@ async function sendGemini(args) {
|
|
|
1462
1529
|
apiKey: args.apiKey,
|
|
1463
1530
|
messages: args.messages,
|
|
1464
1531
|
maxTokens: args.maxTokens,
|
|
1465
|
-
temperature: args.temperature
|
|
1532
|
+
temperature: args.temperature,
|
|
1533
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1466
1534
|
});
|
|
1467
1535
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1468
1536
|
const init = {
|
|
@@ -1513,6 +1581,17 @@ var OPENAI_COMPAT_DEFAULT_URLS = {
|
|
|
1513
1581
|
groq: "https://api.groq.com/openai/v1/chat/completions",
|
|
1514
1582
|
deepseek: "https://api.deepseek.com/v1/chat/completions"
|
|
1515
1583
|
};
|
|
1584
|
+
var OPENAI_COMPAT_NATIVE_STRUCTURED = /* @__PURE__ */ new Set([
|
|
1585
|
+
"openai"
|
|
1586
|
+
]);
|
|
1587
|
+
function supportsNativeJsonSchema(provider, model) {
|
|
1588
|
+
if (!OPENAI_COMPAT_NATIVE_STRUCTURED.has(provider.toLowerCase())) {
|
|
1589
|
+
return false;
|
|
1590
|
+
}
|
|
1591
|
+
const m = model.toLowerCase();
|
|
1592
|
+
if (/^o1(?:-|$)/.test(m)) return false;
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1516
1595
|
function buildOpenAICompatibleRequest(opts) {
|
|
1517
1596
|
const msgs = opts.messages.map((m) => ({
|
|
1518
1597
|
role: m.role,
|
|
@@ -1528,6 +1607,16 @@ function buildOpenAICompatibleRequest(opts) {
|
|
|
1528
1607
|
} else {
|
|
1529
1608
|
body.max_completion_tokens = opts.maxTokens;
|
|
1530
1609
|
}
|
|
1610
|
+
if (opts.jsonSchema && supportsNativeJsonSchema(opts.provider, opts.model)) {
|
|
1611
|
+
body.response_format = {
|
|
1612
|
+
type: "json_schema",
|
|
1613
|
+
json_schema: {
|
|
1614
|
+
name: "structured_output",
|
|
1615
|
+
schema: opts.jsonSchema,
|
|
1616
|
+
strict: true
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1531
1620
|
const headers = {
|
|
1532
1621
|
"content-type": "application/json",
|
|
1533
1622
|
Authorization: `Bearer ${opts.apiKey}`
|
|
@@ -1599,7 +1688,8 @@ async function sendOpenAICompatible(args) {
|
|
|
1599
1688
|
url: args.url,
|
|
1600
1689
|
messages: args.messages,
|
|
1601
1690
|
maxTokens: args.maxTokens,
|
|
1602
|
-
temperature: args.temperature
|
|
1691
|
+
temperature: args.temperature,
|
|
1692
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1603
1693
|
});
|
|
1604
1694
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
1605
1695
|
const init = {
|
|
@@ -2075,11 +2165,13 @@ ${schemaText}`;
|
|
|
2075
2165
|
content: "Your previous response failed validation:\n- " + lastErrs.slice(0, 5).join("\n- ") + "\nFix the issues and re-emit valid JSON only."
|
|
2076
2166
|
});
|
|
2077
2167
|
}
|
|
2168
|
+
const useNative = opts.useNativeStructured !== false;
|
|
2078
2169
|
const ans = await askOne(provider, msgs, {
|
|
2079
2170
|
maxTokens: opts.maxTokens,
|
|
2080
2171
|
temperature: temp,
|
|
2081
2172
|
purpose,
|
|
2082
|
-
...opts.signal ? { signal: opts.signal } : {}
|
|
2173
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
2174
|
+
...useNative ? { jsonSchema: schema } : {}
|
|
2083
2175
|
});
|
|
2084
2176
|
lastAnswer = ans;
|
|
2085
2177
|
if (ans.error !== void 0) {
|
|
@@ -2114,7 +2206,8 @@ async function askOne(provider, messages, opts) {
|
|
|
2114
2206
|
maxTokens: opts.maxTokens,
|
|
2115
2207
|
temperature: opts.temperature,
|
|
2116
2208
|
purpose: opts.purpose,
|
|
2117
|
-
...opts.signal ? { signal: opts.signal } : {}
|
|
2209
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
2210
|
+
...opts.jsonSchema ? { jsonSchema: opts.jsonSchema } : {}
|
|
2118
2211
|
});
|
|
2119
2212
|
const wallMs = Math.trunc(performance.now() - startedWall);
|
|
2120
2213
|
const cpu = process.cpuUsage(startedCpu);
|
|
@@ -2357,7 +2450,7 @@ async function runAudit(args, opts) {
|
|
|
2357
2450
|
const rubricOverride = args["rubric"];
|
|
2358
2451
|
const producing = toStringArray(args["producing_panelists"]).map((s) => s.toLowerCase());
|
|
2359
2452
|
const explicit = typeof args["auditor"] === "string" ? args["auditor"] : null;
|
|
2360
|
-
const cheapMode = boolArg(args["cheap_mode"], true);
|
|
2453
|
+
const cheapMode = boolArg(args["cheap_mode"], opts.ctx?.cheap_mode ?? true);
|
|
2361
2454
|
const allowSelf = boolArg(args["allow_self_audit"], false);
|
|
2362
2455
|
let coalesce = boolArg(args["coalesce"], false);
|
|
2363
2456
|
const strictMode = boolArg(args["strict_mode"], false);
|
|
@@ -3887,7 +3980,7 @@ async function runConfer(args, opts) {
|
|
|
3887
3980
|
};
|
|
3888
3981
|
}
|
|
3889
3982
|
}
|
|
3890
|
-
|
|
3983
|
+
let { selected, unknown: unknownNames, blocked } = resolveProviders(
|
|
3891
3984
|
resolvedProviders,
|
|
3892
3985
|
opts.providers,
|
|
3893
3986
|
opts.allowlist ?? null
|
|
@@ -3904,6 +3997,49 @@ async function runConfer(args, opts) {
|
|
|
3904
3997
|
}
|
|
3905
3998
|
return { tool: "confer", error: "no active providers have API keys in .env" };
|
|
3906
3999
|
}
|
|
4000
|
+
let cheapModePanelMeta = null;
|
|
4001
|
+
if (opts.ctx?.cheap_mode === true && !callerSuppliedProviders && selected.length > 1) {
|
|
4002
|
+
if (!opts.pricing) {
|
|
4003
|
+
cheapModePanelMeta = {
|
|
4004
|
+
before: selected.length,
|
|
4005
|
+
after: selected.length,
|
|
4006
|
+
picked: null,
|
|
4007
|
+
reason: "ctx.cheap_mode=true but no pricing doc wired; kept full panel"
|
|
4008
|
+
};
|
|
4009
|
+
} else {
|
|
4010
|
+
const availableSet = new Set(selected.map((p) => p.name.toLowerCase()));
|
|
4011
|
+
const cheapWeights = opts.storage ? await loadProviderWeights(opts.storage, selected.map((p) => p.name)) : {};
|
|
4012
|
+
const allowOnly = opts.allowlist && opts.allowlist.length > 0 ? opts.allowlist.map((s) => s.toLowerCase()) : void 0;
|
|
4013
|
+
const tierPick = selectForDifficulty({
|
|
4014
|
+
pricing: opts.pricing,
|
|
4015
|
+
tier: "low",
|
|
4016
|
+
availableProviders: availableSet,
|
|
4017
|
+
providerWeights: cheapWeights,
|
|
4018
|
+
...allowOnly !== void 0 ? { allowOnly } : {}
|
|
4019
|
+
});
|
|
4020
|
+
if (tierPick.pick) {
|
|
4021
|
+
const baseProvider = opts.providers[tierPick.pick.provider.toLowerCase()];
|
|
4022
|
+
if (baseProvider) {
|
|
4023
|
+
const beforeCount = selected.length;
|
|
4024
|
+
const retargeted = retargetProvider(baseProvider, tierPick.pick.model);
|
|
4025
|
+
selected = [retargeted];
|
|
4026
|
+
cheapModePanelMeta = {
|
|
4027
|
+
before: beforeCount,
|
|
4028
|
+
after: 1,
|
|
4029
|
+
picked: { provider: tierPick.pick.provider, model: tierPick.pick.model },
|
|
4030
|
+
reason: "ctx.cheap_mode=true; narrowed to cheapest low-tier candidate"
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
4033
|
+
} else {
|
|
4034
|
+
cheapModePanelMeta = {
|
|
4035
|
+
before: selected.length,
|
|
4036
|
+
after: selected.length,
|
|
4037
|
+
picked: null,
|
|
4038
|
+
reason: `ctx.cheap_mode=true; ${tierPick.reason ?? "no candidate"}; kept full panel`
|
|
4039
|
+
};
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
3907
4043
|
const untrusted = Boolean(args["untrusted_input"]);
|
|
3908
4044
|
const canary = untrusted ? mintCanary() : null;
|
|
3909
4045
|
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.";
|
|
@@ -4020,6 +4156,7 @@ ${ctxBody}` });
|
|
|
4020
4156
|
if (claimsBlock !== null) result["claims"] = claimsBlock;
|
|
4021
4157
|
if (leaks.length > 0) result["canary_leaks"] = leaks;
|
|
4022
4158
|
if (autoPanelMeta !== null) result["auto_panel"] = autoPanelMeta;
|
|
4159
|
+
if (cheapModePanelMeta !== null) result["cheap_mode_panel"] = cheapModePanelMeta;
|
|
4023
4160
|
if (requestedWorkerTools.length > 0) {
|
|
4024
4161
|
result["worker_tools"] = {
|
|
4025
4162
|
accepted: acceptedWorkerTools,
|
|
@@ -5198,6 +5335,40 @@ import path6 from "path";
|
|
|
5198
5335
|
|
|
5199
5336
|
// src/tools/orchestrate.ts
|
|
5200
5337
|
import { performance as performance3 } from "perf_hooks";
|
|
5338
|
+
|
|
5339
|
+
// src/core/dead-models.ts
|
|
5340
|
+
var DEAD_MODELS_TTL_MS = 5 * 60 * 1e3;
|
|
5341
|
+
var deadModels = /* @__PURE__ */ new Map();
|
|
5342
|
+
function makeKey(provider, model) {
|
|
5343
|
+
return `${provider.toLowerCase()}:${model.toLowerCase()}`;
|
|
5344
|
+
}
|
|
5345
|
+
function recordDeadModel(provider, model, reason, nowMs = Date.now()) {
|
|
5346
|
+
const key = makeKey(provider, model);
|
|
5347
|
+
deadModels.set(key, {
|
|
5348
|
+
provider: provider.toLowerCase(),
|
|
5349
|
+
model: model.toLowerCase(),
|
|
5350
|
+
reason: reason.slice(0, 200),
|
|
5351
|
+
expires: nowMs + DEAD_MODELS_TTL_MS
|
|
5352
|
+
});
|
|
5353
|
+
}
|
|
5354
|
+
function isModelDead(provider, model, nowMs = Date.now()) {
|
|
5355
|
+
const key = makeKey(provider, model);
|
|
5356
|
+
const entry = deadModels.get(key);
|
|
5357
|
+
if (!entry) return false;
|
|
5358
|
+
if (nowMs >= entry.expires) {
|
|
5359
|
+
deadModels.delete(key);
|
|
5360
|
+
return false;
|
|
5361
|
+
}
|
|
5362
|
+
return true;
|
|
5363
|
+
}
|
|
5364
|
+
function isDeadModelError(err) {
|
|
5365
|
+
if (typeof err.error !== "string") return false;
|
|
5366
|
+
if (err.error_kind !== "client") return false;
|
|
5367
|
+
return /HTTP\s*404|not\s*found|does not exist|deprecated|decommission/i.test(err.error);
|
|
5368
|
+
}
|
|
5369
|
+
|
|
5370
|
+
// src/tools/orchestrate.ts
|
|
5371
|
+
var F1B_MAX_TIER_RETRIES = 2;
|
|
5201
5372
|
var DIFFICULTY_TIERS2 = ["low", "med", "high"];
|
|
5202
5373
|
var EST_TOKENS = {
|
|
5203
5374
|
low: [800, 400],
|
|
@@ -5248,7 +5419,7 @@ async function runOrchestrate(args, opts) {
|
|
|
5248
5419
|
const moderator = opts.providers[moderatorName.toLowerCase()] ?? selected[0];
|
|
5249
5420
|
const failFast = boolArg2(args["fail_fast"], false);
|
|
5250
5421
|
const planOnly = boolArg2(args["plan_only"], false);
|
|
5251
|
-
const cheapMode = boolArg2(args["cheap_mode"], false);
|
|
5422
|
+
const cheapMode = boolArg2(args["cheap_mode"], opts.ctx?.cheap_mode ?? false);
|
|
5252
5423
|
const maxTokens = opts.maxTokens ?? 4096;
|
|
5253
5424
|
const cheapAvailable = new Set(
|
|
5254
5425
|
selected.map((p) => p.name.toLowerCase())
|
|
@@ -5334,12 +5505,51 @@ async function runOrchestrate(args, opts) {
|
|
|
5334
5505
|
failedIds.add(nid);
|
|
5335
5506
|
continue;
|
|
5336
5507
|
}
|
|
5508
|
+
const depsRaw = Array.isArray(node["depends_on"]) ? node["depends_on"] : [];
|
|
5509
|
+
const upstreamBlocks = [];
|
|
5510
|
+
for (const d of depsRaw) {
|
|
5511
|
+
if (typeof d !== "string") continue;
|
|
5512
|
+
const ur = nodeResults[d];
|
|
5513
|
+
if (ur && ur.status === "ok") {
|
|
5514
|
+
upstreamBlocks.push(`[node ${d} output]
|
|
5515
|
+
${ur.output ?? ""}`);
|
|
5516
|
+
} else if (ur && ur.status === "failed") {
|
|
5517
|
+
upstreamBlocks.push(`[node ${d}] [MISSING: failed \u2014 ${ur.error ?? ""}]`);
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
const ctxBlock = upstreamBlocks.length > 0 ? upstreamBlocks.join("\n\n") : "(no upstream nodes)";
|
|
5521
|
+
const sysMsg = "You are a worker LLM in an orchestrated DAG. Complete the assigned task using outputs from upstream nodes when relevant. Be concise.";
|
|
5522
|
+
const role = typeof node["role"] === "string" ? node["role"] : "worker";
|
|
5523
|
+
const task = String(node["task"] ?? "");
|
|
5524
|
+
const difficulty = String(node["difficulty"] ?? "med");
|
|
5525
|
+
const msgs = [
|
|
5526
|
+
{ role: "system", content: sysMsg },
|
|
5527
|
+
{
|
|
5528
|
+
role: "user",
|
|
5529
|
+
content: `ROLE: ${role}
|
|
5530
|
+
DIFFICULTY: ${difficulty}
|
|
5531
|
+
|
|
5532
|
+
UPSTREAM:
|
|
5533
|
+
${ctxBlock}
|
|
5534
|
+
|
|
5535
|
+
TASK:
|
|
5536
|
+
${task}`
|
|
5537
|
+
}
|
|
5538
|
+
];
|
|
5337
5539
|
let chosen;
|
|
5540
|
+
let ans;
|
|
5338
5541
|
let cheapReason = null;
|
|
5542
|
+
const retryAttempts = [];
|
|
5339
5543
|
const pinnedName = typeof node["provider"] === "string" ? node["provider"].toLowerCase() : null;
|
|
5340
5544
|
const pinnedModel = typeof node["model"] === "string" ? node["model"] : null;
|
|
5545
|
+
const started = performance3.now();
|
|
5341
5546
|
if (pinnedName && opts.providers[pinnedName]) {
|
|
5342
5547
|
chosen = opts.providers[pinnedName];
|
|
5548
|
+
ans = await askOne(chosen, msgs, {
|
|
5549
|
+
maxTokens,
|
|
5550
|
+
temperature: 0.4,
|
|
5551
|
+
purpose: "worker"
|
|
5552
|
+
});
|
|
5343
5553
|
} else if (cheapMode && !pinnedName && !pinnedModel && opts.pricing) {
|
|
5344
5554
|
const tier = String(node["difficulty"] ?? "med");
|
|
5345
5555
|
const pick = selectForDifficulty({
|
|
@@ -5349,21 +5559,78 @@ async function runOrchestrate(args, opts) {
|
|
|
5349
5559
|
providerWeights: cheapWeights,
|
|
5350
5560
|
...cheapAllowOnly ? { allowOnly: cheapAllowOnly } : {}
|
|
5351
5561
|
});
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5562
|
+
const aliveCandidates = pick.scored.filter(
|
|
5563
|
+
(c) => !isModelDead(c.provider, c.model)
|
|
5564
|
+
);
|
|
5565
|
+
if (aliveCandidates.length === 0) {
|
|
5566
|
+
cheapReason = pick.reason ?? "all tier candidates filtered by deadModels cache";
|
|
5355
5567
|
} else {
|
|
5356
|
-
|
|
5568
|
+
const tryLimit = Math.min(F1B_MAX_TIER_RETRIES, aliveCandidates.length);
|
|
5569
|
+
for (let i = 0; i < tryLimit; i++) {
|
|
5570
|
+
const c = aliveCandidates[i];
|
|
5571
|
+
const base = opts.providers[c.provider];
|
|
5572
|
+
if (!base) {
|
|
5573
|
+
retryAttempts.push({
|
|
5574
|
+
provider: c.provider,
|
|
5575
|
+
model: c.model,
|
|
5576
|
+
reason: "provider not in active registry"
|
|
5577
|
+
});
|
|
5578
|
+
continue;
|
|
5579
|
+
}
|
|
5580
|
+
const candidateProvider = retargetProvider(base, c.model);
|
|
5581
|
+
const candidateAns = await askOne(candidateProvider, msgs, {
|
|
5582
|
+
maxTokens,
|
|
5583
|
+
temperature: 0.4,
|
|
5584
|
+
purpose: "worker"
|
|
5585
|
+
});
|
|
5586
|
+
if (candidateAns.error === void 0) {
|
|
5587
|
+
chosen = candidateProvider;
|
|
5588
|
+
ans = candidateAns;
|
|
5589
|
+
if (retryAttempts.length > 0) {
|
|
5590
|
+
cheapReason = `recovered after ${retryAttempts.length} dead-model retry(s): ` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ");
|
|
5591
|
+
}
|
|
5592
|
+
break;
|
|
5593
|
+
}
|
|
5594
|
+
if (isDeadModelError(candidateAns)) {
|
|
5595
|
+
recordDeadModel(c.provider, c.model, candidateAns.error ?? "");
|
|
5596
|
+
retryAttempts.push({
|
|
5597
|
+
provider: c.provider,
|
|
5598
|
+
model: c.model,
|
|
5599
|
+
reason: (candidateAns.error ?? "dead").slice(0, 100)
|
|
5600
|
+
});
|
|
5601
|
+
continue;
|
|
5602
|
+
}
|
|
5603
|
+
chosen = candidateProvider;
|
|
5604
|
+
ans = candidateAns;
|
|
5605
|
+
if (retryAttempts.length > 0) {
|
|
5606
|
+
cheapReason = `${retryAttempts.length} dead-model retry(s) before non-dead failure: ` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ");
|
|
5607
|
+
}
|
|
5608
|
+
break;
|
|
5609
|
+
}
|
|
5357
5610
|
}
|
|
5358
5611
|
if (!chosen) {
|
|
5359
5612
|
const idx = djb2Hash(nid) % Math.max(1, selected.length);
|
|
5360
5613
|
chosen = selected[idx];
|
|
5614
|
+
ans = await askOne(chosen, msgs, {
|
|
5615
|
+
maxTokens,
|
|
5616
|
+
temperature: 0.4,
|
|
5617
|
+
purpose: "worker"
|
|
5618
|
+
});
|
|
5619
|
+
if (retryAttempts.length > 0) {
|
|
5620
|
+
cheapReason = `cheap-mode tier exhausted (` + retryAttempts.map((a) => `${a.provider}/${a.model}`).join(", ") + `); fell back to id-hash rotation`;
|
|
5621
|
+
}
|
|
5361
5622
|
}
|
|
5362
5623
|
} else {
|
|
5363
5624
|
const idx = djb2Hash(nid) % Math.max(1, selected.length);
|
|
5364
5625
|
chosen = selected[idx];
|
|
5626
|
+
ans = await askOne(chosen, msgs, {
|
|
5627
|
+
maxTokens,
|
|
5628
|
+
temperature: 0.4,
|
|
5629
|
+
purpose: "worker"
|
|
5630
|
+
});
|
|
5365
5631
|
}
|
|
5366
|
-
|
|
5632
|
+
const wallMs = Math.trunc(performance3.now() - started);
|
|
5633
|
+
if (!chosen || !ans) {
|
|
5367
5634
|
nodeResults[nid] = {
|
|
5368
5635
|
id: nid,
|
|
5369
5636
|
status: "failed",
|
|
@@ -5371,49 +5638,12 @@ async function runOrchestrate(args, opts) {
|
|
|
5371
5638
|
model: null,
|
|
5372
5639
|
error: "no provider available",
|
|
5373
5640
|
wall_ms: 0,
|
|
5374
|
-
cpu_ms: 0
|
|
5641
|
+
cpu_ms: 0,
|
|
5642
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5375
5643
|
};
|
|
5376
5644
|
failedIds.add(nid);
|
|
5377
5645
|
continue;
|
|
5378
5646
|
}
|
|
5379
|
-
const depsRaw = Array.isArray(node["depends_on"]) ? node["depends_on"] : [];
|
|
5380
|
-
const upstreamBlocks = [];
|
|
5381
|
-
for (const d of depsRaw) {
|
|
5382
|
-
if (typeof d !== "string") continue;
|
|
5383
|
-
const ur = nodeResults[d];
|
|
5384
|
-
if (ur && ur.status === "ok") {
|
|
5385
|
-
upstreamBlocks.push(`[node ${d} output]
|
|
5386
|
-
${ur.output ?? ""}`);
|
|
5387
|
-
} else if (ur && ur.status === "failed") {
|
|
5388
|
-
upstreamBlocks.push(`[node ${d}] [MISSING: failed \u2014 ${ur.error ?? ""}]`);
|
|
5389
|
-
}
|
|
5390
|
-
}
|
|
5391
|
-
const ctxBlock = upstreamBlocks.length > 0 ? upstreamBlocks.join("\n\n") : "(no upstream nodes)";
|
|
5392
|
-
const sysMsg = "You are a worker LLM in an orchestrated DAG. Complete the assigned task using outputs from upstream nodes when relevant. Be concise.";
|
|
5393
|
-
const role = typeof node["role"] === "string" ? node["role"] : "worker";
|
|
5394
|
-
const task = String(node["task"] ?? "");
|
|
5395
|
-
const difficulty = String(node["difficulty"] ?? "med");
|
|
5396
|
-
const msgs = [
|
|
5397
|
-
{ role: "system", content: sysMsg },
|
|
5398
|
-
{
|
|
5399
|
-
role: "user",
|
|
5400
|
-
content: `ROLE: ${role}
|
|
5401
|
-
DIFFICULTY: ${difficulty}
|
|
5402
|
-
|
|
5403
|
-
UPSTREAM:
|
|
5404
|
-
${ctxBlock}
|
|
5405
|
-
|
|
5406
|
-
TASK:
|
|
5407
|
-
${task}`
|
|
5408
|
-
}
|
|
5409
|
-
];
|
|
5410
|
-
const started = performance3.now();
|
|
5411
|
-
const ans = await askOne(chosen, msgs, {
|
|
5412
|
-
maxTokens,
|
|
5413
|
-
temperature: 0.4,
|
|
5414
|
-
purpose: "worker"
|
|
5415
|
-
});
|
|
5416
|
-
const wallMs = Math.trunc(performance3.now() - started);
|
|
5417
5647
|
if (ans.error !== void 0) {
|
|
5418
5648
|
nodeResults[nid] = {
|
|
5419
5649
|
id: nid,
|
|
@@ -5423,7 +5653,8 @@ ${task}`
|
|
|
5423
5653
|
error: ans.error,
|
|
5424
5654
|
wall_ms: wallMs,
|
|
5425
5655
|
cpu_ms: ans.cpu_ms,
|
|
5426
|
-
...cheapReason ? { cheap_fallback_reason: cheapReason } : {}
|
|
5656
|
+
...cheapReason ? { cheap_fallback_reason: cheapReason } : {},
|
|
5657
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5427
5658
|
};
|
|
5428
5659
|
failedIds.add(nid);
|
|
5429
5660
|
continue;
|
|
@@ -5436,7 +5667,8 @@ ${task}`
|
|
|
5436
5667
|
output: ans.response ?? "",
|
|
5437
5668
|
wall_ms: wallMs,
|
|
5438
5669
|
cpu_ms: ans.cpu_ms,
|
|
5439
|
-
...cheapReason ? { cheap_fallback_reason: cheapReason } : {}
|
|
5670
|
+
...cheapReason ? { cheap_fallback_reason: cheapReason } : {},
|
|
5671
|
+
...retryAttempts.length > 0 ? { retry_attempts: retryAttempts } : {}
|
|
5440
5672
|
};
|
|
5441
5673
|
}
|
|
5442
5674
|
const missing = Object.keys(nodesById).filter(
|
|
@@ -5463,11 +5695,43 @@ Synthesize the node outputs into a single coherent deliverable. Preserve any [MI
|
|
|
5463
5695
|
{ role: "system", content: "You are the orchestrator. Combine node outputs into the final result." },
|
|
5464
5696
|
{ role: "user", content: recombinePrompt }
|
|
5465
5697
|
];
|
|
5466
|
-
|
|
5698
|
+
let synthProvider = moderator;
|
|
5699
|
+
let synthModel = null;
|
|
5700
|
+
if (cheapMode && opts.pricing) {
|
|
5701
|
+
const pick = selectForDifficulty({
|
|
5702
|
+
pricing: opts.pricing,
|
|
5703
|
+
tier: "med",
|
|
5704
|
+
availableProviders: cheapAvailable,
|
|
5705
|
+
providerWeights: cheapWeights,
|
|
5706
|
+
...cheapAllowOnly ? { allowOnly: cheapAllowOnly } : {}
|
|
5707
|
+
});
|
|
5708
|
+
for (const c of pick.scored) {
|
|
5709
|
+
if (isModelDead(c.provider, c.model)) continue;
|
|
5710
|
+
const base = opts.providers[c.provider];
|
|
5711
|
+
if (base) {
|
|
5712
|
+
synthProvider = retargetProvider(base, c.model);
|
|
5713
|
+
synthModel = `${c.provider}/${c.model}`;
|
|
5714
|
+
break;
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
let synthAns = await askOne(synthProvider, recMsgs, {
|
|
5467
5719
|
maxTokens,
|
|
5468
5720
|
temperature: 0.4,
|
|
5469
5721
|
purpose: "synth"
|
|
5470
5722
|
});
|
|
5723
|
+
if (synthAns.error !== void 0 && synthProvider !== moderator) {
|
|
5724
|
+
if (isDeadModelError(synthAns) && synthModel) {
|
|
5725
|
+
const [prov, mdl] = synthModel.split("/");
|
|
5726
|
+
if (prov && mdl) recordDeadModel(prov, mdl, synthAns.error ?? "");
|
|
5727
|
+
}
|
|
5728
|
+
synthAns = await askOne(moderator, recMsgs, {
|
|
5729
|
+
maxTokens,
|
|
5730
|
+
temperature: 0.4,
|
|
5731
|
+
purpose: "synth"
|
|
5732
|
+
});
|
|
5733
|
+
synthModel = null;
|
|
5734
|
+
}
|
|
5471
5735
|
const finalText = synthAns.error !== void 0 ? "" : synthAns.response ?? "";
|
|
5472
5736
|
const synthErr = synthAns.error;
|
|
5473
5737
|
const publicNodes = Object.keys(nodesById).map(
|
|
@@ -5491,6 +5755,7 @@ Synthesize the node outputs into a single coherent deliverable. Preserve any [MI
|
|
|
5491
5755
|
fail_fast: failFast,
|
|
5492
5756
|
cheap_mode: cheapMode
|
|
5493
5757
|
};
|
|
5758
|
+
if (synthModel) result["synth_model"] = synthModel;
|
|
5494
5759
|
if (synthErr) result["synth_error"] = synthErr;
|
|
5495
5760
|
if (plannerErrors.length > 0) result["planner_errors"] = plannerErrors;
|
|
5496
5761
|
if (unknownNames.length > 0) result["skipped_unknown_providers"] = unknownNames;
|
|
@@ -6062,6 +6327,16 @@ function errorPayload(code, message, hint, kind = "client") {
|
|
|
6062
6327
|
};
|
|
6063
6328
|
}
|
|
6064
6329
|
|
|
6330
|
+
// src/core/call-context.ts
|
|
6331
|
+
function buildCallContext(args) {
|
|
6332
|
+
const ctx = {
|
|
6333
|
+
cheap_mode: args.cheapMode,
|
|
6334
|
+
session_id: args.sessionId
|
|
6335
|
+
};
|
|
6336
|
+
if (args.purpose) ctx.purpose = args.purpose;
|
|
6337
|
+
return ctx;
|
|
6338
|
+
}
|
|
6339
|
+
|
|
6065
6340
|
// src/tools/create.ts
|
|
6066
6341
|
var CREATE_DOC_MAX_BYTES = 32 * 1024;
|
|
6067
6342
|
var CREATE_AUDIT_THRESHOLD = 0.7;
|
|
@@ -6090,6 +6365,10 @@ async function runCreate(args, opts) {
|
|
|
6090
6365
|
const dryRun = boolArg3(args["dry_run"], false);
|
|
6091
6366
|
const planOnly = boolArg3(args["plan_only"], false);
|
|
6092
6367
|
const moderator = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
|
|
6368
|
+
const ctx = opts.ctx ?? buildCallContext({
|
|
6369
|
+
cheapMode,
|
|
6370
|
+
sessionId
|
|
6371
|
+
});
|
|
6093
6372
|
const descriptors = await ingestDocuments(documents, sessionId, opts);
|
|
6094
6373
|
const documentsPayload = formatDocumentsPayload(descriptors);
|
|
6095
6374
|
const okCount = descriptors.filter((d) => d.status === "ok").length;
|
|
@@ -6107,7 +6386,8 @@ ${documentsPayload}`;
|
|
|
6107
6386
|
}, {
|
|
6108
6387
|
providers: opts.providers,
|
|
6109
6388
|
allowlist: opts.allowlist ?? null,
|
|
6110
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6389
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6390
|
+
ctx
|
|
6111
6391
|
});
|
|
6112
6392
|
const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
|
|
6113
6393
|
${a["response"]}`).join("\n\n") : "";
|
|
@@ -6129,7 +6409,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6129
6409
|
providers: opts.providers,
|
|
6130
6410
|
allowlist: opts.allowlist ?? null,
|
|
6131
6411
|
moderator,
|
|
6132
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6412
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6413
|
+
ctx
|
|
6133
6414
|
});
|
|
6134
6415
|
let attempts = 1;
|
|
6135
6416
|
if (planOnly) {
|
|
@@ -6163,7 +6444,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6163
6444
|
}, {
|
|
6164
6445
|
providers: opts.providers,
|
|
6165
6446
|
allowlist: opts.allowlist ?? null,
|
|
6166
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6447
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6448
|
+
ctx
|
|
6167
6449
|
});
|
|
6168
6450
|
}
|
|
6169
6451
|
let auditEnvelope = null;
|
|
@@ -6185,7 +6467,8 @@ ${scopeAnswer || "(none)"}
|
|
|
6185
6467
|
}, {
|
|
6186
6468
|
providers: opts.providers,
|
|
6187
6469
|
allowlist: opts.allowlist ?? null,
|
|
6188
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6470
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6471
|
+
ctx
|
|
6189
6472
|
});
|
|
6190
6473
|
let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6191
6474
|
if (overallF !== null && overallF < auditThreshold && !cheapMode && !boolArg3(args["_no_retry"], false)) {
|
|
@@ -6209,7 +6492,8 @@ ${documentsPayload}`
|
|
|
6209
6492
|
providers: opts.providers,
|
|
6210
6493
|
allowlist: opts.allowlist ?? null,
|
|
6211
6494
|
moderator,
|
|
6212
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6495
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6496
|
+
ctx
|
|
6213
6497
|
}
|
|
6214
6498
|
);
|
|
6215
6499
|
orchestration = retryOrchestration;
|
|
@@ -6228,7 +6512,8 @@ ${documentsPayload}`
|
|
|
6228
6512
|
}, {
|
|
6229
6513
|
providers: opts.providers,
|
|
6230
6514
|
allowlist: opts.allowlist ?? null,
|
|
6231
|
-
...opts.bridge ? { bridge: opts.bridge } : {}
|
|
6515
|
+
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6516
|
+
ctx
|
|
6232
6517
|
});
|
|
6233
6518
|
overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
6234
6519
|
} else {
|
|
@@ -8079,7 +8364,7 @@ CRITERIA:
|
|
|
8079
8364
|
${criteriaBlock}`
|
|
8080
8365
|
}
|
|
8081
8366
|
];
|
|
8082
|
-
const maxTokens = opts.maxTokens ??
|
|
8367
|
+
const maxTokens = opts.maxTokens ?? 4096;
|
|
8083
8368
|
const scoresByProvider = {};
|
|
8084
8369
|
const answersCollected = [];
|
|
8085
8370
|
const scoringErrors = {};
|
|
@@ -8275,9 +8560,23 @@ function toArray(v) {
|
|
|
8275
8560
|
}
|
|
8276
8561
|
|
|
8277
8562
|
// src/tools/plan.ts
|
|
8563
|
+
var PLAN_MODE_PRESETS = {
|
|
8564
|
+
fast: { max_rounds: 2, early_stop: true, early_stop_threshold: 0.7 },
|
|
8565
|
+
thorough: { max_rounds: 5, early_stop: false, early_stop_threshold: 0.7 }
|
|
8566
|
+
};
|
|
8567
|
+
var DEFAULT_PLAN_MODE = "fast";
|
|
8278
8568
|
async function runPlan(args, opts) {
|
|
8279
8569
|
const goal = typeof args["goal"] === "string" ? args["goal"] : String(args["goal"] ?? "");
|
|
8280
8570
|
const constraints = typeof args["constraints"] === "string" ? args["constraints"] : "";
|
|
8571
|
+
const modeArg = args["mode"];
|
|
8572
|
+
const mode = modeArg === "fast" || modeArg === "thorough" ? modeArg : DEFAULT_PLAN_MODE;
|
|
8573
|
+
const preset = PLAN_MODE_PRESETS[mode];
|
|
8574
|
+
const maxRoundsRaw = args["max_rounds"];
|
|
8575
|
+
const earlyStopRaw = args["early_stop"];
|
|
8576
|
+
const earlyStopThresholdRaw = args["early_stop_threshold"];
|
|
8577
|
+
const maxRounds = typeof maxRoundsRaw === "number" && Number.isFinite(maxRoundsRaw) && maxRoundsRaw > 0 ? Math.trunc(maxRoundsRaw) : preset.max_rounds;
|
|
8578
|
+
const earlyStop = typeof earlyStopRaw === "boolean" ? earlyStopRaw : preset.early_stop;
|
|
8579
|
+
const earlyStopThreshold = typeof earlyStopThresholdRaw === "number" && Number.isFinite(earlyStopThresholdRaw) ? earlyStopThresholdRaw : preset.early_stop_threshold;
|
|
8281
8580
|
const merged = `We need a step-by-step plan to achieve this goal.
|
|
8282
8581
|
|
|
8283
8582
|
GOAL: ${goal}
|
|
@@ -8288,7 +8587,10 @@ Return: (1) the plan as numbered steps, (2) risks, (3) alternatives considered.`
|
|
|
8288
8587
|
const debateArgs = {
|
|
8289
8588
|
topic: merged,
|
|
8290
8589
|
context: typeof args["context"] === "string" ? args["context"] : "",
|
|
8291
|
-
structured: Boolean(args["structured"])
|
|
8590
|
+
structured: Boolean(args["structured"]),
|
|
8591
|
+
max_rounds: maxRounds,
|
|
8592
|
+
early_stop: earlyStop,
|
|
8593
|
+
early_stop_threshold: earlyStopThreshold
|
|
8292
8594
|
};
|
|
8293
8595
|
if (args["providers"] !== void 0) debateArgs["providers"] = args["providers"];
|
|
8294
8596
|
if (args["moderator"] !== void 0) debateArgs["moderator"] = args["moderator"];
|
|
@@ -9998,7 +10300,7 @@ function critiqueTool(providers, allowlist, bridge) {
|
|
|
9998
10300
|
function planTool(providers, allowlist, bridge) {
|
|
9999
10301
|
return {
|
|
10000
10302
|
name: "plan",
|
|
10001
|
-
description:
|
|
10303
|
+
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.',
|
|
10002
10304
|
inputSchema: {
|
|
10003
10305
|
type: "object",
|
|
10004
10306
|
additionalProperties: true,
|
|
@@ -10009,7 +10311,11 @@ function planTool(providers, allowlist, bridge) {
|
|
|
10009
10311
|
providers: { type: "array", items: { type: "string" } },
|
|
10010
10312
|
moderator: { type: "string" },
|
|
10011
10313
|
session_id: { type: "string" },
|
|
10012
|
-
structured: { type: "boolean" }
|
|
10314
|
+
structured: { type: "boolean" },
|
|
10315
|
+
mode: { type: "string", enum: ["fast", "thorough"] },
|
|
10316
|
+
max_rounds: { type: "integer", minimum: 1 },
|
|
10317
|
+
early_stop: { type: "boolean" },
|
|
10318
|
+
early_stop_threshold: { type: "number", minimum: 0, maximum: 1 }
|
|
10013
10319
|
},
|
|
10014
10320
|
required: ["goal"]
|
|
10015
10321
|
},
|
|
@@ -10402,8 +10708,19 @@ async function main() {
|
|
|
10402
10708
|
);
|
|
10403
10709
|
}
|
|
10404
10710
|
installShutdownHandlers(bridge);
|
|
10405
|
-
const
|
|
10406
|
-
|
|
10711
|
+
const bundledPricing = (() => {
|
|
10712
|
+
try {
|
|
10713
|
+
return path9.join(path9.dirname(fileURLToPath3(import.meta.url)), "pricing.json");
|
|
10714
|
+
} catch {
|
|
10715
|
+
return void 0;
|
|
10716
|
+
}
|
|
10717
|
+
})();
|
|
10718
|
+
const pricingPath = [
|
|
10719
|
+
process.env["CROSSCHECK_PRICING_PATH"],
|
|
10720
|
+
resolveRepoFile("config/pricing.json"),
|
|
10721
|
+
bundledPricing
|
|
10722
|
+
].find((p) => p && existsSync8(p));
|
|
10723
|
+
const pricing = pricingPath ? loadPricing(pricingPath) : {};
|
|
10407
10724
|
const providers = buildProviders({ env: process.env, pricing });
|
|
10408
10725
|
if (Object.keys(providers).length > 0) {
|
|
10409
10726
|
process.stderr.write(
|