PCAgentinAI / agent6_audit_integration.py
ITNovaML's picture
Add Agent 6 AXIOM audit agent + gold_audit_log integration
58a7d45
Raw
History Blame Contribute Delete
8.06 kB
# ============================================================
# app.py — Integration snippets for Agent 6 (AXIOM Audit Agent)
# Add these to your existing app.py
# ============================================================
# ── 1. Import at top of app.py ───────────────────────────────
from agent6_audit import run_audit_agent, get_audit_for_submission
# ── 2. Call AXIOM at end of pipeline (after NOVA) ───────────
# In your existing pipeline route (wherever NOVA runs), add:
def run_full_pipeline(submission_id: int) -> dict:
"""
Example: call this at the end of your existing pipeline function.
Replace with your actual pipeline call.
"""
# ... your existing agent calls (AURA, TERRA, KARMA, AURUM, NOVA) ...
# ✅ ADD THIS at the very end, after NOVA issues/declines:
audit_result = run_audit_agent(submission_id)
return {
# ... your existing pipeline result dict ...
"audit": audit_result,
}
# ── 3. Flask API route — GET audit for a submission ──────────
from flask import jsonify, request
@app.route("/audit/<int:submission_id>", methods=["GET"])
def get_audit(submission_id):
"""
Returns the audit record for a given submission.
Called by the UI audit panel.
GET /audit/123
"""
record = get_audit_for_submission(submission_id)
if not record:
# Run it on demand if not yet generated
record = run_audit_agent(submission_id)
return jsonify(record)
@app.route("/audit/run/<int:submission_id>", methods=["POST"])
def trigger_audit(submission_id):
"""
Manually trigger audit for a submission (useful for backfill).
POST /audit/run/123
"""
result = run_audit_agent(submission_id)
return jsonify(result)
# ============================================================
# HTML AUDIT PANEL — Add this to your existing policy detail
# page or results screen in your HTML/Jinja templates
# ============================================================
AUDIT_PANEL_HTML = """
<!-- ── AXIOM AUDIT PANEL ─────────────────────────────────── -->
<div id="auditPanel" style="
background: #0a1628;
border: 1px solid rgba(0,212,255,0.2);
border-radius: 4px;
padding: 1.5rem 2rem;
margin-top: 2rem;
font-family: 'DM Mono', monospace;
">
<div style="display:flex; align-items:center; gap:0.8rem; margin-bottom:1.2rem;">
<span style="font-size:1.2rem;">🔍</span>
<div>
<div style="font-weight:700; font-size:0.9rem; color:#f0f6ff; letter-spacing:0.05em;">
AXIOM — Audit Agent
</div>
<div style="font-size:0.65rem; color:#7a9ab8; letter-spacing:0.1em; text-transform:uppercase;">
Agent 6 · Decision Audit · Gold Layer
</div>
</div>
<div id="auditDecisionBadge" style="
margin-left:auto;
font-size:0.7rem;
font-weight:700;
letter-spacing:0.12em;
text-transform:uppercase;
padding:0.3rem 0.9rem;
border:1px solid;
border-radius:2px;
">Loading...</div>
</div>
<!-- Overall summary -->
<div id="auditSummaryText" style="
font-size:0.82rem;
color:#a8c0d8;
line-height:1.7;
background:rgba(255,255,255,0.03);
border-left:3px solid #00d4ff;
padding:0.8rem 1rem;
margin-bottom:1.2rem;
">Loading audit summary...</div>
<!-- Audit score -->
<div style="display:flex; align-items:center; gap:0.8rem; margin-bottom:1.2rem;">
<div style="font-size:0.65rem; color:#7a9ab8; text-transform:uppercase; letter-spacing:0.1em;">
Audit Confidence Score
</div>
<div style="flex:1; height:6px; background:rgba(255,255,255,0.08); border-radius:3px; overflow:hidden;">
<div id="auditScoreBar" style="height:100%; width:0%; background:#00d4ff; transition:width 1s ease; border-radius:3px;"></div>
</div>
<div id="auditScoreVal" style="font-size:0.75rem; font-weight:700; color:#00d4ff; width:36px;">0%</div>
</div>
<!-- Decision factors table -->
<div style="font-size:0.65rem; color:#7a9ab8; text-transform:uppercase; letter-spacing:0.1em; margin-bottom:0.6rem;">
Agent Decision Factors
</div>
<div id="auditFactors" style="display:flex; flex-direction:column; gap:0.5rem;"></div>
<!-- Decline reasons (only shown if declined) -->
<div id="auditDeclineReasons" style="display:none; margin-top:1rem;">
<div style="font-size:0.65rem; color:#ef4444; text-transform:uppercase; letter-spacing:0.1em; margin-bottom:0.5rem;">
Decline Reasons
</div>
<div id="auditDeclineList" style="font-size:0.8rem; color:#fca5a5; line-height:1.7;"></div>
</div>
</div>
<script>
// Load audit panel for a given submission ID
async function loadAuditPanel(submissionId) {
try {
const resp = await fetch('/audit/' + submissionId);
const data = await resp.json();
renderAuditPanel(data);
} catch(e) {
document.getElementById('auditSummaryText').textContent = 'Audit data unavailable.';
}
}
function renderAuditPanel(data) {
const decision = data.decision || data.decision;
const isApproved = decision === 'APPROVED';
// Badge
const badge = document.getElementById('auditDecisionBadge');
badge.textContent = decision;
badge.style.borderColor = isApproved ? '#00e5a0' : '#ef4444';
badge.style.color = isApproved ? '#00e5a0' : '#ef4444';
// Summary
document.getElementById('auditSummaryText').textContent = data.overall_summary || '';
// Score bar
const score = data.audit_score || 0;
document.getElementById('auditScoreBar').style.width = score + '%';
document.getElementById('auditScoreBar').style.background = score > 70 ? '#00e5a0' : score > 40 ? '#f59e0b' : '#ef4444';
document.getElementById('auditScoreVal').textContent = score + '%';
// Factors
const factors = data.decision_factors || [];
const container = document.getElementById('auditFactors');
container.innerHTML = '';
factors.forEach(function(f) {
const outcomeColor = {
'PASS': '#00e5a0', 'APPROVED': '#00e5a0', 'ISSUED': '#00e5a0', 'CALCULATED': '#00d4ff',
'FAIL': '#ef4444', 'DECLINED': '#ef4444', 'DECLINE': '#ef4444',
'REFER': '#f59e0b', 'NOT ISSUED': '#f59e0b'
}[f.outcome] || '#7a9ab8';
const row = document.createElement('div');
row.style.cssText = 'background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.07);padding:0.6rem 0.9rem;border-radius:2px;';
row.innerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.3rem;">
<span style="font-size:0.7rem;color:#f0f6ff;font-weight:600;">${f.agent}</span>
<span style="font-size:0.65rem;font-weight:700;color:${outcomeColor};letter-spacing:0.1em;">${f.outcome}</span>
</div>
<div style="font-size:0.65rem;color:#7a9ab8;margin-bottom:0.2rem;text-transform:uppercase;letter-spacing:0.08em;">${f.factor}</div>
<div style="font-size:0.72rem;color:#a8c0d8;line-height:1.5;">${f.detail}</div>
`;
container.appendChild(row);
});
// Decline reasons
const reasons = data.decline_reasons || [];
if (!isApproved && reasons.length > 0) {
const reasonsDiv = document.getElementById('auditDeclineReasons');
reasonsDiv.style.display = 'block';
const list = document.getElementById('auditDeclineList');
list.innerHTML = reasons.map(function(r, i) {
return `<div style="margin-bottom:0.4rem;"><span style="color:#ef4444;margin-right:0.4rem;">${i+1}.</span>${r}</div>`;
}).join('');
}
}
// Auto-load if submission ID is in the page
document.addEventListener('DOMContentLoaded', function() {
// Replace with however you pass submission_id to your page
// e.g. from a data attribute: <div id="auditPanel" data-submission-id="123">
const panel = document.getElementById('auditPanel');
const sid = panel && panel.dataset.submissionId;
if (sid) loadAuditPanel(sid);
});
</script>
"""