alexmec commited on
Commit
c61fe48
·
verified ·
1 Parent(s): ced3ec5

Upload folder using huggingface_hub

Browse files
Files changed (7) hide show
  1. README.md +106 -21
  2. app.py +2 -117
  3. apps/app.py +155 -811
  4. apps/multiagent_draft.py +1 -1
  5. core/constants.py +2 -49
  6. docs/FEATURES_AND_ENHANCEMENTS.md +137 -197
  7. requirements.txt +4 -17
README.md CHANGED
@@ -11,35 +11,120 @@ license: mit
11
  python_version: 3.11
12
  ---
13
 
14
- # 🏈 Fantasy Draft Multi-Agent Demo
15
 
16
- Experience AI agents with distinct personalities competing in a fantasy football draft! You play as Team 4 with an AI advisor.
17
 
18
- ## Features
19
 
20
- - **6 AI Agents** with unique strategies (Zero RB, Best Player Available, Robust RB, etc.)
21
- - **Two Communication Modes**:
22
- - **Basic Multiagent**: Fast, single-process execution
23
- - **A2A Mode**: Distributed agents with automatic fallback (Full Lightweight → Simulated)
24
- - **Interactive Participation**: Draft alongside AI with strategic advice
25
- - **Real-time Communication**: Agents comment and react to picks
26
- - **Multi-User Support**: Each user gets their own draft session
27
 
28
- ## Setup
29
 
30
- 1. Add your OpenAI API key in **Settings → Repository secrets** as `OPENAI_API_KEY`
31
- 2. The app will start automatically once deployed
 
32
 
33
- ## About Communication Modes
34
 
35
- - **Basic Multiagent (Recommended)**: Works perfectly everywhere! All agents run in a single process with fast, reliable communication.
36
- - **A2A Mode (Adaptive)**: Automatically selects the best distributed mode:
37
- - **Full A2A**: Complete protocol with gRPC (when available)
38
- - **Lightweight A2A**: HTTP-only servers (works on HF Spaces!)
39
- - **Simulated A2A**: Mock distributed experience (fallback)
40
 
41
- ## About
 
 
42
 
