feat: ZeroClaw compliance agent — document analysis + role assignment + email

Add autonomous compliance agent that fetches web documents (cookie banners,
privacy policies), classifies them via Qwen/Ollama, assesses DSGVO compliance,
assigns to the responsible role, and sends notification emails.

Components:
- ZeroClaw SOP (6-step workflow: fetch, classify, assess, summarize, assign, notify)
- Backend: /api/compliance/agent/analyze (combined endpoint)
- Backend: /api/compliance/agent/notify (standalone email)
- Frontend: /sdk/agent page (Manager UI with URL input + results)
- Helper scripts + E2E test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-27 23:27:25 +02:00
parent f528b8e7a9
commit 0c0dd4e3a6
16 changed files with 1095 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
"""
Agent Notification Routes — endpoint for the ZeroClaw compliance agent
to send notification emails via SMTP.
POST /api/compliance/agent/notify
"""
import logging
from datetime import datetime, timezone
from fastapi import APIRouter
from pydantic import BaseModel, EmailStr
from compliance.services.smtp_sender import send_email
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/compliance/agent", tags=["agent"])
class NotifyRequest(BaseModel):
recipient: EmailStr
subject: str
body_html: str
role: str
escalation_id: str | None = None
class NotifyResponse(BaseModel):
status: str
recipient: str
subject: str
role: str
sent_at: str
error: str | None = None
@router.post("/notify", response_model=NotifyResponse)
async def send_agent_notification(req: NotifyRequest):
"""Send a compliance notification email on behalf of the agent."""
result = send_email(
recipient=req.recipient,
subject=req.subject,
body_html=_build_email_body(req),
)
return NotifyResponse(
status=result["status"],
recipient=req.recipient,
subject=req.subject,
role=req.role,
sent_at=datetime.now(timezone.utc).isoformat(),
error=result.get("error"),
)
def _build_email_body(req: NotifyRequest) -> str:
"""Wrap the agent's HTML body with a standard email frame."""
return f"""
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 600px; margin: 0 auto;">
<div style="background: #1a1a2e; color: white; padding: 16px 24px; border-radius: 8px 8px 0 0;">
<h2 style="margin: 0; font-size: 18px;">BreakPilot Compliance Agent</h2>
</div>
<div style="padding: 24px; border: 1px solid #e2e8f0; border-top: none;">
<p style="color: #64748b; font-size: 13px; margin-top: 0;">
Zugewiesen an: <strong>{req.role}</strong>
{f' | Eskalation: {req.escalation_id}' if req.escalation_id else ''}
</p>
{req.body_html}
</div>
<div style="background: #f8fafc; padding: 12px 24px; border: 1px solid #e2e8f0; border-top: none; border-radius: 0 0 8px 8px;">
<p style="color: #94a3b8; font-size: 11px; margin: 0;">
Automatisch generiert vom BreakPilot Compliance Agent (ZeroClaw + Qwen)
</p>
</div>
</div>
"""