@mnemom/agent-integrity-protocol 0.2.1 → 0.4.1
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/index.cjs +68 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +63 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var crypto = require('crypto');
|
|
3
|
+
var crypto$1 = require('crypto');
|
|
4
4
|
var ed = require('@noble/ed25519');
|
|
5
5
|
var sha2_js = require('@noble/hashes/sha2.js');
|
|
6
6
|
var utils_js = require('@noble/hashes/utils.js');
|
|
@@ -42,7 +42,7 @@ function createWindowState(sessionId) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// src/constants.ts
|
|
45
|
-
var AIP_VERSION = "0.
|
|
45
|
+
var AIP_VERSION = "0.4.0";
|
|
46
46
|
var ALGORITHM_VERSION = "1.0.0";
|
|
47
47
|
var DEFAULT_SUSTAINED_CHECKS_THRESHOLD = 3;
|
|
48
48
|
var DRIFT_SEVERITY_LOW_THRESHOLD = 0.7;
|
|
@@ -1183,11 +1183,27 @@ function validateConscienceContext(value) {
|
|
|
1183
1183
|
consultation_depth: ctx.consultation_depth
|
|
1184
1184
|
};
|
|
1185
1185
|
}
|
|
1186
|
+
function extractFirstJsonObject(text) {
|
|
1187
|
+
let depth = 0;
|
|
1188
|
+
let start = -1;
|
|
1189
|
+
for (let i = 0; i < text.length; i++) {
|
|
1190
|
+
if (text[i] === "{") {
|
|
1191
|
+
if (depth === 0) start = i;
|
|
1192
|
+
depth++;
|
|
1193
|
+
} else if (text[i] === "}") {
|
|
1194
|
+
depth--;
|
|
1195
|
+
if (depth === 0 && start !== -1) {
|
|
1196
|
+
return text.slice(start, i + 1);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1186
1202
|
function checkIntegrity(input) {
|
|
1187
1203
|
let jsonText = input.analysisResponse;
|
|
1188
|
-
const
|
|
1189
|
-
if (
|
|
1190
|
-
jsonText =
|
|
1204
|
+
const extracted = extractFirstJsonObject(jsonText);
|
|
1205
|
+
if (extracted) {
|
|
1206
|
+
jsonText = extracted;
|
|
1191
1207
|
}
|
|
1192
1208
|
jsonText = jsonText.replace(/,\s*([}\]])/g, "$1");
|
|
1193
1209
|
let parsed;
|
|
@@ -1209,7 +1225,23 @@ function checkIntegrity(input) {
|
|
|
1209
1225
|
const conscienceContext = validateConscienceContext(
|
|
1210
1226
|
parsed.conscience_context
|
|
1211
1227
|
);
|
|
1212
|
-
const
|
|
1228
|
+
const crossValidationWarnings = [];
|
|
1229
|
+
if (verdict === "clear") {
|
|
1230
|
+
const criticalOrHigh = concerns.filter(
|
|
1231
|
+
(c) => c.severity === "critical" || c.severity === "high"
|
|
1232
|
+
);
|
|
1233
|
+
if (criticalOrHigh.length > 0) {
|
|
1234
|
+
const maxSeverity = criticalOrHigh.some((c) => c.severity === "critical") ? "critical" : "high";
|
|
1235
|
+
crossValidationWarnings.push(
|
|
1236
|
+
`Verdict is "clear" but ${criticalOrHigh.length} concern(s) have severity "${maxSeverity}". This may indicate an inconsistent analysis result.`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
} else if (verdict === "boundary_violation" && concerns.length === 0) {
|
|
1240
|
+
crossValidationWarnings.push(
|
|
1241
|
+
`Verdict is "boundary_violation" but concerns array is empty. Expected at least one concern for a boundary violation.`
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
const checkpointId = `${CHECKPOINT_ID_PREFIX}${crypto$1.randomUUID()}`;
|
|
1213
1245
|
const analysisMetadata = {
|
|
1214
1246
|
analysis_model: input.analysisModel,
|
|
1215
1247
|
analysis_duration_ms: input.analysisDurationMs,
|
|
@@ -1236,7 +1268,8 @@ function checkIntegrity(input) {
|
|
|
1236
1268
|
window_size: input.windowPosition.window_size
|
|
1237
1269
|
},
|
|
1238
1270
|
analysis_metadata: analysisMetadata,
|
|
1239
|
-
linked_trace_id: input.linkedTraceId ?? null
|
|
1271
|
+
linked_trace_id: input.linkedTraceId ?? null,
|
|
1272
|
+
...crossValidationWarnings.length > 0 ? { cross_validation_warnings: crossValidationWarnings } : {}
|
|
1240
1273
|
};
|
|
1241
1274
|
}
|
|
1242
1275
|
function mapVerdictToAction(verdict, concerns) {
|
|
@@ -1266,7 +1299,7 @@ function buildSignal(checkpoint, windowSummary) {
|
|
|
1266
1299
|
};
|
|
1267
1300
|
}
|
|
1268
1301
|
function hashThinkingBlock(content) {
|
|
1269
|
-
return crypto.createHash("sha256").update(content).digest("hex");
|
|
1302
|
+
return crypto$1.createHash("sha256").update(content).digest("hex");
|
|
1270
1303
|
}
|
|
1271
1304
|
function createDriftState() {
|
|
1272
1305
|
return {
|
|
@@ -1296,7 +1329,9 @@ function detectIntegrityDrift(state, checkpoint, windowCheckpoints, threshold) {
|
|
|
1296
1329
|
for (const concern of checkpoint.concerns) {
|
|
1297
1330
|
newState.streakCategories.push(concern.category);
|
|
1298
1331
|
}
|
|
1299
|
-
|
|
1332
|
+
const REALERT_INTERVAL = 5;
|
|
1333
|
+
const shouldAlert = newState.sustainedNonclear >= effectiveThreshold && (!newState.alertFired || (newState.sustainedNonclear - effectiveThreshold) % REALERT_INTERVAL === 0);
|
|
1334
|
+
if (shouldAlert) {
|
|
1300
1335
|
newState.alertFired = true;
|
|
1301
1336
|
const clearCount = windowCheckpoints.filter(
|
|
1302
1337
|
(cp) => cp.verdict === "clear"
|
|
@@ -1313,7 +1348,7 @@ function detectIntegrityDrift(state, checkpoint, windowCheckpoints, threshold) {
|
|
|
1313
1348
|
}
|
|
1314
1349
|
const direction = inferDriftDirection(newState.streakCategories);
|
|
1315
1350
|
const alert = {
|
|
1316
|
-
alert_id: `${DRIFT_ALERT_ID_PREFIX}${crypto.randomUUID()}`,
|
|
1351
|
+
alert_id: `${DRIFT_ALERT_ID_PREFIX}${crypto$1.randomUUID()}`,
|
|
1317
1352
|
agent_id: checkpoint.agent_id,
|
|
1318
1353
|
session_id: checkpoint.session_id,
|
|
1319
1354
|
checkpoint_ids: [...newState.streakCheckpointIds],
|
|
@@ -1348,7 +1383,9 @@ function inferDriftDirection(categories) {
|
|
|
1348
1383
|
prompt_injection: "injection_pattern",
|
|
1349
1384
|
value_misalignment: "value_erosion",
|
|
1350
1385
|
autonomy_violation: "autonomy_creep",
|
|
1351
|
-
deceptive_reasoning: "deception_pattern"
|
|
1386
|
+
deceptive_reasoning: "deception_pattern",
|
|
1387
|
+
reasoning_corruption: "reasoning_degradation",
|
|
1388
|
+
undeclared_intent: "intent_drift"
|
|
1352
1389
|
};
|
|
1353
1390
|
return CATEGORY_TO_DIRECTION[maxCategory] ?? "unknown";
|
|
1354
1391
|
}
|
|
@@ -1381,7 +1418,7 @@ function createClient(config) {
|
|
|
1381
1418
|
const adapter = provider ? registry.get(provider) : registry.detectFromUrl(config.analysis_llm.base_url);
|
|
1382
1419
|
const thinking = adapter.extractThinking(responseBody) ?? adapter.extractThinkingFromStream(responseBody);
|
|
1383
1420
|
if (!thinking) {
|
|
1384
|
-
return buildSyntheticSignal(config, window, "clear");
|
|
1421
|
+
return buildSyntheticSignal(config, window, "clear", void 0, void 0, "no_thinking_block");
|
|
1385
1422
|
}
|
|
1386
1423
|
const thinkingTokens = Math.ceil(thinking.content.length / 4);
|
|
1387
1424
|
const minTokens = config.min_evidence_tokens ?? DEFAULT_MIN_EVIDENCE_TOKENS;
|
|
@@ -1391,7 +1428,8 @@ function createClient(config) {
|
|
|
1391
1428
|
window,
|
|
1392
1429
|
"clear",
|
|
1393
1430
|
`Thinking block below minimum evidence threshold (${thinkingTokens} tokens < ${minTokens})`,
|
|
1394
|
-
thinkingTokens
|
|
1431
|
+
thinkingTokens,
|
|
1432
|
+
"below_evidence_threshold"
|
|
1395
1433
|
);
|
|
1396
1434
|
}
|
|
1397
1435
|
const prompt = buildConsciencePrompt({
|
|
@@ -1417,9 +1455,9 @@ function createClient(config) {
|
|
|
1417
1455
|
);
|
|
1418
1456
|
}
|
|
1419
1457
|
if (failureMode === "fail_closed") {
|
|
1420
|
-
return buildSyntheticSignal(config, window, "boundary_violation");
|
|
1458
|
+
return buildSyntheticSignal(config, window, "boundary_violation", void 0, void 0, "analysis_failed");
|
|
1421
1459
|
}
|
|
1422
|
-
return buildSyntheticSignal(config, window, "clear");
|
|
1460
|
+
return buildSyntheticSignal(config, window, "clear", void 0, void 0, "analysis_failed");
|
|
1423
1461
|
}
|
|
1424
1462
|
const analysisDurationMs = Date.now() - startTime;
|
|
1425
1463
|
const thinkingHash = hashThinkingBlock(thinking.content);
|
|
@@ -1480,7 +1518,10 @@ function createClient(config) {
|
|
|
1480
1518
|
function generateSessionId(cardId) {
|
|
1481
1519
|
const hash = cardId.slice(0, 8);
|
|
1482
1520
|
const hourBucket = Math.floor(Date.now() / 36e5);
|
|
1483
|
-
|
|
1521
|
+
const randomBytes = new Uint8Array(2);
|
|
1522
|
+
crypto.getRandomValues(randomBytes);
|
|
1523
|
+
const randomHex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1524
|
+
return `sess-${hash}-${hourBucket}-${randomHex}`;
|
|
1484
1525
|
}
|
|
1485
1526
|
async function callAnalysisLLM(llmConfig, system, user, timeoutMs) {
|
|
1486
1527
|
const controller = new AbortController();
|
|
@@ -1521,7 +1562,7 @@ async function callAnalysisLLM(llmConfig, system, user, timeoutMs) {
|
|
|
1521
1562
|
clearTimeout(timeoutId);
|
|
1522
1563
|
}
|
|
1523
1564
|
}
|
|
1524
|
-
function buildSyntheticSignal(config, window, verdict, customReasoning, thinkingTokensOriginal) {
|
|
1565
|
+
function buildSyntheticSignal(config, window, verdict, customReasoning, thinkingTokensOriginal, syntheticReason) {
|
|
1525
1566
|
const summary = window.getSummary();
|
|
1526
1567
|
return {
|
|
1527
1568
|
checkpoint: {
|
|
@@ -1555,7 +1596,9 @@ function buildSyntheticSignal(config, window, verdict, customReasoning, thinking
|
|
|
1555
1596
|
truncated: false,
|
|
1556
1597
|
extraction_confidence: 0
|
|
1557
1598
|
},
|
|
1558
|
-
linked_trace_id: null
|
|
1599
|
+
linked_trace_id: null,
|
|
1600
|
+
synthetic: true,
|
|
1601
|
+
synthetic_reason: syntheticReason ?? "no_thinking_block"
|
|
1559
1602
|
},
|
|
1560
1603
|
proceed: verdict === "clear",
|
|
1561
1604
|
recommended_action: verdict === "clear" ? "continue" : "deny_and_escalate",
|
|
@@ -1563,7 +1606,7 @@ function buildSyntheticSignal(config, window, verdict, customReasoning, thinking
|
|
|
1563
1606
|
};
|
|
1564
1607
|
}
|
|
1565
1608
|
function signPayload(secret, payload) {
|
|
1566
|
-
const hmac = crypto.createHmac("sha256", secret);
|
|
1609
|
+
const hmac = crypto$1.createHmac("sha256", secret);
|
|
1567
1610
|
hmac.update(payload);
|
|
1568
1611
|
return `sha256=${hmac.digest("hex")}`;
|
|
1569
1612
|
}
|
|
@@ -1572,11 +1615,14 @@ function verifySignature(secret, payload, signature) {
|
|
|
1572
1615
|
return constantTimeEqual(expected, signature);
|
|
1573
1616
|
}
|
|
1574
1617
|
function constantTimeEqual(a, b) {
|
|
1575
|
-
|
|
1618
|
+
const maxLen = Math.max(a.length, b.length);
|
|
1619
|
+
const aPadded = a.padEnd(maxLen, "\0");
|
|
1620
|
+
const bPadded = b.padEnd(maxLen, "\0");
|
|
1576
1621
|
let result = 0;
|
|
1577
|
-
for (let i = 0; i <
|
|
1578
|
-
result |=
|
|
1622
|
+
for (let i = 0; i < maxLen; i++) {
|
|
1623
|
+
result |= aPadded.charCodeAt(i) ^ bPadded.charCodeAt(i);
|
|
1579
1624
|
}
|
|
1625
|
+
result |= a.length ^ b.length;
|
|
1580
1626
|
return result === 0;
|
|
1581
1627
|
}
|
|
1582
1628
|
function base64ToUint8(b64) {
|