43
- Built with the [any-agent](https://github.com/any-agent/any-agent) framework, showcasing how modern LLMs can create engaging multi-agent experiences.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  [View Source Code](https://github.com/alexmeckes/fantasydraft)
 
11
  python_version: 3.11
12
  ---
13
 
14
+ # 🏈 Fantasy Football Multi-Agent Draft System
15
 
16
+ An interactive fantasy football draft simulation featuring 6 AI agents with distinct personalities and strategies, built using the `any-agent` framework.
17
 
18
+ ## Features
19
 
20
+ - **Interactive Mock Draft**: Play as Team 4 with 5 AI opponents
21
+ - **Distinct Agent Strategies**: Zero RB, Robust RB, Best Player Available, Upside Hunter
22
+ - **Multi-Turn Memory**: Agents remember picks and conversations throughout the draft
23
+ - **Agent Communication**: Agents comment on and respond to each other's picks
24
+ - **Strategic Advisor**: AI advisor helps you make informed draft decisions
25
+ - **Visual Draft Board**: Track all picks with a beautiful, real-time updated interface
26
+ - **Customizable Personalities**: Modify each agent's personality and trash-talk style
27
 
28
+ ## 🚀 Quick Start
29
 
30
+ ### Prerequisites
31
+ - Python 3.8+
32
+ - OpenAI API key
33
 
34
+ ### Installation
35
 
36
+ ```bash
37
+ # Clone the repository
38
+ git clone <your-repo-url>
39
+ cd fantasy-draft-agent
 
40
 
41
+ # Create virtual environment
42
+ python -m venv venv
43
+ source venv/bin/activate # On Windows: venv\Scripts\activate
44
 
45
+ # Install dependencies
46
+ pip install -r requirements.txt
47
+
48
+ # Set your OpenAI API key
49
+ export OPENAI_API_KEY='your-key-here' # On Windows: set OPENAI_API_KEY=your-key-here
50
+ ```
51
+
52
+ ### Running the Application
53
+
54
+ ```bash
55
+ cd apps
56
+ python app.py
57
+ ```
58
+
59
+ Then open your browser to `http://localhost:7860`
60
+
61
+ ## 🎮 How to Play
62
+
63
+ 1. **Start the Draft**: Click "🏈 Start Mock Draft"
64
+ 2. **Watch AI Picks**: Agents draft in snake order with commentary
65
+ 3. **Make Your Pick**: When it's your turn (Position 4), type a player name
66
+ 4. **Get Advice**: Your AI advisor provides recommendations based on available players
67
+ 5. **Enjoy the Banter**: Watch agents trash-talk and defend their strategies
68
+
69
+ ## 🤖 The Agents
70
+
71
+ - **Team 1 - Zero RB** 📘🤓: Avoids RBs early, loads up on WRs
72
+ - **Team 2 - BPA** 📗🧑‍💼: Pure value drafting, mocks reaching
73
+ - **Team 3 - Robust RB** 📙🧔: Old-school RB-heavy approach
74
+ - **Team 4 - YOU** 👤: Your position with AI advisor
75
+ - **Team 5 - Upside Hunter** 📓🤠: High risk/reward picks
76
+ - **Team 6 - BPA** 📗👨‍🏫: Another value drafter
77
+
78
+ ## 🛠️ Technical Details
79
+
80
+ Built with:
81
+ - **any-agent**: Lightweight multi-agent framework
82
+ - **Gradio**: Interactive web interface
83
+ - **OpenAI GPT-4**: Powers agent decision-making
84
+ - **Multi-turn memory**: Agents maintain conversation history
85
+
86
+ ## 📁 Project Structure
87
+
88
+ ```
89
+ fantasy-draft-agent/
90
+ ├── apps/
91
+ │ ├── app.py # Main Gradio interface
92
+ │ ├── multiagent_draft.py # Core draft logic
93
+ │ └── multiagent_scenarios.py # Agent communication scenarios
94
+ ├── core/
95
+ │ ├── agent.py # Base agent implementation
96
+ │ ├── data.py # Player data and rankings
97
+ │ └── constants.py # Configuration constants
98
+ └── requirements.txt
99
+ ```
100
+
101
+ ## 🎯 Key Features Explained
102
+
103
+ ### Multi-Agent System
104
+ - Each agent runs independently with its own strategy
105
+ - Agents maintain memory of all interactions
106
+ - Natural rivalries create engaging commentary
107
+
108
+ ### Interactive Gameplay
109
+ - Real-time draft board visualization
110
+ - Strategic advisor provides contextual recommendations
111
+ - Customizable agent personalities
112
+
113
+ ### Memory System
114
+ - Agents remember previous picks and conversations
115
+ - References to earlier interactions create continuity
116
+ - Strategic adaptation based on draft flow
117
+
118
+ ## 🚦 Deployment
119
+
120
+ The application is designed to run locally or on cloud platforms like Hugging Face Spaces. The single-process architecture ensures reliable performance without complex networking requirements.
121
+
122
+ ## 📝 License
123
+
124
+ [Your License Here]
125
+
126
+ ## 🤝 Contributing
127
+
128
+ Contributions welcome! Please feel free to submit a Pull Request.
129
 
130
  [View Source Code](https://github.com/alexmeckes/fantasydraft)
app.py CHANGED
@@ -1,132 +1,17 @@
1
  #!/usr/bin/env python3
2
  """
3
- Entry point for Hugging Face Spaces and local deployment.
4
- All dependencies should be installed via requirements.txt.
5
  """
6
 
7
  import os
8
  import sys
9
 
10
- # Apply typing compatibility patch for Python 3.11 BEFORE any other imports
11
- from datetime import datetime
12
- print(f"\n===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====\n")
13
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
14
- import typing_patch
15
 
16
  # Simple startup message
17
  if os.getenv("SPACE_ID"):
18
  print("🤗 Running on Hugging Face Spaces...")
19
-
20
- # Check A2A installation
21
- print("🔍 Checking A2A installation...")
22
-
23
- # Check any-agent version
24
- try:
25
- import any_agent
26
- print(f"✅ any-agent version: {any_agent.__version__}")
27
- except ImportError as e:
28
- print(f"❌ any-agent not installed: {e}")
29
-
30
- # Check for httpx
31
- try:
32
- import httpx
33
- print(f"✅ httpx version: {httpx.__version__}")
34
- except ImportError as e:
35
- print(f"❌ httpx not installed: {e}")
36
-
37
- # Check for a2a module
38
- try:
39
- import a2a
40
- import importlib.metadata
41
- a2a_version = importlib.metadata.version('a2a-sdk')
42
- print(f"✅ a2a module found (a2a-sdk version: {a2a_version})")
43
- except ImportError as e:
44
- print(f"❌ a2a module not found: {e}")
45
-
46
- # Check if any_agent.serving exists
47
- try:
48
- import any_agent.serving
49
- print("✅ any_agent.serving module found")
50
- except ImportError as e:
51
- print(f"❌ any_agent.serving module not found: {e}")
52
-
53
- # Check for AgentSkill specifically
54
- try:
55
- from a2a.types import AgentSkill
56
- print("✅ AgentSkill import successful")
57
- except ImportError as e:
58
- print(f"❌ AgentSkill import failed: {e}")
59
-
60
- # Check for server dependencies
61
- print("\n🔍 Checking server dependencies:")
62
- try:
63
- import uvicorn
64
- print(f"✅ uvicorn found: {uvicorn.__version__}")
65
- except ImportError as e:
66
- print(f"❌ uvicorn not found: {e}")
67
-
68
- try:
69
- import starlette
70
- print(f"✅ starlette found: {starlette.__version__}")
71
- except ImportError as e:
72
- print(f"❌ starlette not found: {e}")
73
-
74
- try:
75
- from a2a.server import apps
76
- print("✅ a2a.server.apps found")
77
- except ImportError as e:
78
- print(f"❌ a2a.server.apps not found: {e}")
79
-
80
- try:
81
- import sse_starlette
82
- print("✅ sse-starlette found")
83
- except ImportError as e:
84
- print(f"❌ sse-starlette not found: {e}")
85
-
86
- # Test the specific imports that any_agent.serving tries
87
- print("\n🔍 Testing any_agent.serving imports:")
88
-
89
- # Test A2AServingConfig import
90
- try:
91
- from any_agent.serving.a2a.config_a2a import A2AServingConfig
92
- print("✅ A2AServingConfig direct import successful")
93
- except ImportError as e:
94
- print(f"❌ A2AServingConfig direct import failed: {e}")
95
-
96
- # Test server_a2a imports
97
- try:
98
- from any_agent.serving.a2a.server_a2a import serve_a2a
99
- print("✅ serve_a2a direct import successful")
100
- except ImportError as e:
101
- print(f"❌ serve_a2a direct import failed: {e}")
102
-
103
- # Test other imports from server_a2a
104
- try:
105
- from any_agent.serving.a2a.server_a2a import (
106
- _get_a2a_app,
107
- _get_a2a_app_async,
108
- serve_a2a_async,
109
- )
110
- print("✅ All server_a2a imports successful")
111
- except ImportError as e:
112
- print(f"❌ server_a2a imports failed: {e}")
113
- import traceback
114
- traceback.print_exc()
115
-
116
- # Try to import A2AServingConfig with more detailed error handling
117
- try:
118
- from any_agent.serving import A2AServingConfig
119
- print("✅ A2AServingConfig import successful")
120
- except ImportError as e:
121
- print(f"❌ Import error: {e}")
122
- # Try to get more details
123
- try:
124
- import traceback
125
- print("Full traceback:")
126
- traceback.print_exc()
127
- except:
128
- pass
129
-
130
  else:
131
  print("🖥️ Running locally...")
132
 
 
1
  #!/usr/bin/env python3
2
  """
3
+ Entry point for the Fantasy Draft Multi-Agent application.
 
4
  """
5
 
6
  import os
7
  import sys
8
 
9
+ # Add current directory to path
 
 
10
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
 
11
 
12
  # Simple startup message
13
  if os.getenv("SPACE_ID"):
14
  print("🤗 Running on Hugging Face Spaces...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  else:
16
  print("🖥️ Running locally...")
17
 
apps/app.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
- Fantasy Draft Multi-Agent Demo - Enhanced with A2A Support
4
- Combines the superior UI from the main app with real A2A capabilities
5
  """
6
 
7
  import os
@@ -12,7 +12,7 @@ import nest_asyncio
12
  from typing import List, Tuple, Optional, Dict
13
  from dotenv import load_dotenv
14
  import sys
15
- import os
16
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
17
 
18
  from core.agent import FantasyDraftAgent
@@ -20,21 +20,7 @@ from core.data import TOP_PLAYERS
20
  from core.constants import (
21
  TYPING_DELAY_SECONDS,
22
  MESSAGE_DELAY_SECONDS,
23
- AGENT_START_DELAY,
24
- AGENT_STARTUP_WAIT,
25
- DEFAULT_TIMEOUT,
26
- MAX_COMMENTS_PER_PICK,
27
- RIVAL_PAIRS,
28
- AGENT_CONFIGS
29
- )
30
- from core.a2a_helpers import (
31
- parse_a2a_response,
32
- extract_task_id,
33
- format_available_players
34
  )
35
- # Lazy import A2A components to avoid import errors on HF Spaces
36
- DynamicA2AAgentManager = None
37
- cleanup_session = None
38
 
39
  from apps.multiagent_draft import MultiAgentMockDraft
40
  from apps.multiagent_scenarios import (
@@ -45,9 +31,6 @@ from apps.multiagent_scenarios import (
45
  create_mock_draft_visualization
46
  )
47
 
48
- # A2A components will be imported lazily when needed
49
- # to avoid import errors on Hugging Face Spaces
50
-
51
  # Apply nest_asyncio for async in Gradio
52
  nest_asyncio.apply()
53
 
@@ -58,314 +41,30 @@ os.environ['OPENAI_API_BASE'] = 'https://api.openai.com/v1'
58
  load_dotenv()
59
 
60
 
61
- class EnhancedFantasyDraftApp:
62
  def __init__(self):
63
  self.current_draft = None # Store the current mock draft
64
  self.draft_output = "" # Store the draft output so far
65
- self.a2a_manager = None # Will be created dynamically with session ID
66
- self.use_real_a2a = False
67
- self.a2a_status = "Not initialized"
68
- self.session_id = None
69
  self.custom_prompts = {} # Store custom agent prompts
70
 
71
- async def toggle_a2a_mode(self, use_a2a: bool):
72
- """Toggle between basic multiagent and A2A modes."""
73
- self.use_real_a2a = use_a2a
74
-
75
- if use_a2a:
76
- # Lazy import A2A components only when needed
77
- try:
78
- global DynamicA2AAgentManager, cleanup_session
79
- from core.dynamic_a2a_manager import DynamicA2AAgentManager, cleanup_session
80
- self.real_a2a = True
81
- self.a2a_type = "full"
82
- except ImportError as e:
83
- # Fall back to simulated A2A
84
- try:
85
- from core.simulated_a2a_manager import SimulatedA2AAgentManager, cleanup_session
86
- DynamicA2AAgentManager = SimulatedA2AAgentManager
87
- self.real_a2a = False
88
- self.a2a_type = "simulated"
89
- print("Using simulated A2A mode (real A2A not available)")
90
- except ImportError as e2:
91
- self.a2a_status = f"❌ A2A mode not available: {str(e)}. Please use Basic Multiagent mode."
92
- self.use_real_a2a = False
93
- return self.a2a_status
94
-
95
- # Generate unique session ID if needed
96
- if not self.session_id:
97
- import uuid
98
- self.session_id = str(uuid.uuid4())[:8]
99
-
100
- # Create new dynamic manager for this session with custom prompts
101
- self.a2a_manager = DynamicA2AAgentManager(
102
- self.session_id,
103
- custom_prompts=self.custom_prompts
104
- )
105
-
106
- try:
107
- await self.a2a_manager.start_agents()
108
- ports = self.a2a_manager.allocated_ports
109
- if hasattr(self, 'a2a_type'):
110
- if self.a2a_type == "full":
111
- self.a2a_status = f"✅ Full A2A Mode Active (Session: {self.session_id}, Ports: {ports[0]}-{ports[-1]})"
112
- elif self.a2a_type == "lightweight":
113
- self.a2a_status = f"✅ Lightweight A2A Mode Active (Session: {self.session_id}, HTTP Ports: {ports[0]}-{ports[-1]})"
114
- else: # simulated
115
- self.a2a_status = f"✅ Simulated A2A Mode Active (Session: {self.session_id}, Mock Ports: {ports[0]}-{ports[-1]})"
116
- else:
117
- self.a2a_status = f"✅ A2A Mode Active (Session: {self.session_id}, Ports: {ports[0]}-{ports[-1]})"
118
- except RuntimeError as e:
119
- # Failed to allocate ports or start agents
120
- self.a2a_status = f"❌ Failed to start A2A: {str(e)}"
121
- self.use_real_a2a = False
122
- self.a2a_manager = None
123
- else:
124
- if self.a2a_manager and cleanup_session:
125
- await cleanup_session(self.a2a_manager)
126
- self.a2a_manager = None
127
- self.a2a_status = "✅ Basic Multiagent Mode Active (Using built-in communication)"
128
-
129
- return self.a2a_status
130
-
131
- def run_multiagent_demo(self, use_a2a: bool = False):
132
- """Run the mock draft demonstration with optional A2A support."""
133
  # Reset any previous draft
134
  self.current_draft = None
135
  self.draft_output = ""
136
 
137
- # First, set the mode (like in the working version)
138
- loop = asyncio.new_event_loop()
139
- asyncio.set_event_loop(loop)
140
-
141
- status = loop.run_until_complete(self.toggle_a2a_mode(use_a2a))
142
- yield f"**Mode:** {status}\n\n"
143
-
144
- # Initialize draft
145
- self.current_draft = MultiAgentMockDraft(user_pick_position=4)
146
 
147
- # Run the appropriate draft
148
- if use_a2a and self.a2a_manager:
149
- yield from self.run_a2a_draft()
150
- else:
151
- # Use basic multiagent draft
152
- draft_generator = run_interactive_mock_draft()
153
-
154
- for output in draft_generator:
155
- if isinstance(output, tuple):
156
- # This means it's the user's turn
157
- self.current_draft, self.draft_output = output
158
- yield self.draft_output + "\n<!--USER_TURN-->"
159
- return
160
- else:
161
- self.draft_output = output
162
- yield output
163
-
164
- def run_a2a_draft(self):
165
- """Run draft with A2A communication."""
166
- # Initialize draft
167
- self.current_draft = MultiAgentMockDraft(user_pick_position=4)
168
- self.draft_output = "# 🏈 Mock Draft with A2A Communication\n\n"
169
-
170
- # Welcome message
171
- if hasattr(self, 'a2a_type'):
172
- if self.a2a_type == "full":
173
- welcome_msg = "Welcome to the A2A-powered draft! Each agent is running on its own server with full A2A protocol."
174
- elif self.a2a_type == "lightweight":
175
- welcome_msg = "Welcome to the lightweight A2A draft! Each agent runs on its own HTTP server (no grpcio needed)."
176
- else: # simulated
177
- welcome_msg = "Welcome to the simulated A2A draft! Agents communicate using mock HTTP calls."
178
- else:
179
- welcome_msg = "Welcome to the A2A-powered draft! Each agent is running on its own server."
180
- self.draft_output += format_agent_message(
181
- "commissioner", "ALL",
182
- welcome_msg
183
- )
184
- yield self.draft_output
185
-
186
- # Run draft rounds
187
- loop = asyncio.get_event_loop()
188
-
189
- for round_num in range(1, 4): # 3 rounds
190
- self.draft_output += f"\n## 🔄 ROUND {round_num}\n\n"
191
- yield self.draft_output
192
-
193
- # Snake draft order
194
- if round_num % 2 == 1:
195
- pick_order = list(range(1, 7))
196
  else:
197
- pick_order = list(range(6, 0, -1))
198
-
199
- for pick_in_round, team_num in enumerate(pick_order, 1):
200
- pick_num = (round_num - 1) * 6 + pick_in_round
201
-
202
- # Show draft board at start of round
203
- if pick_in_round == 1:
204
- self.draft_output += create_mock_draft_visualization(self.current_draft, round_num, pick_num)
205
- self.draft_output += "\n"
206
- yield self.draft_output
207
-
208
- if team_num == 4: # User's turn
209
- # Get advisor recommendation - use user_advisor directly
210
- advisor = self.current_draft.user_advisor
211
-
212
- # Get available players
213
- all_picked = [p for picks in self.current_draft.draft_board.values() for p in picks]
214
- available = [p for p in TOP_PLAYERS.keys() if p not in all_picked]
215
-
216
- # Get other agent strategies for advisor context
217
- strategies = {f"Team {i}": agent.strategy for i, agent in self.current_draft.agents.items()}
218
-
219
- # Get advisor recommendation
220
- advice = advisor.advise_user(available, self.current_draft.draft_board, strategies)
221
-
222
- # Show advisor message
223
- self.draft_output += format_agent_message(advisor, "USER", advice)
224
- yield self.draft_output
225
-
226
- self.draft_output += "\n**⏰ YOU'RE ON THE CLOCK! Type your pick below.**\n\n"
227
- yield self.draft_output + "\n<!--USER_TURN-->"
228
- return
229
- else:
230
- # A2A agent pick
231
- messages = loop.run_until_complete(
232
- self.run_a2a_draft_turn(team_num, round_num, pick_num)
233
- )
234
-
235
- # Display messages with typing effect
236
- for msg in messages:
237
- if len(msg) >= 3:
238
- agent, recipient, content = msg[:3]
239
-
240
- # Show "..." first for typing effect
241
- typing_placeholder = format_agent_message(agent, recipient, "...")
242
- self.draft_output += typing_placeholder
243
- yield self.draft_output
244
- time.sleep(TYPING_DELAY_SECONDS)
245
-
246
- # Replace with actual message
247
- self.draft_output = self.draft_output.replace(typing_placeholder, "")
248
- self.draft_output += format_agent_message(agent, recipient, content)
249
- yield self.draft_output
250
- time.sleep(MESSAGE_DELAY_SECONDS)
251
-
252
- time.sleep(TYPING_DELAY_SECONDS)
253
-
254
- # End of round
255
- self.draft_output += format_agent_message("commissioner", "ALL",
256
- f"That's the end of Round {round_num}!")
257
- yield self.draft_output
258
-
259
- # Final summary
260
- self.draft_output += "\n## 📊 FINAL RESULTS\n\n"
261
- self.draft_output += self.current_draft.get_draft_summary()
262
- yield self.draft_output
263
-
264
- # Clear the draft state
265
- self.current_draft = None
266
-
267
- async def run_a2a_draft_turn(self, team_num: int, round_num: int, pick_num: int):
268
- """Run a draft turn using A2A."""
269
- messages = []
270
-
271
- # Commissioner announcement
272
- messages.append((
273
- self.current_draft.commissioner,
274
- "ALL",
275
- f"Team {team_num} is on the clock!"
276
- ))
277
-
278
- # Get available players
279
- all_picked = [p for picks in self.current_draft.draft_board.values() for p in picks]
280
- available = [p for p in TOP_PLAYERS.keys() if p not in all_picked]
281
-
282
- # Get pick from A2A agent
283
- previous_picks = self.current_draft.draft_board.get(team_num, [])
284
- pick_result = await self.a2a_manager.get_pick(team_num, available, previous_picks, round_num)
285
-
286
- if not pick_result or pick_result.type != "pick":
287
- # Fallback to simulation
288
- messages.append((
289
- self.current_draft.commissioner,
290
- "ALL",
291
- f"⚠️ Team {team_num} A2A agent not responding - using simulation"
292
- ))
293
-
294
- sim_messages, _ = self.current_draft.simulate_draft_turn(round_num, pick_num, team_num)
295
- messages.extend(sim_messages)
296
- return messages
297
-
298
- # Make the pick
299
- player = pick_result.player_name
300
- self.current_draft.draft_board[team_num].append(player)
301
-
302
- # Update agent's picks if it exists
303
- agent = self.current_draft.agents.get(team_num)
304
- if agent:
305
- agent.picks.append(player)
306
-
307
- # Commissioner announcement of pick
308
- pick_num = len([p for picks in self.current_draft.draft_board.values() for p in picks])
309
- confirm_msg = self.current_draft.commissioner.confirm_pick(
310
- agent.team_name if agent else f"Team {team_num}",
311
- player,
312
- pick_num
313
- )
314
- messages.append((self.current_draft.commissioner, "ALL", confirm_msg))
315
-
316
- # Agent explains reasoning
317
- messages.append((
318
- agent if agent else "system",
319
- "ALL",
320
- f"{pick_result.reasoning}"
321
- ))
322
-
323
- if pick_result.trash_talk:
324
- messages.append((
325
- agent if agent else "system",
326
- "ALL",
327
- pick_result.trash_talk
328
- ))
329
-
330
- # Get comments from other A2A agents
331
- potential_commenters = [t for t in [1, 2, 3, 5, 6] if t != team_num and t != 4]
332
-
333
- # Sort commenters to prioritize rivals
334
- if team_num in RIVAL_PAIRS and potential_commenters:
335
- rivals = RIVAL_PAIRS[team_num]
336
- if isinstance(rivals, int):
337
- rivals = [rivals]
338
- # Put rivals first in the list
339
- prioritized_commenters = [t for t in rivals if t in potential_commenters]
340
- prioritized_commenters.extend([t for t in potential_commenters if t not in prioritized_commenters])
341
- potential_commenters = prioritized_commenters
342
-
343
- # Collect comments up to the configured limit
344
- comment_count = 0
345
- max_comments = self.a2a_manager.max_comments_per_pick
346
-
347
- # Reduce comments if we're getting late in the draft
348
- if pick_num >= 4: # After pick 4, reduce comments
349
- max_comments = min(max_comments, 1)
350
-
351
- for other_team in potential_commenters:
352
- if comment_count >= max_comments:
353
- break
354
-
355
- comment = await self.a2a_manager.get_comment(other_team, team_num, player, round_num)
356
- if comment:
357
- other_agent = self.current_draft.agents.get(other_team)
358
- if other_agent:
359
- # Use the same pattern as earlier for the picking agent's name
360
- picking_agent_name = agent.team_name if agent else f"Team {team_num}"
361
- messages.append((
362
- other_agent,
363
- picking_agent_name,
364
- comment
365
- ))
366
- comment_count += 1
367
-
368
- return messages
369
 
370
  def continue_mock_draft(self, player_name: str):
371
  """Continue the mock draft after user makes a pick."""
@@ -402,26 +101,16 @@ class EnhancedFantasyDraftApp:
402
  time.sleep(MESSAGE_DELAY_SECONDS)
403
 
404
  # Continue with the rest of the draft
405
- if self.use_real_a2a and self.a2a_manager:
406
- yield from self.continue_a2a_draft()
407
- else:
408
- yield from self.continue_basic_multiagent_draft()
409
 
410
- def continue_a2a_draft(self):
411
- """Continue A2A draft after user pick."""
412
  # Calculate where we are
413
  total_picks = len([p for picks in self.current_draft.draft_board.values() for p in picks])
414
  current_round = ((total_picks - 1) // 6) + 1
415
 
416
- # Get or create event loop
417
- try:
418
- loop = asyncio.get_running_loop()
419
- except RuntimeError:
420
- loop = asyncio.new_event_loop()
421
- asyncio.set_event_loop(loop)
422
-
423
- # Continue from current position
424
- for round_num in range(current_round, 4):
425
  if round_num > current_round:
426
  self.draft_output += f"\n## 🔄 ROUND {round_num}\n\n"
427
  yield self.draft_output
@@ -432,11 +121,15 @@ class EnhancedFantasyDraftApp:
432
  else:
433
  pick_order = list(range(6, 0, -1))
434
 
435
- # Calculate where we are in the current round
436
  picks_in_round = total_picks % 6
437
- start_idx = picks_in_round if round_num == current_round else 0
 
 
 
 
438
 
439
- for pick_in_round, team_num in enumerate(list(pick_order)[start_idx:], start_idx + 1):
440
  pick_num = (round_num - 1) * 6 + pick_in_round
441
 
442
  # Show draft board at start of round
@@ -445,17 +138,21 @@ class EnhancedFantasyDraftApp:
445
  self.draft_output += "\n"
446
  yield self.draft_output
447
 
448
- if team_num == 4: # User's turn again
449
- # Get advisor recommendation - use user_advisor directly
450
  advisor = self.current_draft.user_advisor
451
 
 
452
  all_picked = [p for picks in self.current_draft.draft_board.values() for p in picks]
453
  available = [p for p in TOP_PLAYERS.keys() if p not in all_picked]
454
 
455
  # Get other agent strategies for advisor context
456
  strategies = {f"Team {i}": agent.strategy for i, agent in self.current_draft.agents.items()}
457
 
 
458
  advice = advisor.advise_user(available, self.current_draft.draft_board, strategies)
 
 
459
  self.draft_output += format_agent_message(advisor, "USER", advice)
460
  yield self.draft_output
461
 
@@ -463,19 +160,21 @@ class EnhancedFantasyDraftApp:
463
  yield self.draft_output + "\n<!--USER_TURN-->"
464
  return
465
  else:
466
- # A2A agent pick
467
- messages = loop.run_until_complete(
468
- self.run_a2a_draft_turn(team_num, round_num, pick_num)
469
- )
470
 
 
471
  for msg in messages:
472
  if len(msg) >= 3:
473
  agent, recipient, content = msg[:3]
 
 
474
  typing_placeholder = format_agent_message(agent, recipient, "...")
475
  self.draft_output += typing_placeholder
476
  yield self.draft_output
477
  time.sleep(TYPING_DELAY_SECONDS)
478
 
 
479
  self.draft_output = self.draft_output.replace(typing_placeholder, "")
480
  self.draft_output += format_agent_message(agent, recipient, content)
481
  yield self.draft_output
@@ -483,6 +182,7 @@ class EnhancedFantasyDraftApp:
483
 
484
  time.sleep(TYPING_DELAY_SECONDS)
485
 
 
486
  self.draft_output += format_agent_message("commissioner", "ALL",
487
  f"That's the end of Round {round_num}!")
488
  yield self.draft_output
@@ -492,87 +192,12 @@ class EnhancedFantasyDraftApp:
492
  self.draft_output += self.current_draft.get_draft_summary()
493
  yield self.draft_output
494
 
495
- self.current_draft = None
496
-
497
- def continue_basic_multiagent_draft(self):
498
- """Continue basic multiagent draft after user pick."""
499
- # This is the original logic from app.py
500
- total_picks = len([p for picks in self.current_draft.draft_board.values() for p in picks])
501
- current_round = ((total_picks - 1) // 6) + 1
502
-
503
- draft_memories = []
504
-
505
- for round_num in range(current_round, 4):
506
- if round_num > current_round:
507
- self.draft_output += f"\n## 🔄 ROUND {round_num}\n\n"
508
- yield self.draft_output
509
-
510
- if round_num % 2 == 1:
511
- pick_order = list(range(1, 7))
512
- else:
513
- pick_order = list(range(6, 0, -1))
514
-
515
- picks_in_round = total_picks % 6
516
- start_idx = picks_in_round if round_num == current_round else 0
517
-
518
- for pick_in_round, team_num in enumerate(list(pick_order)[start_idx:], start_idx + 1):
519
- pick_num = (round_num - 1) * 6 + pick_in_round
520
-
521
- if pick_in_round == 1:
522
- self.draft_output += create_mock_draft_visualization(self.current_draft, round_num, pick_num)
523
- self.draft_output += "\n"
524
- yield self.draft_output
525
-
526
- messages, result = self.current_draft.simulate_draft_turn(round_num, pick_num, team_num)
527
-
528
- for msg in messages:
529
- if len(msg) >= 3:
530
- agent, recipient, content = msg[:3]
531
-
532
- if isinstance(agent, str) and agent.startswith("typing_"):
533
- continue
534
- else:
535
- typing_placeholder = format_agent_message(agent, recipient, "...")
536
- self.draft_output += typing_placeholder
537
- yield self.draft_output
538
- time.sleep(TYPING_DELAY_SECONDS)
539
-
540
- self.draft_output = self.draft_output.replace(typing_placeholder, "")
541
- self.draft_output += format_agent_message(agent, recipient, content)
542
- yield self.draft_output
543
- time.sleep(MESSAGE_DELAY_SECONDS)
544
-
545
- if result is None:
546
- self.draft_output += "\n**⏰ YOU'RE ON THE CLOCK! Type your pick below.**\n\n"
547
- yield self.draft_output + "\n<!--USER_TURN-->"
548
- return
549
-
550
- if round_num > 1 and pick_in_round % 2 == 0:
551
- if team_num in self.current_draft.agents:
552
- agent = self.current_draft.agents[team_num]
553
- if len(agent.picks) > 1:
554
- memory = f"{agent.team_name} has drafted: {', '.join(agent.picks)}"
555
- draft_memories.append(memory)
556
-
557
- if draft_memories:
558
- self.draft_output += format_memory_indicator(round_num, draft_memories[-2:])
559
- yield self.draft_output
560
-
561
- time.sleep(TYPING_DELAY_SECONDS)
562
-
563
- self.draft_output += format_agent_message("commissioner", "ALL",
564
- f"That's the end of Round {round_num}!")
565
- yield self.draft_output
566
-
567
- self.draft_output += "\n## 📊 FINAL RESULTS\n\n"
568
- self.draft_output += self.current_draft.get_draft_summary()
569
- yield self.draft_output
570
-
571
  self.current_draft = None
572
 
573
 
574
  def create_gradio_interface():
575
- """Create the main Gradio interface with A2A support."""
576
 
577
  with gr.Blocks(title="Fantasy Draft Multi-Agent Demo", theme=gr.themes.Soft()) as demo:
578
  # Create state for each user session
@@ -588,25 +213,6 @@ def create_gradio_interface():
588
  with gr.Tabs():
589
  # Demo Tab
590
  with gr.TabItem("🎮 Demo"):
591
- # Add A2A Mode Toggle
592
- with gr.Row():
593
- with gr.Column():
594
- gr.Markdown("### 🔧 Communication Mode")
595
- communication_mode = gr.Radio(
596
- ["A2A", "Basic Multiagent"],
597
- value="Basic Multiagent",
598
- label="Select how agents communicate",
599
- info="A2A: Distributed agents on HTTP servers | Basic Multiagent: Single-process execution"
600
- )
601
- mode_info = gr.Markdown(
602
- """
603
- **Basic Multiagent** (Default): Fast single-process execution with reliable performance
604
- **A2A**: Each agent runs on its own HTTP server with distributed architecture
605
-
606
- *Basic Multiagent mode is recommended for Hugging Face Spaces deployments.*
607
- """
608
- )
609
-
610
  # Show agent cards
611
  gr.Markdown("""
612
  ### 🏈 Meet Your Competition
@@ -636,7 +242,7 @@ def create_gradio_interface():
636
  team1_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
637
  with gr.Column(visible=False) as team1_prompt_col:
638
  team1_prompt = gr.Textbox(
639
- label="Team 1 Personality & Strategy (Output format is fixed)",
640
  value="""You are Team 1, a fantasy football manager with Zero RB strategy.
641
 
642
  PERSONALITY & STRATEGY:
@@ -655,7 +261,7 @@ Your EXTREME philosophy: RUNNING BACKS ARE DEAD TO ME! 💀 While others waste e
655
  BE LOUD! BE PROUD! BE UNFORGETTABLE! 🎯""",
656
  lines=15,
657
  interactive=True,
658
- info="Customize personality and strategy. Output format instructions are automatically included."
659
  )
660
  team1_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
661
 
@@ -676,7 +282,7 @@ BE LOUD! BE PROUD! BE UNFORGETTABLE! 🎯""",
676
  team2_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
677
  with gr.Column(visible=False) as team2_prompt_col:
678
  team2_prompt = gr.Textbox(
679
- label="Team 2 Personality & Strategy (Output format is fixed)",
680
  value="""You are Team 2, a fantasy football manager with BPA (Best Player Available) strategy.
681
 
682
  PERSONALITY & STRATEGY:
@@ -694,7 +300,7 @@ Your EXTREME philosophy: PROCESS OVER EVERYTHING! 📊 I don't care about your "
694
  BE RUTHLESS! BE RIGHT! BE THE VALUE VULTURE! 🦅""",
695
  lines=15,
696
  interactive=True,
697
- info="Customize personality and strategy. Output format instructions are automatically included."
698
  )
699
  team2_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
700
 
@@ -715,7 +321,7 @@ BE RUTHLESS! BE RIGHT! BE THE VALUE VULTURE! 🦅""",
715
  team3_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
716
  with gr.Column(visible=False) as team3_prompt_col:
717
  team3_prompt = gr.Textbox(
718
- label="Team 3 Personality & Strategy (Output format is fixed)",
719
  value="""You are Team 3, a fantasy football manager with Robust RB strategy.
720
 
721
  PERSONALITY & STRATEGY:
@@ -733,7 +339,7 @@ Your EXTREME philosophy: GROUND AND POUND FOREVER! 🏃‍♂️ These young pun
733
  BE STUBBORN! BE TRADITIONAL! ESTABLISH THE RUN! 🏈""",
734
  lines=15,
735
  interactive=True,
736
- info="Customize personality and strategy. Output format instructions are automatically included."
737
  )
738
  team3_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
739
 
@@ -768,7 +374,7 @@ BE STUBBORN! BE TRADITIONAL! ESTABLISH THE RUN! 🏈""",
768
  team5_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
769
  with gr.Column(visible=False) as team5_prompt_col:
770
  team5_prompt = gr.Textbox(
771
- label="Team 5 Personality & Strategy (Output format is fixed)",
772
  value="""You are Team 5, a fantasy football manager with Upside Hunter strategy.
773
 
774
  PERSONALITY & STRATEGY:
@@ -786,7 +392,7 @@ Your EXTREME philosophy: BOOM OR BUST, BABY! 💥 Why settle for consistent medi
786
  BE BOLD! BE RECKLESS! SWING FOR THE FENCES! ⚡""",
787
  lines=15,
788
  interactive=True,
789
- info="Customize personality and strategy. Output format instructions are automatically included."
790
  )
791
  team5_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
792
 
@@ -807,7 +413,7 @@ BE BOLD! BE RECKLESS! SWING FOR THE FENCES! ⚡""",
807
  team6_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
808
  with gr.Column(visible=False) as team6_prompt_col:
809
  team6_prompt = gr.Textbox(
810
- label="Team 6 Personality & Strategy (Output format is fixed)",
811
  value="""You are Team 6, a fantasy football manager with BPA (Best Player Available) strategy.
812
 
813
  PERSONALITY & STRATEGY:
@@ -825,7 +431,7 @@ Your EXTREME philosophy: THE SPREADSHEET NEVER LIES! 📈 I have SEVENTEEN model
825
  BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
826
  lines=15,
827
  interactive=True,
828
- info="Customize personality and strategy. Output format instructions are automatically included."
829
  )
830
  team6_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
831
 
@@ -863,40 +469,6 @@ BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
863
  interactive=False
864
  )
865
 
866
- # Debug Tab
867
- with gr.TabItem("🔍 Debug"):
868
- gr.Markdown("""
869
- ## A2A Debugging Tools
870
-
871
- Use these tools to test A2A functionality and diagnose any issues.
872
- """)
873
-
874
- with gr.Row():
875
- with gr.Column():
876
- test_a2a_btn = gr.Button("🧪 Test A2A Dependencies & Ports", variant="primary", size="lg")
877
- test_network_btn = gr.Button("🌐 Test Network Connectivity", variant="secondary", size="lg")
878
-
879
- a2a_test_output = gr.Textbox(
880
- label="Test Results",
881
- lines=20,
882
- interactive=False,
883
- elem_classes=["monospace"]
884
- )
885
-
886
- gr.Markdown("""
887
- ### What this test checks:
888
- - ✓ Python environment and version
889
- - ✓ a2a-sdk package installation
890
- - ✓ Module imports (a2a, any_agent)
891
- - ✓ Port availability for agents
892
- - ✓ A2A agent startup capability
893
-
894
- ### Common issues:
895
- - **Import errors**: Check if a2a-sdk is properly installed
896
- - **Port conflicts**: Other services might be using ports 5000-9000
897
- - **Timeout errors**: Network latency on cloud deployments
898
- """)
899
-
900
  # How It Works Tab
901
  with gr.TabItem("🔧 How It Works"):
902
  gr.Markdown("""
@@ -919,28 +491,15 @@ BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
919
  - **Strategy Memory**: Remembers own strategy and others' approaches
920
  - **Pick History**: Tracks all selections for informed decisions
921
 
922
- ### 💬 Agent-to-Agent (A2A) Communication
923
 
924
- **Two Modes Available:**
925
-
926
- #### 1. A2A Mode (Default)
927
- - **Distributed Architecture**: Each agent runs on its own HTTP server
928
- - **Dynamic Ports**: Each session gets unique ports automatically (5000-9000 range)
929
- - **True Isolation**: No shared memory, HTTP communication only
930
- - **Production Ready**: Scalable to multiple machines
931
- - **Real HTTP Calls**: Agents communicate via actual network requests
932
- - **Task Continuity**: Conversation context maintained across turns
933
-
934
- #### 2. Basic Multiagent Mode
935
- - Single process, direct method calls
936
- - Shared memory between agents
937
- - Fast execution, simple debugging
938
- - Fallback option if A2A requirements aren't met
939
 
940
  ### 📊 Architecture Flow
941
- """)
942
 
943
- gr.Markdown("""
944
  #### 1️⃣ INITIALIZATION
945
  User clicks "Start Mock Draft" → System creates 6 agents
946
 
@@ -959,7 +518,7 @@ BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
959
 
960
  #### 4️⃣ EACH PICK TRIGGERS
961
  - Agent makes selection based on strategy
962
- - Other agents comment (A2A communication)
963
  - Original agent may respond
964
  - All agents update their memory
965
 
@@ -1009,376 +568,161 @@ BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
1009
  "" # Clear the input
1010
  )
1011
 
1012
- # Test A2A functionality
1013
- def test_a2a_functionality():
1014
- """Test A2A dependencies and port availability."""
1015
- import socket
1016
- import subprocess
1017
- import importlib.util
1018
- import site
1019
-
1020
- test_results = []
1021
-
1022
- # 1. Python Environment
1023
- test_results.append("=== Python Environment ===")
1024
- test_results.append(f"Python: {sys.version.split()[0]}")
1025
- test_results.append(f"Platform: {sys.platform}")
1026
- test_results.append(f"SPACE_ID: {os.getenv('SPACE_ID', 'Not on HF Spaces')}")
1027
-
1028
- # 2. Check a2a-sdk installation
1029
- test_results.append("\n=== Package Installation ===")
1030
- try:
1031
- result = subprocess.run([sys.executable, "-m", "pip", "show", "a2a-sdk"],
1032
- capture_output=True, text=True, timeout=5)
1033
- if result.returncode == 0:
1034
- version_line = [line for line in result.stdout.split('\n') if line.startswith('Version:')]
1035
- location_line = [line for line in result.stdout.split('\n') if line.startswith('Location:')]
1036
- test_results.append(f"✅ a2a-sdk installed: {version_line[0] if version_line else 'Unknown version'}")
1037
- if location_line:
1038
- test_results.append(f" {location_line[0]}")
1039
- else:
1040
- test_results.append("❌ a2a-sdk NOT installed according to pip")
1041
- except Exception as e:
1042
- test_results.append(f"❌ Error checking pip: {e}")
1043
-
1044
- # 3. Module search
1045
- test_results.append("\n=== Module Search ===")
1046
- a2a_spec = importlib.util.find_spec("a2a")
1047
- if a2a_spec:
1048
- test_results.append(f"✅ a2a module found at: {a2a_spec.origin}")
1049
- else:
1050
- test_results.append("❌ a2a module NOT found by importlib")
1051
- # Manual search
1052
- for path in site.getsitepackages():
1053
- if os.path.exists(path):
1054
- a2a_path = os.path.join(path, "a2a")
1055
- if os.path.exists(a2a_path):
1056
- test_results.append(f" Found a2a directory at: {a2a_path}")
1057
-
1058
- # 4. Import tests
1059
- test_results.append("\n=== Import Tests ===")
1060
-
1061
- # Basic a2a import
1062
- try:
1063
- import a2a
1064
- test_results.append(f"✅ import a2a: Success")
1065
- try:
1066
- import a2a.types
1067
- test_results.append("✅ import a2a.types: Success")
1068
- try:
1069
- from a2a.types import AgentSkill
1070
- test_results.append("✅ from a2a.types import AgentSkill: Success")
1071
- except ImportError as e:
1072
- test_results.append(f"❌ AgentSkill import: {e}")
1073
- except ImportError as e:
1074
- test_results.append(f"❌ a2a.types import: {e}")
1075
- except ImportError as e:
1076
- test_results.append(f"❌ a2a import failed: {e}")
1077
-
1078
- # any_agent A2A imports
1079
- try:
1080
- from any_agent.serving import A2AServingConfig
1081
- from any_agent.tools import a2a_tool_async
1082
- test_results.append("✅ any_agent A2A components: Success!")
1083
- except ImportError as e:
1084
- test_results.append(f"❌ any_agent A2A import: {e}")
1085
-
1086
- # 5. Port availability
1087
- test_results.append("\n=== Port Availability ===")
1088
- test_ports = [5001, 5002, 5003, 5004, 5005, 5006]
1089
- available_count = 0
1090
-
1091
- for port in test_ports:
1092
- try:
1093
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1094
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1095
- sock.bind(('127.0.0.1', port))
1096
- test_results.append(f"✅ Port {port} available")
1097
- available_count += 1
1098
- sock.close()
1099
- except Exception:
1100
- test_results.append(f"❌ Port {port} not available")
1101
-
1102
- test_results.append(f"\n📊 Summary: {available_count}/{len(test_ports)} ports available")
1103
-
1104
- # 6. Check any-agent version if imports failed
1105
- if "❌ any_agent A2A import" in "\n".join(test_results):
1106
- test_results.append("\n=== Version Check ===")
1107
- try:
1108
- result = subprocess.run([sys.executable, "-m", "pip", "show", "any-agent"],
1109
- capture_output=True, text=True, timeout=5)
1110
- if result.returncode == 0:
1111
- version_line = [line for line in result.stdout.split('\n') if line.startswith('Version:')]
1112
- if version_line:
1113
- test_results.append(f"any-agent version: {version_line[0]}")
1114
- # Check if version is < 0.22
1115
- import re
1116
- version_match = re.search(r'Version: (\d+)\.(\d+)', version_line[0])
1117
- if version_match:
1118
- major, minor = int(version_match.group(1)), int(version_match.group(2))
1119
- if major == 0 and minor < 22:
1120
- test_results.append("⚠️ any-agent version < 0.22.0 - A2A components not available")
1121
- test_results.append("💡 Solution: Update requirements.txt to any-agent[a2a,openai]>=0.22.0")
1122
- except Exception as e:
1123
- test_results.append(f"Could not check any-agent version: {e}")
1124
-
1125
- # Final verdict
1126
- if available_count >= 6 and "✅ any_agent A2A components: Success!" in "\n".join(test_results):
1127
- test_results.append("\n✅ A2A should work! Try selecting A2A mode.")
1128
- else:
1129
- test_results.append("\n❌ A2A requirements not met. Use Basic Multiagent mode.")
1130
-
1131
- return "\n".join(test_results)
1132
-
1133
- # Test network connectivity for A2A
1134
- async def test_network_connectivity():
1135
- """Test network connectivity for A2A servers."""
1136
- import httpx
1137
-
1138
- results = []
1139
- results.append("=== A2A Network Connectivity Test ===")
1140
- results.append(f"Running on HF Spaces: {bool(os.getenv('SPACE_ID'))}\n")
1141
-
1142
- # Test different host configurations
1143
- configs = [
1144
- ("localhost", 8000, "Local loopback"),
1145
- ("127.0.0.1", 8000, "IP loopback"),
1146
- ("0.0.0.0", 8000, "All interfaces"),
1147
- ]
1148
-
1149
- for host, port, desc in configs:
1150
- results.append(f"Testing {host}:{port} ({desc})...")
1151
-
1152
- timeout = httpx.Timeout(timeout=5.0, connect=2.0, read=5.0)
1153
-
1154
- async with httpx.AsyncClient(timeout=timeout) as client:
1155
- # Test basic connectivity
1156
- try:
1157
- response = await client.get(f"http://{host}:{port}/")
1158
- results.append(f" ✅ Connected: HTTP {response.status_code}")
1159
- except httpx.ConnectError:
1160
- results.append(f" ❌ Connection refused (no server)")
1161
- except httpx.ReadTimeout:
1162
- results.append(f" ❌ Read timeout (server not responding)")
1163
- except Exception as e:
1164
- results.append(f" ❌ Error: {type(e).__name__}")
1165
-
1166
- results.append("")
1167
-
1168
- results.append("=== Recommendations ===")
1169
- if os.getenv("SPACE_ID"):
1170
- results.append("On HF Spaces:")
1171
- results.append("• A2A servers bind to 0.0.0.0 for external access")
1172
- results.append("• Clients connect via 127.0.0.1 internally")
1173
- results.append("• Network timeouts are common - retries help")
1174
- results.append("• Consider Basic Multiagent mode for reliability")
1175
- else:
1176
- results.append("Local development:")
1177
- results.append("• Both localhost and 127.0.0.1 should work")
1178
- results.append("• Check firewall if connections fail")
1179
-
1180
- return "\n".join(results)
1181
-
1182
- # No need for separate mode change handler - it happens when draft starts
1183
-
1184
- # Functions to handle prompt editing
1185
  def toggle_prompt_visibility():
1186
- """Toggle prompt editor visibility."""
1187
  return gr.update(visible=True)
1188
 
 
1189
  def save_prompt(team_num, prompt_text, app, prompts_dict):
1190
- """Save custom prompt for a team."""
1191
  if app is None:
1192
- app = EnhancedFantasyDraftApp()
1193
- if prompts_dict is None:
1194
- prompts_dict = {}
1195
-
1196
  prompts_dict[team_num] = prompt_text
1197
- app.custom_prompts[team_num] = prompt_text
1198
  return app, prompts_dict, gr.update(visible=False)
1199
 
1200
- # Run multi-agent demo with control visibility handling
1201
- def run_and_check(mode, app, prompts_dict):
1202
- """Run demo and check for user turn."""
1203
- # Create a new app instance for this user if needed
1204
  if app is None:
1205
- app = EnhancedFantasyDraftApp()
1206
-
1207
- # Apply custom prompts if any
1208
- if prompts_dict:
1209
  app.custom_prompts = prompts_dict
1210
 
1211
- use_a2a = (mode == "A2A")
1212
- for output in app.run_multiagent_demo(use_a2a):
1213
- result = check_user_turn(output, app)
1214
- yield result + (app,) # Return the app state as the last element
1215
-
1216
- # Wire up settings buttons for each team
1217
- team1_settings_btn.click(toggle_prompt_visibility, [], [team1_prompt_col])
1218
- team2_settings_btn.click(toggle_prompt_visibility, [], [team2_prompt_col])
1219
- team3_settings_btn.click(toggle_prompt_visibility, [], [team3_prompt_col])
1220
- team5_settings_btn.click(toggle_prompt_visibility, [], [team5_prompt_col])
1221
- team6_settings_btn.click(toggle_prompt_visibility, [], [team6_prompt_col])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1222
 
1223
- # Wire up save buttons
1224
  team1_save_btn.click(
1225
- lambda p, a, d: save_prompt(1, p, a, d),
1226
- [team1_prompt, app_state, agent_prompts],
1227
- [app_state, agent_prompts, team1_prompt_col]
1228
  )
1229
  team2_save_btn.click(
1230
- lambda p, a, d: save_prompt(2, p, a, d),
1231
- [team2_prompt, app_state, agent_prompts],
1232
- [app_state, agent_prompts, team2_prompt_col]
1233
  )
1234
  team3_save_btn.click(
1235
- lambda p, a, d: save_prompt(3, p, a, d),
1236
- [team3_prompt, app_state, agent_prompts],
1237
- [app_state, agent_prompts, team3_prompt_col]
1238
  )
1239
  team5_save_btn.click(
1240
- lambda p, a, d: save_prompt(5, p, a, d),
1241
- [team5_prompt, app_state, agent_prompts],
1242
- [app_state, agent_prompts, team5_prompt_col]
1243
  )
1244
  team6_save_btn.click(
1245
- lambda p, a, d: save_prompt(6, p, a, d),
1246
- [team6_prompt, app_state, agent_prompts],
1247
- [app_state, agent_prompts, team6_prompt_col]
1248
  )
1249
 
 
1250
  run_multiagent_btn.click(
1251
- run_and_check,
1252
- [communication_mode, app_state, agent_prompts],
1253
- [multiagent_output, mock_draft_controls, available_accordion, available_players_display, draft_pick_input, app_state],
1254
- show_progress=True
1255
- )
1256
-
1257
- # Wrapper for async network test
1258
- def run_network_test():
1259
- """Run the async network test."""
1260
- loop = asyncio.new_event_loop()
1261
- asyncio.set_event_loop(loop)
1262
- return loop.run_until_complete(test_network_connectivity())
1263
-
1264
- # Wire up test buttons
1265
- test_a2a_btn.click(
1266
- test_a2a_functionality,
1267
- [],
1268
- [a2a_test_output]
1269
- )
1270
-
1271
- test_network_btn.click(
1272
- run_network_test,
1273
- [],
1274
- [a2a_test_output]
1275
  )
1276
 
1277
- # Continue draft after user pick
1278
- def submit_and_continue(player_name, app):
1279
- """Submit pick and continue draft."""
1280
- if app is None:
1281
- yield ("No active draft. Please start a new mock draft.",
1282
- gr.update(visible=False), gr.update(visible=False), "", "", None)
1283
- return
1284
-
1285
- for output in app.continue_mock_draft(player_name):
1286
- result = check_user_turn(output, app)
1287
- yield result + (app,) # Return the app state as the last element
1288
-
1289
  submit_pick_btn.click(
1290
  submit_and_continue,
1291
- [draft_pick_input, app_state],
1292
- [multiagent_output, mock_draft_controls, available_accordion, available_players_display, draft_pick_input, app_state],
1293
- show_progress=True
1294
  )
1295
 
1296
- # Also submit on enter
1297
  draft_pick_input.submit(
1298
  submit_and_continue,
1299
- [draft_pick_input, app_state],
1300
- [multiagent_output, mock_draft_controls, available_accordion, available_players_display, draft_pick_input, app_state],
1301
- show_progress=True
1302
  )
1303
 
1304
- # Minimal CSS for layout only
1305
  demo.css = """
1306
  #main-container {
1307
- max-width: 1200px;
1308
  margin: 0 auto;
1309
  }
1310
 
1311
  .multiagent-output {
1312
- max-height: 800px;
1313
  overflow-y: auto;
 
 
 
1314
  }
1315
 
1316
- /* Force dark text in message cards */
1317
- .multiagent-output div[style*="background-color"] {
1318
- color: #212121 !important;
1319
- }
1320
-
1321
- .multiagent-output div[style*="background-color"] * {
1322
- color: #212121 !important;
1323
  }
1324
 
1325
  #start-button {
1326
- margin-top: 20px;
 
1327
  }
1328
 
1329
- /* Monospace font for debug output */
1330
- .monospace textarea {
1331
- font-family: 'Courier New', Courier, monospace;
1332
- font-size: 12px;
1333
- }
1334
-
1335
- /* Settings button styling */
1336
- button[variant="secondary"] {
1337
- margin-top: 8px;
1338
- width: 100%;
1339
- }
1340
-
1341
- /* Prompt editor styling */
1342
- .prompt-editor {
1343
- margin-top: 10px;
1344
- padding: 10px;
1345
- background-color: #f5f5f5;
1346
- border-radius: 4px;
1347
  }
1348
  """
1349
-
1350
- # Note: Gradio's unload() doesn't support inputs, so automatic cleanup
1351
- # happens when the Python process ends or when new sessions override old ones
1352
 
1353
  return demo
1354
 
1355
 
1356
  def main():
1357
- """Main entry point."""
1358
- # Check for API key - but don't exit on Hugging Face Spaces
1359
- if not os.getenv("OPENAI_API_KEY"):
1360
- if os.getenv("SPACE_ID"): # Running on Hugging Face Spaces
1361
- print("⚠️ OPENAI_API_KEY not found - please set it in Space Settings > Repository secrets")
1362
- else:
1363
- print("Error: OPENAI_API_KEY not found in environment")
1364
- print("Please set it using: export OPENAI_API_KEY='your-key-here'")
1365
- exit(1)
1366
 
1367
  # Create and launch the interface
1368
  demo = create_gradio_interface()
1369
 
1370
- print("🚀 Launching Enhanced Fantasy Draft App with A2A Support...")
1371
-
1372
- # Check if running on Hugging Face Spaces
1373
- if os.getenv("SPACE_ID"):
1374
- demo.launch() # Hugging Face handles server config
1375
- else:
1376
- demo.launch(
1377
- server_name="0.0.0.0",
1378
- server_port=7860,
1379
- share=True,
1380
- show_error=True
1381
- )
1382
 
1383
 
1384
  if __name__ == "__main__":
 
1
  #!/usr/bin/env python3
2
  """
3
+ Fantasy Draft Multi-Agent Demo
4
+ Multi-agent system using the any-agent framework for fantasy football drafts
5
  """
6
 
7
  import os
 
12
  from typing import List, Tuple, Optional, Dict
13
  from dotenv import load_dotenv
14
  import sys
15
+
16
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
17
 
18
  from core.agent import FantasyDraftAgent
 
20
  from core.constants import (
21
  TYPING_DELAY_SECONDS,
22
  MESSAGE_DELAY_SECONDS,
 
 
 
 
 
 
 
 
 
 
 
23
  )
 
 
 
24
 
25
  from apps.multiagent_draft import MultiAgentMockDraft
26
  from apps.multiagent_scenarios import (
 
31
  create_mock_draft_visualization
32
  )
33
 
 
 
 
34
  # Apply nest_asyncio for async in Gradio
35
  nest_asyncio.apply()
36
 
 
41
  load_dotenv()
42
 
43
 
44
+ class FantasyDraftApp:
45
  def __init__(self):
46
  self.current_draft = None # Store the current mock draft
47
  self.draft_output = "" # Store the draft output so far
 
 
 
 
48
  self.custom_prompts = {} # Store custom agent prompts
49
 
50
+ def run_multiagent_demo(self):
51
+ """Run the mock draft demonstration."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  # Reset any previous draft
53
  self.current_draft = None
54
  self.draft_output = ""
55
 
56
+ # Use basic multiagent draft
57
+ draft_generator = run_interactive_mock_draft()
 
 
 
 
 
 
 
58
 
59
+ for output in draft_generator:
60
+ if isinstance(output, tuple):
61
+ # This means it's the user's turn
62
+ self.current_draft, self.draft_output = output
63
+ yield self.draft_output + "\n<!--USER_TURN-->"
64
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  else:
66
+ self.draft_output = output
67
+ yield output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  def continue_mock_draft(self, player_name: str):
70
  """Continue the mock draft after user makes a pick."""
 
101
  time.sleep(MESSAGE_DELAY_SECONDS)
102
 
103
  # Continue with the rest of the draft
104
+ yield from self.continue_basic_multiagent_draft()
 
 
 
105
 
106
+ def continue_basic_multiagent_draft(self):
107
+ """Continue basic multiagent draft after user pick."""
108
  # Calculate where we are
109
  total_picks = len([p for picks in self.current_draft.draft_board.values() for p in picks])
110
  current_round = ((total_picks - 1) // 6) + 1
111
 
112
+ # Continue from where we left off
113
+ for round_num in range(current_round, 4): # Continue through round 3
 
 
 
 
 
 
 
114
  if round_num > current_round:
115
  self.draft_output += f"\n## 🔄 ROUND {round_num}\n\n"
116
  yield self.draft_output
 
121
  else:
122
  pick_order = list(range(6, 0, -1))
123
 
124
+ # Calculate where we are in this round
125
  picks_in_round = total_picks % 6
126
+ if round_num == current_round:
127
+ # Skip picks already made
128
+ start_idx = picks_in_round
129
+ else:
130
+ start_idx = 0
131
 
132
+ for pick_in_round, team_num in enumerate(pick_order[start_idx:], start_idx + 1):
133
  pick_num = (round_num - 1) * 6 + pick_in_round
134
 
135
  # Show draft board at start of round
 
138
  self.draft_output += "\n"
139
  yield self.draft_output
140
 
141
+ if team_num == 4: # User's turn
142
+ # Get advisor recommendation
143
  advisor = self.current_draft.user_advisor
144
 
145
+ # Get available players
146
  all_picked = [p for picks in self.current_draft.draft_board.values() for p in picks]
147
  available = [p for p in TOP_PLAYERS.keys() if p not in all_picked]
148
 
149
  # Get other agent strategies for advisor context
150
  strategies = {f"Team {i}": agent.strategy for i, agent in self.current_draft.agents.items()}
151
 
152
+ # Get advisor recommendation
153
  advice = advisor.advise_user(available, self.current_draft.draft_board, strategies)
154
+
155
+ # Show advisor message
156
  self.draft_output += format_agent_message(advisor, "USER", advice)
157
  yield self.draft_output
158
 
 
160
  yield self.draft_output + "\n<!--USER_TURN-->"
161
  return
162
  else:
163
+ # AI agent pick
164
+ messages, _ = self.current_draft.simulate_draft_turn(round_num, pick_num, team_num)
 
 
165
 
166
+ # Display messages with typing effect
167
  for msg in messages:
168
  if len(msg) >= 3:
169
  agent, recipient, content = msg[:3]
170
+
171
+ # Show "..." first for typing effect
172
  typing_placeholder = format_agent_message(agent, recipient, "...")
173
  self.draft_output += typing_placeholder
174
  yield self.draft_output
175
  time.sleep(TYPING_DELAY_SECONDS)
176
 
177
+ # Replace with actual message
178
  self.draft_output = self.draft_output.replace(typing_placeholder, "")
179
  self.draft_output += format_agent_message(agent, recipient, content)
180
  yield self.draft_output
 
182
 
183
  time.sleep(TYPING_DELAY_SECONDS)
184
 
185
+ # End of round
186
  self.draft_output += format_agent_message("commissioner", "ALL",
187
  f"That's the end of Round {round_num}!")
188
  yield self.draft_output
 
192
  self.draft_output += self.current_draft.get_draft_summary()
193
  yield self.draft_output
194
 
195
+ # Clear the draft state
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  self.current_draft = None
197
 
198
 
199
  def create_gradio_interface():
200
+ """Create the main Gradio interface."""
201
 
202
  with gr.Blocks(title="Fantasy Draft Multi-Agent Demo", theme=gr.themes.Soft()) as demo:
203
  # Create state for each user session
 
213
  with gr.Tabs():
214
  # Demo Tab
215
  with gr.TabItem("🎮 Demo"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  # Show agent cards
217
  gr.Markdown("""
218
  ### 🏈 Meet Your Competition
 
242
  team1_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
243
  with gr.Column(visible=False) as team1_prompt_col:
244
  team1_prompt = gr.Textbox(
245
+ label="Team 1 Personality & Strategy",
246
  value="""You are Team 1, a fantasy football manager with Zero RB strategy.
247
 
248
  PERSONALITY & STRATEGY:
 
261
  BE LOUD! BE PROUD! BE UNFORGETTABLE! 🎯""",
262
  lines=15,
263
  interactive=True,
264
+ info="Customize personality and strategy."
265
  )
266
  team1_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
267
 
 
282
  team2_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
283
  with gr.Column(visible=False) as team2_prompt_col:
284
  team2_prompt = gr.Textbox(
285
+ label="Team 2 Personality & Strategy",
286
  value="""You are Team 2, a fantasy football manager with BPA (Best Player Available) strategy.
287
 
288
  PERSONALITY & STRATEGY:
 
300
  BE RUTHLESS! BE RIGHT! BE THE VALUE VULTURE! 🦅""",
301
  lines=15,
302
  interactive=True,
303
+ info="Customize personality and strategy."
304
  )
305
  team2_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
306
 
 
321
  team3_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
322
  with gr.Column(visible=False) as team3_prompt_col:
323
  team3_prompt = gr.Textbox(
324
+ label="Team 3 Personality & Strategy",
325
  value="""You are Team 3, a fantasy football manager with Robust RB strategy.
326
 
327
  PERSONALITY & STRATEGY:
 
339
  BE STUBBORN! BE TRADITIONAL! ESTABLISH THE RUN! 🏈""",
340
  lines=15,
341
  interactive=True,
342
+ info="Customize personality and strategy."
343
  )
344
  team3_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
345
 
 
374
  team5_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
375
  with gr.Column(visible=False) as team5_prompt_col:
376
  team5_prompt = gr.Textbox(
377
+ label="Team 5 Personality & Strategy",
378
  value="""You are Team 5, a fantasy football manager with Upside Hunter strategy.
379
 
380
  PERSONALITY & STRATEGY:
 
392
  BE BOLD! BE RECKLESS! SWING FOR THE FENCES! ⚡""",
393
  lines=15,
394
  interactive=True,
395
+ info="Customize personality and strategy."
396
  )
397
  team5_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
398
 
 
413
  team6_settings_btn = gr.Button("⚙️ Customize", size="sm", variant="secondary")
414
  with gr.Column(visible=False) as team6_prompt_col:
415
  team6_prompt = gr.Textbox(
416
+ label="Team 6 Personality & Strategy",
417
  value="""You are Team 6, a fantasy football manager with BPA (Best Player Available) strategy.
418
 
419
  PERSONALITY & STRATEGY:
 
431
  BE ANALYTICAL! BE MERCILESS! TRUST THE PROCESS! 🤖""",
432
  lines=15,
433
  interactive=True,
434
+ info="Customize personality and strategy."
435
  )
436
  team6_save_btn = gr.Button("💾 Save", size="sm", variant="primary")
437
 
 
469
  interactive=False
470
  )
471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  # How It Works Tab
473
  with gr.TabItem("🔧 How It Works"):
474
  gr.Markdown("""
 
491
  - **Strategy Memory**: Remembers own strategy and others' approaches
492
  - **Pick History**: Tracks all selections for informed decisions
493
 
494
+ ### 💬 Single-Process Multi-Agent Communication
495
 
496
+ - **In-Memory Communication**: Agents interact directly via method calls
497
+ - **Shared Draft State**: All agents see the same draft board
498
+ - **Fast Execution**: No network overhead
499
+ - **Conversation Memory**: Each agent remembers interactions
 
 
 
 
 
 
 
 
 
 
 
500
 
501
  ### 📊 Architecture Flow
 
502
 
 
503
  #### 1️⃣ INITIALIZATION
504
  User clicks "Start Mock Draft" → System creates 6 agents
505
 
 
518
 
519
  #### 4️⃣ EACH PICK TRIGGERS
520
  - Agent makes selection based on strategy
521
+ - Other agents comment based on rivalries
522
  - Original agent may respond
523
  - All agents update their memory
524
 
 
568
  "" # Clear the input
569
  )
570
 
571
+ # Toggle prompt visibility
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  def toggle_prompt_visibility():
 
573
  return gr.update(visible=True)
574
 
575
+ # Save prompt
576
  def save_prompt(team_num, prompt_text, app, prompts_dict):
577
+ """Save a custom prompt for a team."""
578
  if app is None:
579
+ app = FantasyDraftApp()
 
 
 
580
  prompts_dict[team_num] = prompt_text
581
+ app.custom_prompts = prompts_dict
582
  return app, prompts_dict, gr.update(visible=False)
583
 
584
+ # Run and check function
585
+ def run_and_check(app, prompts_dict):
586
+ """Run the draft and check for user turns."""
 
587
  if app is None:
588
+ app = FantasyDraftApp()
 
 
 
589
  app.custom_prompts = prompts_dict
590
 
591
+ generator = app.run_multiagent_demo()
592
+ output = ""
593
+
594
+ for chunk in generator:
595
+ output = chunk
596
+ # Check if it's user's turn
597
+ if "<!--USER_TURN-->" in output:
598
+ break
599
+ yield output, app, gr.update(), gr.update(), gr.update(), ""
600
+
601
+ # Final yield with turn check
602
+ clean_output, controls_update, accordion_update, available_text, input_clear = check_user_turn(output, app)
603
+ yield clean_output, app, controls_update, accordion_update, available_text, input_clear
604
+
605
+ # Set up event handlers
606
+ # Team prompt toggles
607
+ team1_settings_btn.click(
608
+ toggle_prompt_visibility,
609
+ outputs=team1_prompt_col
610
+ )
611
+ team2_settings_btn.click(
612
+ toggle_prompt_visibility,
613
+ outputs=team2_prompt_col
614
+ )
615
+ team3_settings_btn.click(
616
+ toggle_prompt_visibility,
617
+ outputs=team3_prompt_col
618
+ )
619
+ team5_settings_btn.click(
620
+ toggle_prompt_visibility,
621
+ outputs=team5_prompt_col
622
+ )
623
+ team6_settings_btn.click(
624
+ toggle_prompt_visibility,
625
+ outputs=team6_prompt_col
626
+ )
627
 
628
+ # Save prompts
629
  team1_save_btn.click(
630
+ lambda prompt, app, prompts: save_prompt(1, prompt, app, prompts),
631
+ inputs=[team1_prompt, app_state, agent_prompts],
632
+ outputs=[app_state, agent_prompts, team1_prompt_col]
633
  )
634
  team2_save_btn.click(
635
+ lambda prompt, app, prompts: save_prompt(2, prompt, app, prompts),
636
+ inputs=[team2_prompt, app_state, agent_prompts],
637
+ outputs=[app_state, agent_prompts, team2_prompt_col]
638
  )
639
  team3_save_btn.click(
640
+ lambda prompt, app, prompts: save_prompt(3, prompt, app, prompts),
641
+ inputs=[team3_prompt, app_state, agent_prompts],
642
+ outputs=[app_state, agent_prompts, team3_prompt_col]
643
  )
644
  team5_save_btn.click(
645
+ lambda prompt, app, prompts: save_prompt(5, prompt, app, prompts),
646
+ inputs=[team5_prompt, app_state, agent_prompts],
647
+ outputs=[app_state, agent_prompts, team5_prompt_col]
648
  )
649
  team6_save_btn.click(
650
+ lambda prompt, app, prompts: save_prompt(6, prompt, app, prompts),
651
+ inputs=[team6_prompt, app_state, agent_prompts],
652
+ outputs=[app_state, agent_prompts, team6_prompt_col]
653
  )
654
 
655
+ # Start mock draft
656
  run_multiagent_btn.click(
657
+ lambda app, prompts: run_and_check(app, prompts),
658
+ inputs=[app_state, agent_prompts],
659
+ outputs=[multiagent_output, app_state, mock_draft_controls, available_accordion, available_players_display, draft_pick_input]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
  )
661
 
662
+ # Submit pick button
 
 
 
 
 
 
 
 
 
 
 
663
  submit_pick_btn.click(
664
  submit_and_continue,
665
+ inputs=[draft_pick_input, app_state],
666
+ outputs=[multiagent_output, app_state, mock_draft_controls, available_accordion, available_players_display, draft_pick_input]
 
667
  )
668
 
669
+ # Submit pick on Enter
670
  draft_pick_input.submit(
671
  submit_and_continue,
672
+ inputs=[draft_pick_input, app_state],
673
+ outputs=[multiagent_output, app_state, mock_draft_controls, available_accordion, available_players_display, draft_pick_input]
 
674
  )
675
 
676
+ # Custom CSS for styling
677
  demo.css = """
678
  #main-container {
679
+ max-width: 1400px;
680
  margin: 0 auto;
681
  }
682
 
683
  .multiagent-output {
684
+ max-height: 600px;
685
  overflow-y: auto;
686
+ padding: 20px;
687
+ background: #f5f5f5;
688
+ border-radius: 8px;
689
  }
690
 
691
+ #draft-pick-input {
692
+ font-size: 1.2em;
693
+ padding: 10px;
 
 
 
 
694
  }
695
 
696
  #start-button {
697
+ font-size: 1.2em;
698
+ padding: 15px 30px;
699
  }
