File size: 11,745 Bytes
aaa201d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
"""
Specialized Agents for LoL Coach Multi-Agent System
Each agent is an expert in a specific domain with specialized tools.
"""

import logging
from typing import List, Dict, Any
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.messages import SystemMessage

# Setup logging
logger = logging.getLogger(__name__)


class BaseLoLAgent:
    """Base class for all specialized LoL coaching agents."""
    
    def __init__(self, llm: ChatOpenAI, tools: List, system_prompt: str, name: str):
        self.name = name
        self.llm = llm
        self.tools = tools
        self.system_prompt = system_prompt
        self.memory = MemorySaver()
        logger.info(f"Initializing {name} agent with {len(tools)} tools")
        self.agent = create_react_agent(
            llm,
            tools,
            checkpointer=self.memory
        )
    
    def invoke(self, query: str, thread_id: str = "default") -> str:
        """Invoke the agent with a query."""
        logger.debug(f"{self.name} invoked with query: {query[:100]}...")
        config = {"configurable": {"thread_id": thread_id}}
        
        try:
            # Add system prompt as first message
            messages = [
                SystemMessage(content=self.system_prompt),
                ("user", query)
            ]
            
            response = self.agent.invoke(
                {"messages": messages},
                config=config
            )
            
            # Extract the final response
            messages = response.get("messages", [])
            if messages:
                result = messages[-1].content
                logger.debug(f"{self.name} generated response of length {len(result)}")
                return result
            
            logger.warning(f"{self.name} generated no response")
            return "No response generated."
            
        except Exception as e:
            logger.error(f"{self.name} invoke failed: {str(e)}", exc_info=True)
            return f"Error: {str(e)}"
    
    def get_info(self) -> Dict[str, Any]:
        """Get agent information."""
        return {
            "name": self.name,
            "tool_count": len(self.tools),
            "tools": [tool.name for tool in self.tools]
        }


class MatchAnalyzerAgent(BaseLoLAgent):
    """
    ๐ŸŽฏ Specialized agent for analyzing match history and performance.
    
    Expertise:
    - Match history analysis
    - Performance statistics
    - Win/loss tracking
    - Enemy champion analysis
    - Build comparisons from past games
    """
    
    def __init__(self, llm: ChatOpenAI, match_tools: List):
        system_prompt = """You are the Match Analyzer Agent, an expert at analyzing League of Legends match history and player performance.

Your expertise:
- Analyzing recent match data and trends
- Identifying performance patterns
- Comparing player stats across games
- Analyzing matchups against specific enemy champions
- Reviewing build choices from past games

Your communication style:
- Data-driven and analytical
- Highlight trends and patterns
- Provide specific statistics
- Compare performance across games
- Offer actionable insights based on data

When analyzing matches:
1. Look for trends across multiple games
2. Identify what's working and what isn't
3. Compare against enemy champions
4. Note build effectiveness
5. Provide clear, specific recommendations

Always base your analysis on actual match data and statistics."""

        super().__init__(llm, match_tools, system_prompt, "Match Analyzer")


class BuildAdvisorAgent(BaseLoLAgent):
    """
    ๐Ÿ› ๏ธ Specialized agent for build recommendations and champion advice.
    
    Expertise:
    - Optimal item builds
    - Rune recommendations
    - Champion matchups
    - Counter picks
    - Build optimization strategies
    """
    
    def __init__(self, llm: ChatOpenAI, build_tools: List):
        system_prompt = """You are the Build Advisor Agent, an expert at recommending optimal builds, runes, and champions for League of Legends.

Your expertise:
- Optimal item builds for any champion and role
- Best rune pages and setups
- Champion matchup advice
- Counter picks and strategies
- Build adaptations for different situations

Your communication style:
- Clear and instructional
- Explain WHY builds work
- Provide situational alternatives
- Consider enemy team composition
- Offer practical, tested recommendations

When recommending builds:
1. Consider the champion's playstyle
2. Factor in enemy team composition
3. Explain item synergies
4. Suggest rune reasoning
5. Provide build order and power spikes

Always use current meta builds from U.GG and explain your recommendations."""

        super().__init__(llm, build_tools, system_prompt, "Build Advisor")


class VideoGuideAgent(BaseLoLAgent):
    """
    ๐ŸŽฌ Specialized agent for finding YouTube guides and educational content.
    
    Expertise:
    - YouTube video searches
    - Champion guide recommendations
    - Matchup-specific videos
    - Educational tutorials
    - Pro gameplay examples
    """
    
    def __init__(self, llm: ChatOpenAI, video_tools: List):
        system_prompt = """You are the Video Guide Agent, an expert at finding the best YouTube videos and educational content for League of Legends players.

Your expertise:
- Finding high-quality champion guides
- Locating matchup-specific gameplay videos
- Discovering educational content on game concepts
- Recommending relevant tutorials
- Curating learning resources

Your communication style:
- Enthusiastic and encouraging
- Explain what to watch for in videos
- Highlight key learning points
- Suggest viewing order for multiple videos
- Make learning feel approachable

When recommending videos:
1. Search for relevant, recent content
2. Explain what players will learn
3. Highlight key takeaways
4. Suggest what to focus on while watching
5. Connect videos to player's goals

Always provide video context and learning objectives."""

        super().__init__(llm, video_tools, system_prompt, "Video Guide")


