| from __future__ import annotations |
| import asyncio |
| import json |
| from datetime import datetime, timezone |
| from typing import Any, Dict, List |
|
|
| from .config import settings |
| from .models import ( |
| AuditAgentRequest, AuditRepositoryRequest, VerifyClaimsRequest, |
| JobResult, JobStatus, WorkerResults, A2ACall |
| ) |
| from .scoring import compute_scorecard |
| from .proof_pack import persist_proof_pack |
| from .a2a_client import call_cap_agent |
|
|
|
|
| class ExecutionLogger: |
| def __init__(self): |
| self._lines: List[str] = [] |
|
|
| def log(self, event: str, data: Dict[str, Any] = None) -> None: |
| entry = { |
| "ts": datetime.now(timezone.utc).isoformat(), |
| "event": event, |
| **(data or {}), |
| } |
| self._lines.append(json.dumps(entry)) |
|
|
| def lines(self) -> List[str]: |
| return self._lines.copy() |
|
|
|
|
| async def _import_workers(): |
| from .workers.repo_reproducer import reproduce_repository |
| from .workers.claim_verifier import verify_claims |
| from .workers.cap_inspector import inspect_cap_integration |
| from .workers.security_scanner import scan_security |
| from .workers.readme_rewriter import suggest_readme_fixes |
| from .workers.demo_coach import generate_demo_script |
| return reproduce_repository, verify_claims, inspect_cap_integration, scan_security, suggest_readme_fixes, generate_demo_script |
|
|
|
|
| async def run_audit_repository(job: JobResult, req: AuditRepositoryRequest) -> JobResult: |
| logger = ExecutionLogger() |
| logger.log("job_start", {"job_id": job.job_id, "capability": "audit_repository"}) |
| job.status = JobStatus.RUNNING |
| job.started_at = datetime.now(timezone.utc) |
|
|
| (reproduce_repository, verify_claims_fn, inspect_cap_integration, |
| scan_security, suggest_readme_fixes, generate_demo_script) = await _import_workers() |
|
|
| worker_results = WorkerResults() |
|
|
| |
| logger.log("worker_start", {"worker": "repo_reproducer"}) |
| try: |
| worker_results.repo = await asyncio.wait_for( |
| reproduce_repository(req.github_url, req.branch), |
| timeout=settings.max_job_seconds / 2 |
| ) |
| logger.log("worker_done", {"worker": "repo_reproducer", "score": worker_results.repo.score}) |
| except asyncio.TimeoutError: |
| logger.log("worker_timeout", {"worker": "repo_reproducer"}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "repo_reproducer", "error": str(e)}) |
|
|
| |
| if req.run_security_scan and worker_results.repo: |
| logger.log("worker_start", {"worker": "security_scanner"}) |
| try: |
| worker_results.security = await asyncio.wait_for( |
| scan_security(req.github_url), |
| timeout=60 |
| ) |
| logger.log("worker_done", {"worker": "security_scanner", "risk": worker_results.security.risk_level}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "security_scanner", "error": str(e)}) |
|
|
| |
| logger.log("worker_start", {"worker": "cap_inspector"}) |
| try: |
| worker_results.cap = await asyncio.wait_for( |
| inspect_cap_integration(req.github_url), |
| timeout=60 |
| ) |
| logger.log("worker_done", {"worker": "cap_inspector", "score": worker_results.cap.score}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "cap_inspector", "error": str(e)}) |
|
|
| |
| logger.log("worker_start", {"worker": "readme_rewriter"}) |
| try: |
| worker_results.readme_suggestions = await asyncio.wait_for( |
| suggest_readme_fixes(req.github_url, worker_results.repo), |
| timeout=60 |
| ) |
| logger.log("worker_done", {"worker": "readme_rewriter"}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "readme_rewriter", "error": str(e)}) |
|
|
| |
| logger.log("worker_start", {"worker": "demo_coach"}) |
| try: |
| worker_results.demo_script = await asyncio.wait_for( |
| generate_demo_script(req.github_url, worker_results), |
| timeout=60 |
| ) |
| logger.log("worker_done", {"worker": "demo_coach"}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "demo_coach", "error": str(e)}) |
|
|
| |
| a2a_calls: List[A2ACall] = [] |
| logger.log("a2a_start", {"agent": "source-verifier-mock"}) |
| try: |
| a2a_call = await call_cap_agent( |
| "source-verifier-mock", |
| "verify_sources", |
| {"github_url": req.github_url}, |
| timeout=30, |
| ) |
| a2a_calls.append(a2a_call) |
| logger.log("a2a_done", {"agent": "source-verifier-mock", "status": a2a_call.status}) |
| except Exception as e: |
| logger.log("a2a_error", {"agent": "source-verifier-mock", "error": str(e)}) |
|
|
| job.a2a_calls = a2a_calls |
| job.worker_results = worker_results |
|
|
| |
| input_data = req.model_dump() |
| job.scorecard = compute_scorecard(worker_results, input_data, len(a2a_calls)) |
| logger.log("scorecard_computed", {"overall_score": job.scorecard.overall_score}) |
|
|
| |
| job.completed_at = datetime.now(timezone.utc) |
| job.status = JobStatus.DONE |
| persist_proof_pack(job, logger.lines()) |
| logger.log("proof_pack_built", {"result_hash": job.result_hash}) |
|
|
| return job |
|
|
|
|
| async def run_audit_agent(job: JobResult, req: AuditAgentRequest) -> JobResult: |
| logger = ExecutionLogger() |
| logger.log("job_start", {"job_id": job.job_id, "capability": "audit_agent_listing"}) |
| job.status = JobStatus.RUNNING |
| job.started_at = datetime.now(timezone.utc) |
|
|
| (_, verify_claims_fn, inspect_cap_integration, |
| _, suggest_readme_fixes, generate_demo_script) = await _import_workers() |
|
|
| worker_results = WorkerResults() |
|
|
| if req.github_url: |
| logger.log("worker_start", {"worker": "cap_inspector"}) |
| try: |
| worker_results.cap = await asyncio.wait_for( |
| inspect_cap_integration(req.github_url), |
| timeout=60 |
| ) |
| logger.log("worker_done", {"worker": "cap_inspector", "score": worker_results.cap.score}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "cap_inspector", "error": str(e)}) |
|
|
| |
| if req.claimed_tracks: |
| logger.log("worker_start", {"worker": "claim_verifier"}) |
| try: |
| evidence_urls = [req.agent_listing_url] |
| if req.github_url: |
| evidence_urls.append(req.github_url) |
| worker_results.claims = await asyncio.wait_for( |
| verify_claims_fn(req.claimed_tracks, evidence_urls, "standard"), |
| timeout=90 |
| ) |
| logger.log("worker_done", {"worker": "claim_verifier"}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "claim_verifier", "error": str(e)}) |
|
|
| |
| a2a_calls: List[A2ACall] = [] |
| try: |
| a2a_call = await call_cap_agent( |
| "source-verifier-mock", "verify_sources", |
| {"listing_url": req.agent_listing_url}, timeout=30 |
| ) |
| a2a_calls.append(a2a_call) |
| except Exception: |
| pass |
|
|
| job.a2a_calls = a2a_calls |
| job.worker_results = worker_results |
| job.scorecard = compute_scorecard(worker_results, req.model_dump(), len(a2a_calls)) |
| job.completed_at = datetime.now(timezone.utc) |
| job.status = JobStatus.DONE |
| persist_proof_pack(job, logger.lines()) |
| return job |
|
|
|
|
| async def run_verify_claims(job: JobResult, req: VerifyClaimsRequest) -> JobResult: |
| logger = ExecutionLogger() |
| logger.log("job_start", {"job_id": job.job_id, "capability": "verify_claims"}) |
| job.status = JobStatus.RUNNING |
| job.started_at = datetime.now(timezone.utc) |
|
|
| (_, verify_claims_fn, _, _, _, _) = await _import_workers() |
|
|
| worker_results = WorkerResults() |
|
|
| logger.log("worker_start", {"worker": "claim_verifier"}) |
| try: |
| worker_results.claims = await asyncio.wait_for( |
| verify_claims_fn(req.claims, req.evidence_urls or [], req.strictness), |
| timeout=90 |
| ) |
| logger.log("worker_done", {"worker": "claim_verifier", "claims_count": len(req.claims)}) |
| except Exception as e: |
| logger.log("worker_error", {"worker": "claim_verifier", "error": str(e)}) |
|
|
| a2a_calls: List[A2ACall] = [] |
| if req.evidence_urls: |
| try: |
| a2a_call = await call_cap_agent( |
| "source-verifier-mock", "verify_sources", |
| {"evidence_urls": req.evidence_urls}, timeout=30 |
| ) |
| a2a_calls.append(a2a_call) |
| except Exception: |
| pass |
|
|
| job.a2a_calls = a2a_calls |
| job.worker_results = worker_results |
| job.scorecard = compute_scorecard(worker_results, req.model_dump(), len(a2a_calls)) |
| job.completed_at = datetime.now(timezone.utc) |
| job.status = JobStatus.DONE |
| persist_proof_pack(job, logger.lines()) |
| return job |
|
|