700
 
701
+ .monospace {
702
+ font-family: 'Courier New', monospace;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
703
  }
704
  """
 
 
 
705
 
706
  return demo
707
 
708
 
709
  def main():
710
+ """Launch the Gradio app."""
711
+ # Set environment variables for cloud deployment
712
+ if os.getenv("SPACE_ID"): # Running on Hugging Face Spaces
713
+ print("🤗 Running on Hugging Face Spaces")
714
+ os.environ["GRADIO_SERVER_NAME"] = "0.0.0.0"
715
+ os.environ["GRADIO_SERVER_PORT"] = "7860"
 
 
 
716
 
717
  # Create and launch the interface
718
  demo = create_gradio_interface()
719
 
720
+ # Launch with appropriate settings
721
+ demo.launch(
722
+ share=False,
723
+ server_name="0.0.0.0" if os.getenv("SPACE_ID") else None,
724
+ server_port=7860 if os.getenv("SPACE_ID") else None
725
+ )
 
 
 
 
 
 
726
 
727
 
728
  if __name__ == "__main__":
apps/multiagent_draft.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
  Multi-Agent Mock Draft Implementation
4
- Demonstrates A2A communication and multi-turn memory
5
  """
6
 
7
  import time
 
1
  #!/usr/bin/env python3
