Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -202,6 +202,85 @@ class OpenFloorResearchAgent:
|
|
202 |
"""Return the OpenFloor manifest for this research agent"""
|
203 |
return self.manifest
|
204 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
def get_session_id(request: gr.Request = None) -> str:
|
206 |
"""Generate or retrieve session ID"""
|
207 |
if request and hasattr(request, 'session_hash'):
|
@@ -273,6 +352,8 @@ class VisualConsensusEngine:
|
|
273 |
'sec_edgar': OpenFloorResearchAgent(SECSearchTool(), port=8005)
|
274 |
}
|
275 |
|
|
|
|
|
276 |
# Available research agents for discovery
|
277 |
self.available_research_agents = list(self.research_agents.keys())
|
278 |
|
@@ -540,7 +621,7 @@ class VisualConsensusEngine:
|
|
540 |
|
541 |
|
542 |
def _execute_research_function(self, function_name: str, arguments: dict, requesting_model_name: str = None) -> str:
|
543 |
-
"""Execute research function using proper OpenFloor protocol
|
544 |
|
545 |
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
546 |
|
@@ -562,56 +643,58 @@ class VisualConsensusEngine:
|
|
562 |
|
563 |
if function_name in function_to_agent:
|
564 |
agent_name = function_to_agent[function_name]
|
565 |
-
research_agent = self.research_agents[agent_name]
|
566 |
|
567 |
-
|
|
|
568 |
|
569 |
-
|
570 |
-
|
|
|
571 |
|
572 |
-
# Create
|
|
|
573 |
request_dialog = DialogEvent(
|
574 |
speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}",
|
575 |
-
features={
|
576 |
-
"text": TextFeature(values=[query_param])
|
577 |
-
}
|
578 |
)
|
579 |
|
580 |
-
# Create request envelope using OpenFloor protocol
|
581 |
request_envelope = Envelope(
|
582 |
conversation=conversation,
|
583 |
sender=Sender(speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}"),
|
584 |
events=[
|
585 |
UtteranceEvent(
|
586 |
dialogEvent=request_dialog,
|
587 |
-
to=To(speakerUri=
|
588 |
)
|
589 |
]
|
590 |
)
|
591 |
|
592 |
-
|
593 |
-
|
594 |
-
# Send request to research agent using OpenFloor protocol
|
595 |
-
response_envelope = research_agent.handle_utterance_event(request_envelope)
|
596 |
-
|
597 |
-
# Extract result from OpenFloor response
|
598 |
-
result = self._extract_research_result_from_envelope(response_envelope)
|
599 |
|
600 |
-
|
|
|
|
|
|
|
|
|
601 |
|
602 |
elif function_name == "multi_source_research":
|
603 |
-
self.update_research_progress("
|
604 |
|
605 |
-
# Use multiple
|
606 |
results = []
|
607 |
agents_to_use = ["web_search", "wikipedia", "arxiv"]
|
608 |
|
609 |
for i, agent_name in enumerate(agents_to_use, 1):
|
610 |
-
|
|
|
|
|
|
|
|
|
611 |
try:
|
612 |
-
|
613 |
|
614 |
-
# Create OpenFloor request
|
615 |
conversation = Conversation()
|
616 |
request_dialog = DialogEvent(
|
617 |
speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}",
|
@@ -623,27 +706,28 @@ class VisualConsensusEngine:
|
|
623 |
sender=Sender(speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}"),
|
624 |
events=[UtteranceEvent(
|
625 |
dialogEvent=request_dialog,
|
626 |
-
to=To(speakerUri=
|
627 |
)]
|
628 |
)
|
629 |
|
630 |
-
#
|
631 |
-
|
632 |
-
agent_result = self._extract_research_result_from_envelope(response_envelope)
|
633 |
|
634 |
-
if
|
635 |
-
|
636 |
-
|
|
|
|
|
637 |
except Exception as e:
|
638 |
-
self.update_research_progress(f"Phase {i}: {agent_name}
|
639 |
continue
|
640 |
|
641 |
# Combine results
|
642 |
if results:
|
643 |
-
result = f"**Multi-Source OpenFloor Research for: {query_param}**\n\n" + "\n\n---\n\n".join(results)
|
644 |
-
self.update_research_progress(f"Multi-source
|
645 |
else:
|
646 |
-
result = f"Multi-source
|
647 |
|
648 |
else:
|
649 |
result = f"Unknown research function: {function_name}"
|
@@ -658,7 +742,35 @@ class VisualConsensusEngine:
|
|
658 |
error_msg = str(e)
|
659 |
if query_param:
|
660 |
self.show_research_error(function_name, query_param, error_msg, requesting_model_name)
|
661 |
-
return f"OpenFloor research error: {error_msg}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
662 |
|
663 |
def _extract_research_result_from_envelope(self, envelope: Envelope) -> str:
|
664 |
"""Extract research result from OpenFloor response envelope"""
|
|
|
202 |
"""Return the OpenFloor manifest for this research agent"""
|
203 |
return self.manifest
|
204 |
|
205 |
+
|
206 |
+
class OpenFloorAgentServer:
|
207 |
+
"""Run a research agent as an actual OpenFloor service"""
|
208 |
+
|
209 |
+
def __init__(self, research_agent: OpenFloorResearchAgent, port: int):
|
210 |
+
self.agent = research_agent
|
211 |
+
self.port = port
|
212 |
+
self.app = None
|
213 |
+
|
214 |
+
def start_server(self):
|
215 |
+
"""Start the OpenFloor agent server"""
|
216 |
+
from flask import Flask, request, jsonify
|
217 |
+
|
218 |
+
app = Flask(f"research-agent-{self.port}")
|
219 |
+
|
220 |
+
@app.route('/openfloor/conversation', methods=['POST'])
|
221 |
+
def handle_conversation():
|
222 |
+
try:
|
223 |
+
# Parse incoming OpenFloor envelope
|
224 |
+
envelope_data = request.get_json()
|
225 |
+
envelope = Envelope.from_json(json.dumps(envelope_data))
|
226 |
+
|
227 |
+
# Process the request
|
228 |
+
response_envelope = self.agent.handle_utterance_event(envelope)
|
229 |
+
|
230 |
+
# Return OpenFloor response
|
231 |
+
return jsonify(json.loads(response_envelope.to_json()))
|
232 |
+
|
233 |
+
except Exception as e:
|
234 |
+
error_response = self.agent._create_error_response(
|
235 |
+
envelope if 'envelope' in locals() else None,
|
236 |
+
str(e)
|
237 |
+
)
|
238 |
+
return jsonify(json.loads(error_response.to_json())), 500
|
239 |
+
|
240 |
+
@app.route('/openfloor/manifest', methods=['GET'])
|
241 |
+
def get_manifest():
|
242 |
+
"""Return agent manifest"""
|
243 |
+
return jsonify(json.loads(self.agent.manifest.to_json()))
|
244 |
+
|
245 |
+
# Start server in background thread
|
246 |
+
import threading
|
247 |
+
server_thread = threading.Thread(
|
248 |
+
target=lambda: app.run(host='localhost', port=self.port, debug=False)
|
249 |
+
)
|
250 |
+
server_thread.daemon = True
|
251 |
+
server_thread.start()
|
252 |
+
|
253 |
+
print(f"🚀 OpenFloor agent '{self.agent.manifest.identification.conversationalName}' started on port {self.port}")
|
254 |
+
return True
|
255 |
+
|
256 |
+
def start_openfloor_research_agents(self):
|
257 |
+
"""Start all research agents as proper OpenFloor services"""
|
258 |
+
|
259 |
+
agent_ports = {
|
260 |
+
'web_search': 8001,
|
261 |
+
'wikipedia': 8002,
|
262 |
+
'arxiv': 8003,
|
263 |
+
'github': 8004,
|
264 |
+
'sec_edgar': 8005
|
265 |
+
}
|
266 |
+
|
267 |
+
self.agent_servers = {}
|
268 |
+
|
269 |
+
for agent_name, port in agent_ports.items():
|
270 |
+
agent = self.research_agents[agent_name]
|
271 |
+
server = OpenFloorAgentServer(agent, port)
|
272 |
+
|
273 |
+
if server.start_server():
|
274 |
+
self.agent_servers[agent_name] = {
|
275 |
+
'server': server,
|
276 |
+
'port': port,
|
277 |
+
'url': f"http://localhost:{port}/openfloor/conversation",
|
278 |
+
'manifest_url': f"http://localhost:{port}/openfloor/manifest"
|
279 |
+
}
|
280 |
+
|
281 |
+
# Small delay between starting servers
|
282 |
+
time.sleep(0.5)
|
283 |
+
|
284 |
def get_session_id(request: gr.Request = None) -> str:
|
285 |
"""Generate or retrieve session ID"""
|
286 |
if request and hasattr(request, 'session_hash'):
|
|
|
352 |
'sec_edgar': OpenFloorResearchAgent(SECSearchTool(), port=8005)
|
353 |
}
|
354 |
|
355 |
+
self.start_openfloor_research_agents()
|
356 |
+
|
357 |
# Available research agents for discovery
|
358 |
self.available_research_agents = list(self.research_agents.keys())
|
359 |
|
|
|
621 |
|
622 |
|
623 |
def _execute_research_function(self, function_name: str, arguments: dict, requesting_model_name: str = None) -> str:
|
624 |
+
"""Execute research function using proper OpenFloor HTTP protocol"""
|
625 |
|
626 |
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
627 |
|
|
|
643 |
|
644 |
if function_name in function_to_agent:
|
645 |
agent_name = function_to_agent[function_name]
|
|
|
646 |
|
647 |
+
if agent_name not in self.agent_servers:
|
648 |
+
return f"Research agent '{agent_name}' not available"
|
649 |
|
650 |
+
agent_server = self.agent_servers[agent_name]
|
651 |
+
|
652 |
+
self.update_research_progress(f"Sending HTTP request to OpenFloor agent...")
|
653 |
|
654 |
+
# Create OpenFloor envelope
|
655 |
+
conversation = Conversation()
|
656 |
request_dialog = DialogEvent(
|
657 |
speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}",
|
658 |
+
features={"text": TextFeature(values=[query_param])}
|
|
|
|
|
659 |
)
|
660 |
|
|
|
661 |
request_envelope = Envelope(
|
662 |
conversation=conversation,
|
663 |
sender=Sender(speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}"),
|
664 |
events=[
|
665 |
UtteranceEvent(
|
666 |
dialogEvent=request_dialog,
|
667 |
+
to=To(speakerUri=self.research_agents[agent_name].manifest.identification.speakerUri)
|
668 |
)
|
669 |
]
|
670 |
)
|
671 |
|
672 |
+
# Send HTTP POST request to OpenFloor agent service
|
673 |
+
response = self._send_openfloor_request(agent_server['url'], request_envelope)
|
|
|
|
|
|
|
|
|
|
|
674 |
|
675 |
+
if response:
|
676 |
+
result = self._extract_research_result_from_envelope(response)
|
677 |
+
self.update_research_progress(f"OpenFloor HTTP response received - {len(result)} characters")
|
678 |
+
else:
|
679 |
+
result = f"Failed to get response from {agent_name} OpenFloor service"
|
680 |
|
681 |
elif function_name == "multi_source_research":
|
682 |
+
self.update_research_progress("Starting multi-agent OpenFloor HTTP research...")
|
683 |
|
684 |
+
# Use multiple agents via HTTP
|
685 |
results = []
|
686 |
agents_to_use = ["web_search", "wikipedia", "arxiv"]
|
687 |
|
688 |
for i, agent_name in enumerate(agents_to_use, 1):
|
689 |
+
if agent_name not in self.agent_servers:
|
690 |
+
continue
|
691 |
+
|
692 |
+
self.update_research_progress(f"Phase {i}: HTTP request to {agent_name.replace('_', ' ').title()}...")
|
693 |
+
|
694 |
try:
|
695 |
+
agent_server = self.agent_servers[agent_name]
|
696 |
|
697 |
+
# Create OpenFloor request
|
698 |
conversation = Conversation()
|
699 |
request_dialog = DialogEvent(
|
700 |
speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}",
|
|
|
706 |
sender=Sender(speakerUri=f"tag:consilium.ai,2025:{requesting_model_name or 'expert'}"),
|
707 |
events=[UtteranceEvent(
|
708 |
dialogEvent=request_dialog,
|
709 |
+
to=To(speakerUri=self.research_agents[agent_name].manifest.identification.speakerUri)
|
710 |
)]
|
711 |
)
|
712 |
|
713 |
+
# Send HTTP request
|
714 |
+
response = self._send_openfloor_request(agent_server['url'], request_envelope)
|
|
|
715 |
|
716 |
+
if response:
|
717 |
+
agent_result = self._extract_research_result_from_envelope(response)
|
718 |
+
if agent_result and len(agent_result) > 100:
|
719 |
+
results.append(f"**{agent_name.replace('_', ' ').title()} Results:**\n{agent_result}")
|
720 |
+
|
721 |
except Exception as e:
|
722 |
+
self.update_research_progress(f"Phase {i}: {agent_name} HTTP error - {str(e)[:50]}...")
|
723 |
continue
|
724 |
|
725 |
# Combine results
|
726 |
if results:
|
727 |
+
result = f"**Multi-Source OpenFloor HTTP Research for: {query_param}**\n\n" + "\n\n---\n\n".join(results)
|
728 |
+
self.update_research_progress(f"Multi-source HTTP research complete - {len(result)} characters")
|
729 |
else:
|
730 |
+
result = f"Multi-source HTTP research failed for '{query_param}'"
|
731 |
|
732 |
else:
|
733 |
result = f"Unknown research function: {function_name}"
|
|
|
742 |
error_msg = str(e)
|
743 |
if query_param:
|
744 |
self.show_research_error(function_name, query_param, error_msg, requesting_model_name)
|
745 |
+
return f"OpenFloor HTTP research error: {error_msg}"
|
746 |
+
|
747 |
+
def _send_openfloor_request(self, agent_url: str, envelope: Envelope) -> Optional[Envelope]:
|
748 |
+
"""Send HTTP request to OpenFloor agent service"""
|
749 |
+
try:
|
750 |
+
import requests
|
751 |
+
|
752 |
+
# Serialize envelope to JSON
|
753 |
+
envelope_json = json.loads(envelope.to_json())
|
754 |
+
|
755 |
+
# Send HTTP POST request
|
756 |
+
response = requests.post(
|
757 |
+
agent_url,
|
758 |
+
json=envelope_json,
|
759 |
+
headers={'Content-Type': 'application/json'},
|
760 |
+
timeout=30
|
761 |
+
)
|
762 |
+
|
763 |
+
if response.status_code == 200:
|
764 |
+
# Parse response back to OpenFloor envelope
|
765 |
+
response_data = response.json()
|
766 |
+
return Envelope.from_json(json.dumps(response_data))
|
767 |
+
else:
|
768 |
+
print(f"OpenFloor HTTP error: {response.status_code} - {response.text}")
|
769 |
+
return None
|
770 |
+
|
771 |
+
except Exception as e:
|
772 |
+
print(f"Error sending OpenFloor HTTP request: {e}")
|
773 |
+
return None
|
774 |
|
775 |
def _extract_research_result_from_envelope(self, envelope: Envelope) -> str:
|
776 |
"""Extract research result from OpenFloor response envelope"""
|