"""Reviewer Agent — reviews work, validates quality, finds issues. Reviews the output of other agents. Can approve or reject work, and suggest improvements. Runs after each step is completed. """ from __future__ import annotations import logging from typing import Any from .agent_base import BaseAgent from ..memory.goal_memory import Goal logger = logging.getLogger(__name__) class ReviewerAgent(BaseAgent): """Reviews work done by other agents and validates quality.""" def __init__(self, goal_memory, persistent_memory=None, generate_fn=None): super().__init__( name="reviewer", role="Quality Reviewer", description="Reviews work, validates quality, and finds issues", goal_memory=goal_memory, persistent_memory=persistent_memory, generate_fn=generate_fn, poll_interval_s=4.0, ) def _can_handle(self, goal: Goal) -> bool: """Reviewer handles goals in reviewing status.""" return goal.status == "reviewing" def process_goal(self, goal: Goal) -> dict[str, Any]: """Review the most recent step output.""" if goal.current_step == 0 and not goal.steps: return {"success": True, "output": "Nothing to review"} # Review the last completed step review_idx = max(0, goal.current_step - 1) if review_idx >= len(goal.steps): return {"success": True, "output": "No steps to review"} step = goal.steps[review_idx] if step.get("status") != "completed": return {"success": True, "output": "Step not completed yet"} prompt = ( f"You are a quality reviewer. Review this work:\n" f"Goal: {goal.title}\n" f"Step: {step['title']}\n" f"Result: {step.get('result', '')[:500]}\n\n" f"Evaluate: Is this correct and complete? Reply APPROVED or NEEDS_WORK with reason.\n" ) response = self._generate(prompt) approved = "APPROVED" in response.upper() if self.persistent_memory: self.persistent_memory.add_episodic( "review", f"Review of '{step['title']}': {'approved' if approved else 'needs work'}", importance=0.6, tags=["review", goal.title[:20]] ) if approved: return {"success": True, "output": f"Approved: {response[:100]}"} else: return {"success": False, "output": "", "error": f"Needs work: {response[:100]}"}