2
  """
3
  Multi-Agent Mock Draft Implementation
4
+ Demonstrates agent communication and multi-turn memory
5
  """
6
 
7
  import time
core/constants.py CHANGED
@@ -1,13 +1,10 @@
1
  """
2
- Constants for the Fantasy Draft A2A implementation.
3
  """
4
 
5
  # Timing constants (in seconds)
6
  TYPING_DELAY_SECONDS = 0.5
7
  MESSAGE_DELAY_SECONDS = 1.0
8
- AGENT_START_DELAY = 5.0 # Increased from 3.0 to give agents more time to fully initialize
9
- AGENT_STARTUP_WAIT = 1.0 # Increased from 0.5 to ensure each agent is ready
10
- DEFAULT_TIMEOUT = 90.0 # Increased further for HF Spaces network latency
11
 
12
  # Comment configuration
13
  MAX_COMMENTS_PER_PICK = 1 # Reduced for more concise draft flow
@@ -19,48 +16,4 @@ RIVAL_PAIRS = {
19
  5: [2, 6], # Upside Hunter vs BPA agents
20
  2: 5, # BPA vs Upside Hunter
21
  6: 5, # BPA vs Upside Hunter
22
- }
23
-
24
- # A2A Agent configurations
25
- AGENT_CONFIGS = [
26
- {
27
- "team_name": "Team 1",
28
- "team_num": 1,
29
- "strategy": "Zero RB",
30
- "port": 5001,
31
- "philosophy": "RBs are INJURY MAGNETS! 🏥 WRs are the future! I'm building an AIR RAID OFFENSE that will DESTROY your pathetic ground game! 💨✈️",
32
- "emoji_style": ["✈️", "💨", "🏥", "🎯"],
33
- },
34
- {
35
- "team_name": "Team 2",
36
- "team_num": 2,
37
- "strategy": "BPA",
38
- "port": 5002,
39
- "philosophy": "I am the VALUE VULTURE! 🦅 I feast on your emotional reaches while I build a CHAMPIONSHIP ROSTER with pure analytics! 📊📈",
40
- "emoji_style": ["🦅", "📊", "📈", "💰"],
41
- },
42
- {
43
- "team_name": "Team 3",
44
- "team_num": 3,
45
- "strategy": "Robust RB",
46
- "port": 5003,
47
- "philosophy": "GROUND AND POUND, BABY! 💪 Your fancy WRs will be watching from the sidelines while my RBs BULLDOZE their way to victory! 🚜💥",
48
- "emoji_style": ["💪", "🚜", "💥", "🏃"],
49
- },
50
- {
51
- "team_name": "Team 5",
52
- "team_num": 5,
53
- "strategy": "Upside Hunter",
54
- "port": 5005,
55
- "philosophy": "BOOM OR BUST! 🎰🚀 Safe picks are for COWARDS! I'm swinging for the fences while you play it safe like a SCARED LITTLE MOUSE! 🐭💣",
56
- "emoji_style": ["🎰", "🚀", "💣", "⚡"],
57
- },
58
- {
59
- "team_name": "Team 6",
60
- "team_num": 6,
61
- "strategy": "BPA",
62
- "port": 5006,
63
- "philosophy": "Another spreadsheet warrior here to EXPLOIT your terrible decisions! 🤓💻 My algorithm laughs at your 'gut feelings'! 🤖📉",
64
- "emoji_style": ["🤓", "💻", "🤖", "📉"],
65
- },
66
- ]
 
