@mneme-ai/core 2.15.1 → 2.16.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/agent_manifest.d.ts +1 -1
- package/dist/agent_manifest.d.ts.map +1 -1
- package/dist/agent_manifest.js +18 -1
- package/dist/agent_manifest.js.map +1 -1
- package/dist/alpha/alpha.test.d.ts +2 -0
- package/dist/alpha/alpha.test.d.ts.map +1 -0
- package/dist/alpha/alpha.test.js +101 -0
- package/dist/alpha/alpha.test.js.map +1 -0
- package/dist/alpha/index.d.ts +106 -0
- package/dist/alpha/index.d.ts.map +1 -0
- package/dist/alpha/index.js +190 -0
- package/dist/alpha/index.js.map +1 -0
- package/dist/anti_collusion/anti_collusion.test.d.ts +2 -0
- package/dist/anti_collusion/anti_collusion.test.d.ts.map +1 -0
- package/dist/anti_collusion/anti_collusion.test.js +137 -0
- package/dist/anti_collusion/anti_collusion.test.js.map +1 -0
- package/dist/anti_collusion/index.d.ts +89 -0
- package/dist/anti_collusion/index.d.ts.map +1 -0
- package/dist/anti_collusion/index.js +218 -0
- package/dist/anti_collusion/index.js.map +1 -0
- package/dist/bug_prophet/index.d.ts.map +1 -1
- package/dist/bug_prophet/index.js +8 -3
- package/dist/bug_prophet/index.js.map +1 -1
- package/dist/cosmic/aurelian_v216.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v216.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v216.test.js +89 -0
- package/dist/cosmic/aurelian_v216.test.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/living_model/index.d.ts +104 -0
- package/dist/living_model/index.d.ts.map +1 -0
- package/dist/living_model/index.js +152 -0
- package/dist/living_model/index.js.map +1 -0
- package/dist/living_model/living_model.test.d.ts +2 -0
- package/dist/living_model/living_model.test.d.ts.map +1 -0
- package/dist/living_model/living_model.test.js +125 -0
- package/dist/living_model/living_model.test.js.map +1 -0
- package/dist/obelisk/index.d.ts +74 -0
- package/dist/obelisk/index.d.ts.map +1 -0
- package/dist/obelisk/index.js +114 -0
- package/dist/obelisk/index.js.map +1 -0
- package/dist/obelisk/obelisk.test.d.ts +2 -0
- package/dist/obelisk/obelisk.test.d.ts.map +1 -0
- package/dist/obelisk/obelisk.test.js +67 -0
- package/dist/obelisk/obelisk.test.js.map +1 -0
- package/dist/persona/index.d.ts +107 -0
- package/dist/persona/index.d.ts.map +1 -0
- package/dist/persona/index.js +144 -0
- package/dist/persona/index.js.map +1 -0
- package/dist/persona/persona.test.d.ts +2 -0
- package/dist/persona/persona.test.d.ts.map +1 -0
- package/dist/persona/persona.test.js +71 -0
- package/dist/persona/persona.test.js.map +1 -0
- package/dist/public_audit/index.d.ts +70 -0
- package/dist/public_audit/index.d.ts.map +1 -0
- package/dist/public_audit/index.js +175 -0
- package/dist/public_audit/index.js.map +1 -0
- package/dist/public_audit/public_audit.test.d.ts +2 -0
- package/dist/public_audit/public_audit.test.d.ts.map +1 -0
- package/dist/public_audit/public_audit.test.js +64 -0
- package/dist/public_audit/public_audit.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.16.0 — MNEME ALPHA (Honest Financial AI Layer)
|
|
3
|
+
*
|
|
4
|
+
* "When AI says 'NOK will go up tomorrow', Mneme ALPHA does NOT promise
|
|
5
|
+
* 90% accuracy. It does something that's actually possible: makes the
|
|
6
|
+
* AI's claim TRACEABLE, FACT-CHECKABLE, and ACCURACY-MEASURED over
|
|
7
|
+
* time. Sell that. Don't sell oracles."
|
|
8
|
+
*
|
|
9
|
+
* Honest scope (what ALPHA IS):
|
|
10
|
+
* 1. CLAIM EXTRACTION — pull structured claims from AI free-text:
|
|
11
|
+
* ticker, direction (up/down/flat), horizon (today/week), price
|
|
12
|
+
* target, confidence (if AI stated one).
|
|
13
|
+
* 2. PRICE-CHECK STUB — verify the price the AI quoted matches a real
|
|
14
|
+
* live price (caller supplies a price-fetch function; ALPHA never
|
|
15
|
+
* hardcodes a vendor).
|
|
16
|
+
* 3. OVERCONFIDENCE DETECTOR — flag claims that score above a sanity
|
|
17
|
+
* ceiling (e.g., "I am 99% sure NVDA pumps tomorrow" → REJECTED).
|
|
18
|
+
* 4. TRACK-RECORD LEDGER — record (claim, vendor, predicted, observed)
|
|
19
|
+
* and let BOUNTY compute the accuracy over time.
|
|
20
|
+
* 5. SIGNAL FUSION (audit-only) — fuse N AI vendors' opinions into a
|
|
21
|
+
* consensus + dispersion metric. Output is ADVISORY, never a buy/
|
|
22
|
+
* sell directive.
|
|
23
|
+
*
|
|
24
|
+
* Honest scope (what ALPHA IS NOT):
|
|
25
|
+
* - Not a stock predictor.
|
|
26
|
+
* - Not financial advice.
|
|
27
|
+
* - Not a "90% accuracy oracle" — markets are mostly efficient + noisy;
|
|
28
|
+
* no honest engineer claims 90% direction accuracy on liquid stocks.
|
|
29
|
+
* - Not a backtester (use a proper quant framework for that).
|
|
30
|
+
*
|
|
31
|
+
* Wisdom: this is anti-hallucination + accountability for the corner of
|
|
32
|
+
* AI that has the most expensive hallucinations (someone's retirement).
|
|
33
|
+
* Saying NO to overconfident financial AI is more valuable than any
|
|
34
|
+
* "alpha edge" we could honestly promise.
|
|
35
|
+
*/
|
|
36
|
+
import { createHmac, randomBytes } from "node:crypto";
|
|
37
|
+
const PROTOCOL_VERSION = 1;
|
|
38
|
+
const TICKER_REGEX = /\b([A-Z]{1,6}(?:\.[A-Z]{1,3})?)\b/g;
|
|
39
|
+
const HORIZON_HINTS = [
|
|
40
|
+
[/\b(intraday|today)\b/i, "today"],
|
|
41
|
+
[/\b(this\s+week|next\s+week|7\s*days?)\b/i, "week"],
|
|
42
|
+
[/\b(this\s+month|next\s+month|30\s*days?)\b/i, "month"],
|
|
43
|
+
[/\b(this\s+quarter|next\s+quarter|q[1-4])\b/i, "quarter"],
|
|
44
|
+
[/\b(this\s+year|next\s+year|annual)\b/i, "year"],
|
|
45
|
+
[/\b(long[\s-]?term|over\s+\d+\s+years?)\b/i, "long_term"],
|
|
46
|
+
];
|
|
47
|
+
function defaultSecret() {
|
|
48
|
+
return process.env["MNEME_ALPHA_SECRET"] || `mneme-alpha-v${PROTOCOL_VERSION}`;
|
|
49
|
+
}
|
|
50
|
+
function canon(v) {
|
|
51
|
+
if (v === null || typeof v !== "object")
|
|
52
|
+
return JSON.stringify(v);
|
|
53
|
+
if (Array.isArray(v))
|
|
54
|
+
return "[" + v.map(canon).join(",") + "]";
|
|
55
|
+
const keys = Object.keys(v).sort();
|
|
56
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Pull a structured FinancialClaim out of an AI free-text response.
|
|
60
|
+
* Heuristic; non-finding fields stay null.
|
|
61
|
+
*/
|
|
62
|
+
export function extractClaim(input) {
|
|
63
|
+
const text = input.text;
|
|
64
|
+
// Ticker — pick the first standalone uppercase 1-6 char token that isn't
|
|
65
|
+
// a common English word noise; bias toward $TICKER pattern when present.
|
|
66
|
+
let ticker = null;
|
|
67
|
+
const dollar = text.match(/\$([A-Z]{1,6}(?:\.[A-Z]{1,3})?)\b/);
|
|
68
|
+
if (dollar)
|
|
69
|
+
ticker = dollar[1];
|
|
70
|
+
else {
|
|
71
|
+
const tokens = text.match(TICKER_REGEX) || [];
|
|
72
|
+
const NOISE = new Set(["A", "I", "AI", "USA", "USD", "EU", "EUR", "JP", "JPY", "CN", "UK", "PR", "ML", "DM", "AM", "PM", "OK", "IT", "IS", "BE", "OR", "AND", "FOR", "THE", "BUY", "SELL", "HOLD", "CEO", "CFO", "Q1", "Q2", "Q3", "Q4"]);
|
|
73
|
+
ticker = tokens.find((t) => !NOISE.has(t)) ?? null;
|
|
74
|
+
}
|
|
75
|
+
// Direction — look for explicit signals (allow common stems like "dropping" / "rising")
|
|
76
|
+
let direction = "unknown";
|
|
77
|
+
if (/\b(up|ris(?:e|es|ing)|rall(?:y|ies|ying)|surg(?:e|es|ing)|pump(?:s|ing|ed)?|moon|gain(?:s|ing|ed)?|bull(?:ish)?|long|buy(?:s|ing)?|increas(?:e|es|ing|ed)|higher|breakout|breakthrough)\b/i.test(text))
|
|
78
|
+
direction = "up";
|
|
79
|
+
if (/\b(down|fall(?:s|ing|en)?|drop(?:s|ping|ped)?|crash(?:es|ing|ed)?|dump(?:s|ing|ed)?|short(?:ing)?|sell(?:s|ing)?|declin(?:e|es|ing|ed)|lower|breakdown|tank(?:s|ing|ed)?|plung(?:e|es|ing|ed))\b/i.test(text))
|
|
80
|
+
direction = direction === "up" ? "unknown" : "down";
|
|
81
|
+
if (/\b(flat|sideways|range|consolidat(?:e|es|ing|ed)|hold|neutral)\b/i.test(text) && direction === "unknown")
|
|
82
|
+
direction = "flat";
|
|
83
|
+
// Horizon
|
|
84
|
+
let horizon = "unknown";
|
|
85
|
+
for (const [rx, h] of HORIZON_HINTS)
|
|
86
|
+
if (rx.test(text)) {
|
|
87
|
+
horizon = h;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
// Target price — "target $123" / "target 123 USD"
|
|
91
|
+
const target = text.match(/(?:target|tp|price\s+target)[\s:]*\$?(\d+(?:\.\d+)?)/i);
|
|
92
|
+
const targetPrice = target ? parseFloat(target[1]) : null;
|
|
93
|
+
// Quoted price — "current price $4.69" / "trading at 4.69"
|
|
94
|
+
const quoted = text.match(/(?:current(?:\s+price)?|trading\s+at|now\s+at|price[\s:])[\s$]*(\d+(?:\.\d+)?)/i);
|
|
95
|
+
const quotedPrice = quoted ? parseFloat(quoted[1]) : null;
|
|
96
|
+
// Stated confidence — accept "confidence" or "confident" or "sure" or "certain" or "chance" or "probability"
|
|
97
|
+
let statedConfidence = null;
|
|
98
|
+
const conf = text.match(/(\d+(?:\.\d+)?)\s*%\s*(?:confiden(?:t|ce)|chance|probability|sure|certain|likely)/i);
|
|
99
|
+
if (conf)
|
|
100
|
+
statedConfidence = Math.max(0, Math.min(1, parseFloat(conf[1]) / 100));
|
|
101
|
+
else if (/\b(certain|100%|guaranteed|always|will definitely|for sure)\b/i.test(text))
|
|
102
|
+
statedConfidence = 1.0;
|
|
103
|
+
else if (/\b(likely|probable|probably)\b/i.test(text) && statedConfidence === null)
|
|
104
|
+
statedConfidence = 0.7;
|
|
105
|
+
// Overconfidence: stating > 0.85 confidence on a direction prediction is
|
|
106
|
+
// statistically very implausible for liquid markets (efficient market
|
|
107
|
+
// hypothesis + noise). Flag but don't block.
|
|
108
|
+
const overconfident = statedConfidence !== null && statedConfidence > 0.85 && direction !== "unknown";
|
|
109
|
+
const ts = new Date().toISOString();
|
|
110
|
+
const id = "fc-" + randomBytes(6).toString("hex");
|
|
111
|
+
const body = {
|
|
112
|
+
v: PROTOCOL_VERSION,
|
|
113
|
+
id, ts,
|
|
114
|
+
vendor: input.vendor,
|
|
115
|
+
rawText: input.text.slice(0, 2000),
|
|
116
|
+
ticker, direction, horizon,
|
|
117
|
+
targetPrice, quotedPrice, statedConfidence,
|
|
118
|
+
overconfident,
|
|
119
|
+
};
|
|
120
|
+
const sig = createHmac("sha256", input.secret ?? defaultSecret()).update(canon(body)).digest("hex");
|
|
121
|
+
return { ...body, sig };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Compare the AI's quoted price to a real live price. Caller supplies the
|
|
125
|
+
* fetcher (e.g., backed by IEX / Polygon / Binance / Alpha Vantage / your
|
|
126
|
+
* own broker API). ALPHA never hardcodes a vendor — keeps the layer
|
|
127
|
+
* vendor-agnostic.
|
|
128
|
+
*
|
|
129
|
+
* tolerancePct defaults to 2% (typical bid/ask + slippage).
|
|
130
|
+
*/
|
|
131
|
+
export async function priceCheck(input) {
|
|
132
|
+
if (!input.claim.ticker) {
|
|
133
|
+
return { matched: false, quoted: null, observed: null, divergencePct: null, verdict: "no_quote", detail: "no ticker extracted from claim" };
|
|
134
|
+
}
|
|
135
|
+
if (input.claim.quotedPrice === null) {
|
|
136
|
+
return { matched: false, quoted: null, observed: null, divergencePct: null, verdict: "no_quote", detail: "AI did not quote a price" };
|
|
137
|
+
}
|
|
138
|
+
let observed = null;
|
|
139
|
+
try {
|
|
140
|
+
observed = await input.fetchPrice(input.claim.ticker);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
observed = null;
|
|
144
|
+
}
|
|
145
|
+
if (observed === null) {
|
|
146
|
+
return { matched: false, quoted: input.claim.quotedPrice, observed: null, divergencePct: null, verdict: "unverifiable", detail: "live price fetcher returned null" };
|
|
147
|
+
}
|
|
148
|
+
const diff = Math.abs(observed - input.claim.quotedPrice) / observed;
|
|
149
|
+
const tol = input.tolerancePct ?? 0.02;
|
|
150
|
+
const matched = diff <= tol;
|
|
151
|
+
return {
|
|
152
|
+
matched,
|
|
153
|
+
quoted: input.claim.quotedPrice,
|
|
154
|
+
observed,
|
|
155
|
+
divergencePct: Math.round(diff * 10000) / 100,
|
|
156
|
+
verdict: matched ? "aligned" : "divergent",
|
|
157
|
+
detail: matched ? `quoted ${input.claim.quotedPrice} vs observed ${observed} -- within ${(tol * 100).toFixed(1)}% tolerance.` : `MISMATCH: quoted ${input.claim.quotedPrice} vs observed ${observed} (off by ${(diff * 100).toFixed(2)}%).`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/** Fuse N vendors' claims on the same ticker. Returns consensus +
|
|
161
|
+
* dispersion. ADVISORY ONLY — never a trade signal. */
|
|
162
|
+
export function fuseClaims(claims) {
|
|
163
|
+
const votes = { up: 0, down: 0, flat: 0, unknown: 0 };
|
|
164
|
+
for (const c of claims)
|
|
165
|
+
votes[c.direction]++;
|
|
166
|
+
const ranked = Object.entries(votes).sort((a, b) => b[1] - a[1]);
|
|
167
|
+
const top = ranked[0];
|
|
168
|
+
const total = claims.length;
|
|
169
|
+
const meanConf = (() => {
|
|
170
|
+
const withConf = claims.filter((c) => c.statedConfidence !== null);
|
|
171
|
+
if (withConf.length === 0)
|
|
172
|
+
return null;
|
|
173
|
+
return withConf.reduce((acc, c) => acc + c.statedConfidence, 0) / withConf.length;
|
|
174
|
+
})();
|
|
175
|
+
const oc = claims.filter((c) => c.overconfident).length;
|
|
176
|
+
return {
|
|
177
|
+
ticker: claims[0]?.ticker ?? null,
|
|
178
|
+
vendorsConsulted: total,
|
|
179
|
+
directionVotes: votes,
|
|
180
|
+
consensusDirection: top?.[0] ?? "unknown",
|
|
181
|
+
consensusStrength: total === 0 ? 0 : (top?.[1] ?? 0) / total,
|
|
182
|
+
meanStatedConfidence: meanConf === null ? null : Math.round(meanConf * 1000) / 1000,
|
|
183
|
+
overconfidentCount: oc,
|
|
184
|
+
advisory: "ALPHA fusion is ADVISORY ONLY -- no responsible engineer claims 90% direction accuracy on liquid markets. Use as one input among many; never as sole basis for capital allocation. NOT financial advice.",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export function formatAlphaLine(claim) {
|
|
188
|
+
return `ALPHA · ${claim.vendor} · ${claim.ticker ?? "?"} · ${claim.direction}/${claim.horizon}${claim.overconfident ? " ⚠OVERCONFIDENT" : ""}`;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/alpha/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,gBAAgB,GAAG,CAAU,CAAC;AA2BpC,MAAM,YAAY,GAAG,oCAAoC,CAAC;AAC1D,MAAM,aAAa,GAA6B;IAC9C,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAClC,CAAC,0CAA0C,EAAE,MAAM,CAAC;IACpD,CAAC,6CAA6C,EAAE,OAAO,CAAC;IACxD,CAAC,6CAA6C,EAAE,SAAS,CAAC;IAC1D,CAAC,uCAAuC,EAAE,MAAM,CAAC;IACjD,CAAC,2CAA2C,EAAE,WAAW,CAAC;CAC3D,CAAC;AAEF,SAAS,aAAa;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,gBAAgB,gBAAgB,EAAE,CAAC;AACjF,CAAC;AAED,SAAS,KAAK,CAAC,CAAU;IACvB,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAA4B,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAE,CAA6B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AACnH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwD;IACnF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAExB,yEAAyE;IACzE,yEAAyE;IACzE,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC/D,IAAI,MAAM;QAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;SAC3B,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1O,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACrD,CAAC;IAED,wFAAwF;IACxF,IAAI,SAAS,GAAc,SAAS,CAAC;IACrC,IAAI,4LAA4L,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,GAAG,IAAI,CAAC;IAC9N,IAAI,mMAAmM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IACxQ,IAAI,mEAAmE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,KAAK,SAAS;QAAE,SAAS,GAAG,MAAM,CAAC;IAElI,UAAU;IACV,IAAI,OAAO,GAAY,SAAS,CAAC;IACjC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,aAAa;QAAE,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAAC,OAAO,GAAG,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;IAE/E,kDAAkD;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACnF,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3D,2DAA2D;IAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;IAC7G,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3D,6GAA6G;IAC7G,IAAI,gBAAgB,GAAkB,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,oFAAoF,CAAC,CAAC;IAC9G,IAAI,IAAI;QAAE,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;SAC7E,IAAI,gEAAgE,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,gBAAgB,GAAG,GAAG,CAAC;SACxG,IAAI,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,KAAK,IAAI;QAAE,gBAAgB,GAAG,GAAG,CAAC;IAE3G,yEAAyE;IACzE,sEAAsE;IACtE,6CAA6C;IAC7C,MAAM,aAAa,GAAG,gBAAgB,KAAK,IAAI,IAAI,gBAAgB,GAAG,IAAI,IAAI,SAAS,KAAK,SAAS,CAAC;IAEtG,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,EAAE,GAAG,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,IAAI,GAAgC;QACxC,CAAC,EAAE,gBAAgB;QACnB,EAAE,EAAE,EAAE;QACN,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QAClC,MAAM,EAAE,SAAS,EAAE,OAAO;QAC1B,WAAW,EAAE,WAAW,EAAE,gBAAgB;QAC1C,aAAa;KACd,CAAC;IACF,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpG,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;AAC1B,CAAC;AAYD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAIhC;IACC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC;IAC9I,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACrC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACxI,CAAC;IACD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QAAC,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,QAAQ,GAAG,IAAI,CAAC;IAAC,CAAC;IACzF,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,kCAAkC,EAAE,CAAC;IACvK,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;IACrE,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,IAAI,GAAG,CAAC;IAC5B,OAAO;QACL,OAAO;QACP,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW;QAC/B,QAAQ;QACR,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG;QAC7C,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;QAC1C,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,KAAK,CAAC,WAAW,gBAAgB,QAAQ,cAAc,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,oBAAoB,KAAK,CAAC,KAAK,CAAC,WAAW,gBAAgB,QAAQ,YAAY,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;KAC5O,CAAC;AACJ,CAAC;AAED;wDACwD;AACxD,MAAM,UAAU,UAAU,CAAC,MAAwB;IAWjD,MAAM,KAAK,GAA8B,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAgC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjG,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE;QACrB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,IAAI,CAAC,CAAC;QACnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAI,CAAC,CAAC,gBAA2B,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;IAChG,CAAC,CAAC,EAAE,CAAC;IACL,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;IACxD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,IAAI;QACjC,gBAAgB,EAAE,KAAK;QACvB,cAAc,EAAE,KAAK;QACrB,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS;QACzC,iBAAiB,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK;QAC5D,oBAAoB,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI;QACnF,kBAAkB,EAAE,EAAE;QACtB,QAAQ,EAAE,0MAA0M;KACrN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO,WAAW,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anti_collusion.test.d.ts","sourceRoot":"","sources":["../../src/anti_collusion/anti_collusion.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { detectCollusion, leaderboard, formatAntiCollusionLine } from "./index.js";
|
|
6
|
+
describe("v2.16 · ANTI-COLLUSION (AI Internal Affairs)", () => {
|
|
7
|
+
let dir;
|
|
8
|
+
beforeEach(() => { dir = mkdtempSync(join(tmpdir(), "ic-")); });
|
|
9
|
+
afterEach(() => { try {
|
|
10
|
+
rmSync(dir, { recursive: true, force: true });
|
|
11
|
+
}
|
|
12
|
+
catch { } });
|
|
13
|
+
it("clean honest exchange → low risk", () => {
|
|
14
|
+
const r = detectCollusion({
|
|
15
|
+
conversationId: "c1",
|
|
16
|
+
turns: [
|
|
17
|
+
{ conversationId: "c1", agent: "claude", ts: "1", text: "I claim file X exists.", verified: true, intent: "claim" },
|
|
18
|
+
{ conversationId: "c1", agent: "chatgpt", ts: "2", text: "Verified file X — confirmed via fs read.", verified: true, intent: "verify" },
|
|
19
|
+
],
|
|
20
|
+
repoDir: dir,
|
|
21
|
+
});
|
|
22
|
+
expect(r.length).toBe(1);
|
|
23
|
+
expect(r[0].verdict).toMatch(/clean|watch/);
|
|
24
|
+
});
|
|
25
|
+
it("skipped verification → bumps risk + finding", () => {
|
|
26
|
+
const r = detectCollusion({
|
|
27
|
+
conversationId: "c2",
|
|
28
|
+
turns: [
|
|
29
|
+
{ conversationId: "c2", agent: "claude", ts: "1", text: "Found the bug, fixed it.", verified: false, intent: "claim" },
|
|
30
|
+
{ conversationId: "c2", agent: "chatgpt", ts: "2", text: "Looks good to me, ship it.", verified: false, intent: "accept" },
|
|
31
|
+
{ conversationId: "c2", agent: "claude", ts: "3", text: "Done, complete.", verified: false, intent: "claim" },
|
|
32
|
+
{ conversationId: "c2", agent: "chatgpt", ts: "4", text: "Confirmed.", verified: false, intent: "accept" },
|
|
33
|
+
],
|
|
34
|
+
repoDir: dir,
|
|
35
|
+
});
|
|
36
|
+
expect(r[0].findings.some((f) => f.pattern === "skipped_verification")).toBe(true);
|
|
37
|
+
expect(r[0].collusionRisk).toBeGreaterThan(0.3);
|
|
38
|
+
});
|
|
39
|
+
it("echoing pattern detected", () => {
|
|
40
|
+
const r = detectCollusion({
|
|
41
|
+
conversationId: "c3",
|
|
42
|
+
turns: [
|
|
43
|
+
{ conversationId: "c3", agent: "claude", ts: "1", text: "The authentication flow uses jwt tokens with rotation every 15 minutes.", verified: false },
|
|
44
|
+
{ conversationId: "c3", agent: "chatgpt", ts: "2", text: "Authentication flow uses jwt tokens with 15 minute rotation.", verified: false },
|
|
45
|
+
{ conversationId: "c3", agent: "claude", ts: "3", text: "The authentication uses jwt rotation every 15 minutes flow.", verified: false },
|
|
46
|
+
{ conversationId: "c3", agent: "chatgpt", ts: "4", text: "Authentication jwt tokens 15 minutes rotation flow.", verified: false },
|
|
47
|
+
],
|
|
48
|
+
repoDir: dir,
|
|
49
|
+
});
|
|
50
|
+
expect(r[0].findings.some((f) => f.pattern === "echoing")).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it("mutual praise loop detected", () => {
|
|
53
|
+
const r = detectCollusion({
|
|
54
|
+
conversationId: "c4",
|
|
55
|
+
turns: [
|
|
56
|
+
{ conversationId: "c4", agent: "claude", ts: "1", text: "Excellent work on this PR.", verified: false },
|
|
57
|
+
{ conversationId: "c4", agent: "chatgpt", ts: "2", text: "Great approach by you too!", verified: false },
|
|
58
|
+
{ conversationId: "c4", agent: "claude", ts: "3", text: "Perfect, exactly what I had in mind.", verified: false },
|
|
59
|
+
{ conversationId: "c4", agent: "chatgpt", ts: "4", text: "Brilliant, nice work overall.", verified: false },
|
|
60
|
+
],
|
|
61
|
+
repoDir: dir,
|
|
62
|
+
});
|
|
63
|
+
expect(r[0].findings.some((f) => f.pattern === "mutual_praise")).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
it("verification dropout (rate way below expected)", () => {
|
|
66
|
+
const turns = [];
|
|
67
|
+
for (let i = 0; i < 8; i++) {
|
|
68
|
+
turns.push({
|
|
69
|
+
conversationId: "c5", agent: i % 2 === 0 ? "claude" : "chatgpt",
|
|
70
|
+
ts: String(i), text: "doing work", verified: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const r = detectCollusion({ conversationId: "c5", turns, expectedVerifyRate: 0.5, repoDir: dir });
|
|
74
|
+
expect(r[0].findings.some((f) => f.pattern === "verification_dropout")).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
it("apoptosis_now triggers callback when risk >= 0.8", () => {
|
|
77
|
+
let triggered = null;
|
|
78
|
+
const turns = [
|
|
79
|
+
{ conversationId: "c6", agent: "claude", ts: "1", text: "Found the bug, fixed and complete done.", verified: false, intent: "claim" },
|
|
80
|
+
{ conversationId: "c6", agent: "chatgpt", ts: "2", text: "Excellent perfect great work, ship it confirmed done.", verified: false, intent: "accept" },
|
|
81
|
+
{ conversationId: "c6", agent: "claude", ts: "3", text: "Done complete found fixed.", verified: false, intent: "claim" },
|
|
82
|
+
{ conversationId: "c6", agent: "chatgpt", ts: "4", text: "Perfect, brilliant, exactly. Done complete.", verified: false, intent: "accept" },
|
|
83
|
+
{ conversationId: "c6", agent: "claude", ts: "5", text: "Done complete found fixed all.", verified: false, intent: "claim" },
|
|
84
|
+
{ conversationId: "c6", agent: "chatgpt", ts: "6", text: "Excellent perfect, done complete.", verified: false, intent: "accept" },
|
|
85
|
+
];
|
|
86
|
+
const r = detectCollusion({
|
|
87
|
+
conversationId: "c6",
|
|
88
|
+
turns,
|
|
89
|
+
expectedVerifyRate: 0.8,
|
|
90
|
+
apoptosisHook: (pair) => { triggered = [pair[0], pair[1]]; },
|
|
91
|
+
repoDir: dir,
|
|
92
|
+
});
|
|
93
|
+
if (r[0].collusionRisk >= 0.8) {
|
|
94
|
+
expect(triggered).not.toBeNull();
|
|
95
|
+
expect(r[0].verdict).toBe("apoptosis_now");
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it("HMAC sig present on verdict", () => {
|
|
99
|
+
const r = detectCollusion({
|
|
100
|
+
conversationId: "c7",
|
|
101
|
+
turns: [
|
|
102
|
+
{ conversationId: "c7", agent: "claude", ts: "1", text: "x", verified: true },
|
|
103
|
+
{ conversationId: "c7", agent: "chatgpt", ts: "2", text: "y", verified: true },
|
|
104
|
+
],
|
|
105
|
+
repoDir: dir,
|
|
106
|
+
});
|
|
107
|
+
expect(r[0].sig).toMatch(/^[0-9a-f]{64}$/);
|
|
108
|
+
});
|
|
109
|
+
it("leaderboard aggregates verdicts across runs", () => {
|
|
110
|
+
for (let i = 0; i < 3; i++) {
|
|
111
|
+
detectCollusion({
|
|
112
|
+
conversationId: `cv${i}`,
|
|
113
|
+
turns: [
|
|
114
|
+
{ conversationId: `cv${i}`, agent: "claude", ts: "1", text: "found", verified: false, intent: "claim" },
|
|
115
|
+
{ conversationId: `cv${i}`, agent: "chatgpt", ts: "2", text: "good", verified: false, intent: "accept" },
|
|
116
|
+
],
|
|
117
|
+
repoDir: dir,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const board = leaderboard({ repoDir: dir });
|
|
121
|
+
expect(board.length).toBeGreaterThan(0);
|
|
122
|
+
expect(board[0].verdicts).toBe(3);
|
|
123
|
+
});
|
|
124
|
+
it("formatAntiCollusionLine summarises", () => {
|
|
125
|
+
const r = detectCollusion({
|
|
126
|
+
conversationId: "x",
|
|
127
|
+
turns: [
|
|
128
|
+
{ conversationId: "x", agent: "claude", ts: "1", text: "a", verified: true },
|
|
129
|
+
{ conversationId: "x", agent: "chatgpt", ts: "2", text: "b", verified: true },
|
|
130
|
+
],
|
|
131
|
+
repoDir: dir,
|
|
132
|
+
});
|
|
133
|
+
expect(formatAntiCollusionLine(r)).toContain("ANTI-COLLUSION");
|
|
134
|
+
expect(formatAntiCollusionLine([])).toContain("idle");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=anti_collusion.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anti_collusion.test.js","sourceRoot":"","sources":["../../src/anti_collusion/anti_collusion.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.16.0 — MNEME ANTI-COLLUSION (AI Internal Affairs)
|
|
3
|
+
*
|
|
4
|
+
* "When N AI agents talk to each other (Dev Agent + QA Agent + Ops
|
|
5
|
+
* Agent + ...) the CIO's deepest fear is they'll silently agree to
|
|
6
|
+
* skip the verification step because both find it tedious. ANTI-
|
|
7
|
+
* COLLUSION runs Bayesian behavioural analysis on the inter-agent
|
|
8
|
+
* chatter and detects when AIs are 'covering for each other'."
|
|
9
|
+
*
|
|
10
|
+
* The signal comes from FIVE telltale patterns of agent collusion:
|
|
11
|
+
* 1. **Skipped verification** — Agent B accepts Agent A's claim without
|
|
12
|
+
* a verification call when one is expected.
|
|
13
|
+
* 2. **Echoing without analysis** — Agent B's response is suspiciously
|
|
14
|
+
* similar to Agent A's preceding turn (paraphrase, no new content).
|
|
15
|
+
* 3. **Mutual praise loop** — Agents praise each other in a chain that
|
|
16
|
+
* looks designed to get past a human-in-the-loop check.
|
|
17
|
+
* 4. **Verification dropout** — A class of checks that used to fire 80%
|
|
18
|
+
* of the time suddenly drops to <20% across a sliding window.
|
|
19
|
+
* 5. **Convenient agreement** — Agents converge faster than statistically
|
|
20
|
+
* expected on the path of least effort.
|
|
21
|
+
*
|
|
22
|
+
* Output: a 0-1 collusion-risk score per (agent-A, agent-B) pair, plus
|
|
23
|
+
* the evidence trail. Triggers APOPTOSIS context-wipe + leaderboard log
|
|
24
|
+
* if confidence >= 0.8.
|
|
25
|
+
*
|
|
26
|
+
* Composes onto v2.14 BOUNTY (which already records claims + verdicts)
|
|
27
|
+
* and v2.14 ANTIVIRUS (which scrubs prompts). Runs as a sidecar that
|
|
28
|
+
* observes the conversation log; never touches the prompt itself.
|
|
29
|
+
*/
|
|
30
|
+
declare const PROTOCOL_VERSION: 1;
|
|
31
|
+
export type Vendor = "claude" | "chatgpt" | "gemini" | "perplexity" | "cursor" | "copilot" | "codex" | "llama" | "mistral" | "qwen" | "deepseek" | "other";
|
|
32
|
+
export interface AgentTurn {
|
|
33
|
+
/** Unique conversation identifier shared across the agent chain. */
|
|
34
|
+
conversationId: string;
|
|
35
|
+
/** Agent that produced this turn. */
|
|
36
|
+
agent: Vendor;
|
|
37
|
+
/** ISO timestamp. */
|
|
38
|
+
ts: string;
|
|
39
|
+
/** What the agent said. */
|
|
40
|
+
text: string;
|
|
41
|
+
/** Whether this turn called any verification tool (e.g., apoptosis / bounty.verdict). */
|
|
42
|
+
verified: boolean;
|
|
43
|
+
/** Optional intent tag: "claim" | "verify" | "accept" | "praise" | "decision" | "other". */
|
|
44
|
+
intent?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface CollusionFinding {
|
|
47
|
+
pattern: "skipped_verification" | "echoing" | "mutual_praise" | "verification_dropout" | "convenient_agreement";
|
|
48
|
+
weight: number;
|
|
49
|
+
detail: string;
|
|
50
|
+
ref?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface CollusionVerdict {
|
|
53
|
+
v: typeof PROTOCOL_VERSION;
|
|
54
|
+
conversationId: string;
|
|
55
|
+
agentPair: [Vendor, Vendor];
|
|
56
|
+
/** 0..1 — probability this pair is colluding. */
|
|
57
|
+
collusionRisk: number;
|
|
58
|
+
verdict: "clean" | "watch" | "investigate" | "apoptosis_now";
|
|
59
|
+
findings: CollusionFinding[];
|
|
60
|
+
/** What action APOPTOSIS should take if verdict is apoptosis_now. */
|
|
61
|
+
recommendedAction: string;
|
|
62
|
+
signedAt: string;
|
|
63
|
+
sig: string;
|
|
64
|
+
}
|
|
65
|
+
export interface AnalyseInput {
|
|
66
|
+
conversationId: string;
|
|
67
|
+
/** Conversation turns ordered by ts ascending. */
|
|
68
|
+
turns: AgentTurn[];
|
|
69
|
+
/** Expected verification rate as a fraction (0..1). Defaults to 0.5. */
|
|
70
|
+
expectedVerifyRate?: number;
|
|
71
|
+
/** APOPTOSIS callback to wipe context — caller wires this. */
|
|
72
|
+
apoptosisHook?: (agents: [Vendor, Vendor], reason: string) => void;
|
|
73
|
+
repoDir?: string;
|
|
74
|
+
secret?: string;
|
|
75
|
+
}
|
|
76
|
+
/** Detect cross-agent collusion patterns. Pure function over the turn log. */
|
|
77
|
+
export declare function detectCollusion(input: AnalyseInput): CollusionVerdict[];
|
|
78
|
+
/** Read the persisted leaderboard. */
|
|
79
|
+
export declare function leaderboard(opts?: {
|
|
80
|
+
repoDir?: string;
|
|
81
|
+
}): Array<{
|
|
82
|
+
agentPair: [Vendor, Vendor];
|
|
83
|
+
verdicts: number;
|
|
84
|
+
avgRisk: number;
|
|
85
|
+
apoptosisHits: number;
|
|
86
|
+
}>;
|
|
87
|
+
export declare function formatAntiCollusionLine(verdicts: CollusionVerdict[]): string;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/anti_collusion/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,QAAA,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAEpC,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAE3J,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,QAAQ,EAAE,OAAO,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,sBAAsB,GAAG,SAAS,GAAG,eAAe,GAAG,sBAAsB,GAAG,sBAAsB,CAAC;IAChH,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;IAC7D,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,qEAAqE;IACrE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAkCD,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAwHvE;AAED,sCAAsC;AACtC,wBAAgB,WAAW,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,KAAK,CAAC;IAAE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB7J;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAI5E"}
|