from typing import Dict, Any class ReviewerAgent: """ Reviewer Agent - Collects outputs from Grammar, Style, and Clarity agents - Combines their confidence, number of changes, and readability - Selects the best final output - Returns a full explanation + candidate comparison """ def __init__(self): pass @staticmethod def _length_score(text: str) -> float: """ Simple readability heuristic based on text length. Penalizes texts that are too short or too long. """ words = text.split() n = len(words) if n == 0: return 0.0 # Ideal range: 8–40 words if n < 8: return 0.4 if n > 40: return 0.6 return 1.0 def review( self, original: str, grammar_result: Dict[str, Any], style_result: Dict[str, Any], clarity_result: Dict[str, Any], ) -> Dict[str, Any]: """ Decide which version is best and explain the decision. Returns: { "final_text": ..., "candidates": [...], "decision_explanation": "..." } """ candidates = [] # ----------------------- # 1) Original Input # ----------------------- orig_score = 0.3 candidates.append({ "name": "original", "text": original, "score": round(orig_score, 3), "notes": "Raw user input; no improvements applied." }) # ----------------------- # 2) Grammar Agent Output # ----------------------- g_text = grammar_result["corrected"] g_changes = len(grammar_result.get("changes", [])) g_conf = grammar_result.get("confidence", 0.7) g_score = (0.4 * g_conf) + (0.3 + min(g_changes, 5) * 0.05) g_score *= self._length_score(g_text) candidates.append({ "name": "grammar", "text": g_text, "score": round(g_score, 3), "notes": f"Grammar agent fixed {g_changes} issue(s)." }) # ----------------------- # 3) Style Agent Output # ----------------------- s_text = style_result["styled"] s_changes = len(style_result.get("changes", [])) s_conf = style_result.get("confidence", 0.75) s_score = (0.4 * s_conf) + (0.35 + min(s_changes, 5) * 0.04) s_score *= self._length_score(s_text) candidates.append({ "name": "style", "text": s_text, "score": round(s_score, 3), "notes": f"Style agent applied {s_changes} improvements." }) # ----------------------- # 4) Clarity Agent Output # ----------------------- c_text = clarity_result["clarified"] c_changes = len(clarity_result.get("changes", [])) c_conf = clarity_result.get("confidence", 0.8) c_score = (0.4 * c_conf) + (0.4 + min(c_changes, 5) * 0.03) c_score *= self._length_score(c_text) candidates.append({ "name": "clarity", "text": c_text, "score": round(c_score, 3), "notes": f"Clarity agent rewrote {c_changes} part(s) for readability." }) # ----------------------- # Decide the winner # ----------------------- best = max(candidates, key=lambda c: c["score"]) explanation = ( f"The reviewer selected the final output from the '{best['name']}' agent " f"because it achieved the highest overall quality score ({best['score']}). " "Scores are based on: (1) the agent’s confidence, (2) number of improvements, " "(3) readability via length heuristic. This ensures the final text is " "clear, professional, and client-ready." ) return { "final_text": best["text"], "candidates": candidates, "decision_explanation": explanation }