1
  """
2
+ Constants for the Fantasy Draft Multi-Agent implementation.
3
  """
4
 
5
  # Timing constants (in seconds)
6
  TYPING_DELAY_SECONDS = 0.5
7
  MESSAGE_DELAY_SECONDS = 1.0
 
 
 
8
 
9
  # Comment configuration
10
  MAX_COMMENTS_PER_PICK = 1 # Reduced for more concise draft flow
 
16
  5: [2, 6], # Upside Hunter vs BPA agents
17
  2: 5, # BPA vs Upside Hunter
18
  6: 5, # BPA vs Upside Hunter
19
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/FEATURES_AND_ENHANCEMENTS.md CHANGED
@@ -2,203 +2,143 @@
2
 
3
  ## Core Features
4
 
5
- ### 🤖 Multi-Agent System
6
- - **6 AI Agents**: Each with distinct personality and strategy
7
- - **User Position**: Player drafts at position 4 with AI advisor
8
- - **3-Round Draft**: Snake draft format (1→6, 6→1, 1→6)
9
- - **Real-time Interaction**: Agents comment and react to picks
10
-
11
- ### 🎭 Agent Personalities
12
-
13
- #### Team 1 - Zero RB (📘🤓)
14
- - **Strategy**: Avoids RBs early, loads up on elite WRs
15
- - **Personality**: Analytical, confident in contrarian approach
16
- - **Catchphrase**: "RBs get injured. I'll build around elite WRs."
17
-
18
- #### Team 2 & 6 - Best Player Available (📗🧑‍💼/👨‍🏫)
19
- - **Strategy**: Pure value drafting, ignores positional needs
20
- - **Personality**: Disciplined, mocks others for reaching
21
- - **Catchphrase**: "Value is value. I don't reach for needs."
22
-
23
- #### Team 3 - Robust RB (📙🧔)
24
- - **Strategy**: Prioritizes RBs in rounds 1-2
25
- - **Personality**: Traditional, old-school approach
26
- - **Catchphrase**: "RBs win championships. Period."
27
-
28
- #### Team 5 - Upside Hunter (📓🤠)
29
- - **Strategy**: Seeks high-risk, high-reward players
30
- - **Personality**: Bold, mocks conservative picks
31
- - **Catchphrase**: "Safe picks are for losers!"
32
-
33
- #### User's Advisor (📕🧙)
34
- - **Role**: Provides strategic advice to the user
35
- - **Features**: Analyzes board state, suggests best picks, explains reasoning
36
-
37
- ### 🎨 UI/UX Enhancements
38
-
39
- #### Visual Design
40
- - **Agent Cards**: Color-coded with emojis for easy identification
41
- - **Message Formatting**: Speaker badges with recipient indicators
42
- - **Draft Board**: Visual grid showing all picks by round
43
- - **Dark Text Fix**: Ensures readability on all backgrounds
44
-
45
- #### Interactive Elements
46
- - **Typing Animation**: "..." indicator for realistic feel
47
- - **Progressive Updates**: Draft unfolds in real-time
48
- - **Available Players**: Dropdown showing top 20 options
49
- - **User Input**: Clean interface for making picks
50
-
51
- ### 💬 Communication Features
52
-
53
- #### Conversation System
54
- - **Directed Messages**: Clear sender → recipient format
55
- - **Commissioner Announcements**: Official draft updates
56
- - **Trash Talk**: Agents comment on rivals' picks
57
- - **Memory Indicators**: Shows when agents reference past events
58
-
59
- #### Comment Limiting
60
- - **Smart Throttling**: Max 2-3 comments per pick
61
- - **Rival Priority**: Rivals more likely to comment
62
- - **Natural Flow**: Prevents conversation overload
63
-
64
- ### 🔧 Technical Features
65
-
66
- #### Dual Mode Operation
67
- 1. **Basic Multiagent Mode**
68
- - Single process execution
69
- - Fast response times
70
- - Perfect for development
71
-
72
- 2. **A2A Mode (Agent-to-Agent)**
73
- - Distributed architecture
74
- - Each agent on HTTP server
75
- - Production-ready setup
76
-
77
- #### Multi-User Support
78
- - **Session Isolation**: Each user gets separate instance
79
- - **Gradio State Management**: Proper state handling
80
- - **Dynamic Port Allocation**: No conflicts in A2A mode
81
- - **Concurrent Users**: Supports multiple simultaneous drafts
82
-
83
- ### 📊 Draft Features
84
-
85
- #### Snake Draft Logic
86
- - **Round 1**: Picks 1→2→3→4→5→6
87
- - **Round 2**: Picks 6→5→4→3→2→1 (reverses)
88
- - **Round 3**: Picks 1→2→3→4→5→6
89
-
90
- #### Player Database
91
- - **50+ Players**: Real NFL players with positions
92
- - **Team Info**: Current NFL team assignments
93
- - **Positional Balance**: QBs, RBs, WRs, TEs
94
- - **Realistic Rankings**: Based on fantasy relevance
95
-
96
- #### Draft Intelligence
97
- - **Strategy Adherence**: Agents follow their strategies
98
- - **Contextual Decisions**: React to draft flow
99
- - **Position Scarcity**: Recognize run on positions
100
- - **Value Recognition**: Identify steals and reaches
101
-
102
- ### 🚀 Performance Optimizations
103
-
104
- #### Configurable Delays
105
  ```python
106
- TYPING_DELAY_SECONDS = 0.3 # "..." display time
107
- MESSAGE_DELAY_SECONDS = 0.1 # Between messages
108
- AGENT_START_DELAY = 0.5 # A2A startup spacing
109
  ```
