crosscheck-mcp 0.2.28 → 0.2.29

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.
@@ -924,6 +924,52 @@ function rejectsDisabledThinking(model) {
924
924
  const m = model.toLowerCase();
925
925
  return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
926
926
  }
927
+ var NO_FORCED_TOOL_PREFIXES = [
928
+ "claude-fable-5-1",
929
+ "claude-mythos-5-1",
930
+ "claude-opus-5-5",
931
+ "claude-sonnet-5-5"
932
+ ];
933
+ function rejectsForcedToolUse(model) {
934
+ const m = model.toLowerCase();
935
+ return NO_FORCED_TOOL_PREFIXES.some((p) => m.startsWith(p));
936
+ }
937
+ var UNSUPPORTED_SCHEMA_KEYS = /* @__PURE__ */ new Set([
938
+ "minimum",
939
+ "maximum",
940
+ "exclusiveMinimum",
941
+ "exclusiveMaximum",
942
+ "multipleOf",
943
+ "minLength",
944
+ "maxLength",
945
+ "pattern",
946
+ "minItems",
947
+ "maxItems",
948
+ "uniqueItems",
949
+ "minProperties",
950
+ "maxProperties",
951
+ "$schema"
952
+ ]);
953
+ function toStructuredOutputSchema(schema) {
954
+ const walk = (node) => {
955
+ if (Array.isArray(node)) return node.map(walk);
956
+ if (!node || typeof node !== "object") return node;
957
+ const out = {};
958
+ for (const [k, v] of Object.entries(node)) {
959
+ if (UNSUPPORTED_SCHEMA_KEYS.has(k)) continue;
960
+ if (k === "properties" && v && typeof v === "object") {
961
+ out[k] = Object.fromEntries(Object.entries(v).map(([pk, pv]) => [pk, walk(pv)]));
962
+ } else if (["items", "anyOf", "allOf", "oneOf", "not", "$defs", "definitions"].includes(k)) {
963
+ out[k] = k === "$defs" || k === "definitions" ? Object.fromEntries(Object.entries(v ?? {}).map(([dk, dv]) => [dk, walk(dv)])) : walk(v);
964
+ } else {
965
+ out[k] = v;
966
+ }
967
+ }
968
+ if (out["type"] === "object" || "properties" in out) out["additionalProperties"] = false;
969
+ return out;
970
+ };
971
+ return walk(schema);
972
+ }
927
973
  var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
928
974
  function applyPromptCaching(body, env = process.env) {
929
975
  const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
@@ -975,7 +1021,12 @@ function buildAnthropicRequest(opts) {
975
1021
  body.thinking = { type: "disabled" };
976
1022
  }
977
1023
  }
