nexus-agents 2.150.3 → 2.151.0
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/{chunk-OSOHRYY5.js → chunk-KRCL3VT6.js} +51 -6
- package/dist/{chunk-OSOHRYY5.js.map → chunk-KRCL3VT6.js.map} +1 -1
- package/dist/{chunk-DFK6H3KT.js → chunk-O6PPXOH6.js} +3 -3
- package/dist/{chunk-SF3AM3SY.js → chunk-UIL37D2V.js} +193 -30
- package/dist/chunk-UIL37D2V.js.map +1 -0
- package/dist/{chunk-NQN3RNFP.js → chunk-VXN3GODL.js} +2 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +5 -5
- package/dist/cli.js.map +1 -1
- package/dist/{consensus-vote-3R7MNO26.js → consensus-vote-72AX6HNF.js} +4 -2
- package/dist/{consensus-vote-types-DotaODdb.d.ts → consensus-vote-types-DOCnPzfx.d.ts} +13 -0
- package/dist/index.d.ts +15 -3
- package/dist/index.js +4 -4
- package/dist/{setup-command-PPHPJCSN.js → setup-command-JERVOJ5Z.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-SF3AM3SY.js.map +0 -1
- /package/dist/{chunk-DFK6H3KT.js.map → chunk-O6PPXOH6.js.map} +0 -0
- /package/dist/{chunk-NQN3RNFP.js.map → chunk-VXN3GODL.js.map} +0 -0
- /package/dist/{consensus-vote-3R7MNO26.js.map → consensus-vote-72AX6HNF.js.map} +0 -0
- /package/dist/{setup-command-PPHPJCSN.js.map → setup-command-JERVOJ5Z.js.map} +0 -0
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
} from "./chunk-DHVMSIT5.js";
|
|
43
43
|
|
|
44
44
|
// src/version.ts
|
|
45
|
-
var VERSION = true ? "2.
|
|
45
|
+
var VERSION = true ? "2.151.0" : "dev";
|
|
46
46
|
|
|
47
47
|
// src/config/schemas-core.ts
|
|
48
48
|
import { z } from "zod";
|
|
@@ -2132,7 +2132,7 @@ async function runDoctorFix(result) {
|
|
|
2132
2132
|
writeLine2("\u2500".repeat(40));
|
|
2133
2133
|
let fixCount = 0;
|
|
2134
2134
|
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
|
|
2135
|
-
const { runSetup } = await import("./setup-command-
|
|
2135
|
+
const { runSetup } = await import("./setup-command-JERVOJ5Z.js");
|
|
2136
2136
|
const setupResult = runSetup({
|
|
2137
2137
|
skipMcp: true,
|
|
2138
2138
|
skipRules: true,
|
|
@@ -2245,4 +2245,4 @@ export {
|
|
|
2245
2245
|
startStdioServer,
|
|
2246
2246
|
closeServer
|
|
2247
2247
|
};
|
|
2248
|
-
//# sourceMappingURL=chunk-
|
|
2248
|
+
//# sourceMappingURL=chunk-O6PPXOH6.js.map
|
|
@@ -550,16 +550,63 @@ Respond with a JSON object containing:
|
|
|
550
550
|
|
|
551
551
|
${VOTE_PROMPT_EXAMPLES}`;
|
|
552
552
|
}
|
|
553
|
+
function stepInString(state, ch) {
|
|
554
|
+
if (ch === "\\") state.escaped = true;
|
|
555
|
+
else if (ch === '"') state.inString = false;
|
|
556
|
+
}
|
|
557
|
+
function stepStructural(state, ch) {
|
|
558
|
+
if (ch === '"') state.inString = true;
|
|
559
|
+
else if (ch === "{") state.closers.push("}");
|
|
560
|
+
else if (ch === "[") state.closers.push("]");
|
|
561
|
+
else if (ch === "}" || ch === "]") {
|
|
562
|
+
if (state.closers.pop() === void 0) return "unbalanced";
|
|
563
|
+
if (state.closers.length === 0) return "complete";
|
|
564
|
+
}
|
|
565
|
+
return "continue";
|
|
566
|
+
}
|
|
567
|
+
function stepJsonScan(state, ch) {
|
|
568
|
+
if (state.escaped) {
|
|
569
|
+
state.escaped = false;
|
|
570
|
+
return "continue";
|
|
571
|
+
}
|
|
572
|
+
if (state.inString) {
|
|
573
|
+
stepInString(state, ch);
|
|
574
|
+
return "continue";
|
|
575
|
+
}
|
|
576
|
+
return stepStructural(state, ch);
|
|
577
|
+
}
|
|
578
|
+
function repairTruncatedObject(fragment, state) {
|
|
579
|
+
let repaired = state.inString ? `${fragment}"` : fragment;
|
|
580
|
+
for (let i = state.closers.length - 1; i >= 0; i--) {
|
|
581
|
+
const closer = state.closers[i];
|
|
582
|
+
if (closer !== void 0) repaired += closer;
|
|
583
|
+
}
|
|
584
|
+
return repaired;
|
|
585
|
+
}
|
|
586
|
+
function extractFirstJsonObject(text) {
|
|
587
|
+
const start = text.indexOf("{");
|
|
588
|
+
if (start === -1) return void 0;
|
|
589
|
+
const state = { closers: [], inString: false, escaped: false };
|
|
590
|
+
for (let i = start; i < text.length; i++) {
|
|
591
|
+
const result = stepJsonScan(state, text[i]);
|
|
592
|
+
if (result === "complete") return text.slice(start, i + 1);
|
|
593
|
+
if (result === "unbalanced") return void 0;
|
|
594
|
+
}
|
|
595
|
+
return state.closers.length > 0 ? repairTruncatedObject(text.slice(start), state) : void 0;
|
|
596
|
+
}
|
|
553
597
|
function extractJsonFromResponse(text) {
|
|
554
|
-
const
|
|
555
|
-
if (
|
|
556
|
-
return
|
|
598
|
+
const jsonFence = /```json\s*([\s\S]*?)```/i.exec(text);
|
|
599
|
+
if (jsonFence?.[1] !== void 0) {
|
|
600
|
+
return extractFirstJsonObject(jsonFence[1]) ?? jsonFence[1].trim();
|
|
557
601
|
}
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
602
|
+
for (const match of text.matchAll(/```[a-zA-Z0-9]*\s*([\s\S]*?)```/g)) {
|
|
603
|
+
const inner = match[1];
|
|
604
|
+
if (inner?.trimStart().startsWith("{") === true) {
|
|
605
|
+
const obj = extractFirstJsonObject(inner);
|
|
606
|
+
if (obj !== void 0) return obj;
|
|
607
|
+
}
|
|
561
608
|
}
|
|
562
|
-
return text.trim();
|
|
609
|
+
return extractFirstJsonObject(text) ?? text.trim();
|
|
563
610
|
}
|
|
564
611
|
function createFallbackVote(output, _role, reason) {
|
|
565
612
|
const lower = output.toLowerCase();
|
|
@@ -581,6 +628,30 @@ function createFallbackVote(output, _role, reason) {
|
|
|
581
628
|
// Mark as synthetic
|
|
582
629
|
};
|
|
583
630
|
}
|
|
631
|
+
var REASONING_MAX_CHARS = 4e3;
|
|
632
|
+
var CLAIM_MAX_CHARS = 2e3;
|
|
633
|
+
var TRUNCATION_MARKER = " \u2026[truncated]";
|
|
634
|
+
function clampWithMarker(s, max) {
|
|
635
|
+
if (s.length <= max) return s;
|
|
636
|
+
return s.slice(0, Math.max(0, max - TRUNCATION_MARKER.length)) + TRUNCATION_MARKER;
|
|
637
|
+
}
|
|
638
|
+
function clampOversizeVoteStrings(parsed) {
|
|
639
|
+
if (typeof parsed !== "object" || parsed === null) return parsed;
|
|
640
|
+
const obj = { ...parsed };
|
|
641
|
+
if (typeof obj["reasoning"] === "string") {
|
|
642
|
+
obj["reasoning"] = clampWithMarker(obj["reasoning"], REASONING_MAX_CHARS);
|
|
643
|
+
}
|
|
644
|
+
if (Array.isArray(obj["findings"])) {
|
|
645
|
+
obj["findings"] = obj["findings"].map((finding) => {
|
|
646
|
+
if (typeof finding === "object" && finding !== null && typeof finding["claim"] === "string") {
|
|
647
|
+
const f = finding;
|
|
648
|
+
return { ...f, claim: clampWithMarker(f["claim"], CLAIM_MAX_CHARS) };
|
|
649
|
+
}
|
|
650
|
+
return finding;
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return obj;
|
|
654
|
+
}
|
|
584
655
|
function buildParsedVote(data) {
|
|
585
656
|
return {
|
|
586
657
|
decision: data.decision,
|
|
@@ -597,7 +668,7 @@ function parseVoteResponse(output, role, options) {
|
|
|
597
668
|
try {
|
|
598
669
|
const jsonStr = extractJsonFromResponse(output);
|
|
599
670
|
const parsed = JSON.parse(jsonStr);
|
|
600
|
-
const validated = VoteResponseSchema.safeParse(parsed);
|
|
671
|
+
const validated = VoteResponseSchema.safeParse(clampOversizeVoteStrings(parsed));
|
|
601
672
|
if (validated.success) {
|
|
602
673
|
return buildParsedVote(validated.data);
|
|
603
674
|
}
|
|
@@ -721,8 +792,12 @@ function buildVoteRequest(role, proposal, timeoutMs, withResponseFormat) {
|
|
|
721
792
|
{ role: "system", content: VOTER_SYSTEM_PROMPTS[role] },
|
|
722
793
|
{ role: "user", content: buildVotePrompt(proposal) }
|
|
723
794
|
],
|
|
724
|
-
//
|
|
725
|
-
|
|
795
|
+
// 4000 (#4131): headroom so a findings-bearing verdict (JSON envelope +
|
|
796
|
+
// reasoning + structured findings) isn't cut mid-JSON by the token cap and
|
|
797
|
+
// silently dropped. Was 2000 (#2245, up from 500); large contrarian findings
|
|
798
|
+
// still overflowed it. Non-findings votes stop at natural completion, so the
|
|
799
|
+
// higher cap adds no cost for them.
|
|
800
|
+
maxTokens: 4e3,
|
|
726
801
|
temperature: 0.3,
|
|
727
802
|
// Low temperature for consistent evaluations
|
|
728
803
|
// Thread the vote budget so the CLI timeout doesn't fire first (#3304); pass
|
|
@@ -4230,7 +4305,12 @@ var HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR = 0.65;
|
|
|
4230
4305
|
function shouldEscalateLowPosterior(strategy, outcome, quickMode, posteriorApproval) {
|
|
4231
4306
|
return quickMode && outcome === "approved" && isHigherOrderStrategy(strategy) && posteriorApproval !== void 0 && posteriorApproval < HIGHER_ORDER_ESCALATION_POSTERIOR_FLOOR;
|
|
4232
4307
|
}
|
|
4233
|
-
var ErrorPolicySchema = z6.enum([
|
|
4308
|
+
var ErrorPolicySchema = z6.enum([
|
|
4309
|
+
"reduce_denominator",
|
|
4310
|
+
"count_as_abstain",
|
|
4311
|
+
"fail_closed",
|
|
4312
|
+
"absolute_quorum"
|
|
4313
|
+
]);
|
|
4234
4314
|
var VoteThresholdSchema = z6.enum(["majority", "supermajority", "unanimous"]);
|
|
4235
4315
|
var ERROR_FLOOR_FRACTION = 0.5;
|
|
4236
4316
|
function getDefaultErrorPolicy(strategy) {
|
|
@@ -4248,7 +4328,7 @@ var ConsensusVoteInputSchema = z6.object({
|
|
|
4248
4328
|
"Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order (Bayesian-optimal)"
|
|
4249
4329
|
),
|
|
4250
4330
|
errorPolicy: ErrorPolicySchema.optional().describe(
|
|
4251
|
-
"How to treat voters that errored or timed out (#2630). Default: fail_closed for unanimous only; reduce_denominator for all other strategies incl. higher_order/opinion_wise (#3138 \u2014 a single infra timeout should not void an otherwise-unanimous vote). Regardless of policy, errors > 50% always fails."
|
|
4331
|
+
"How to treat voters that errored or timed out (#2630). Default: fail_closed for unanimous only; reduce_denominator for all other strategies incl. higher_order/opinion_wise (#3138 \u2014 a single infra timeout should not void an otherwise-unanimous vote). Opt-in absolute_quorum (#4132): an errored voter \u2014 especially the contrarian (catfish) \u2014 degrades the verdict to no_quorum (recoverable re-run) instead of being dropped from the denominator; never manufactures approved/rejected from an induced error. Regardless of policy, errors > 50% always fails."
|
|
4252
4332
|
),
|
|
4253
4333
|
quickMode: z6.boolean().optional().default(false).describe("Use 3 agents instead of the full 7-role panel for faster execution"),
|
|
4254
4334
|
simulateVotes: z6.boolean().optional().default(false).describe(
|
|
@@ -4331,12 +4411,69 @@ function panelDegradationWarning(errorCount, total) {
|
|
|
4331
4411
|
if (errorCount <= 0 || errorCount >= total) return void 0;
|
|
4332
4412
|
return `Panel degraded: ${String(errorCount)} of ${String(total)} voters errored; decision rests on ${String(total - errorCount)} voter(s).`;
|
|
4333
4413
|
}
|
|
4414
|
+
var degradedPanelCount = 0;
|
|
4415
|
+
function absoluteQuorumFraction(strategy) {
|
|
4416
|
+
switch (strategy) {
|
|
4417
|
+
case "supermajority":
|
|
4418
|
+
return 2 / 3;
|
|
4419
|
+
case "unanimous":
|
|
4420
|
+
return 1;
|
|
4421
|
+
default:
|
|
4422
|
+
return 0.5;
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
function absoluteQuorumDegradeReason(result, errorCount) {
|
|
4426
|
+
const contrarianVote = result.votes.find((v) => v.role === "catfish");
|
|
4427
|
+
const contrarianOk = contrarianVote !== void 0 && contrarianVote.source !== "error";
|
|
4428
|
+
const contrarianDegraded = result.contrarianRequested === true && !contrarianOk;
|
|
4429
|
+
if (errorCount === 0 && !contrarianDegraded) return void 0;
|
|
4430
|
+
const erroredRoles = result.votes.filter((v) => v.source === "error").map((v) => v.role);
|
|
4431
|
+
const named = contrarianDegraded && !erroredRoles.includes("catfish") ? [...erroredRoles, "catfish"] : erroredRoles;
|
|
4432
|
+
const list = named.length > 0 ? named.join(", ") : "contrarian";
|
|
4433
|
+
return `no_quorum: re-run \u2014 voter(s) [${list}] errored (absolute_quorum)`;
|
|
4434
|
+
}
|
|
4435
|
+
function computeAbsoluteQuorumDecision(result, errorCount, allErrors) {
|
|
4436
|
+
const degradeReason = absoluteQuorumDegradeReason(result, errorCount);
|
|
4437
|
+
if (degradeReason !== void 0) return { decision: "no_quorum", degradeReason };
|
|
4438
|
+
const panel = result.panelSize ?? result.votes.length;
|
|
4439
|
+
const needed = Math.ceil(absoluteQuorumFraction(result.strategy) * panel);
|
|
4440
|
+
const approveCount = result.votes.filter(
|
|
4441
|
+
(v) => v.source !== "error" && v.vote.decision === "approve"
|
|
4442
|
+
).length;
|
|
4443
|
+
if (result.result.outcome === "approved" && approveCount >= needed) {
|
|
4444
|
+
return { decision: "approved" };
|
|
4445
|
+
}
|
|
4446
|
+
if (result.result.outcome === "rejected" && !allErrors) {
|
|
4447
|
+
return { decision: "rejected" };
|
|
4448
|
+
}
|
|
4449
|
+
return {
|
|
4450
|
+
decision: "no_quorum",
|
|
4451
|
+
degradeReason: `no_quorum: absolute quorum not met (${String(approveCount)}/${String(needed)} approvals over ${String(panel)}-voter panel, absolute_quorum)`
|
|
4452
|
+
};
|
|
4453
|
+
}
|
|
4454
|
+
function resolveVoteDecision(input, result, errorCount) {
|
|
4455
|
+
const allErrors = errorCount === result.votes.length && errorCount > 0;
|
|
4456
|
+
if (result.policyReason !== void 0 || !result.result.quorumReached && allErrors) {
|
|
4457
|
+
return { decision: "no_quorum" };
|
|
4458
|
+
}
|
|
4459
|
+
if (input.errorPolicy === "absolute_quorum") {
|
|
4460
|
+
return computeAbsoluteQuorumDecision(result, errorCount, allErrors);
|
|
4461
|
+
}
|
|
4462
|
+
return { decision: mapOutcomeToDecision(result.result.outcome) };
|
|
4463
|
+
}
|
|
4464
|
+
function applyAbsoluteQuorumTelemetry(response, input, decision, degradeReason) {
|
|
4465
|
+
if (input.errorPolicy === "absolute_quorum" && decision === "no_quorum") {
|
|
4466
|
+
degradedPanelCount++;
|
|
4467
|
+
}
|
|
4468
|
+
if (degradeReason !== void 0) {
|
|
4469
|
+
response.policyReason ??= degradeReason;
|
|
4470
|
+
response.panelWarning ??= degradeReason;
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4334
4473
|
function buildResponse(input, result, costSummary, voteRecord) {
|
|
4335
4474
|
const proposalTruncated = input.proposal.length > 200 ? input.proposal.slice(0, 200) + "..." : input.proposal;
|
|
4336
4475
|
const errorCount = result.votes.filter((v) => v.source === "error").length;
|
|
4337
|
-
const
|
|
4338
|
-
const errorVoidedVote = result.policyReason !== void 0;
|
|
4339
|
-
const decision = errorVoidedVote || !result.result.quorumReached && allErrors ? "no_quorum" : mapOutcomeToDecision(result.result.outcome);
|
|
4476
|
+
const { decision, degradeReason } = resolveVoteDecision(input, result, errorCount);
|
|
4340
4477
|
const response = {
|
|
4341
4478
|
proposal: proposalTruncated,
|
|
4342
4479
|
strategy: result.strategy,
|
|
@@ -4359,6 +4496,7 @@ function buildResponse(input, result, costSummary, voteRecord) {
|
|
|
4359
4496
|
response.voteRecordNote = voteRecord.detail;
|
|
4360
4497
|
}
|
|
4361
4498
|
applyOptionalResponseFields(response, input, result, errorCount, costSummary);
|
|
4499
|
+
applyAbsoluteQuorumTelemetry(response, input, decision, degradeReason);
|
|
4362
4500
|
return response;
|
|
4363
4501
|
}
|
|
4364
4502
|
function applyOptionalResponseFields(response, input, result, errorCount, costSummary) {
|
|
@@ -4415,7 +4553,7 @@ function applyErrorPolicy(votes, policy) {
|
|
|
4415
4553
|
engineVotes: []
|
|
4416
4554
|
};
|
|
4417
4555
|
}
|
|
4418
|
-
if (policy === "count_as_abstain") {
|
|
4556
|
+
if (policy === "count_as_abstain" || policy === "absolute_quorum") {
|
|
4419
4557
|
return {
|
|
4420
4558
|
shortCircuit: false,
|
|
4421
4559
|
engineVotes: votes.map(
|
|
@@ -5750,9 +5888,10 @@ async function runContrarianCheck(proposal, log) {
|
|
|
5750
5888
|
'{"decision":"approve","confidence":0.0-1.0,"reasoning":"why it is acceptable"}'
|
|
5751
5889
|
].join("\n");
|
|
5752
5890
|
const result = await executeExpert("architecture", prompt);
|
|
5753
|
-
if (!result.success) return { shouldEscalate: false, reason: "", confidence: 0 };
|
|
5891
|
+
if (!result.success) return { shouldEscalate: false, reason: "", confidence: 0, errored: true };
|
|
5754
5892
|
const jsonMatch = result.text.match(/\{[\s\S]*\}/);
|
|
5755
|
-
if (jsonMatch === null)
|
|
5893
|
+
if (jsonMatch === null)
|
|
5894
|
+
return { shouldEscalate: false, reason: "", confidence: 0, errored: false };
|
|
5756
5895
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
5757
5896
|
const isRejection = parsed.decision === "reject";
|
|
5758
5897
|
const confidence = typeof parsed.confidence === "number" ? parsed.confidence : 0;
|
|
@@ -5762,13 +5901,13 @@ async function runContrarianCheck(proposal, log) {
|
|
|
5762
5901
|
confidence,
|
|
5763
5902
|
reasoning: reasoning.slice(0, 200)
|
|
5764
5903
|
});
|
|
5765
|
-
return { shouldEscalate: true, reason: reasoning, confidence };
|
|
5904
|
+
return { shouldEscalate: true, reason: reasoning, confidence, errored: false };
|
|
5766
5905
|
}
|
|
5767
|
-
return { shouldEscalate: false, reason: "", confidence };
|
|
5906
|
+
return { shouldEscalate: false, reason: "", confidence, errored: false };
|
|
5768
5907
|
} catch (error) {
|
|
5769
5908
|
const message = error instanceof Error ? error.message : String(error);
|
|
5770
5909
|
log.warn("Contrarian check failed; defaulting to no escalation", { error: message });
|
|
5771
|
-
return { shouldEscalate: false, reason: "", confidence: 0 };
|
|
5910
|
+
return { shouldEscalate: false, reason: "", confidence: 0, errored: true };
|
|
5772
5911
|
}
|
|
5773
5912
|
}
|
|
5774
5913
|
function buildPolicyShortCircuitResult(args) {
|
|
@@ -5785,27 +5924,37 @@ function buildPolicyShortCircuitResult(args) {
|
|
|
5785
5924
|
totalTimeMs,
|
|
5786
5925
|
simulateVotes: args.input.simulateVotes,
|
|
5787
5926
|
strategy: args.strategy,
|
|
5927
|
+
// #4132: thread the requested panel shape so the absolute_quorum predicate
|
|
5928
|
+
// in buildResponse has PANEL_SIZE + contrarian-presence even on a short-circuit.
|
|
5929
|
+
panelSize: args.roles.length,
|
|
5930
|
+
contrarianRequested: args.roles.includes("catfish"),
|
|
5788
5931
|
// #3124: surface WHY a high-approval result is still 'rejected' so callers
|
|
5789
5932
|
// don't mistake a fail-closed policy short-circuit for a genuine rejection.
|
|
5790
5933
|
policyReason: args.reason
|
|
5791
5934
|
};
|
|
5792
5935
|
}
|
|
5793
5936
|
async function maybeEscalateContrarian(input, outcome, ctx, logger10, opts) {
|
|
5794
|
-
if (!input.quickMode || outcome !== "approved" || input.simulateVotes) return
|
|
5937
|
+
if (!input.quickMode || outcome !== "approved" || input.simulateVotes) return {};
|
|
5795
5938
|
if (shouldEscalateLowPosterior(ctx.strategy, outcome, input.quickMode, ctx.posteriorApproval)) {
|
|
5796
5939
|
logger10.warn("Posterior-confidence escalation: re-running with full vote (#3174)", {
|
|
5797
5940
|
strategy: ctx.strategy,
|
|
5798
5941
|
posteriorApproval: ctx.posteriorApproval
|
|
5799
5942
|
});
|
|
5800
|
-
return executeVoting({ ...input, quickMode: false }, logger10, opts);
|
|
5943
|
+
return { escalated: await executeVoting({ ...input, quickMode: false }, logger10, opts) };
|
|
5801
5944
|
}
|
|
5802
5945
|
const escalation = await runContrarianCheck(input.proposal, logger10);
|
|
5803
|
-
if (
|
|
5946
|
+
if (escalation.errored && input.errorPolicy === "absolute_quorum") {
|
|
5947
|
+
logger10.warn("Contrarian check errored under absolute_quorum \u2014 degrading to no_quorum (#4132)");
|
|
5948
|
+
return {
|
|
5949
|
+
degradeReason: "no_quorum: re-run \u2014 contrarian check errored (absolute_quorum quick-mode)"
|
|
5950
|
+
};
|
|
5951
|
+
}
|
|
5952
|
+
if (!escalation.shouldEscalate) return {};
|
|
5804
5953
|
logger10.warn("Contrarian escalation: re-running with full vote", {
|
|
5805
5954
|
reason: escalation.reason,
|
|
5806
5955
|
confidence: escalation.confidence
|
|
5807
5956
|
});
|
|
5808
|
-
return executeVoting({ ...input, quickMode: false }, logger10, opts);
|
|
5957
|
+
return { escalated: await executeVoting({ ...input, quickMode: false }, logger10, opts) };
|
|
5809
5958
|
}
|
|
5810
5959
|
async function executeVoting(input, logger10, opts) {
|
|
5811
5960
|
const strategy = resolveStrategy(input);
|
|
@@ -5832,6 +5981,7 @@ async function executeVoting(input, logger10, opts) {
|
|
|
5832
5981
|
input,
|
|
5833
5982
|
strategy,
|
|
5834
5983
|
algorithm,
|
|
5984
|
+
roles,
|
|
5835
5985
|
votes,
|
|
5836
5986
|
errorPolicy,
|
|
5837
5987
|
reason: policyDecision.reason ?? "error policy short-circuit",
|
|
@@ -5850,18 +6000,19 @@ async function executeVoting(input, logger10, opts) {
|
|
|
5850
6000
|
}
|
|
5851
6001
|
);
|
|
5852
6002
|
recordVotesToTracker(votes, outcome, logger10);
|
|
5853
|
-
const
|
|
6003
|
+
const escalation = await maybeEscalateContrarian(
|
|
5854
6004
|
input,
|
|
5855
6005
|
outcome,
|
|
5856
6006
|
{ strategy, posteriorApproval: higherOrderResult?.posteriorApproval },
|
|
5857
6007
|
logger10,
|
|
5858
6008
|
opts
|
|
5859
6009
|
);
|
|
5860
|
-
if (escalated !== void 0) return escalated;
|
|
5861
|
-
|
|
6010
|
+
if (escalation.escalated !== void 0) return escalation.escalated;
|
|
6011
|
+
const finalized = finalizeVotingResult({
|
|
5862
6012
|
input,
|
|
5863
6013
|
strategy,
|
|
5864
6014
|
algorithm,
|
|
6015
|
+
roles,
|
|
5865
6016
|
engineResult,
|
|
5866
6017
|
higherOrderResult,
|
|
5867
6018
|
votes,
|
|
@@ -5870,6 +6021,11 @@ async function executeVoting(input, logger10, opts) {
|
|
|
5870
6021
|
startTime,
|
|
5871
6022
|
logger: logger10
|
|
5872
6023
|
});
|
|
6024
|
+
return applyContrarianDegrade(finalized, escalation.degradeReason);
|
|
6025
|
+
}
|
|
6026
|
+
function applyContrarianDegrade(result, degradeReason) {
|
|
6027
|
+
if (degradeReason === void 0 || result.policyReason !== void 0) return result;
|
|
6028
|
+
return { ...result, policyReason: degradeReason };
|
|
5873
6029
|
}
|
|
5874
6030
|
async function runConsensusForGoal(goal, logger10 = createLogger({ tool: "consensus_vote" }), gatewayAdapters) {
|
|
5875
6031
|
return executeVoting(ConsensusVoteInputSchema.parse({ proposal: goal }), logger10, {
|
|
@@ -5891,7 +6047,10 @@ function finalizeVotingResult(args) {
|
|
|
5891
6047
|
votes: args.votes,
|
|
5892
6048
|
totalTimeMs,
|
|
5893
6049
|
simulateVotes: args.input.simulateVotes,
|
|
5894
|
-
strategy: args.strategy
|
|
6050
|
+
strategy: args.strategy,
|
|
6051
|
+
// #4132: PANEL_SIZE + contrarian-presence for the absolute_quorum predicate.
|
|
6052
|
+
panelSize: args.roles.length,
|
|
6053
|
+
contrarianRequested: args.roles.includes("catfish")
|
|
5895
6054
|
};
|
|
5896
6055
|
if (args.higherOrderResult !== void 0) result.higherOrderResult = args.higherOrderResult;
|
|
5897
6056
|
return result;
|
|
@@ -6108,6 +6267,9 @@ var CONSENSUS_VOTE_TOOL_SCHEMA = {
|
|
|
6108
6267
|
strategy: VotingStrategySchema.optional().describe(
|
|
6109
6268
|
"Voting strategy: simple_majority (default), supermajority, unanimous, proof_of_learning, or higher_order"
|
|
6110
6269
|
),
|
|
6270
|
+
errorPolicy: ErrorPolicySchema.optional().describe(
|
|
6271
|
+
"How to treat errored/timed-out voters (#2630): reduce_denominator (default non-strict) | count_as_abstain | fail_closed (default unanimous) | absolute_quorum (#4132 opt-in \u2014 an errored voter, esp. the contrarian, degrades the verdict to no_quorum instead of being dropped; never manufactures approved/rejected from an induced error). Errors > 50% always fails."
|
|
6272
|
+
),
|
|
6111
6273
|
quickMode: z10.boolean().optional().default(false).describe("Use 3 agents instead of 7"),
|
|
6112
6274
|
simulateVotes: z10.boolean().optional().default(false).describe("TESTS ONLY \u2014 random output, must not be used for real decisions (#2319)"),
|
|
6113
6275
|
ratifies: z10.string().min(1).max(256).optional().describe(
|
|
@@ -6212,9 +6374,10 @@ export {
|
|
|
6212
6374
|
warnIfSimulatedOutsideTests,
|
|
6213
6375
|
resetCorrelationTracker,
|
|
6214
6376
|
createPolicyFailedResult,
|
|
6377
|
+
maybeEscalateContrarian,
|
|
6215
6378
|
executeVoting,
|
|
6216
6379
|
runConsensusForGoal,
|
|
6217
6380
|
CONSENSUS_VOTE_OUTPUT_SCHEMA,
|
|
6218
6381
|
registerConsensusVoteTool
|
|
6219
6382
|
};
|
|
6220
|
-
//# sourceMappingURL=chunk-
|
|
6383
|
+
//# sourceMappingURL=chunk-UIL37D2V.js.map
|