110
 
111
- #### Resource Management
112
- - **Async Operations**: Non-blocking agent communication
113
- - **Timeout Handling**: 30-second default with fallbacks
114
- - **Memory Efficiency**: Clean state management
115
- - **Port Cleanup**: Automatic resource release
116
-
117
- ### 🔐 Reliability Features
118
-
119
- #### Error Handling
120
- - **Graceful Fallbacks**: A2A → simulation if needed
121
- - **Clear Error Messages**: User-friendly notifications
122
- - **Validation**: Player name and state checking
123
- - **Recovery**: Continues draft after errors
124
-
125
- #### State Management
126
- - **Draft Persistence**: Maintains state across turns
127
- - **Conversation History**: Full context preservation
128
- - **Pick Validation**: Prevents duplicate selections
129
- - **Board Updates**: Real-time synchronization
130
-
131
- ## Recent Enhancements
132
-
133
- ### 🎨 Custom Agent Prompts (ENHANCED!)
134
- - **Customizable Personalities**: Edit personality and strategy for each agent
135
- - **Settings Buttons**: ⚙️ button on each agent card
136
- - **Live Editing**: Modify prompts before starting draft
137
- - **Prompt Persistence**: Custom prompts used throughout session
138
- - **Safe Customization**: Output format instructions are protected
139
- - **A2A Compatible**: Works with both Basic and A2A modes
140
-
141
- #### How to Use:
142
- 1. Click ⚙️ Customize on any agent card
143
- 2. Edit the personality and strategy in the text area
144
- 3. Click 💾 Save to apply changes
145
- 4. Start draft with customized agents
146
-
147
- #### Safety Features:
148
- - **Protected Output Format**: Critical JSON output instructions cannot be modified
149
- - **Automatic Prepending**: System always includes proper format instructions
150
- - **Clear Separation**: UI shows only editable personality/strategy parts
151
- - **Error Prevention**: Prevents users from breaking agent responses
152
-
153
- #### Example Customizations:
154
- - Make Team 1 obsessed with tight ends instead of WRs
155
- - Turn Team 3 into a modern analytics-based drafter
156
- - Create a peaceful Team 5 that never trash talks
157
- - Give agents specific player targets or avoid lists
158
- - Change personality traits while maintaining functionality
159
-
160
- ### Task ID Implementation
161
- - Simplified A2A conversation tracking
162
- - Removed redundant history management
163
- - Cleaner code architecture
164
- - Better framework integration
165
-
166
- ### Text Readability Fix
167
- - Dark text on all backgrounds
168
- - Explicit color styling
169
- - Fixed message card contrast
170
- - Improved overall readability
171
-
172
- ### Dynamic Port Allocation
173
- - Support for 100+ concurrent A2A sessions
174
- - Automatic port assignment (5000-9000)
175
- - Session-based isolation
176
- - Conflict prevention
177
-
178
- ### Enhanced Multi-User Support
179
- - Full session isolation
180
- - Gradio State implementation
181
- - Proper callback handling
182
- - Warning messages for A2A limitations
183
-
184
- ## Usage Tips
185
-
186
- ### For Best Experience
187
- 1. Start with Basic Multiagent mode for speed
188
- 2. Try A2A mode to see distributed architecture
189
- 3. Watch for memory indicators showing context
190
- 4. Pay attention to rival interactions
191
-
192
- ### Customization Options
193
- - Adjust delays in `constants.py`
194
- - Modify agent strategies in `agent.py`
195
- - Add players to `data.py`
196
- - Customize UI in `apps/app.py`
197
-
198
- ## Future Possibilities
199
- - WebSocket real-time updates
200
- - Custom league settings
201
- - More agent personalities
202
- - Advanced statistics
203
- - Trade negotiations
204
- - Dynasty league support
 
