crosscheck-mcp 0.2.28 → 0.2.30

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.
@@ -578,6 +578,11 @@ function reasoningSharesOutputBudget(provider) {
578
578
  }
579
579
 
580
580
  // src/providers/types.ts
581
+ var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
582
+ function imagesOf(m) {
583
+ if (m.role !== "user" || !Array.isArray(m.images)) return [];
584
+ return m.images.filter((i) => Boolean(i) && typeof i.data === "string" && i.data.length > 0 && IMAGE_MEDIA_TYPES.includes(i.mediaType));
585
+ }
581
586
  var ProviderError = class extends Error {
582
587
  name = "ProviderError";
583
588
  kind;
@@ -891,6 +896,52 @@ function rejectsDisabledThinking(model) {
891
896
  const m = model.toLowerCase();
892
897
  return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
893
898
  }
899
+ var NO_FORCED_TOOL_PREFIXES = [
900
+ "claude-fable-5-1",
901
+ "claude-mythos-5-1",
902
+ "claude-opus-5-5",
903
+ "claude-sonnet-5-5"
904
+ ];
905
+ function rejectsForcedToolUse(model) {
906
+ const m = model.toLowerCase();
907
+ return NO_FORCED_TOOL_PREFIXES.some((p) => m.startsWith(p));
908
+ }
909
+ var UNSUPPORTED_SCHEMA_KEYS = /* @__PURE__ */ new Set([
910
+ "minimum",
911
+ "maximum",
912
+ "exclusiveMinimum",
913
+ "exclusiveMaximum",
914
+ "multipleOf",
915
+ "minLength",
916
+ "maxLength",
917
+ "pattern",
918
+ "minItems",
919
+ "maxItems",
920
+ "uniqueItems",
921
+ "minProperties",
922
+ "maxProperties",
923
+ "$schema"
924
+ ]);
925
+ function toStructuredOutputSchema(schema) {
926
+ const walk = (node) => {
927
+ if (Array.isArray(node)) return node.map(walk);
928
+ if (!node || typeof node !== "object") return node;
929
+ const out = {};
930
+ for (const [k, v] of Object.entries(node)) {
931
+ if (UNSUPPORTED_SCHEMA_KEYS.has(k)) continue;
932
+ if (k === "properties" && v && typeof v === "object") {
933
+ out[k] = Object.fromEntries(Object.entries(v).map(([pk, pv]) => [pk, walk(pv)]));
934
+ } else if (["items", "anyOf", "allOf", "oneOf", "not", "$defs", "definitions"].includes(k)) {
935
+ out[k] = k === "$defs" || k === "definitions" ? Object.fromEntries(Object.entries(v ?? {}).map(([dk, dv]) => [dk, walk(dv)])) : walk(v);
936
+ } else {
937
+ out[k] = v;
938
+ }
939
+ }
940
+ if (out["type"] === "object" || "properties" in out) out["additionalProperties"] = false;
941
+ return out;
942
+ };
943
+ return walk(schema);
944
+ }
894
945
  var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
895
946
  function applyPromptCaching(body, env = process.env) {
896
947
  const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
@@ -920,7 +971,12 @@ function buildAnthropicRequest(opts) {
920
971
  }
921
972
  continue;
922
973
  }
923
- convo.push({ role: m.role, content: typeof m.content === "string" ? m.content : "" });
974
+ const text = typeof m.content === "string" ? m.content : "";
975
+ const images = imagesOf(m);
976
+ convo.push(images.length ? { role: m.role, content: [
977
+ ...images.map((i) => ({ type: "image", source: { type: "base64", media_type: i.mediaType, data: i.data } })),
978
+ { type: "text", text }
979
+ ] } : { role: m.role, content: text });
924
980
  }
925
981
  const body = {
926
982
  model: opts.model,
@@ -942,7 +998,12 @@ function buildAnthropicRequest(opts) {
942
998
  body.thinking = { type: "disabled" };
943
999
  }
944
1000
  }