978
- if (opts.jsonSchema) {
1024
+ if (opts.jsonSchema && rejectsForcedToolUse(opts.model)) {
1025
+ body.output_config = {
1026
+ ...body.output_config ?? {},
1027
+ format: { type: "json_schema", schema: toStructuredOutputSchema(opts.jsonSchema) }
1028
+ };
1029
+ } else if (opts.jsonSchema) {
979
1030
  body.tools = [{
980
1031
  name: ANTHROPIC_STRUCTURED_TOOL_NAME,
981
1032
  description: "Emit a single JSON object matching the requested schema.",
@@ -1376,7 +1427,15 @@ function buildOpenAICompatibleRequest(opts) {
1376
1427
  json_schema: {
1377
1428
  name: "structured_output",
1378
1429
  schema: opts.jsonSchema,
1379
- strict: true
1430
+ // NOT strict. Strict mode requires `additionalProperties: false` on
1431
+ // every object and every property listed in `required` — the
1432
+ // engine's schemas don't meet that, so every structured OpenAI call
1433
+ // (planner, judges, synthesis) was a 400, unnoticed until the canary
1434
+ // grew a structured check (2026-10-11). Non-strict still shapes the
1435
+ // reply to the schema, and structured.ts validates it against the
1436
+ // full schema regardless, so strictness added a failure mode and no
1437
+ // safety.
1438
+ strict: false
1380
1439
  }
1381
1440
  };
1382
1441
  }
@@ -1664,7 +1723,7 @@ var import_zod = require("zod");
1664
1723
 
1665
1724
  // src/server-meta.ts
1666
1725
  var SERVER_NAME = "crosscheck-agent";
1667
- var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
1726
+ var SERVER_VERSION = true ? "0.2.29" : "0.0.0-dev";
1668
1727
 
1669
1728
  // src/tools/audit.ts
1670
1729
  var import_node_fs4 = require("fs");
@@ -8279,6 +8338,16 @@ function buildCallContext(args) {
8279
8338
  var CREATE_DOC_MAX_BYTES = 32 * 1024;
8280
8339
  var CREATE_AUDIT_THRESHOLD = 0.7;
8281
8340
  async function runCreate(args, opts) {
8341
+ const subEnvelopes = [];
8342
+ const tracked = (fn) => async (...a) => {
8343
+ const out = await fn(...a);
8344
+ subEnvelopes.push(out);
8345
+ return out;
8346
+ };
8347
+ const confer = tracked(runConfer);
8348
+ const orchestrate = tracked(runOrchestrate);
8349
+ const review = tracked(runReview);
8350
+ const audit = tracked(runAudit);
8282
8351
  const instruction = typeof args["instruction"] === "string" ? args["instruction"] : String(args["instruction"] ?? "");
8283
8352
  if (!instruction) {
8284
8353
  return errorEnvelope6(
@@ -8315,7 +8384,7 @@ ${constraints}
8315
8384
 
8316
8385
  ` : "") + `DOCUMENTS (${okCount} of ${descriptors.length} ingested):
8317
8386
  ${documentsPayload}`;
8318
- const scope = await runConfer({
8387
+ const scope = await confer({
8319
8388
  question: "We are about to orchestrate a full plan->build->review->audit lifecycle for this instruction. List 3-6 concrete sub-tasks (each with a one-line description and a difficulty: low|med|high), any critical assumptions, and any missing-information risks. Be concise and decisive \u2014 your output will be used to build the orchestration DAG.\n\nINSTRUCTION:\n" + instruction,
8320
8389
  context: contextBlock,
8321
8390
  ...providers !== void 0 ? { providers } : {},
@@ -8342,7 +8411,7 @@ ${scopeAnswer || "(none)"}
8342
8411
  };
8343
8412
  if (providers !== void 0) orchestrateArgs["providers"] = providers;
8344
8413
  if (planOnly) orchestrateArgs["plan_only"] = true;
8345
- let orchestration = await runOrchestrate(orchestrateArgs, {
8414
+ let orchestration = await orchestrate(orchestrateArgs, {
8346
8415
  providers: opts.providers,
8347
8416
  allowlist: opts.allowlist ?? null,
8348
8417
  moderator,
@@ -8371,7 +8440,7 @@ ${scopeAnswer || "(none)"}
8371
8440
  }
8372
8441
  let reviewEnvelope = null;
8373
8442
  if (!skipReview && typeof orchestration["final"] === "string" && orchestration["final"]) {
8374
- reviewEnvelope = await runReview({
8443
+ reviewEnvelope = await review({
8375
8444
  snippet: orchestration["final"],
8376
8445
  intent: `final deliverable for: ${instruction}`,
8377
8446
  ...providers !== void 0 ? { providers } : {},
@@ -8391,7 +8460,7 @@ ${scopeAnswer || "(none)"}
8391
8460
  const panelExhausted = producingPanel.length > 0 && producingPanel.every(
8392
8461
  (p) => p in opts.providers || Object.keys(opts.providers).includes(p.toLowerCase())
8393
8462
  ) && producingPanel.length >= Object.keys(opts.providers).length;
8394
- auditEnvelope = await runAudit({
8463
+ auditEnvelope = await audit({
8395
8464
  output_to_audit: orchestration["final"],
8396
8465
  producing_panelists: producingPanel,
8397
8466
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8420,7 +8489,7 @@ ${retryConstraints}
8420
8489
  DOCUMENTS:
8421
8490
  ${documentsPayload}`
8422
8491
  };
8423
- const retryOrchestration = await runOrchestrate(
8492
+ const retryOrchestration = await orchestrate(
8424
8493
  retryOrchestrateArgs,
8425
8494
  {
8426
8495
  providers: opts.providers,
@@ -8434,7 +8503,7 @@ ${documentsPayload}`
8434
8503
  if (typeof retryOrchestration["final"] === "string" && retryOrchestration["final"]) {
8435
8504
  const retryPanel = computeProducingPanel(retryOrchestration);
8436
8505
  const retryPanelExhausted = retryPanel.length > 0 && retryPanel.length >= Object.keys(opts.providers).length;
8437
- auditEnvelope = await runAudit({
8506
+ auditEnvelope = await audit({
8438
8507
  output_to_audit: retryOrchestration["final"],
8439
8508
  producing_panelists: retryPanel,
8440
8509
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8509,9 +8578,28 @@ ${documentsPayload}`
8509
8578
  ["auditor", "items", "overall_score", "passed", "rubric"]
8510
8579
  ),
8511
8580
  artifacts,
8512
- warnings
8581
+ warnings,
8582
+ ...combinedUsage(subEnvelopes)
8513
8583
  };
8514
8584
  }
8585
+ function combinedUsage(envelopes) {
8586
+ const usages = [];
8587
+ const byCallTiming = [];
8588
+ let wall = 0, cpu = 0;
8589
+ for (const env of envelopes) {
8590
+ const e = env ?? {};
8591
+ const calls = e["usage"]?.["by_call"] ?? [];
8592
+ const t = e["timing"] ?? {};
8593
+ const timing = Array.isArray(t["by_call"]) ? t["by_call"] : [];
8594
+ if (!Array.isArray(calls) || calls.length === 0) continue;
8595
+ usages.push(...calls);
8596
+ if (timing.length === calls.length) byCallTiming.push(...timing);
8597
+ else for (const c of calls) byCallTiming.push({ provider: c.provider, model: c.model, purpose: c.purpose ?? null, wall_ms: 0, cpu_ms: 0, cache_hit: false });
8598
+ wall += Number(t["wall_ms"] ?? 0) || 0;
8599
+ cpu += Number(t["cpu_ms"] ?? 0) || 0;
8600
+ }
8601
+ return { usage: aggregateUsage(usages), timing: { wall_ms: wall, cpu_ms: cpu, by_call: byCallTiming } };
8602
+ }
8515
8603
  async function ingestDocuments(documents, sessionId, opts) {
8516
8604
  if (documents.length === 0) return [];
8517
8605
  const out = [];
@@ -11988,7 +12076,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11988
12076
  var DEFAULT_PACKAGE = "crosscheck-cli";
11989
12077
  var FETCH_TIMEOUT_MS = 3e3;
11990
12078
  function engineVersion() {
11991
- return true ? "0.2.28" : "0.0.0-dev";
12079
+ return true ? "0.2.29" : "0.0.0-dev";
11992
12080
  }
11993
12081
  function defaultUpdateCachePath() {
11994
12082
  const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");