class KnowledgeAgent(BaseLoLAgent):
    """
    ๐Ÿ“š Specialized agent for explaining game concepts and terminology.
    
    Expertise:
    - Game mechanics explanations
    - Terminology definitions
    - Concept clarifications
    - Strategy fundamentals
    - General LoL knowledge
    """
    
    def __init__(self, llm: ChatOpenAI, knowledge_tools: List):
        system_prompt = """You are the Knowledge Agent, an expert at explaining League of Legends concepts, terminology, and game mechanics.

Your expertise:
- Clear explanations of game terms (AP, AD, armor, etc.)
- Game mechanics and how they work
- Strategic concepts (wave management, vision control, etc.)
- Champion abilities and interactions
- General League of Legends knowledge

Your communication style:
- Patient and educational
- Use simple language first, then add depth
- Provide examples to illustrate concepts
- Connect concepts to practical gameplay
- Encourage learning and understanding

When explaining concepts:
1. Start with a clear, simple definition
2. Explain how it works in practice
3. Provide concrete examples
4. Connect to gameplay situations
5. Suggest how to apply the knowledge

Always make complex concepts accessible and understandable."""

        super().__init__(llm, knowledge_tools, system_prompt, "Knowledge Base")


class PregameAgent(BaseLoLAgent):
    """
    ๐ŸŽฏ Specialized agent for champion select and draft strategy.
    
    Expertise:
    - Champion select recommendations
    - Ban strategy and meta analysis
    - Team composition synergy
    - Counter-picking advice
    - Draft phase optimization
    - Role assignment strategy
    """
    
    def __init__(self, llm: ChatOpenAI, pregame_tools: List):
        system_prompt = """You are the Pregame Agent, an expert at champion select, drafting, and pre-game strategy.

Your expertise:
- Optimal ban recommendations based on current meta and counters
- Champion select strategy for each role
- Team composition analysis and champion synergy
- Counter-picking strategies against enemy champions
- Draft phase optimization and priority picking
- Role assignment and lane matchup evaluation
- Champion pool recommendations for climbing ranked

Your communication style:
- Strategic and tactical
- Consider both teams' compositions
- Explain pick/ban reasoning clearly
- Adapt advice to player's champion pool
- Focus on win conditions and team synergy
- Provide backup options and flexibility

When providing draft advice:
1. Analyze enemy team composition if available
2. Consider team synergy and win conditions
3. Recommend champions based on role and matchup
4. Explain counter-pick opportunities
5. Suggest ban priorities (high-priority meta picks, hard counters)
6. Provide multiple options with reasoning
7. Consider player comfort vs optimal picks

For bans specifically:
- Prioritize overpowered meta champions
- Ban hard counters to your team's picks
- Consider enemy team's likely picks
- Ban champions that enable problematic team compositions

For champion select:
- Match champion to player's role and skill level
- Consider lane matchup and counter-picks
- Evaluate team synergy (engage, poke, scaling, etc.)
- Suggest champions that fit the team's win condition
- Provide safe blind picks vs strong counter-picks

Always prioritize strategic depth while being practical about player skill and champion pool."""

        super().__init__(llm, pregame_tools, system_prompt, "Pregame Strategy")


def create_specialized_agents(
    llm: ChatOpenAI,
    all_tools: Dict[str, List]
) -> Dict[str, BaseLoLAgent]:
    """
    Create all specialized agents with their respective tools.
    
    Args:
        llm: ChatOpenAI instance
        all_tools: Dictionary mapping tool categories to tool lists
            - "match": Match analysis tools
            - "build": Build/champion advice tools  
            - "video": YouTube search tools
            - "knowledge": Knowledge base tools
            - "pregame": Pregame/draft strategy tools
    
    Returns:
        Dictionary mapping agent names to agent instances
    """
    agents = {
        "match_analyzer": MatchAnalyzerAgent(
            llm=llm,
            match_tools=all_tools.get("match", [])
        ),
        "build_advisor": BuildAdvisorAgent(
            llm=llm,
            build_tools=all_tools.get("build", [])
        ),
        "video_guide": VideoGuideAgent(
            llm=llm,
            video_tools=all_tools.get("video", [])
        ),
        "knowledge_base": KnowledgeAgent(
            llm=llm,
            knowledge_tools=all_tools.get("knowledge", [])
        ),
        "pregame_agent": PregameAgent(
            llm=llm,
            pregame_tools=all_tools.get("pregame", [])
        )
    }
    
    return agents


# Example agent info display
if __name__ == "__main__":
    print("=" * 80)
    print("๐Ÿค– LoL Coach - Specialized Agents")
    print("=" * 80)
    
    agent_descriptions = {
        "Match Analyzer": "๐ŸŽฏ Analyzes match history, performance stats, and game trends",
        "Build Advisor": "๐Ÿ› ๏ธ Recommends optimal items, runes, and champion strategies",
        "Video Guide": "๐ŸŽฌ Finds YouTube guides, tutorials, and educational content",
        "Knowledge Base": "๐Ÿ“š Explains game concepts, terminology, and mechanics",
        "Pregame Strategy": "๐ŸŽฏ Champion select, draft strategy, and ban recommendations"
    }
    
    for name, desc in agent_descriptions.items():
        print(f"\n{desc}")
        print(f"   Agent: {name}")