"use strict";
/**
* @file Denial tracker — records tool denials to avoid repeated blocked attempts.
*
* When the model hits a security/permission boundary, the denial is recorded.
* On subsequent calls, if the same denial pattern would recur, the model gets
* a consolidated reminder listing all active denials — this saves context tokens
* and prevents frustration loops.
*
* Denials expire after 10 minutes to handle config changes mid-session.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.denialTracker = exports.DenialTracker = void 0;
const EXPIRY_MS = 10 * 60_000; // 10 minutes
class DenialTracker {
constructor() {
this.denials = new Map();
}
/**
* Record a denial. Key is tool name + error code to group similar denials.
*/
record(toolName, errorCode, reason) {
const key = `${toolName}:${errorCode}`;
const now = Date.now();
const existing = this.denials.get(key);
if (existing) {
existing.count++;
existing.lastAt = now;
existing.reason = reason; // keep latest reason
}
else {
this.denials.set(key, { toolName, reason, errorCode, count: 1, firstAt: now, lastAt: now });
}
this.cleanup();
}
/**
* Check if a tool+code combination has been denied before.
* Returns the denial entry if found and not expired, null otherwise.
*/
check(toolName, errorCode) {
const key = `${toolName}:${errorCode}`;
const d = this.denials.get(key);
if (!d)
return null;
if (Date.now() - d.lastAt > EXPIRY_MS) {
this.denials.delete(key);
return null;
}
return d;
}
/**
* Get a consolidated summary of all active denials.
* Returns null if there are no active denials.
*/
getSummary() {
this.cleanup();
if (this.denials.size === 0)
return null;
const lines = ["⛔ ACTIVE RESTRICTIONS (do not retry these):"];
for (const d of this.denials.values()) {
const countNote = d.count > 1 ? ` (denied ${d.count}×)` : "";
lines.push(` • ${d.toolName}: ${d.reason}${countNote}`);
}
return lines.join("\n");
}
/**
* Check if a specific denial has been hit too many times (3+).
* If so, return a warning to prepend to the tool response.
*/
getRepeatWarning(toolName, errorCode) {
const d = this.check(toolName, errorCode);
if (!d || d.count < 3)
return null;
return `⚠️ You have already been denied "${toolName}" ${d.count} times for the same reason. ` +
`Do NOT retry — try a different approach or ask the user for help.`;
}
/** Remove expired entries. */
cleanup() {
const now = Date.now();
for (const [key, d] of this.denials) {
if (now - d.lastAt > EXPIRY_MS)
this.denials.delete(key);
}
}
/** Reset all denials (e.g. when config changes). */
reset() {
this.denials.clear();
}
}
exports.DenialTracker = DenialTracker;
/** Singleton instance shared across all tools. */
exports.denialTracker = new DenialTracker();
//# sourceMappingURL=denialTracker.js.map