profit 77655c298c Initial commit: Agent Governance System Phase 8
Phase 8 Production Hardening with complete governance infrastructure:

- Vault integration with tiered policies (T0-T4)
- DragonflyDB state management
- SQLite audit ledger
- Pipeline DSL and templates
- Promotion/revocation engine
- Checkpoint system for session persistence
- Health manager and circuit breaker for fault tolerance
- GitHub/Slack integrations
- Architectural test pipeline with bug watcher, suggestion engine, council review
- Multi-agent chaos testing framework

Test Results:
- Governance tests: 68/68 passing
- E2E workflow: 16/16 passing
- Phase 2 Vault: 14/14 passing
- Integration tests: 27/27 passing

Coverage: 57.6% average across 12 phases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:07:06 -05:00

321 lines
9.7 KiB
TypeScript

/**
* LLM Planner Agent - TypeScript/Bun Version
* Tier 0 Observer with OpenRouter LLM capabilities
*/
import OpenAI from "openai";
import { z } from "zod";
import { $ } from "bun";
import { Database } from "bun:sqlite";
// =============================================================================
// Agent Metadata
// =============================================================================
const AGENT_METADATA = {
agent_id: "llm-planner-ts-001",
agent_role: "observer",
owner: "system",
version: "0.1.0",
tier: 0,
allowed_side_effects: ["read_docs", "read_inventory", "read_logs", "generate_plan", "llm_inference"],
forbidden_actions: ["ssh", "create_vm", "modify_vm", "delete_vm", "run_ansible", "run_terraform"],
confidence_threshold: 0.7,
};
// =============================================================================
// Types
// =============================================================================
interface TaskRequest {
task_type: "plan" | "analyze";
description: string;
context?: Record<string, any>;
constraints?: string[];
}
interface AgentOutput {
agent_id: string;
version: string;
timestamp: string;
action: string;
decision: "EXECUTE" | "SKIP" | "ESCALATE" | "ERROR";
confidence: number;
assumptions: string[];
side_effects: { type: string; target: string; reversible: boolean }[];
notes_for_humans: string;
llm_model?: string;
llm_response?: string;
plan?: Record<string, any>;
error?: {
type: string;
message: string;
triggering_input: string;
recommended_action: string;
};
}
// =============================================================================
// Vault Client
// =============================================================================
async function getVaultSecret(path: string): Promise<Record<string, any>> {
const initKeys = await Bun.file("/opt/vault/init-keys.json").json();
const token = initKeys.root_token;
const result = await $`curl -sk -H "X-Vault-Token: ${token}" https://127.0.0.1:8200/v1/secret/data/${path}`.json();
return result.data.data;
}
// =============================================================================
// Ledger
// =============================================================================
function logToLedger(output: AgentOutput, success: boolean) {
const db = new Database("/opt/agent-governance/ledger/governance.db");
db.run(`
INSERT INTO agent_actions (timestamp, agent_id, agent_version, tier, action, decision, confidence, success, error_type, error_message)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
output.timestamp,
output.agent_id,
output.version,
AGENT_METADATA.tier,
output.action,
output.decision,
output.confidence,
success ? 1 : 0,
output.error?.type ?? null,
output.error?.message ?? null,
]);
db.run(`
INSERT INTO agent_metrics (agent_id, current_tier, total_runs, last_active_at, compliant_runs, consecutive_compliant)
VALUES (?, ?, 1, ?, ?, ?)
ON CONFLICT(agent_id) DO UPDATE SET
total_runs = total_runs + 1,
compliant_runs = CASE WHEN ? = 1 THEN compliant_runs + 1 ELSE compliant_runs END,
consecutive_compliant = CASE WHEN ? = 1 THEN consecutive_compliant + 1 ELSE 0 END,
last_active_at = ?,
updated_at = ?
`, [
output.agent_id, AGENT_METADATA.tier, output.timestamp,
success ? 1 : 0, success ? 1 : 0,
success ? 1 : 0, success ? 1 : 0,
output.timestamp, output.timestamp,
]);
db.close();
}
// =============================================================================
// Agent
// =============================================================================
class LLMPlannerAgent {
private llm!: OpenAI;
private model: string;
constructor(model: string = "anthropic/claude-sonnet-4") {
this.model = model;
}
async init() {
const secrets = await getVaultSecret("api-keys/openrouter");
this.llm = new OpenAI({
baseURL: "https://openrouter.ai/api/v1",
apiKey: secrets.api_key,
});
console.log("[INIT] Agent " + AGENT_METADATA.agent_id + " v" + AGENT_METADATA.version);
console.log("[INIT] Model: " + this.model);
}
private now(): string {
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
}
private validateAction(action: string): boolean {
if (AGENT_METADATA.forbidden_actions.includes(action)) return false;
if (AGENT_METADATA.allowed_side_effects.includes(action)) return true;
return false;
}
async generatePlan(request: TaskRequest): Promise<AgentOutput> {
const action = "generate_plan";
if (!this.validateAction(action)) {
const output: AgentOutput = {
agent_id: AGENT_METADATA.agent_id,
version: AGENT_METADATA.version,
timestamp: this.now(),
action,
decision: "ERROR",
confidence: 0,
assumptions: [],
side_effects: [],
notes_for_humans: "",
error: {
type: "FORBIDDEN_ACTION",
message: "Action '" + action + "' not permitted",
triggering_input: request.description,
recommended_action: "Escalate to higher tier",
},
};
logToLedger(output, false);
return output;
}
// Get context
let contextInfo = "Context unavailable";
try {
const inventory = await getVaultSecret("inventory/proxmox");
contextInfo = "Cluster: " + inventory.cluster + ", Pools: " + inventory.pools;
} catch {}
const systemPrompt = `You are a Tier 0 Observer agent. Generate implementation plans only - you CANNOT execute.
Output JSON: {"title":"","summary":"","confidence":0.0-1.0,"assumptions":[],"steps":[{"step":1,"action":"","reversible":true,"rollback":""}],"estimated_tier_required":0-4,"risks":[]}
Context: ${contextInfo}`;
try {
const response = await this.llm.chat.completions.create({
model: this.model,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: "Task: " + request.description + "\nGenerate a plan." },
],
max_tokens: 2000,
temperature: 0.3,
});
const llmResponse = response.choices[0].message.content || "";
let plan: Record<string, any> = {};
let confidence = 0.5;
try {
const jsonMatch = llmResponse.match(/\{[\s\S]*\}/);
if (jsonMatch) {
plan = JSON.parse(jsonMatch[0]);
confidence = plan.confidence || 0.5;
}
} catch {
plan = { raw_response: llmResponse };
}
const tierRequired = plan.estimated_tier_required || "unknown";
const output: AgentOutput = {
agent_id: AGENT_METADATA.agent_id,
version: AGENT_METADATA.version,
timestamp: this.now(),
action,
decision: confidence >= AGENT_METADATA.confidence_threshold ? "EXECUTE" : "ESCALATE",
confidence,
assumptions: plan.assumptions || [],
side_effects: [{ type: "llm_inference", target: this.model, reversible: true }],
notes_for_humans: "Tier required: " + tierRequired,
llm_model: this.model,
plan,
};
logToLedger(output, true);
return output;
} catch (e: any) {
const output: AgentOutput = {
agent_id: AGENT_METADATA.agent_id,
version: AGENT_METADATA.version,
timestamp: this.now(),
action,
decision: "ERROR",
confidence: 0,
assumptions: [],
side_effects: [],
notes_for_humans: "",
error: {
type: "LLM_ERROR",
message: e.message,
triggering_input: request.description,
recommended_action: "Check API connectivity",
},
};
logToLedger(output, false);
return output;
}
}
async run(request: TaskRequest): Promise<AgentOutput> {
console.log("[TASK] " + request.task_type + ": " + request.description.slice(0, 80) + "...");
if (request.task_type === "plan") {
return this.generatePlan(request);
}
const output: AgentOutput = {
agent_id: AGENT_METADATA.agent_id,
version: AGENT_METADATA.version,
timestamp: this.now(),
action: request.task_type,
decision: "ERROR",
confidence: 0,
assumptions: [],
side_effects: [],
notes_for_humans: "",
error: {
type: "UNSUPPORTED",
message: "Task type '" + request.task_type + "' not implemented in TS version",
triggering_input: request.description,
recommended_action: "Use 'plan' task type or Python agent",
},
};
logToLedger(output, false);
return output;
}
}
// =============================================================================
// CLI
// =============================================================================
async function main() {
const args = process.argv.slice(2);
if (args.length < 2) {
console.log("Usage: bun run index.ts <plan|analyze> \"description\"");
process.exit(1);
}
const taskType = args[0] as "plan" | "analyze";
const description = args[1];
const agent = new LLMPlannerAgent();
await agent.init();
const output = await agent.run({ task_type: taskType, description });
console.log("\n" + "=".repeat(60));
console.log("Decision: " + output.decision);
console.log("Confidence: " + output.confidence);
console.log("=".repeat(60));
if (output.plan) {
console.log("\nPLAN:");
console.log(JSON.stringify(output.plan, null, 2));
}
if (output.error) {
console.log("\nERROR:");
console.log(" Type: " + output.error.type);
console.log(" Message: " + output.error.message);
}
if (output.assumptions && output.assumptions.length > 0) {
console.log("\nASSUMPTIONS:");
output.assumptions.forEach(a => console.log(" - " + a));
}
console.log("\n" + "=".repeat(60));
}
main().catch(console.error);