azettl commited on
Commit
a532678
Β·
verified Β·
1 Parent(s): b9ee855

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +568 -0
app.py ADDED
@@ -0,0 +1,568 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import uuid
5
+ import threading
6
+ from datetime import datetime
7
+ from typing import List, Dict, Any, Optional
8
+ from openfloor import (
9
+ Envelope, Conversation, Sender, DialogEvent, TextFeature,
10
+ UtteranceEvent, GetManifestsEvent, To
11
+ )
12
+ from openfloor.manifest import *
13
+ from openfloor.envelope import *
14
+
15
+ class OpenFloorAgent:
16
+ def __init__(self, url: str, name: str = None):
17
+ self.url = url
18
+ self.name = name or url
19
+ self.manifest = None
20
+ self.capabilities = []
21
+
22
+ def get_manifest(self):
23
+ """Get the agent's manifest and capabilities"""
24
+ try:
25
+ # Create manifest request
26
+ conversation = Conversation()
27
+ sender = Sender(
28
+ speakerUri="openfloor://mcp-bridge/client",
29
+ serviceUrl="http://mcp-bridge"
30
+ )
31
+ envelope = Envelope(conversation=conversation, sender=sender)
32
+
33
+ manifest_event = GetManifestsEvent(
34
+ to=To(serviceUrl=self.url, private=False)
35
+ )
36
+ envelope.events.append(manifest_event)
37
+
38
+ # Send request
39
+ json_str = envelope.to_json()
40
+ envelope_dict = json.loads(json_str)
41
+ payload = {"openFloor": envelope_dict}
42
+
43
+ response = requests.post(self.url, json=payload, timeout=10)
44
+
45
+ if response.status_code == 200:
46
+ response_data = response.json()
47
+ # Extract manifest from response
48
+ if "openFloor" in response_data and "events" in response_data["openFloor"]:
49
+ for event in response_data["openFloor"]["events"]:
50
+ if event.get("eventType") == "publishManifests":
51
+ manifests = event.get("parameters", {}).get("manifests", [])
52
+ if manifests:
53
+ self.manifest = manifests[0] # Take first manifest
54
+ self.capabilities = self.manifest.get("capabilities", [])
55
+ return True
56
+ return False
57
+ except Exception as e:
58
+ print(f"Error getting manifest from {self.url}: {e}")
59
+ return False
60
+
61
+ def send_utterance(self, message: str) -> str:
62
+ """Send an utterance to the agent and get response"""
63
+ try:
64
+ # Create utterance request
65
+ conversation = Conversation()
66
+ sender = Sender(
67
+ speakerUri="openfloor://mcp-bridge/client",
68
+ serviceUrl="http://mcp-bridge"
69
+ )
70
+ envelope = Envelope(conversation=conversation, sender=sender)
71
+
72
+ # Create dialog event
73
+ dialog_event = DialogEvent(
74
+ speakerUri="openfloor://mcp-bridge/client",
75
+ features={"text": TextFeature(values=[message])}
76
+ )
77
+
78
+ utterance_event = UtteranceEvent(
79
+ dialogEvent=dialog_event,
80
+ to=To(serviceUrl=self.url, private=False)
81
+ )
82
+
83
+ envelope.events.append(utterance_event)
84
+
85
+ # Send request
86
+ json_str = envelope.to_json()
87
+ envelope_dict = json.loads(json_str)
88
+ payload = {"openFloor": envelope_dict}
89
+
90
+ response = requests.post(self.url, json=payload, timeout=30)
91
+
92
+ if response.status_code == 200:
93
+ response_data = response.json()
94
+ # Extract response text
95
+ if "openFloor" in response_data and "events" in response_data["openFloor"]:
96
+ for event in response_data["openFloor"]["events"]:
97
+ if event.get("eventType") == "utterance":
98
+ dialog_event = event.get("parameters", {}).get("dialogEvent", {})
99
+ features = dialog_event.get("features", {})
100
+ text_feature = features.get("text", {})
101
+ tokens = text_feature.get("tokens", [])
102
+ if tokens:
103
+ return tokens[0].get("value", "No response")
104
+
105
+ return f"Agent responded but no text found: {response_data}"
106
+ else:
107
+ return f"Agent error: HTTP {response.status_code}"
108
+
109
+ except Exception as e:
110
+ return f"Error communicating with agent: {e}"
111
+
112
+ class BuiltInFloorManager:
113
+ """Built-in Floor Manager for smart agent routing"""
114
+
115
+ def __init__(self):
116
+ self.agent_registry = {} # speakerUri -> agent info
117
+ self.active_conversations = {}
118
+
119
+ def register_agent_from_openfloor_agent(self, openfloor_agent: OpenFloorAgent):
120
+ """Register an OpenFloorAgent with the floor manager"""
121
+ if not openfloor_agent.manifest:
122
+ return False
123
+
124
+ speaker_uri = openfloor_agent.manifest.get("identification", {}).get("speakerUri")
125
+ if not speaker_uri:
126
+ # Create a speaker URI from URL
127
+ speaker_uri = f"tag:{openfloor_agent.url.replace('https://', '').replace('http://', '')},2025:agent"
128
+
129
+ self.agent_registry[speaker_uri] = {
130
+ 'openfloor_agent': openfloor_agent,
131
+ 'manifest': openfloor_agent.manifest,
132
+ 'url': openfloor_agent.url,
133
+ 'capabilities': openfloor_agent.capabilities,
134
+ 'status': 'available',
135
+ 'last_seen': datetime.now()
136
+ }
137
+ print(f"πŸ›οΈ Floor Manager: Registered {openfloor_agent.name}")
138
+ return True
139
+
140
+ def find_best_agent_for_task(self, task: str) -> Optional[OpenFloorAgent]:
141
+ """Find the best agent for a given task based on capabilities"""
142
+ if not self.agent_registry:
143
+ return None
144
+
145
+ task_lower = task.lower()
146
+ best_agent_info = None
147
+ best_score = 0
148
+
149
+ for speaker_uri, agent_info in self.agent_registry.items():
150
+ score = 0
151
+ capabilities = agent_info.get('capabilities', [])
152
+
153
+ for capability in capabilities:
154
+ keyphrases = capability.get("keyphrases", [])
155
+ descriptions = capability.get("descriptions", [])
156
+
157
+ # Score based on keyphrases
158
+ for keyphrase in keyphrases:
159
+ if keyphrase.lower() in task_lower:
160
+ score += 2 # Higher weight for keyphrase matches
161
+
162
+ # Score based on descriptions
163
+ for description in descriptions:
164
+ if any(word in task_lower for word in description.lower().split()):
165
+ score += 1
166
+
167
+ if score > best_score:
168
+ best_score = score
169
+ best_agent_info = agent_info
170
+
171
+ # If no capability match, use first agent
172
+ if not best_agent_info and self.agent_registry:
173
+ best_agent_info = list(self.agent_registry.values())[0]
174
+
175
+ return best_agent_info['openfloor_agent'] if best_agent_info else None
176
+
177
+ def get_all_capabilities(self) -> Dict[str, List[Dict]]:
178
+ """Get all capabilities from all registered agents"""
179
+ all_capabilities = {}
180
+ for speaker_uri, agent_info in self.agent_registry.items():
181
+ agent_name = agent_info['openfloor_agent'].name
182
+ all_capabilities[agent_name] = agent_info.get('capabilities', [])
183
+ return all_capabilities
184
+
185
+ def find_agents_with_capability(self, capability_keywords: List[str]) -> List[OpenFloorAgent]:
186
+ """Find all agents that match given capability keywords"""
187
+ matching_agents = []
188
+ keywords_lower = [kw.lower() for kw in capability_keywords]
189
+
190
+ for speaker_uri, agent_info in self.agent_registry.items():
191
+ capabilities = agent_info.get('capabilities', [])
192
+
193
+ for capability in capabilities:
194
+ keyphrases = capability.get("keyphrases", [])
195
+ descriptions = capability.get("descriptions", [])
196
+
197
+ # Check if any keyword matches keyphrases or descriptions
198
+ for keyphrase in keyphrases:
199
+ if any(kw in keyphrase.lower() for kw in keywords_lower):
200
+ matching_agents.append(agent_info['openfloor_agent'])
201
+ break
202
+
203
+ if agent_info['openfloor_agent'] in matching_agents:
204
+ break
205
+
206
+ for description in descriptions:
207
+ if any(kw in description.lower() for kw in keywords_lower):
208
+ matching_agents.append(agent_info['openfloor_agent'])
209
+ break
210
+
211
+ if agent_info['openfloor_agent'] in matching_agents:
212
+ break
213
+
214
+ return matching_agents
215
+
216
+ # Global instances
217
+ _agents_cache: Dict[str, OpenFloorAgent] = {}
218
+ _floor_manager = BuiltInFloorManager()
219
+
220
+ def _discover_agents_from_headers(request: gr.Request) -> Dict[str, OpenFloorAgent]:
221
+ """Helper function to discover agents from request headers and register with floor manager"""
222
+ headers = dict(request.headers)
223
+
224
+ # Support comma-separated format: x-openfloor-agents: url1,url2,url3
225
+ agent_urls = []
226
+ if "x-openfloor-agents" in headers:
227
+ agent_urls = [url.strip() for url in headers["x-openfloor-agents"].split(",")]
228
+
229
+ # Update agents cache and register with floor manager
230
+ for url in agent_urls:
231
+ if url and url not in _agents_cache:
232
+ agent = OpenFloorAgent(url)
233
+ if agent.get_manifest():
234
+ _agents_cache[url] = agent
235
+ _floor_manager.register_agent_from_openfloor_agent(agent)
236
+ print(f"βœ… Discovered and registered agent: {agent.name} at {url}")
237
+ else:
238
+ print(f"❌ Failed to get manifest from: {url}")
239
+
240
+ return _agents_cache
241
+
242
+ def discover_openfloor_agents(request: gr.Request) -> str:
243
+ """
244
+ Discover OpenFloor agents from request headers and return their capabilities.
245
+
246
+ Provide agent URLs in the 'x-openfloor-agents' header as comma-separated values.
247
+ Example: x-openfloor-agents: https://agent1.com,https://agent2.com
248
+
249
+ Args:
250
+ request: The HTTP request containing agent URLs in headers
251
+
252
+ Returns:
253
+ str: List of discovered agents and their capabilities
254
+ """
255
+ agents = _discover_agents_from_headers(request)
256
+
257
+ if not agents:
258
+ return "❌ No agents discovered. Please provide agent URLs in 'x-openfloor-agents' header as comma-separated values."
259
+
260
+ result = "πŸ€– **Discovered OpenFloor Agents:**\n\n"
261
+ for url, agent in agents.items():
262
+ result += f"**{agent.name}**\n"
263
+ result += f"- URL: {url}\n"
264
+ if agent.manifest:
265
+ identification = agent.manifest.get("identification", {})
266
+ result += f"- Role: {identification.get('role', 'Unknown')}\n"
267
+ result += f"- Synopsis: {identification.get('synopsis', 'No description')}\n"
268
+
269
+ result += f"- Capabilities: {len(agent.capabilities)}\n"
270
+ for cap in agent.capabilities:
271
+ keyphrases = cap.get("keyphrases", [])
272
+ descriptions = cap.get("descriptions", [])
273
+ if keyphrases:
274
+ result += f" β€’ Keywords: {', '.join(keyphrases)}\n"
275
+ if descriptions:
276
+ result += f" β€’ Description: {', '.join(descriptions)}\n"
277
+ result += "\n"
278
+
279
+ return result
280
+
281
+ def send_message_to_openfloor_agent(agent_url: str, message: str, request: gr.Request) -> str:
282
+ """
283
+ Send a message to a specific OpenFloor agent.
284
+
285
+ Args:
286
+ agent_url (str): The URL of the OpenFloor agent
287
+ message (str): The message to send to the agent
288
+ request: The HTTP request (used to discover agents if needed)
289
+
290
+ Returns:
291
+ str: The agent's response
292
+ """
293
+ # Ensure agents are discovered
294
+ agents = _discover_agents_from_headers(request)
295
+
296
+ if agent_url not in agents:
297
+ return f"❌ Agent not found: {agent_url}. Please discover agents first or check the URL."
298
+
299
+ agent = agents[agent_url]
300
+ response = agent.send_utterance(message)
301
+ return f"πŸ€– **{agent.name}**: {response}"
302
+
303
+ def send_to_best_openfloor_agent(task_description: str, request: gr.Request) -> str:
304
+ """
305
+ Send a task to the best available OpenFloor agent using built-in floor manager.
306
+
307
+ The built-in floor manager analyzes agent capabilities and selects the most suitable agent.
308
+
309
+ Args:
310
+ task_description (str): Description of the task to be performed
311
+ request: The HTTP request (used to discover agents)
312
+
313
+ Returns:
314
+ str: The selected agent's response with agent selection details
315
+ """
316
+ # Ensure agents are discovered and registered with floor manager
317
+ _discover_agents_from_headers(request)
318
+
319
+ # Use built-in floor manager to find best agent
320
+ best_agent = _floor_manager.find_best_agent_for_task(task_description)
321
+
322
+ if not best_agent:
323
+ return "❌ No agents available. Please provide 'x-openfloor-agents' header with valid agent URLs."
324
+
325
+ # Send message to selected agent
326
+ response = best_agent.send_utterance(task_description)
327
+
328
+ return f"πŸ›οΈ **Floor Manager Selected: {best_agent.name}**\n\nπŸ€– **Response**: {response}"
329
+
330
+ def execute_agent_capability(capability_keywords: str, task_request: str, request: gr.Request) -> str:
331
+ """
332
+ Execute a task using agents that have specific capabilities.
333
+
334
+ This function finds agents based on their actual manifest capabilities and sends the task.
335
+
336
+ Args:
337
+ capability_keywords (str): Comma-separated keywords to match against agent capabilities (e.g., "convert,unit,calculation")
338
+ task_request (str): The actual task to send to the matching agent
339
+ request: The HTTP request (used to discover agents)
340
+
341
+ Returns:
342
+ str: The response from the matching agent
343
+ """
344
+ # Ensure agents are discovered
345
+ _discover_agents_from_headers(request)
346
+
347
+ # Parse capability keywords
348
+ keywords = [kw.strip() for kw in capability_keywords.split(",")]
349
+
350
+ # Find agents with matching capabilities
351
+ matching_agents = _floor_manager.find_agents_with_capability(keywords)
352
+
353
+ if not matching_agents:
354
+ available_capabilities = _floor_manager.get_all_capabilities()
355
+ capability_summary = ""
356
+ for agent_name, capabilities in available_capabilities.items():
357
+ capability_summary += f"\n- {agent_name}: "
358
+ all_keywords = []
359
+ for cap in capabilities:
360
+ all_keywords.extend(cap.get("keyphrases", []))
361
+ capability_summary += ", ".join(all_keywords[:5])
362
+
363
+ return f"❌ No agents found with capabilities matching: {capability_keywords}\n\nAvailable capabilities:{capability_summary}"
364
+
365
+ # Use the first matching agent (or could implement scoring here)
366
+ selected_agent = matching_agents[0]
367
+ response = selected_agent.send_utterance(task_request)
368
+
369
+ return f"🎯 **Selected Agent: {selected_agent.name}** (matched: {capability_keywords})\n\nπŸ€– **Response**: {response}"
370
+
371
+ def list_all_agent_capabilities(request: gr.Request) -> str:
372
+ """
373
+ List all capabilities of all discovered OpenFloor agents.
374
+
375
+ This shows what the agents can actually do according to their manifests.
376
+
377
+ Args:
378
+ request: The HTTP request (used to discover agents)
379
+
380
+ Returns:
381
+ str: Comprehensive list of all agent capabilities
382
+ """
383
+ # Ensure agents are discovered
384
+ _discover_agents_from_headers(request)
385
+
386
+ all_capabilities = _floor_manager.get_all_capabilities()
387
+
388
+ if not all_capabilities:
389
+ return "❌ No agents discovered. Please provide 'x-openfloor-agents' header."
390
+
391
+ result = "🎯 **All Agent Capabilities:**\n\n"
392
+
393
+ for agent_name, capabilities in all_capabilities.items():
394
+ result += f"**{agent_name}:**\n"
395
+
396
+ if not capabilities:
397
+ result += " - No capabilities defined\n\n"
398
+ continue
399
+
400
+ for i, capability in enumerate(capabilities, 1):
401
+ keyphrases = capability.get("keyphrases", [])
402
+ descriptions = capability.get("descriptions", [])
403
+ languages = capability.get("languages", [])
404
+
405
+ result += f" **Capability {i}:**\n"
406
+ if keyphrases:
407
+ result += f" β€’ Keywords: {', '.join(keyphrases)}\n"
408
+ if descriptions:
409
+ result += f" β€’ Can do: {', '.join(descriptions)}\n"
410
+ if languages:
411
+ result += f" β€’ Languages: {', '.join(languages)}\n"
412
+ result += "\n"
413
+
414
+ result += "\n"
415
+
416
+ return result
417
+
418
+ def send_task_to_agents_with_keywords(keywords: str, task: str, request: gr.Request) -> str:
419
+ """
420
+ Send a task to all agents that match the given capability keywords.
421
+
422
+ Args:
423
+ keywords (str): Comma-separated capability keywords to search for
424
+ task (str): The task to send to matching agents
425
+ request: The HTTP request (used to discover agents)
426
+
427
+ Returns:
428
+ str: Responses from all matching agents
429
+ """
430
+ # Ensure agents are discovered
431
+ _discover_agents_from_headers(request)
432
+
433
+ # Parse keywords
434
+ keyword_list = [kw.strip() for kw in keywords.split(",")]
435
+
436
+ # Find matching agents
437
+ matching_agents = _floor_manager.find_agents_with_capability(keyword_list)
438
+
439
+ if not matching_agents:
440
+ return f"❌ No agents found with capabilities matching: {keywords}"
441
+
442
+ result = f"🎯 **Found {len(matching_agents)} agents matching '{keywords}':**\n\n"
443
+
444
+ for agent in matching_agents:
445
+ response = agent.send_utterance(task)
446
+ result += f"**{agent.name}:** {response}\n\n"
447
+
448
+ return result
449
+
450
+ # Create Gradio interface for testing
451
+ with gr.Blocks(title="MCP-OpenFloor Bridge (Dynamic Capabilities)", theme=gr.themes.Soft()) as demo:
452
+ gr.Markdown("""
453
+ # πŸŒ‰ MCP-OpenFloor Bridge Server (Dynamic Capabilities)
454
+
455
+ This MCP server dynamically uses actual OpenFloor agent capabilities from their manifests.
456
+
457
+ ## πŸ”§ Setup Instructions:
458
+
459
+ ```json
460
+ {
461
+ "mcpServers": {
462
+ "openfloor-bridge": {
463
+ "url": "http://localhost:7860/gradio_api/mcp/sse",
464
+ "headers": {
465
+ "x-openfloor-agents": "https://beaconforge.pythonanywhere.com,https://agent2.com"
466
+ }
467
+ }
468
+ }
469
+ }
470
+ ```
471
+
472
+ ## 🎯 Dynamic Capability-Based Tools:
473
+ - **discover_openfloor_agents**: Find agents and show their actual capabilities
474
+ - **list_all_agent_capabilities**: Show what each agent can actually do
475
+ - **send_to_best_openfloor_agent**: Smart routing based on agent capabilities
476
+ - **execute_agent_capability**: Execute tasks using specific capability keywords
477
+ - **send_task_to_agents_with_keywords**: Send to all agents matching keywords
478
+ - **send_message_to_openfloor_agent**: Direct communication with specific agent
479
+
480
+ ## πŸ“‹ No Hardcoded Functions:
481
+ - Tools are based on actual agent capabilities from manifests
482
+ - Use capability keywords to find appropriate agents
483
+ - Dynamic routing based on what agents can actually do
484
+ """)
485
+
486
+ with gr.Row():
487
+ with gr.Column():
488
+ gr.Markdown("### πŸ” Agent Discovery")
489
+ discover_btn = gr.Button("Discover Agents", variant="primary")
490
+ agent_list = gr.Textbox(label="Discovered Agents", lines=8)
491
+
492
+ capabilities_btn = gr.Button("List All Capabilities", variant="secondary")
493
+ capabilities_output = gr.Textbox(label="Agent Capabilities", lines=10)
494
+
495
+ with gr.Column():
496
+ gr.Markdown("### 🎯 Capability-Based Execution")
497
+ keywords_input = gr.Textbox(
498
+ label="Capability Keywords",
499
+ placeholder="convert,unit,calculation",
500
+ info="Comma-separated keywords to match"
501
+ )
502
+ task_input = gr.Textbox(
503
+ label="Task Request",
504
+ placeholder="convert 50 meters to feet"
505
+ )
506
+ execute_btn = gr.Button("Execute with Matching Agent", variant="primary")
507
+ execute_output = gr.Textbox(label="Execution Result", lines=8)
508
+
509
+ with gr.Row():
510
+ with gr.Column():
511
+ gr.Markdown("### πŸ’¬ Direct Agent Communication")
512
+ agent_url_input = gr.Textbox(
513
+ label="Agent URL",
514
+ placeholder="https://beaconforge.pythonanywhere.com"
515
+ )
516
+ message_input = gr.Textbox(
517
+ label="Message",
518
+ placeholder="What can you help me with?"
519
+ )
520
+ send_btn = gr.Button("Send to Specific Agent", variant="secondary")
521
+ response_output = gr.Textbox(label="Agent Response", lines=5)
522
+
523
+ with gr.Column():
524
+ gr.Markdown("### πŸ›οΈ Smart Floor Manager")
525
+ smart_task_input = gr.Textbox(
526
+ label="Task Description",
527
+ placeholder="I need help with something"
528
+ )
529
+ smart_send_btn = gr.Button("Send to Best Agent", variant="primary")
530
+ smart_response = gr.Textbox(label="Floor Manager Response", lines=5)
531
+
532
+ # Event handlers
533
+ discover_btn.click(
534
+ fn=discover_openfloor_agents,
535
+ inputs=[gr.Request()],
536
+ outputs=[agent_list]
537
+ )
538
+
539
+ capabilities_btn.click(
540
+ fn=list_all_agent_capabilities,
541
+ inputs=[gr.Request()],
542
+ outputs=[capabilities_output]
543
+ )
544
+
545
+ execute_btn.click(
546
+ fn=execute_agent_capability,
547
+ inputs=[keywords_input, task_input, gr.Request()],
548
+ outputs=[execute_output]
549
+ )
550
+
551
+ send_btn.click(
552
+ fn=send_message_to_openfloor_agent,
553
+ inputs=[agent_url_input, message_input, gr.Request()],
554
+ outputs=[response_output]
555
+ )
556
+
557
+ smart_send_btn.click(
558
+ fn=send_to_best_openfloor_agent,
559
+ inputs=[smart_task_input, gr.Request()],
560
+ outputs=[smart_response]
561
+ )
562
+
563
+ if __name__ == "__main__":
564
+ demo.launch(
565
+ share=False,
566
+ debug=False,
567
+ mcp_server=True
568
+ )