@mandatedev/agent 0.1.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/index.d.mts +275 -0
- package/dist/index.d.ts +275 -0
- package/dist/index.js +643 -0
- package/dist/index.mjs +615 -0
- package/package.json +42 -0
- package/src/buffer/index.ts +152 -0
- package/src/degradation/index.ts +128 -0
- package/src/evaluator/js-evaluator.ts +183 -0
- package/src/hooks/anthropic.ts +134 -0
- package/src/hooks/langchain.ts +141 -0
- package/src/hooks/openai.ts +142 -0
- package/src/index.ts +175 -0
- package/src/types.ts +162 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MANDATE — LangChain / LangGraph Hook
|
|
3
|
+
// Uses before_tool_call callback for full semantic enforcement.
|
|
4
|
+
// Compatible with LangChain.js and LangGraph.
|
|
5
|
+
// ============================================================
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AgentIntent,
|
|
9
|
+
MandateConfig,
|
|
10
|
+
EvaluationResult,
|
|
11
|
+
} from '../types';
|
|
12
|
+
import type { JSPolicyEvaluator } from '../evaluator/js-evaluator';
|
|
13
|
+
import type { AuditBuffer } from '../buffer';
|
|
14
|
+
import type { DegradationManager } from '../degradation';
|
|
15
|
+
|
|
16
|
+
interface LangChainToolCall {
|
|
17
|
+
name: string;
|
|
18
|
+
args: Record<string, unknown>;
|
|
19
|
+
id?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class MandateLangChainHook {
|
|
23
|
+
private evaluator: JSPolicyEvaluator;
|
|
24
|
+
private buffer: AuditBuffer;
|
|
25
|
+
private degradation: DegradationManager;
|
|
26
|
+
private config: MandateConfig;
|
|
27
|
+
private sessionId: string;
|
|
28
|
+
private stepCounter: number = 0;
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
config: MandateConfig,
|
|
32
|
+
evaluator: JSPolicyEvaluator,
|
|
33
|
+
buffer: AuditBuffer,
|
|
34
|
+
degradation: DegradationManager
|
|
35
|
+
) {
|
|
36
|
+
this.config = config;
|
|
37
|
+
this.evaluator = evaluator;
|
|
38
|
+
this.buffer = buffer;
|
|
39
|
+
this.degradation = degradation;
|
|
40
|
+
this.sessionId = `sess_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Returns a before_tool_call callback for LangChain
|
|
44
|
+
// Usage: agent.beforeToolCall = mandateHook.getBeforeToolCallHook()
|
|
45
|
+
getBeforeToolCallHook(): (
|
|
46
|
+
toolCall: LangChainToolCall
|
|
47
|
+
) => Promise<LangChainToolCall | null> {
|
|
48
|
+
return async (
|
|
49
|
+
toolCall: LangChainToolCall
|
|
50
|
+
): Promise<LangChainToolCall | null> => {
|
|
51
|
+
const step = this.stepCounter++;
|
|
52
|
+
const intent = this.buildIntent(toolCall, step);
|
|
53
|
+
const result = this.evaluator.evaluate(intent);
|
|
54
|
+
|
|
55
|
+
this.logToBuffer(intent, result);
|
|
56
|
+
|
|
57
|
+
if (result.decision === 'ALLOW') {
|
|
58
|
+
return toolCall;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (result.decision === 'THROTTLE') {
|
|
62
|
+
await this.delay(2000);
|
|
63
|
+
this.config.onAlert?.(intent, result.anomalyScore ?? 0);
|
|
64
|
+
return toolCall;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// DENY or ESCALATE — block the tool call
|
|
68
|
+
this.config.onViolation?.(intent, result);
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Direct interception for manual use
|
|
74
|
+
async interceptToolCall(
|
|
75
|
+
toolCall: LangChainToolCall
|
|
76
|
+
): Promise<{ allowed: boolean; result: EvaluationResult }> {
|
|
77
|
+
const step = this.stepCounter++;
|
|
78
|
+
const intent = this.buildIntent(toolCall, step);
|
|
79
|
+
const result = this.evaluator.evaluate(intent);
|
|
80
|
+
|
|
81
|
+
this.logToBuffer(intent, result);
|
|
82
|
+
|
|
83
|
+
if (result.decision === 'DENY' || result.decision === 'ESCALATE') {
|
|
84
|
+
this.config.onViolation?.(intent, result);
|
|
85
|
+
return { allowed: false, result };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (result.decision === 'THROTTLE') {
|
|
89
|
+
await this.delay(2000);
|
|
90
|
+
this.config.onAlert?.(intent, result.anomalyScore ?? 0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { allowed: true, result };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================================
|
|
97
|
+
// PRIVATE
|
|
98
|
+
// ============================================================
|
|
99
|
+
|
|
100
|
+
private buildIntent(
|
|
101
|
+
toolCall: LangChainToolCall,
|
|
102
|
+
step: number
|
|
103
|
+
): AgentIntent {
|
|
104
|
+
return {
|
|
105
|
+
toolName: toolCall.name,
|
|
106
|
+
args: toolCall.args,
|
|
107
|
+
context: {
|
|
108
|
+
agentId: this.config.agentId,
|
|
109
|
+
sessionId: this.sessionId,
|
|
110
|
+
environment: this.config.environment,
|
|
111
|
+
stepInChain: step,
|
|
112
|
+
framework: 'langchain',
|
|
113
|
+
timestamp: Date.now(),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private logToBuffer(intent: AgentIntent, result: EvaluationResult): void {
|
|
119
|
+
if (this.config.auditLevel === 'off') return;
|
|
120
|
+
|
|
121
|
+
this.buffer.append({
|
|
122
|
+
timestamp: Date.now(),
|
|
123
|
+
source: 'REALTIME',
|
|
124
|
+
agentId: this.config.agentId,
|
|
125
|
+
orgId: this.config.orgId,
|
|
126
|
+
policyHash: this.config.policy.policyHash,
|
|
127
|
+
degradationTier: this.degradation.getCurrentTier(),
|
|
128
|
+
toolName: intent.toolName,
|
|
129
|
+
toolArgs: this.config.auditLevel === 'full' ? intent.args : {},
|
|
130
|
+
intentContext: intent.context,
|
|
131
|
+
anomalyScore: result.anomalyScore ?? 0,
|
|
132
|
+
policyDecision: result.decision,
|
|
133
|
+
responseLevel: 1,
|
|
134
|
+
evalLatencyMs: result.latencyMs,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private delay(ms: number): Promise<void> {
|
|
139
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MANDATE — OpenAI Assistants API + Function Calling Hook
|
|
3
|
+
// Intercepts function_call declarations before execution.
|
|
4
|
+
// Full semantic enforcement on structured tool-call intent.
|
|
5
|
+
// ============================================================
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AgentIntent,
|
|
9
|
+
MandateConfig,
|
|
10
|
+
EvaluationResult,
|
|
11
|
+
} from '../types';
|
|
12
|
+
import type { JSPolicyEvaluator } from '../evaluator/js-evaluator';
|
|
13
|
+
import type { AuditBuffer } from '../buffer';
|
|
14
|
+
import type { DegradationManager } from '../degradation';
|
|
15
|
+
|
|
16
|
+
interface OpenAIFunctionCall {
|
|
17
|
+
name: string;
|
|
18
|
+
arguments: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface OpenAIToolCall {
|
|
22
|
+
id: string;
|
|
23
|
+
type: 'function';
|
|
24
|
+
function: OpenAIFunctionCall;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface InterceptResult {
|
|
28
|
+
allowed: OpenAIToolCall[];
|
|
29
|
+
blocked: Array<{ toolCall: OpenAIToolCall; result: EvaluationResult }>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class MandateOpenAIHook {
|
|
33
|
+
private evaluator: JSPolicyEvaluator;
|
|
34
|
+
private buffer: AuditBuffer;
|
|
35
|
+
private degradation: DegradationManager;
|
|
36
|
+
private config: MandateConfig;
|
|
37
|
+
private sessionId: string;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
config: MandateConfig,
|
|
41
|
+
evaluator: JSPolicyEvaluator,
|
|
42
|
+
buffer: AuditBuffer,
|
|
43
|
+
degradation: DegradationManager
|
|
44
|
+
) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.evaluator = evaluator;
|
|
47
|
+
this.buffer = buffer;
|
|
48
|
+
this.degradation = degradation;
|
|
49
|
+
this.sessionId = this.generateSessionId();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Intercept OpenAI tool calls before execution
|
|
53
|
+
async interceptToolCalls(
|
|
54
|
+
toolCalls: OpenAIToolCall[],
|
|
55
|
+
stepInChain: number = 0
|
|
56
|
+
): Promise<InterceptResult> {
|
|
57
|
+
const allowed: OpenAIToolCall[] = [];
|
|
58
|
+
const blocked: Array<{
|
|
59
|
+
toolCall: OpenAIToolCall;
|
|
60
|
+
result: EvaluationResult;
|
|
61
|
+
}> = [];
|
|
62
|
+
|
|
63
|
+
for (const toolCall of toolCalls) {
|
|
64
|
+
const intent = this.buildIntent(toolCall, stepInChain);
|
|
65
|
+
const result = this.evaluator.evaluate(intent);
|
|
66
|
+
|
|
67
|
+
this.logToBuffer(intent, result);
|
|
68
|
+
|
|
69
|
+
if (result.decision === 'ALLOW') {
|
|
70
|
+
allowed.push(toolCall);
|
|
71
|
+
} else if (result.decision === 'THROTTLE') {
|
|
72
|
+
await this.delay(2000);
|
|
73
|
+
this.config.onAlert?.(intent, result.anomalyScore ?? 0);
|
|
74
|
+
allowed.push(toolCall);
|
|
75
|
+
} else {
|
|
76
|
+
blocked.push({ toolCall, result });
|
|
77
|
+
this.config.onViolation?.(intent, result);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { allowed, blocked };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================================
|
|
85
|
+
// PRIVATE
|
|
86
|
+
// ============================================================
|
|
87
|
+
|
|
88
|
+
private buildIntent(
|
|
89
|
+
toolCall: OpenAIToolCall,
|
|
90
|
+
stepInChain: number
|
|
91
|
+
): AgentIntent {
|
|
92
|
+
let args: Record<string, unknown> = {};
|
|
93
|
+
try {
|
|
94
|
+
const parsed: unknown = JSON.parse(toolCall.function.arguments);
|
|
95
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
96
|
+
args = parsed as Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
args = { raw: toolCall.function.arguments };
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
toolName: toolCall.function.name,
|
|
103
|
+
args,
|
|
104
|
+
context: {
|
|
105
|
+
agentId: this.config.agentId,
|
|
106
|
+
sessionId: this.sessionId,
|
|
107
|
+
environment: this.config.environment,
|
|
108
|
+
stepInChain,
|
|
109
|
+
framework: 'openai-assistants',
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private logToBuffer(intent: AgentIntent, result: EvaluationResult): void {
|
|
116
|
+
if (this.config.auditLevel === 'off') return;
|
|
117
|
+
|
|
118
|
+
this.buffer.append({
|
|
119
|
+
timestamp: Date.now(),
|
|
120
|
+
source: 'REALTIME',
|
|
121
|
+
agentId: this.config.agentId,
|
|
122
|
+
orgId: this.config.orgId,
|
|
123
|
+
policyHash: this.config.policy.policyHash,
|
|
124
|
+
degradationTier: this.degradation.getCurrentTier(),
|
|
125
|
+
toolName: intent.toolName,
|
|
126
|
+
toolArgs: this.config.auditLevel === 'full' ? intent.args : {},
|
|
127
|
+
intentContext: intent.context,
|
|
128
|
+
anomalyScore: result.anomalyScore ?? 0,
|
|
129
|
+
policyDecision: result.decision,
|
|
130
|
+
responseLevel: 1,
|
|
131
|
+
evalLatencyMs: result.latencyMs,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private generateSessionId(): string {
|
|
136
|
+
return `sess_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private delay(ms: number): Promise<void> {
|
|
140
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
141
|
+
}
|
|
142
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// @mandate/agent — Trust Engine for the Agent Economy
|
|
3
|
+
// The Mandate Agent SDK main entry point
|
|
4
|
+
// Every developer imports from here
|
|
5
|
+
// ============================================================
|
|
6
|
+
|
|
7
|
+
import { JSPolicyEvaluator } from './evaluator/js-evaluator';
|
|
8
|
+
import { AuditBuffer } from './buffer';
|
|
9
|
+
import { DegradationManager } from './degradation';
|
|
10
|
+
import { MandateOpenAIHook } from './hooks/openai';
|
|
11
|
+
import { MandateLangChainHook } from './hooks/langchain';
|
|
12
|
+
import { MandateAnthropicHook } from './hooks/anthropic';
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
MandateConfig,
|
|
16
|
+
AgentIntent,
|
|
17
|
+
EvaluationResult,
|
|
18
|
+
AuditEvent,
|
|
19
|
+
DegradationTier,
|
|
20
|
+
MandatePolicy,
|
|
21
|
+
} from './types';
|
|
22
|
+
|
|
23
|
+
// Re-export all types for developer use
|
|
24
|
+
export type {
|
|
25
|
+
MandateConfig,
|
|
26
|
+
MandatePolicy,
|
|
27
|
+
AgentIntent,
|
|
28
|
+
EvaluationResult,
|
|
29
|
+
AuditEvent,
|
|
30
|
+
DegradationTier,
|
|
31
|
+
AgentFramework,
|
|
32
|
+
AgentEnvironment,
|
|
33
|
+
AgentRiskTier,
|
|
34
|
+
PolicyDecision,
|
|
35
|
+
PolicyRule,
|
|
36
|
+
PolicyCondition,
|
|
37
|
+
ResponseLevel,
|
|
38
|
+
} from './types';
|
|
39
|
+
|
|
40
|
+
// ============================================================
|
|
41
|
+
// MANDATE AGENT — main class
|
|
42
|
+
// ============================================================
|
|
43
|
+
|
|
44
|
+
export class MandateAgent {
|
|
45
|
+
private config: MandateConfig;
|
|
46
|
+
private evaluator: JSPolicyEvaluator;
|
|
47
|
+
private buffer: AuditBuffer;
|
|
48
|
+
private degradation: DegradationManager;
|
|
49
|
+
|
|
50
|
+
// Framework hooks — use the one matching your agent framework
|
|
51
|
+
public readonly openai: MandateOpenAIHook;
|
|
52
|
+
public readonly langchain: MandateLangChainHook;
|
|
53
|
+
public readonly anthropic: MandateAnthropicHook;
|
|
54
|
+
|
|
55
|
+
constructor(config: MandateConfig) {
|
|
56
|
+
this.config = config;
|
|
57
|
+
|
|
58
|
+
// Initialize core components
|
|
59
|
+
this.evaluator = new JSPolicyEvaluator(config.policy);
|
|
60
|
+
|
|
61
|
+
this.buffer = new AuditBuffer({
|
|
62
|
+
maxSize: 10000,
|
|
63
|
+
flushCallback: async (events) => {
|
|
64
|
+
await this.sendToControlPlane(events);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
this.degradation = new DegradationManager({
|
|
69
|
+
gracePeriodMs: config.policy.localAutonomy.gracePeriodMs,
|
|
70
|
+
riskTier: config.riskTier ?? 'STANDARD',
|
|
71
|
+
onTierChange: (from, to) => {
|
|
72
|
+
config.onDegradation?.(from, to);
|
|
73
|
+
console.warn(`[Mandate] Degradation: ${from} → ${to}`);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Initialize framework-specific hooks
|
|
78
|
+
this.openai = new MandateOpenAIHook(
|
|
79
|
+
config,
|
|
80
|
+
this.evaluator,
|
|
81
|
+
this.buffer,
|
|
82
|
+
this.degradation
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
this.langchain = new MandateLangChainHook(
|
|
86
|
+
config,
|
|
87
|
+
this.evaluator,
|
|
88
|
+
this.buffer,
|
|
89
|
+
this.degradation
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
this.anthropic = new MandateAnthropicHook(
|
|
93
|
+
config,
|
|
94
|
+
this.evaluator,
|
|
95
|
+
this.buffer,
|
|
96
|
+
this.degradation
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
console.log(
|
|
100
|
+
`[Mandate] Agent "${config.agentId}" initialized | ` +
|
|
101
|
+
`env: ${config.environment} | ` +
|
|
102
|
+
`framework: ${config.framework} | ` +
|
|
103
|
+
`policy: ${config.policy.policyHash}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Direct evaluation for custom frameworks
|
|
108
|
+
evaluate(intent: AgentIntent): EvaluationResult {
|
|
109
|
+
return this.evaluator.evaluate(intent);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Flush the audit buffer manually
|
|
113
|
+
async flushAuditBuffer(): Promise<AuditEvent[]> {
|
|
114
|
+
return this.buffer.flush();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Verify the cryptographic integrity of the audit chain
|
|
118
|
+
verifyAuditChain(): { valid: boolean; corruptedAt?: number } {
|
|
119
|
+
return this.buffer.verify();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Get current degradation tier
|
|
123
|
+
getDegradationTier(): DegradationTier {
|
|
124
|
+
return this.degradation.getCurrentTier();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get current audit buffer size
|
|
128
|
+
getBufferSize(): number {
|
|
129
|
+
return this.buffer.size();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Update policy — hot reload, no restart required
|
|
133
|
+
updatePolicy(policy: MandatePolicy): void {
|
|
134
|
+
this.evaluator.updatePolicy(policy);
|
|
135
|
+
console.log(`[Mandate] Policy updated: ${policy.policyHash}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ============================================================
|
|
139
|
+
// PRIVATE
|
|
140
|
+
// ============================================================
|
|
141
|
+
|
|
142
|
+
private async sendToControlPlane(events: AuditEvent[]): Promise<void> {
|
|
143
|
+
if (!this.config.controlPlaneUrl || !this.config.apiKey) return;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(
|
|
147
|
+
`${this.config.controlPlaneUrl}/v1/events`,
|
|
148
|
+
{
|
|
149
|
+
method: 'POST',
|
|
150
|
+
headers: {
|
|
151
|
+
'Content-Type': 'application/json',
|
|
152
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify({ events }),
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
throw new Error(`Control plane responded with ${response.status}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.degradation.onControlPlaneReconnected();
|
|
163
|
+
} catch {
|
|
164
|
+
this.degradation.onControlPlaneUnreachable();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ============================================================
|
|
170
|
+
// CONVENIENCE FACTORY — three lines of code to wrap any agent
|
|
171
|
+
// ============================================================
|
|
172
|
+
|
|
173
|
+
export function createMandateAgent(config: MandateConfig): MandateAgent {
|
|
174
|
+
return new MandateAgent(config);
|
|
175
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MANDATE CORE TYPES
|
|
3
|
+
// Every component in the SDK depends on these definitions
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
// The framework the agent is built on
|
|
7
|
+
export type AgentFramework =
|
|
8
|
+
| 'openai-assistants'
|
|
9
|
+
| 'langchain'
|
|
10
|
+
| 'autogen'
|
|
11
|
+
| 'crewai'
|
|
12
|
+
| 'anthropic'
|
|
13
|
+
| 'custom';
|
|
14
|
+
|
|
15
|
+
// Environment the agent runs in
|
|
16
|
+
export type AgentEnvironment = 'production' | 'staging' | 'development';
|
|
17
|
+
|
|
18
|
+
// Risk level assigned to this agent
|
|
19
|
+
export type AgentRiskTier = 'LOW' | 'STANDARD' | 'HIGH' | 'CRITICAL';
|
|
20
|
+
|
|
21
|
+
// Degradation tiers — V3 five-tier state machine
|
|
22
|
+
export type DegradationTier =
|
|
23
|
+
| 'NOMINAL' // Full real-time enforcement, live audit streaming
|
|
24
|
+
| 'DEGRADED' // Local cache active, audit buffered, agent at full capacity
|
|
25
|
+
| 'ISOLATED' // Control plane unreachable, local enforcement only
|
|
26
|
+
| 'GRACE_STD' // 30min grace elapsed, standard risk agent continues
|
|
27
|
+
| 'GRACE_HIGH'; // 30min grace elapsed, high risk agent → PAUSE
|
|
28
|
+
|
|
29
|
+
// Policy decision returned by the evaluator
|
|
30
|
+
export type PolicyDecision = 'ALLOW' | 'DENY' | 'ESCALATE' | 'THROTTLE';
|
|
31
|
+
|
|
32
|
+
// Kill switch response levels
|
|
33
|
+
export type ResponseLevel = 1 | 2 | 3 | 4 | 5;
|
|
34
|
+
// 1=ALERT 2=THROTTLE 3=PAUSE 4=SCOPED_KILL 5=FULL_KILL
|
|
35
|
+
|
|
36
|
+
// ============================================================
|
|
37
|
+
// INTENT — what Mandate intercepts from agent frameworks
|
|
38
|
+
// ============================================================
|
|
39
|
+
|
|
40
|
+
export interface IntentContext {
|
|
41
|
+
agentId: string;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
environment: AgentEnvironment;
|
|
44
|
+
stepInChain: number;
|
|
45
|
+
framework: AgentFramework;
|
|
46
|
+
timestamp: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface AgentIntent {
|
|
50
|
+
toolName: string;
|
|
51
|
+
args: Record<string, unknown>;
|
|
52
|
+
context: IntentContext;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ============================================================
|
|
56
|
+
// EVALUATION RESULT
|
|
57
|
+
// ============================================================
|
|
58
|
+
|
|
59
|
+
export interface EvaluationResult {
|
|
60
|
+
decision: PolicyDecision;
|
|
61
|
+
reason: string;
|
|
62
|
+
latencyMs: number;
|
|
63
|
+
ruleMatched?: string;
|
|
64
|
+
anomalyScore?: number;
|
|
65
|
+
responseLevel?: ResponseLevel;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================
|
|
69
|
+
// POLICY — JSON representation (MPL compiles to this format)
|
|
70
|
+
// ============================================================
|
|
71
|
+
|
|
72
|
+
export type ConditionOperator =
|
|
73
|
+
| 'eq' | 'neq'
|
|
74
|
+
| 'lt' | 'lte'
|
|
75
|
+
| 'gt' | 'gte'
|
|
76
|
+
| 'in' | 'nin'
|
|
77
|
+
| 'startsWith'
|
|
78
|
+
| 'endsWith'
|
|
79
|
+
| 'contains';
|
|
80
|
+
|
|
81
|
+
export interface PolicyCondition {
|
|
82
|
+
field: string; // dot-notation: "intent.args.amount"
|
|
83
|
+
operator: ConditionOperator;
|
|
84
|
+
value: unknown;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface PolicyRule {
|
|
88
|
+
tool: string; // supports wildcards: "read_*", "*", "process_payment"
|
|
89
|
+
conditions?: PolicyCondition[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface PolicyIdentity {
|
|
93
|
+
org: string;
|
|
94
|
+
env: AgentEnvironment;
|
|
95
|
+
framework?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface AnomalyThresholds {
|
|
99
|
+
alert: number; // default 0.60 — fires ALERT
|
|
100
|
+
throttle: number; // default 0.80 — fires THROTTLE
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface LocalAutonomyConfig {
|
|
104
|
+
gracePeriodMs: number; // default 1800000 (30 minutes)
|
|
105
|
+
postGrace: 'PAUSE' | 'STOP';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface MandatePolicy {
|
|
109
|
+
agentId: string;
|
|
110
|
+
version: string;
|
|
111
|
+
policyHash: string;
|
|
112
|
+
identity: PolicyIdentity;
|
|
113
|
+
allow: PolicyRule[];
|
|
114
|
+
deny: PolicyRule[];
|
|
115
|
+
anomalyThresholds: AnomalyThresholds;
|
|
116
|
+
localAutonomy: LocalAutonomyConfig;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ============================================================
|
|
120
|
+
// AUDIT EVENT — written to the hash-chain buffer
|
|
121
|
+
// ============================================================
|
|
122
|
+
|
|
123
|
+
export interface AuditEvent {
|
|
124
|
+
eventId: string;
|
|
125
|
+
prevHash: string;
|
|
126
|
+
eventHash: string;
|
|
127
|
+
timestamp: number;
|
|
128
|
+
source: 'REALTIME' | 'BUFFER_SYNC';
|
|
129
|
+
agentId: string;
|
|
130
|
+
orgId: string;
|
|
131
|
+
policyHash: string;
|
|
132
|
+
degradationTier: DegradationTier;
|
|
133
|
+
toolName: string;
|
|
134
|
+
toolArgs: Record<string, unknown>;
|
|
135
|
+
intentContext: IntentContext;
|
|
136
|
+
anomalyScore: number;
|
|
137
|
+
blastRadiusEst?: string;
|
|
138
|
+
policyDecision: PolicyDecision;
|
|
139
|
+
responseLevel: ResponseLevel;
|
|
140
|
+
evalLatencyMs: number;
|
|
141
|
+
tokensUsed?: number;
|
|
142
|
+
costUsd?: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ============================================================
|
|
146
|
+
// MANDATE CONFIGURATION
|
|
147
|
+
// ============================================================
|
|
148
|
+
|
|
149
|
+
export interface MandateConfig {
|
|
150
|
+
agentId: string;
|
|
151
|
+
orgId: string;
|
|
152
|
+
apiKey?: string;
|
|
153
|
+
controlPlaneUrl?: string;
|
|
154
|
+
policy: MandatePolicy;
|
|
155
|
+
framework: AgentFramework;
|
|
156
|
+
environment: AgentEnvironment;
|
|
157
|
+
auditLevel: 'full' | 'minimal' | 'off';
|
|
158
|
+
riskTier?: AgentRiskTier;
|
|
159
|
+
onViolation?: (intent: AgentIntent, result: EvaluationResult) => void;
|
|
160
|
+
onAlert?: (intent: AgentIntent, score: number) => void;
|
|
161
|
+
onDegradation?: (from: DegradationTier, to: DegradationTier) => void;
|
|
162
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2020", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"exactOptionalPropertyTypes": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"noImplicitReturns": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"outDir": "./dist",
|
|
16
|
+
"rootDir": "./src",
|
|
17
|
+
"skipLibCheck": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|