945
- if (opts.jsonSchema) {
1001
+ if (opts.jsonSchema && rejectsForcedToolUse(opts.model)) {
1002
+ body.output_config = {
1003
+ ...body.output_config ?? {},
1004
+ format: { type: "json_schema", schema: toStructuredOutputSchema(opts.jsonSchema) }
1005
+ };
1006
+ } else if (opts.jsonSchema) {
946
1007
  body.tools = [{
947
1008
  name: ANTHROPIC_STRUCTURED_TOOL_NAME,
948
1009
  description: "Emit a single JSON object matching the requested schema.",
@@ -1155,7 +1216,10 @@ function buildGeminiRequest(opts) {
1155
1216
  const role = m.role === "user" ? "user" : "model";
1156
1217
  contents.push({
1157
1218
  role,
1158
- parts: [{ text: typeof m.content === "string" ? m.content : "" }]
1219
+ parts: [
1220
+ ...imagesOf(m).map((i) => ({ inline_data: { mime_type: i.mediaType, data: i.data } })),
1221
+ { text: typeof m.content === "string" ? m.content : "" }
1222
+ ]
1159
1223
  });
1160
1224
  }
1161
1225
  const body = {
@@ -1323,10 +1387,11 @@ function supportsNativeJsonSchema(provider, model) {
1323
1387
  return true;
1324
1388
  }
1325
1389
  function buildOpenAICompatibleRequest(opts) {
1326
- const msgs = opts.messages.map((m) => ({
1327
- role: m.role,
1328
- content: typeof m.content === "string" ? m.content : ""
1329
- }));
1390
+ const msgs = opts.messages.map((m) => {
1391
+ const text = typeof m.content === "string" ? m.content : "";
1392
+ const images = imagesOf(m);
1393
+ return images.length ? { role: m.role, content: [{ type: "text", text }, ...images.map((i) => ({ type: "image_url", image_url: { url: `data:${i.mediaType};base64,${i.data}` } }))] } : { role: m.role, content: text };
1394
+ });
1330
1395
  const body = {
1331
1396
  model: opts.model,
1332
1397
  messages: msgs
@@ -1343,7 +1408,15 @@ function buildOpenAICompatibleRequest(opts) {
1343
1408
  json_schema: {
1344
1409
  name: "structured_output",
1345
1410
  schema: opts.jsonSchema,
1346
- strict: true
1411
+ // NOT strict. Strict mode requires `additionalProperties: false` on
1412
+ // every object and every property listed in `required` — the
1413
+ // engine's schemas don't meet that, so every structured OpenAI call
1414
+ // (planner, judges, synthesis) was a 400, unnoticed until the canary
1415
+ // grew a structured check (2026-10-11). Non-strict still shapes the
1416
+ // reply to the schema, and structured.ts validates it against the
1417
+ // full schema regardless, so strictness added a failure mode and no
1418
+ // safety.
1419
+ strict: false
1347
1420
  }
1348
1421
  };
1349
1422
  }
@@ -1631,7 +1704,7 @@ import { z } from "zod";
1631
1704
 
1632
1705
  // src/server-meta.ts
1633
1706
  var SERVER_NAME = "crosscheck-agent";
1634
- var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
1707
+ var SERVER_VERSION = true ? "0.2.30" : "0.0.0-dev";
1635
1708
 
1636
1709
  // src/tools/audit.ts
1637
1710
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -4595,6 +4668,7 @@ async function pickAutoPanel(storage, purpose, n, providers, allowlist) {
4595
4668
  }
4596
4669
 
4597
4670
  // src/core/super-mode.ts
4671
+ import { AsyncLocalStorage } from "async_hooks";
4598
4672
  var SUPER_MODELS = {
4599
4673
  // Fable 5.1 verified present on the account; 5 as the fallback for accounts
4600
4674
  // that haven't been granted 5.1 yet.
@@ -4637,7 +4711,9 @@ function parseChain(v) {
4637
4711
  }
4638
4712
  return out;
4639
4713
  }
4640
- function superChainFor(provider, env = process.env) {
4714
+ var superEnvStore = new AsyncLocalStorage();
4715
+ var currentEnv = () => superEnvStore.getStore() ?? process.env;
4716
+ function superChainFor(provider, env = currentEnv()) {
4641
4717
  const varName = SUPER_ENV_VARS[provider];
4642
4718
  const user = varName ? parseChain(env[varName]) : [];
4643
4719
  if (user.length > 0) {
@@ -4646,14 +4722,14 @@ function superChainFor(provider, env = process.env) {
4646
4722
  }
4647
4723
  return SUPER_MODELS[provider] ?? [];
4648
4724
  }
4649
- function superPrimary(provider, env = process.env) {
4725
+ function superPrimary(provider, env = currentEnv()) {
4650
4726
  return superChainFor(provider, env)[0];
4651
4727
  }
4652
4728
  var SUPER_PROVIDER_NAMES = Object.keys(SUPER_MODELS);
4653
4729
  function isSuperRequested(args) {
4654
4730
  return args["super"] === true;
4655
4731
  }
4656
- function retargetForSuper(p, env = process.env) {
4732
+ function retargetForSuper(p, env = currentEnv()) {
4657
4733
  const chain = superChainFor(p.name, env);
4658
4734
  if (chain.length === 0) return p;
4659
4735
  const [primary, ...fallbacks] = chain;
@@ -6731,9 +6807,9 @@ import path6 from "path";
6731
6807
  import { performance as performance7 } from "perf_hooks";
6732
6808
 
6733
6809
  // src/core/progress.ts
6734
- import { AsyncLocalStorage } from "async_hooks";
6810
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
6735
6811
  import { performance as performance6 } from "perf_hooks";
6736
- var progressStorage = new AsyncLocalStorage();
6812
+ var progressStorage = new AsyncLocalStorage2();
6737
6813
  async function emitProgress(message, opts) {
6738
6814
  const ctx = progressStorage.getStore();
6739
6815
  const wallStart = ctx ? ctx.wallStart : performance6.now();
@@ -8263,6 +8339,16 @@ function buildCallContext(args) {
8263
8339
  var CREATE_DOC_MAX_BYTES = 32 * 1024;
8264
8340
  var CREATE_AUDIT_THRESHOLD = 0.7;
8265
8341
  async function runCreate(args, opts) {
8342
+ const subEnvelopes = [];
8343
+ const tracked = (fn) => async (...a) => {
8344
+ const out = await fn(...a);
8345
+ subEnvelopes.push(out);
8346
+ return out;
8347
+ };
8348
+ const confer = tracked(runConfer);
8349
+ const orchestrate = tracked(runOrchestrate);
8350
+ const review = tracked(runReview);
8351
+ const audit = tracked(runAudit);
8266
8352
  const instruction = typeof args["instruction"] === "string" ? args["instruction"] : String(args["instruction"] ?? "");
8267
8353
  if (!instruction) {
8268
8354
  return errorEnvelope6(
@@ -8299,7 +8385,7 @@ ${constraints}
8299
8385
 
8300
8386
  ` : "") + `DOCUMENTS (${okCount} of ${descriptors.length} ingested):
8301
8387
  ${documentsPayload}`;
8302
- const scope = await runConfer({
8388
+ const scope = await confer({
8303
8389
  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,
8304
8390
  context: contextBlock,
8305
8391
  ...providers !== void 0 ? { providers } : {},
@@ -8326,7 +8412,7 @@ ${scopeAnswer || "(none)"}
8326
8412
  };
8327
8413
  if (providers !== void 0) orchestrateArgs["providers"] = providers;
8328
8414
  if (planOnly) orchestrateArgs["plan_only"] = true;
8329
- let orchestration = await runOrchestrate(orchestrateArgs, {
8415
+ let orchestration = await orchestrate(orchestrateArgs, {
8330
8416
  providers: opts.providers,
8331
8417
  allowlist: opts.allowlist ?? null,
8332
8418
  moderator,
@@ -8355,7 +8441,7 @@ ${scopeAnswer || "(none)"}
8355
8441
  }
8356
8442
  let reviewEnvelope = null;
8357
8443
  if (!skipReview && typeof orchestration["final"] === "string" && orchestration["final"]) {
8358
- reviewEnvelope = await runReview({
8444
+ reviewEnvelope = await review({
8359
8445
  snippet: orchestration["final"],
8360
8446
  intent: `final deliverable for: ${instruction}`,
8361
8447
  ...providers !== void 0 ? { providers } : {},
@@ -8375,7 +8461,7 @@ ${scopeAnswer || "(none)"}
8375
8461
  const panelExhausted = producingPanel.length > 0 && producingPanel.every(
8376
8462
  (p) => p in opts.providers || Object.keys(opts.providers).includes(p.toLowerCase())
8377
8463
  ) && producingPanel.length >= Object.keys(opts.providers).length;
8378
- auditEnvelope = await runAudit({
8464
+ auditEnvelope = await audit({
8379
8465
  output_to_audit: orchestration["final"],
8380
8466
  producing_panelists: producingPanel,
8381
8467
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8404,7 +8490,7 @@ ${retryConstraints}
8404
8490
  DOCUMENTS:
8405
8491
  ${documentsPayload}`
8406
8492
  };
8407
- const retryOrchestration = await runOrchestrate(
8493
+ const retryOrchestration = await orchestrate(
8408
8494
  retryOrchestrateArgs,
8409
8495
  {
8410
8496
  providers: opts.providers,
@@ -8418,7 +8504,7 @@ ${documentsPayload}`
8418
8504
  if (typeof retryOrchestration["final"] === "string" && retryOrchestration["final"]) {
8419
8505
  const retryPanel = computeProducingPanel(retryOrchestration);
8420
8506
  const retryPanelExhausted = retryPanel.length > 0 && retryPanel.length >= Object.keys(opts.providers).length;
8421
- auditEnvelope = await runAudit({
8507
+ auditEnvelope = await audit({
8422
8508
  output_to_audit: retryOrchestration["final"],
8423
8509
  producing_panelists: retryPanel,
8424
8510
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8493,9 +8579,28 @@ ${documentsPayload}`
8493
8579
  ["auditor", "items", "overall_score", "passed", "rubric"]
8494
8580
  ),
8495
8581
  artifacts,
8496
- warnings
8582
+ warnings,
8583
+ ...combinedUsage(subEnvelopes)
8497
8584
  };
8498
8585
  }
8586
+ function combinedUsage(envelopes) {
8587
+ const usages = [];
8588
+ const byCallTiming = [];
8589
+ let wall = 0, cpu = 0;
8590
+ for (const env of envelopes) {
8591
+ const e = env ?? {};
8592
+ const calls = e["usage"]?.["by_call"] ?? [];
8593
+ const t = e["timing"] ?? {};
8594
+ const timing = Array.isArray(t["by_call"]) ? t["by_call"] : [];
8595
+ if (!Array.isArray(calls) || calls.length === 0) continue;
8596
+ usages.push(...calls);
8597
+ if (timing.length === calls.length) byCallTiming.push(...timing);
8598
+ 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 });
8599
+ wall += Number(t["wall_ms"] ?? 0) || 0;
8600
+ cpu += Number(t["cpu_ms"] ?? 0) || 0;
8601
+ }
8602
+ return { usage: aggregateUsage(usages), timing: { wall_ms: wall, cpu_ms: cpu, by_call: byCallTiming } };
8603
+ }
8499
8604
  async function ingestDocuments(documents, sessionId, opts) {
8500
8605
  if (documents.length === 0) return [];
8501
8606
  const out = [];
@@ -11972,7 +12077,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11972
12077
  var DEFAULT_PACKAGE = "crosscheck-cli";
11973
12078
  var FETCH_TIMEOUT_MS = 3e3;
11974
12079
  function engineVersion() {
11975
- return true ? "0.2.28" : "0.0.0-dev";
12080
+ return true ? "0.2.30" : "0.0.0-dev";
11976
12081
  }
11977
12082
  function defaultUpdateCachePath() {
11978
12083
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");