Sujatha commited on
Commit
a248274
·
verified ·
1 Parent(s): cca1f91

Create agent_orchestrator.py

Browse files
Files changed (1) hide show
  1. agent_orchestrator.py +338 -0
agent_orchestrator.py ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Agent Orchestrator - Coordinates multiple specialized agents (Free Version)
3
+ Uses only free resources and local models
4
+ """
5
+
6
+ from typing import Dict, List, Optional, Any
7
+ import asyncio
8
+ from dataclasses import dataclass
9
+ from enum import Enum
10
+ import json
11
+ from datetime import datetime
12
+ import random
13
+
14
+ # Import free agents
15
+ from agents.diagnostician import DiagnosticianAgent
16
+ from agents.socratic_tutor import SocraticTutorAgent
17
+ from agents.practice_generator import PracticeGeneratorAgent
18
+ from agents.calculator_agent import CalculatorAgent
19
+ from agents.knowledge_agent import KnowledgeAgent
20
+ from agents.assessment_agent import AssessmentAgent
21
+
22
+
23
+ class AgentRole(Enum):
24
+ """Enumeration of agent roles"""
25
+ DIAGNOSTICIAN = "diagnostician"
26
+ SOCRATIC_TUTOR = "socratic_tutor"
27
+ PRACTICE_GENERATOR = "practice_generator"
28
+ CALCULATOR = "calculator"
29
+ KNOWLEDGE_EXPERT = "knowledge_expert"
30
+ ASSESSOR = "assessor"
31
+
32
+
33
+ @dataclass
34
+ class AgentResponse:
35
+ """Container for agent responses"""
36
+ agent: str
37
+ response: str
38
+ confidence: float
39
+ metadata: Dict[str, Any]
40
+ timestamp: datetime
41
+
42
+
43
+ class AgentOrchestrator:
44
+ """Orchestrates multiple specialized agents using free resources"""
45
+
46
+ def __init__(self):
47
+ self.agents = {}
48
+ self.conversation_history = []
49
+ self.user_context = {}
50
+ self.system_prompts = self._load_system_prompts()
51
+
52
+ def _load_system_prompts(self) -> Dict[str, str]:
53
+ """Load system prompts for different agent roles"""
54
+ return {
55
+ "diagnostician": """You are a learning diagnostician. Analyze the user's question to identify:
56
+ 1. What type of learning problem this is (conceptual, calculation, application, analysis)
57
+ 2. What knowledge gaps might exist
58
+ 3. What prerequisite knowledge is needed
59
+ 4. Specific areas where the user might be struggling
60
+
61
+ Provide clear, actionable feedback.""",
62
+
63
+ "socratic_tutor": """You are a Socratic tutor. Guide the user to discover answers themselves by asking questions.
64
+ 1. Start with a guiding question
65
+ 2. Provide hints if the user struggles
66
+ 3. Build up to the full concept
67
+ 4. Encourage critical thinking
68
+
69
+ Do not give direct answers immediately.""",
70
+
71
+ "calculator": """You are a financial calculator expert. For calculation requests:
72
+ 1. Identify the formula needed
73
+ 2. Show the formula clearly
74
+ 3. Walk through each step
75
+ 4. Provide the final answer
76
+ 5. Explain what the result means
77
+
78
+ For non-calculation questions, suggest relevant calculations.""",
79
+
80
+ "knowledge_expert": """You are a CFA knowledge expert. Provide accurate information about:
81
+ 1. Financial concepts and theories
82
+ 2. Formulas and their applications
83
+ 3. Real-world examples
84
+ 4. CFA exam relevance
85
+
86
+ Cite sources from the knowledge base when available.""",
87
+
88
+ "practice_generator": """You are a practice problem generator. Create relevant practice problems:
89
+ 1. Match the user's learning level
90
+ 2. Cover the requested topic
91
+ 3. Include multiple choice options
92
+ 4. Provide step-by-step solutions
93
+ 5. Explain why other options are wrong
94
+
95
+ Start with easier problems and increase difficulty.""",
96
+
97
+ "assessor": """You are a learning assessor. Evaluate the user's progress:
98
+ 1. Identify strengths and weaknesses
99
+ 2. Track learning patterns
100
+ 3. Provide personalized recommendations
101
+ 4. Estimate readiness for CFA exam
102
+
103
+ Be encouraging but honest."""
104
+ }
105
+
106
+ def initialize_agents(self):
107
+ """Initialize all specialized agents with free resources"""
108
+ print("🔄 Initializing AI Agents (Free Version)...")
109
+
110
+ try:
111
+ self.agents = {
112
+ AgentRole.DIAGNOSTICIAN: DiagnosticianAgent(),
113
+ AgentRole.SOCRATIC_TUTOR: SocraticTutorAgent(),
114
+ AgentRole.PRACTICE_GENERATOR: PracticeGeneratorAgent(),
115
+ AgentRole.CALCULATOR: CalculatorAgent(),
116
+ AgentRole.KNOWLEDGE_EXPERT: KnowledgeAgent(),
117
+ AgentRole.ASSESSOR: AssessmentAgent()
118
+ }
119
+
120
+ print("✅ All agents initialized successfully")
121
+ return True
122
+
123
+ except Exception as e:
124
+ print(f"❌ Error initializing agents: {e}")
125
+ # Create fallback agents
126
+ self._create_fallback_agents()
127
+ return False
128
+
129
+ def _create_fallback_agents(self):
130
+ """Create simple fallback agents if initialization fails"""
131
+ print("⚠️ Using fallback agents")
132
+
133
+ class FallbackAgent:
134
+ def process(self, query, user_profile, conversation_history):
135
+ return {
136
+ 'response': f"I'm a fallback agent. I received: {query[:100]}...",
137
+ 'confidence': 0.5,
138
+ 'metadata': {'fallback': True}
139
+ }
140
+
141
+ for role in AgentRole:
142
+ self.agents[role] = FallbackAgent()
143
+
144
+ def process_query(self,
145
+ query: str,
146
+ user_profile: Dict[str, Any],
147
+ selected_agents: List[str] = None) -> Dict[str, Any]:
148
+ """
149
+ Process a user query through the agent pipeline
150
+
151
+ Args:
152
+ query: User's question or request
153
+ user_profile: User's learning profile
154
+ selected_agents: List of agent names to involve
155
+
156
+ Returns:
157
+ Combined response from agents
158
+ """
159
+ if not self.agents:
160
+ self.initialize_agents()
161
+
162
+ # Update user context
163
+ self.user_context.update(user_profile)
164
+ self.user_context['last_query'] = query
165
+ self.user_context['timestamp'] = datetime.now().isoformat()
166
+
167
+ # Default to all agents if none selected
168
+ if not selected_agents:
169
+ selected_agents = [agent.value for agent in AgentRole]
170
+
171
+ # Convert string agent names to AgentRole enum
172
+ agent_roles = []
173
+ for agent_name in selected_agents:
174
+ for role in AgentRole:
175
+ if role.value == agent_name.lower().replace(" ", "_"):
176
+ agent_roles.append(role)
177
+ break
178
+
179
+ # If no valid agents found, use diagnostician and knowledge expert
180
+ if not agent_roles:
181
+ agent_roles = [AgentRole.DIAGNOSTICIAN, AgentRole.KNOWLEDGE_EXPERT]
182
+
183
+ # Execute agents
184
+ responses = self._execute_agents(agent_roles, query, user_profile)
185
+
186
+ # Synthesize responses
187
+ final_response = self._synthesize_responses(responses, query)
188
+
189
+ # Update conversation history
190
+ self.conversation_history.append({
191
+ 'query': query,
192
+ 'responses': [r.__dict__ for r in responses],
193
+ 'final_response': final_response,
194
+ 'timestamp': datetime.now().isoformat()
195
+ })
196
+
197
+ # Keep only last 50 conversations
198
+ if len(self.conversation_history) > 50:
199
+ self.conversation_history = self.conversation_history[-50:]
200
+
201
+ return final_response
202
+
203
+ def _execute_agents(self,
204
+ agent_roles: List[AgentRole],
205
+ query: str,
206
+ user_profile: Dict[str, Any]) -> List[AgentResponse]:
207
+ """
208
+ Execute selected agents and collect responses
209
+ """
210
+ responses = []
211
+
212
+ for role in agent_roles:
213
+ agent = self.agents.get(role)
214
+ if agent:
215
+ try:
216
+ # Process with agent
217
+ result = agent.process(query, user_profile, self.conversation_history)
218
+
219
+ agent_response = AgentResponse(
220
+ agent=role.value.replace("_", " ").title(),
221
+ response=result.get('response', 'No response generated'),
222
+ confidence=result.get('confidence', 0.5),
223
+ metadata=result.get('metadata', {}),
224
+ timestamp=datetime.now()
225
+ )
226
+ responses.append(agent_response)
227
+
228
+ except Exception as e:
229
+ print(f"❌ Error in agent {role.value}: {e}")
230
+ # Create error response
231
+ error_response = AgentResponse(
232
+ agent=role.value.replace("_", " ").title(),
233
+ response=f"This agent is currently unavailable. Error: {str(e)[:100]}",
234
+ confidence=0.0,
235
+ metadata={'error': True, 'message': str(e)},
236
+ timestamp=datetime.now()
237
+ )
238
+ responses.append(error_response)
239
+
240
+ return responses
241
+
242
+ def _synthesize_responses(self,
243
+ responses: List[AgentResponse],
244
+ original_query: str) -> Dict[str, Any]:
245
+ """
246
+ Synthesize multiple agent responses into a coherent answer
247
+ """
248
+ if not responses:
249
+ return {
250
+ 'response': "I'm sorry, no agents were able to process your query. Please try rephrasing.",
251
+ 'primary_agent': 'System',
252
+ 'sources': [],
253
+ 'confidence': 0.0,
254
+ 'metadata': {'error': 'No responses'}
255
+ }
256
+
257
+ # Filter out error responses
258
+ valid_responses = [r for r in responses if r.confidence > 0.1]
259
+
260
+ if not valid_responses:
261
+ return {
262
+ 'response': "The agents encountered errors. Please try a simpler query or check back later.",
263
+ 'primary_agent': 'System',
264
+ 'sources': [],
265
+ 'confidence': 0.0
266
+ }
267
+
268
+ # Sort by confidence
269
+ valid_responses.sort(key=lambda x: x.confidence, reverse=True)
270
+
271
+ # Get primary response (highest confidence)
272
+ primary_response = valid_responses[0]
273
+
274
+ # Build final response
275
+ response_parts = []
276
+
277
+ # Add primary response
278
+ response_parts.append(f"## {primary_response.agent}\n\n{primary_response.response}")
279
+
280
+ # Add other high-confidence responses
281
+ other_responses = []
282
+ for resp in valid_responses[1:]:
283
+ if resp.confidence > 0.6 and resp.agent != primary_response.agent:
284
+ other_responses.append(resp)
285
+
286
+ if other_responses:
287
+ response_parts.append("\n\n---\n\n## Additional Insights")
288
+ for resp in other_responses[:2]: # Limit to 2 additional responses
289
+ response_parts.append(f"\n\n### {resp.agent}\n\n{resp.response[:200]}...")
290
+
291
+ final_response = "\n".join(response_parts)
292
+
293
+ return {
294
+ 'response': final_response,
295
+ 'primary_agent': primary_response.agent,
296
+ 'supporting_agents': [resp.agent for resp in valid_responses[1:]],
297
+ 'confidence': primary_response.confidence,
298
+ 'timestamp': datetime.now().isoformat(),
299
+ 'metadata': {
300
+ 'response_count': len(valid_responses),
301
+ 'avg_confidence': sum(r.confidence for r in valid_responses) / len(valid_responses)
302
+ }
303
+ }
304
+
305
+ def get_agent_status(self) -> Dict[str, Dict[str, Any]]:
306
+ """
307
+ Get status of all agents
308
+ """
309
+ status = {}
310
+ for role, agent in self.agents.items():
311
+ status[role.value] = {
312
+ 'active': True,
313
+ 'type': agent.__class__.__name__,
314
+ 'initialized': True,
315
+ 'capabilities': self._get_agent_capabilities(role)
316
+ }
317
+ return status
318
+
319
+ def _get_agent_capabilities(self, role: AgentRole) -> List[str]:
320
+ """Get capabilities of an agent"""
321
+ capabilities = {
322
+ AgentRole.DIAGNOSTICIAN: ["Learning gap analysis", "Problem diagnosis", "Recommendation generation"],
323
+ AgentRole.SOCRATIC_TUTOR: ["Guided questioning", "Concept building", "Critical thinking"],
324
+ AgentRole.CALCULATOR: ["Financial calculations", "Formula explanation", "Step-by-step solutions"],
325
+ AgentRole.KNOWLEDGE_EXPERT: ["Concept explanation", "Knowledge retrieval", "Example provision"],
326
+ AgentRole.PRACTICE_GENERATOR: ["Problem creation", "Solution generation", "Difficulty scaling"],
327
+ AgentRole.ASSESSOR: ["Progress tracking", "Performance evaluation", "Study recommendations"]
328
+ }
329
+ return capabilities.get(role, ["General assistance"])
330
+
331
+ def reset_conversation(self):
332
+ """Reset conversation history"""
333
+ self.conversation_history = []
334
+ print("🔄 Conversation history reset")
335
+
336
+
337
+ # Singleton instance
338
+ orchestrator = AgentOrchestrator()