2
 
3
  ## Core Features
4
 
5
+ ### 1. Interactive Mock Draft Experience
6
+ - **User Participation**: Play as Team 4 with 5 AI opponents
7
+ - **Real-time Advisor**: Get strategic recommendations based on:
8
+ - Your current roster needs
9
+ - Available player values
10
+ - Other teams' strategies
11
+ - Position scarcity
12
+
13
+ ### 2. Advanced Multi-Agent System
14
+ - **6 Distinct Agents**: Each with unique strategies and personalities
15
+ - **Multi-Turn Memory**: Agents remember all interactions
16
+ - **Dynamic Comments**: Context-aware reactions to picks
17
+ - **Natural Rivalries**: Zero RB vs Robust RB create engaging banter
18
+
19
+ ### 3. Visual Draft Experience
20
+ - **Live Draft Board**: See all picks organized by team
21
+ - **Round Progress**: Track current round and pick number
22
+ - **Team Rosters**: Visual representation of each team's selections
23
+ - **Available Players**: Searchable list with positions and teams
24
+
25
+ ### 4. Customizable Agents
26
+ - **Personality Editor**: Modify each agent's trash-talk style
27
+ - **Strategy Tuning**: Adjust how aggressive or conservative agents are
28
+ - **Emoji Styles**: Each agent has their own emoji personality
29
+ - **Memory References**: Agents callback to earlier interactions
30
+
31
+ ## Technical Enhancements
32
+
33
+ ### 1. Memory System
34
+ - **Conversation History**: Full context maintained across turns
35
+ - **Pick Tracking**: Agents know who picked whom and when
36
+ - **Strategy Awareness**: Agents understand opponents' approaches
37
+ - **Grudge Memory**: Agents remember who mocked their picks
38
+
39
+ ### 2. Performance Optimizations
40
+ - **Typing Effect**: Natural conversation flow with "..." indicators
41
+ - **Async Processing**: Non-blocking UI during agent turns
42
+ - **Efficient State Management**: Minimal re-renders
43
+ - **Smart Comment Selection**: Rivals prioritized for reactions
44
+
45
+ ### 3. User Experience
46
+ - **Keyboard Shortcuts**: Enter to submit picks
47
+ - **Auto-scroll**: Keeps current action in view
48
+ - **Responsive Design**: Works on various screen sizes
49
+ - **Error Recovery**: Graceful handling of invalid picks
50
+
51
+ ## Configuration Options
52
+
53
+ ### Timing Controls
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  ```python
55
+ TYPING_DELAY_SECONDS = 0.5 # "..." display time
56
+ MESSAGE_DELAY_SECONDS = 1.0 # Between messages
57
+ MAX_COMMENTS_PER_PICK = 1 # Keeps draft moving
58
  ```
