tasq/node_modules/@claude-flow/guidance/dist/trust.js

473 lines
15 KiB
JavaScript

/**
* Trust Score Accumulation System
*
* Builds trust gradients from gate outcomes over time. Sits alongside the
* CoherenceScheduler (coherence.ts) but tracks a separate dimension:
* accumulated trust from successful/failed gate evaluations.
*
* TrustAccumulator:
* - Maintains a running trust score per agent (0.0 to 1.0)
* - Accumulates trust from gate outcomes (allow, deny, warn)
* - Applies exponential decay toward the initial value when idle
* - Maps trust scores to privilege tiers (trusted, standard, probation, untrusted)
*
* TrustLedger:
* - Records every trust score change with full context
* - Supports export/import for persistence
* - Querying by agent or threshold
*
* Trust-based rate limiting:
* - Adjusts rate limits proportionally to accumulated trust
*
* @module @claude-flow/guidance/trust
*/
// ============================================================================
// Default Configuration
// ============================================================================
const DEFAULT_TRUST_CONFIG = {
initialTrust: 0.5,
allowDelta: 0.01,
denyDelta: -0.05,
warnDelta: -0.02,
decayRate: 0.01,
decayIntervalMs: 60_000, // 1 minute
};
// ============================================================================
// Trust Tier Thresholds
// ============================================================================
const TIER_THRESHOLDS = {
trusted: 0.8,
standard: 0.5,
probation: 0.3,
};
// ============================================================================
// Rate Limit Multipliers
// ============================================================================
const RATE_LIMIT_MULTIPLIERS = {
trusted: 2.0,
standard: 1.0,
probation: 0.5,
untrusted: 0.1,
};
// ============================================================================
// Trust Accumulator
// ============================================================================
/**
* Maintains running trust scores per agent, accumulates trust from gate
* outcomes, applies time-based exponential decay, and maps scores to
* privilege tiers.
*/
export class TrustAccumulator {
config;
agents = new Map();
constructor(config = {}) {
this.config = { ...DEFAULT_TRUST_CONFIG, ...config };
}
/**
* Record a gate outcome for an agent, adjusting their trust score.
*
* - 'allow' increases trust by `allowDelta`
* - 'deny' decreases trust by `denyDelta` (negative value)
* - 'warn' decreases trust by `warnDelta` (negative value)
*
* Before applying the delta, exponential decay is applied if enough
* time has elapsed since the last update.
*
* Returns the trust record describing the change.
*/
recordOutcome(agentId, outcome, reason) {
const state = this.getOrCreateState(agentId);
const now = Date.now();
// Apply decay before the outcome delta
this.applyDecay(state, now);
const previousScore = state.score;
// Determine delta from outcome
let delta;
switch (outcome) {
case 'allow':
delta = this.config.allowDelta;
break;
case 'deny':
delta = this.config.denyDelta;
break;
case 'warn':
delta = this.config.warnDelta;
break;
}
// Apply delta and clamp to [0, 1]
state.score = clamp(state.score + delta, 0, 1);
state.totalEvents++;
state.lastUpdated = now;
return {
agentId,
previousScore,
newScore: state.score,
delta,
reason,
timestamp: now,
gateDecision: outcome,
};
}
/**
* Get the current trust score for an agent.
* Returns the configured initial trust if the agent is unknown.
*/
getScore(agentId) {
const state = this.agents.get(agentId);
if (!state)
return this.config.initialTrust;
// Apply decay before reading (non-mutating copy for read)
const now = Date.now();
const elapsed = now - state.lastUpdated;
if (elapsed >= this.config.decayIntervalMs) {
this.applyDecay(state, now);
}
return state.score;
}
/**
* Determine the privilege tier for an agent based on their trust score.
*
* - >= 0.8: 'trusted' (expanded privileges, higher rate limits)
* - >= 0.5: 'standard' (normal operation)
* - >= 0.3: 'probation' (restricted tools, lower rate limits)
* - < 0.3: 'untrusted' (read-only, must earn trust back)
*/
getTier(agentId) {
const score = this.getScore(agentId);
return scoreToTier(score);
}
/**
* Get a full snapshot of an agent's trust state.
*/
getSnapshot(agentId) {
const score = this.getScore(agentId);
const state = this.agents.get(agentId);
return {
agentId,
score,
tier: scoreToTier(score),
totalEvents: state?.totalEvents ?? 0,
lastUpdated: state?.lastUpdated ?? 0,
};
}
/**
* Get snapshots for all tracked agents.
*/
getAllSnapshots() {
const snapshots = [];
for (const agentId of this.agents.keys()) {
snapshots.push(this.getSnapshot(agentId));
}
return snapshots;
}
/**
* Get a trust-adjusted rate limit for an agent.
*
* Multipliers by tier:
* - trusted: 2x base limit
* - standard: 1x base limit
* - probation: 0.5x base limit
* - untrusted: 0.1x base limit
*/
getTrustBasedRateLimit(agentId, baseLimit) {
const tier = this.getTier(agentId);
return Math.floor(baseLimit * RATE_LIMIT_MULTIPLIERS[tier]);
}
/**
* Manually set an agent's trust score (e.g., from persistence restore).
* Clamps to [0, 1].
*/
setScore(agentId, score) {
const state = this.getOrCreateState(agentId);
state.score = clamp(score, 0, 1);
state.lastUpdated = Date.now();
}
/**
* Remove an agent from tracking entirely.
*/
removeAgent(agentId) {
return this.agents.delete(agentId);
}
/**
* Get the number of tracked agents.
*/
get agentCount() {
return this.agents.size;
}
/**
* Get all tracked agent IDs.
*/
getAgentIds() {
return [...this.agents.keys()];
}
/**
* Get the current configuration.
*/
getConfig() {
return { ...this.config };
}
/**
* Reset all tracked agents.
*/
clear() {
this.agents.clear();
}
// ===== Private =====
getOrCreateState(agentId) {
let state = this.agents.get(agentId);
if (!state) {
state = {
score: this.config.initialTrust,
totalEvents: 0,
lastUpdated: Date.now(),
};
this.agents.set(agentId, state);
}
return state;
}
/**
* Apply exponential decay toward the initial trust value.
*
* The decay formula moves the score toward `initialTrust` by a fraction
* proportional to the number of decay intervals elapsed:
*
* score = score + (initialTrust - score) * (1 - (1 - decayRate)^intervals)
*
* This ensures idle agents gradually return to the baseline.
*/
applyDecay(state, now) {
const elapsed = now - state.lastUpdated;
if (elapsed < this.config.decayIntervalMs)
return;
const intervals = Math.floor(elapsed / this.config.decayIntervalMs);
if (intervals <= 0)
return;
const retainFactor = Math.pow(1 - this.config.decayRate, intervals);
const target = this.config.initialTrust;
// Exponential interpolation toward target
state.score = target + (state.score - target) * retainFactor;
state.lastUpdated = now;
}
}
// ============================================================================
// Trust Ledger
// ============================================================================
/**
* Records all trust score changes with full context. Supports persistence
* via export/import and querying by agent or threshold.
*/
export class TrustLedger {
records = [];
static MAX_RECORDS = 10_000;
/**
* Append a trust record to the ledger.
*/
record(entry) {
this.records.push(entry);
// Evict oldest records when the ledger exceeds capacity
if (this.records.length > TrustLedger.MAX_RECORDS) {
this.records = this.records.slice(-TrustLedger.MAX_RECORDS);
}
}
/**
* Get the full trust history for a specific agent, ordered chronologically.
*/
getHistoryForAgent(agentId) {
return this.records.filter(r => r.agentId === agentId);
}
/**
* Get all agents whose most recent score is below the given threshold.
* Returns one record per agent (the most recent).
*/
getAgentsBelowThreshold(threshold) {
const latestByAgent = new Map();
for (const record of this.records) {
const existing = latestByAgent.get(record.agentId);
if (!existing || record.timestamp > existing.timestamp) {
latestByAgent.set(record.agentId, record);
}
}
const result = [];
for (const record of latestByAgent.values()) {
if (record.newScore < threshold) {
result.push(record);
}
}
return result;
}
/**
* Get all agents whose most recent score is at or above the given threshold.
* Returns one record per agent (the most recent).
*/
getAgentsAboveThreshold(threshold) {
const latestByAgent = new Map();
for (const record of this.records) {
const existing = latestByAgent.get(record.agentId);
if (!existing || record.timestamp > existing.timestamp) {
latestByAgent.set(record.agentId, record);
}
}
const result = [];
for (const record of latestByAgent.values()) {
if (record.newScore >= threshold) {
result.push(record);
}
}
return result;
}
/**
* Get records within a time range.
*/
getRecordsInRange(startMs, endMs) {
return this.records.filter(r => r.timestamp >= startMs && r.timestamp <= endMs);
}
/**
* Get the most recent N records.
*/
getRecentRecords(count) {
return this.records.slice(-count);
}
/**
* Get the total number of records.
*/
get recordCount() {
return this.records.length;
}
/**
* Export all records for persistence.
*/
exportRecords() {
return [...this.records];
}
/**
* Import records from persistence. Appends to existing records.
*/
importRecords(records) {
this.records.push(...records);
// Re-enforce capacity limit after import
if (this.records.length > TrustLedger.MAX_RECORDS) {
this.records = this.records.slice(-TrustLedger.MAX_RECORDS);
}
}
/**
* Clear all records.
*/
clear() {
this.records = [];
}
}
// ============================================================================
// Integrated Trust System
// ============================================================================
/**
* Combines TrustAccumulator and TrustLedger into a single coordinated
* system. Gate outcomes are accumulated and automatically logged.
*/
export class TrustSystem {
accumulator;
ledger;
constructor(config = {}) {
this.accumulator = new TrustAccumulator(config);
this.ledger = new TrustLedger();
}
/**
* Record a gate outcome, update the accumulator, and log to the ledger.
*/
recordOutcome(agentId, outcome, reason) {
const record = this.accumulator.recordOutcome(agentId, outcome, reason);
this.ledger.record(record);
return record;
}
/**
* Get the current trust score for an agent.
*/
getScore(agentId) {
return this.accumulator.getScore(agentId);
}
/**
* Get the current privilege tier for an agent.
*/
getTier(agentId) {
return this.accumulator.getTier(agentId);
}
/**
* Get a trust-adjusted rate limit for an agent.
*/
getTrustBasedRateLimit(agentId, baseLimit) {
return this.accumulator.getTrustBasedRateLimit(agentId, baseLimit);
}
/**
* Get a full snapshot of an agent's trust state.
*/
getSnapshot(agentId) {
return this.accumulator.getSnapshot(agentId);
}
/**
* Get snapshots for all tracked agents.
*/
getAllSnapshots() {
return this.accumulator.getAllSnapshots();
}
}
// ============================================================================
// Standalone Rate Limit Helper
// ============================================================================
/**
* Compute a trust-adjusted rate limit from a score and base limit.
*
* This is a stateless utility for cases where you have a trust score
* but no TrustAccumulator instance.
*
* Multipliers by tier:
* - trusted (>= 0.8): 2x
* - standard (>= 0.5): 1x
* - probation (>= 0.3): 0.5x
* - untrusted (< 0.3): 0.1x
*/
export function getTrustBasedRateLimit(score, baseLimit) {
const tier = scoreToTier(score);
return Math.floor(baseLimit * RATE_LIMIT_MULTIPLIERS[tier]);
}
// ============================================================================
// Factory Functions
// ============================================================================
/**
* Create a TrustAccumulator with optional configuration.
*/
export function createTrustAccumulator(config) {
return new TrustAccumulator(config);
}
/**
* Create an empty TrustLedger.
*/
export function createTrustLedger() {
return new TrustLedger();
}
/**
* Create a coordinated TrustSystem (accumulator + ledger).
*/
export function createTrustSystem(config) {
return new TrustSystem(config);
}
// ============================================================================
// Helpers
// ============================================================================
/**
* Map a trust score to a privilege tier.
*/
function scoreToTier(score) {
if (score >= TIER_THRESHOLDS.trusted)
return 'trusted';
if (score >= TIER_THRESHOLDS.standard)
return 'standard';
if (score >= TIER_THRESHOLDS.probation)
return 'probation';
return 'untrusted';
}
/**
* Clamp a number to the range [min, max].
*/
function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
//# sourceMappingURL=trust.js.map