File size: 2,942 Bytes
8a1fc38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
"""
ADK Orchestrator

Chains the 5 agents together (Planner -> Memory -> Solver -> Verifier -> Formatter).
Replaces the monolithic MathAIEngine.
"""

import logging
from typing import Dict, Any

from backend.src.agents.planner import PlannerAgent
from backend.src.agents.memory import MemoryAgent
from backend.src.agents.solver import SolverAgent
from backend.src.agents.verifier import VerifierAgent
from backend.src.agents.formatter import FormatterAgent

logger = logging.getLogger("math_assistant.agents.orchestrator")

class ADKOrchestrator:
    """Orchestrates the multi-agent ADK pipeline."""
    
    def __init__(self, uid: str, session_id: str):
        self.uid = uid
        self.session_id = session_id
        
        self.planner = PlannerAgent()
        self.memory = MemoryAgent()
        self.solver = SolverAgent()
        self.verifier = VerifierAgent()
        self.formatter = FormatterAgent()
        
    def query(self, user_query: str) -> Dict[str, Any]:
        """Execute the full agent pipeline."""
        logger.info(f"Starting ADK Orchestrator for session {self.session_id}")
        
        # 1. Plan
        plan = self.planner.plan(user_query)
        logger.info(f"Plan: {plan}")
        class_level = plan.get("class", 10)
        
        # 2. Memory Retrieval
        mem_context = self.memory.retrieve(self.uid, self.session_id)
        
        # 3. Solver + RAG
        rag_context = self.solver.retrieve_context(user_query)
        raw_solution = self.solver.solve(user_query, rag_context, mem_context["history"])
        
        # 4. Verify
        # We allow up to 2 retries on verification failure
        verification = self.verifier.verify(user_query, raw_solution)
        retries = 0
        while not verification.get("is_correct", True) and retries < 2:
            logger.warning(f"Verification failed: {verification.get('feedback')}. Retrying...")
            feedback = verification.get("feedback")
            # Inject feedback into prompt
            refined_query = f"{user_query}\nNote: Your previous attempt had an error: {feedback}. Please fix it."
            raw_solution = self.solver.solve(refined_query, rag_context, mem_context["history"])
            verification = self.verifier.verify(user_query, raw_solution)
            retries += 1
            
        # 5. Format
        final_answer = self.formatter.format(user_query, raw_solution, class_level)
        
        # Save to memory (Memory agent handles retrieval, but we use memory service directly for saving)
        from backend.src.services.memory_service import FirestoreChatMemory
        mem_svc = FirestoreChatMemory(uid=self.uid, session_id=self.session_id)
        mem_svc.add_message("human", user_query)
        mem_svc.add_message("assistant", final_answer)
        
        return {
            "answer": final_answer,
            "session_id": self.session_id,
            "is_adk": True
        }