59
 
60
+ ### Rivalry System
61
+ ```python
62
+ RIVAL_PAIRS = {
63
+ 1: 3, # Zero RB vs Robust RB
64
+ 3: 1, # Mutual rivalry
65
+ 5: [2, 6], # Upside vs BPA agents
66
+ }
67
+ ```
68
+
69
+ ## Agent Strategies
70
+
71
+ ### 1. Zero RB (Team 1)
72
+ - Avoids RBs in early rounds
73
+ - Prioritizes elite WRs
74
+ - Mocks traditional RB-heavy approaches
75
+ - Gets RB value in later rounds
76
+
77
+ ### 2. Best Player Available (Teams 2 & 6)
78
+ - Pure value-based drafting
79
+ - Ignores positional needs
80
+ - Critical of "reaching" for positions
81
+ - Cold, analytical approach
82
+
83
+ ### 3. Robust RB (Team 3)
84
+ - RBs in rounds 1-2 mandatory
85
+ - Old-school philosophy
86
+ - Hates modern passing game trends
87
+ - Values "workhorse" backs
88
+
89
+ ### 4. Upside Hunter (Team 5)
90
+ - Seeks high-ceiling players
91
+ - Willing to take risks
92
+ - Mocks "safe" picks
93
+ - Boom-or-bust mentality
94
+
95
+ ## Unique Implementation Details
96
+
97
+ ### 1. Dynamic Prompt Generation
98
+ - Context-aware responses based on:
99
+ - Current round
100
+ - Previous picks
101
+ - Available players
102
+ - Recent conversations
103
+
104
+ ### 2. Natural Language Processing
105
+ - Agents avoid raw statistics in speech
106
+ - Convert ADP numbers to natural phrases
107
+ - Use strategy-appropriate vocabulary
108
+ - Maintain consistent personality
109
+
110
+ ### 3. Competitive Dynamics
111
+ - Agents defend their strategies aggressively
112
+ - No polite, generic responses
113
+ - Real draft room atmosphere
114
+ - Escalating rivalries as draft progresses
115
+
116
+ ## Future Enhancement Ideas
117
+
118
+ 1. **Draft Analysis**
119
+ - Post-draft grades for each team
120
+ - Strategy effectiveness metrics
121
+ - Win probability projections
122
+
123
+ 2. **Extended Rounds**
124
+ - Support for full 15+ round drafts
125
+ - Bench strategy considerations
126
+ - Late-round sleeper picks
127
+
128
+ 3. **Custom Scoring**
129
+ - PPR vs Standard scoring impacts
130
+ - Dynasty league considerations
131
+ - Keeper league strategies
132
+
133
+ 4. **Historical Data**
134
+ - Previous season performance
135
+ - Injury history considerations
136
+ - Breakout candidate identification
137
+
138
+ ## Tips for Best Experience
139
+
140
+ 1. **Starting Fresh**: Each draft is independent
141
+ 2. **Pick Timing**: Take your time, agents will wait
142
+ 3. **Name Matching**: Type player names as shown
143
+ 4. **Enjoy the Banter**: Let agents build rivalries
144
+ 5. **Experiment**: Try different strategies yourself
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -5,31 +5,18 @@ python-dotenv
5
  pydantic>=2.0.0
6
  typing-extensions
7
  nest-asyncio
8
- aiohttp
9
 
10
- # Step 2: Install a2a-sdk (provides 'a2a' module)
11
- # Pin to specific version for consistency
12
- a2a-sdk==0.2.9
13
-
14
- # Step 3: Install any-agent with both a2a and openai extras
15
  # Version 0.22+ required for any_agent.serving module
16
- any-agent[a2a,openai]>=0.22.0
17
 
18
- # Step 4: Additional dependencies (if not pulled in by any-agent)
19
  # These might already be installed by any-agent[openai] but we list them to be sure
20
  openai>=1.0.0
21
  litellm>=1.0.0
22
 
23
- # Step 5: Gradio last (it has many dependencies)
24
  gradio==4.36.0
25
 
26
  # Compatibility pins to satisfy transitive dependency constraints discovered during HF Spaces build
27
  markupsafe==2.1.5 # gradio constraint (~=2.0)
28
- fsspec>=2023.1.0,<=2025.3.0 # datasets constraint (<=2025.3.0)
29
-
30
- # Optional: HTTP dependencies for lightweight A2A
31
- httpx>=0.24.0
32
- fastapi>=0.115.0
33
- uvicorn>=0.22.0
34
- starlette>=0.46.0,<0.47.0
35
- sse-starlette>=2.3.6,<2.4.0
 
5
  pydantic>=2.0.0
6
  typing-extensions
7
  nest-asyncio
 
8
 
9
+ # Step 2: Install any-agent with OpenAI support
 
 
 
 
10
  # Version 0.22+ required for any_agent.serving module
11
+ any-agent[openai]>=0.22.0
12
 
13
+ # Step 3: Additional dependencies (if not pulled in by any-agent)
14
  # These might already be installed by any-agent[openai] but we list them to be sure
15
  openai>=1.0.0
16
  litellm>=1.0.0
17
 
18
+ # Step 4: Gradio last (it has many dependencies)
19
  gradio==4.36.0
20
 
21
  # Compatibility pins to satisfy transitive dependency constraints discovered during HF Spaces build
22
  markupsafe==2.1.5 # gradio constraint (~=2.0)