add details about research
Browse files
app.py
CHANGED
|
@@ -177,105 +177,6 @@ class VisualConsensusEngine:
|
|
| 177 |
"""Update the visual roundtable state for this session"""
|
| 178 |
if self.update_callback:
|
| 179 |
self.update_callback(state_update)
|
| 180 |
-
|
| 181 |
-
def show_research_activity(self, speaker: str, function: str, query: str):
|
| 182 |
-
"""Show research happening in the UI with Research Agent activation"""
|
| 183 |
-
# Get current state properly
|
| 184 |
-
session = get_or_create_session_state(self.session_id)
|
| 185 |
-
current_state = session["roundtable_state"]
|
| 186 |
-
all_messages = list(current_state.get("messages", [])) # Make a copy
|
| 187 |
-
participants = current_state.get("participants", [])
|
| 188 |
-
|
| 189 |
-
# PRESERVE existing bubbles throughout research
|
| 190 |
-
existing_bubbles = list(set(msg["speaker"] for msg in all_messages if msg.get("speaker") and msg["speaker"] != "Research Agent"))
|
| 191 |
-
|
| 192 |
-
# Get function display name
|
| 193 |
-
function_display = {
|
| 194 |
-
'search_web': 'Web Search',
|
| 195 |
-
'search_wikipedia': 'Wikipedia',
|
| 196 |
-
'search_academic': 'Academic Papers',
|
| 197 |
-
'search_technology_trends': 'Technology Trends',
|
| 198 |
-
'search_financial_data': 'Financial Data',
|
| 199 |
-
'multi_source_research': 'Multi-Source Research'
|
| 200 |
-
}.get(function, function.replace('_', ' ').title())
|
| 201 |
-
|
| 202 |
-
# Step 1: Show expert requesting research
|
| 203 |
-
request_message = {
|
| 204 |
-
"speaker": speaker,
|
| 205 |
-
"text": f"π **Research Request**: {function_display}\nπ Query: \"{query}\"",
|
| 206 |
-
"type": "research_request"
|
| 207 |
-
}
|
| 208 |
-
all_messages.append(request_message)
|
| 209 |
-
|
| 210 |
-
self.update_visual_state({
|
| 211 |
-
"participants": participants,
|
| 212 |
-
"messages": all_messages,
|
| 213 |
-
"currentSpeaker": speaker,
|
| 214 |
-
"thinking": [],
|
| 215 |
-
"showBubbles": existing_bubbles + [speaker]
|
| 216 |
-
})
|
| 217 |
-
time.sleep(1.5)
|
| 218 |
-
|
| 219 |
-
# Step 2: Research Agent starts thinking
|
| 220 |
-
self.update_visual_state({
|
| 221 |
-
"participants": participants,
|
| 222 |
-
"messages": all_messages,
|
| 223 |
-
"currentSpeaker": None,
|
| 224 |
-
"thinking": ["Research Agent"],
|
| 225 |
-
"showBubbles": existing_bubbles + [speaker, "Research Agent"]
|
| 226 |
-
})
|
| 227 |
-
time.sleep(2)
|
| 228 |
-
|
| 229 |
-
# Step 3: Research Agent working - show detailed activity
|
| 230 |
-
working_message = {
|
| 231 |
-
"speaker": "Research Agent",
|
| 232 |
-
"text": f"π **Conducting Research**: {function_display}\nπ Analyzing: \"{query}\"\nβ³ Please wait while I gather information...",
|
| 233 |
-
"type": "research_activity"
|
| 234 |
-
}
|
| 235 |
-
all_messages.append(working_message)
|
| 236 |
-
|
| 237 |
-
self.update_visual_state({
|
| 238 |
-
"participants": participants,
|
| 239 |
-
"messages": all_messages,
|
| 240 |
-
"currentSpeaker": "Research Agent",
|
| 241 |
-
"thinking": [],
|
| 242 |
-
"showBubbles": existing_bubbles + [speaker, "Research Agent"]
|
| 243 |
-
})
|
| 244 |
-
time.sleep(3) # Longer pause to see research happening
|
| 245 |
-
|
| 246 |
-
# Step 4: Research completion notification
|
| 247 |
-
completion_message = {
|
| 248 |
-
"speaker": "Research Agent",
|
| 249 |
-
"text": f"β
**Research Complete**: {function_display}\nπ Results ready for analysis",
|
| 250 |
-
"type": "research_complete"
|
| 251 |
-
}
|
| 252 |
-
all_messages.append(completion_message)
|
| 253 |
-
|
| 254 |
-
self.update_visual_state({
|
| 255 |
-
"participants": participants,
|
| 256 |
-
"messages": all_messages,
|
| 257 |
-
"currentSpeaker": "Research Agent",
|
| 258 |
-
"thinking": [],
|
| 259 |
-
"showBubbles": existing_bubbles + [speaker, "Research Agent"]
|
| 260 |
-
})
|
| 261 |
-
time.sleep(1.5)
|
| 262 |
-
|
| 263 |
-
# Step 5: Expert processing results
|
| 264 |
-
processing_message = {
|
| 265 |
-
"speaker": speaker,
|
| 266 |
-
"text": f"π **Processing Research Results**\nπ§ Integrating {function_display} findings into analysis...",
|
| 267 |
-
"type": "research_processing"
|
| 268 |
-
}
|
| 269 |
-
all_messages.append(processing_message)
|
| 270 |
-
|
| 271 |
-
self.update_visual_state({
|
| 272 |
-
"participants": participants,
|
| 273 |
-
"messages": all_messages,
|
| 274 |
-
"currentSpeaker": speaker,
|
| 275 |
-
"thinking": [],
|
| 276 |
-
"showBubbles": existing_bubbles + [speaker, "Research Agent"] # Keep Research Agent visible longer
|
| 277 |
-
})
|
| 278 |
-
time.sleep(2)
|
| 279 |
|
| 280 |
def log_research_activity(self, speaker: str, function: str, query: str, result: str, log_function=None):
|
| 281 |
"""Log research activity to the discussion log"""
|
|
@@ -342,12 +243,33 @@ class VisualConsensusEngine:
|
|
| 342 |
function_name = tool_call.function.name
|
| 343 |
arguments = json.loads(tool_call.function.arguments)
|
| 344 |
|
| 345 |
-
# Show research activity in UI
|
| 346 |
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
| 347 |
if query_param:
|
| 348 |
-
self.
|
| 349 |
-
|
| 350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
result = self._execute_research_function(function_name, arguments)
|
| 352 |
|
| 353 |
# Ensure result is a string
|
|
@@ -365,9 +287,11 @@ class VisualConsensusEngine:
|
|
| 365 |
**kwargs
|
| 366 |
})
|
| 367 |
|
|
|
|
|
|
|
| 368 |
if query_param and result:
|
| 369 |
self.log_research_activity(calling_model_name, function_name, query_param, result, session_log_function)
|
| 370 |
-
|
| 371 |
# Add function result to conversation
|
| 372 |
messages.append({
|
| 373 |
"role": "tool",
|
|
@@ -435,42 +359,298 @@ class VisualConsensusEngine:
|
|
| 435 |
print(f"Error in follow-up completion for {calling_model}: {str(e)}")
|
| 436 |
return message.content or "Analysis completed with research integration."
|
| 437 |
|
|
|
|
| 438 |
def _execute_research_function(self, function_name: str, arguments: dict) -> str:
|
| 439 |
-
"""Execute research function with
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
try:
|
|
|
|
|
|
|
|
|
|
| 441 |
if function_name == "search_web":
|
|
|
|
| 442 |
depth = arguments.get("depth", "standard")
|
| 443 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
|
| 445 |
elif function_name == "search_wikipedia":
|
| 446 |
-
|
|
|
|
|
|
|
|
|
|
| 447 |
|
| 448 |
elif function_name == "search_academic":
|
| 449 |
source = arguments.get("source", "both")
|
|
|
|
| 450 |
if source == "arxiv":
|
| 451 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
elif source == "scholar":
|
| 453 |
-
|
| 454 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 455 |
arxiv_result = self.search_agent.tools['arxiv'].search(arguments["query"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
scholar_result = self.search_agent.tools['scholar'].search(arguments["query"])
|
| 457 |
-
|
|
|
|
|
|
|
|
|
|
| 458 |
|
| 459 |
elif function_name == "search_technology_trends":
|
| 460 |
-
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
elif function_name == "search_financial_data":
|
| 463 |
-
|
|
|
|
|
|
|
|
|
|
| 464 |
|
| 465 |
elif function_name == "multi_source_research":
|
| 466 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
|
| 468 |
else:
|
| 469 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 470 |
|
|
|
|
|
|
|
| 471 |
except Exception as e:
|
| 472 |
-
|
|
|
|
|
|
|
|
|
|
| 473 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 474 |
def call_model(self, model: str, prompt: str, context: str = "") -> Optional[str]:
|
| 475 |
"""Enhanced model calling with native function calling support"""
|
| 476 |
if not self.models[model]['available']:
|
|
@@ -516,7 +696,7 @@ class VisualConsensusEngine:
|
|
| 516 |
|
| 517 |
# Check if model supports function calling
|
| 518 |
supports_functions = sambanova_model in [
|
| 519 |
-
'DeepSeek-
|
| 520 |
'Meta-Llama-3.1-8B-Instruct',
|
| 521 |
'Meta-Llama-3.1-405B-Instruct',
|
| 522 |
'Meta-Llama-3.3-70B-Instruct'
|
|
@@ -727,8 +907,9 @@ class VisualConsensusEngine:
|
|
| 727 |
# Log and set thinking state - PRESERVE BUBBLES
|
| 728 |
log_event('thinking', speaker=self.models[model]['name'])
|
| 729 |
|
| 730 |
-
|
| 731 |
-
|
|
|
|
| 732 |
|
| 733 |
self.update_visual_state({
|
| 734 |
"participants": visual_participant_names,
|
|
@@ -776,7 +957,7 @@ Provide your expert analysis:"""
|
|
| 776 |
log_event('speaking', speaker=self.models[model]['name'])
|
| 777 |
|
| 778 |
# Calculate existing bubbles
|
| 779 |
-
existing_bubbles = list(
|
| 780 |
|
| 781 |
self.update_visual_state({
|
| 782 |
"participants": visual_participant_names,
|
|
@@ -853,7 +1034,7 @@ Provide your expert analysis:"""
|
|
| 853 |
# Log thinking with preserved bubbles
|
| 854 |
log_event('thinking', speaker=self.models[model]['name'])
|
| 855 |
|
| 856 |
-
existing_bubbles = list(
|
| 857 |
|
| 858 |
self.update_visual_state({
|
| 859 |
"participants": visual_participant_names,
|
|
@@ -902,7 +1083,7 @@ Your expert response:"""
|
|
| 902 |
# Log speaking with preserved bubbles
|
| 903 |
log_event('speaking', speaker=self.models[model]['name'])
|
| 904 |
|
| 905 |
-
existing_bubbles = list(
|
| 906 |
|
| 907 |
self.update_visual_state({
|
| 908 |
"participants": visual_participant_names,
|
|
@@ -979,7 +1160,7 @@ Your expert response:"""
|
|
| 979 |
expert_names = [self.models[model]['name'] for model in available_models]
|
| 980 |
|
| 981 |
# Preserve existing bubbles during final thinking
|
| 982 |
-
existing_bubbles = list(
|
| 983 |
|
| 984 |
self.update_visual_state({
|
| 985 |
"participants": visual_participant_names,
|
|
@@ -1057,7 +1238,7 @@ Provide your synthesis:"""
|
|
| 1057 |
log_event('speaking', speaker=moderator_title, content="Synthesizing expert analysis into final recommendation...")
|
| 1058 |
|
| 1059 |
# Preserve existing bubbles during final speaking
|
| 1060 |
-
existing_bubbles = list(
|
| 1061 |
|
| 1062 |
self.update_visual_state({
|
| 1063 |
"participants": visual_participant_names,
|
|
|
|
| 177 |
"""Update the visual roundtable state for this session"""
|
| 178 |
if self.update_callback:
|
| 179 |
self.update_callback(state_update)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
def log_research_activity(self, speaker: str, function: str, query: str, result: str, log_function=None):
|
| 182 |
"""Log research activity to the discussion log"""
|
|
|
|
| 243 |
function_name = tool_call.function.name
|
| 244 |
arguments = json.loads(tool_call.function.arguments)
|
| 245 |
|
|
|
|
| 246 |
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
| 247 |
if query_param:
|
| 248 |
+
session = get_or_create_session_state(self.session_id)
|
| 249 |
+
current_state = session["roundtable_state"]
|
| 250 |
+
all_messages = list(current_state.get("messages", []))
|
| 251 |
+
|
| 252 |
+
# Add request message to the CALLING MODEL (Mistral)
|
| 253 |
+
request_message = {
|
| 254 |
+
"speaker": calling_model_name,
|
| 255 |
+
"text": f"π **Research Request**: {function_name.replace('_', ' ').title()}\nπ Query: \"{query_param}\"\nβ³ Waiting for research results...",
|
| 256 |
+
"type": "research_request"
|
| 257 |
+
}
|
| 258 |
+
all_messages.append(request_message)
|
| 259 |
+
|
| 260 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 261 |
+
if calling_model_name not in existing_bubbles:
|
| 262 |
+
existing_bubbles.append(calling_model_name)
|
| 263 |
+
|
| 264 |
+
self.update_visual_state({
|
| 265 |
+
"participants": current_state.get("participants", []),
|
| 266 |
+
"messages": all_messages,
|
| 267 |
+
"currentSpeaker": calling_model_name,
|
| 268 |
+
"thinking": [],
|
| 269 |
+
"showBubbles": existing_bubbles
|
| 270 |
+
})
|
| 271 |
+
time.sleep(1)
|
| 272 |
+
|
| 273 |
result = self._execute_research_function(function_name, arguments)
|
| 274 |
|
| 275 |
# Ensure result is a string
|
|
|
|
| 287 |
**kwargs
|
| 288 |
})
|
| 289 |
|
| 290 |
+
# Get query parameter for logging
|
| 291 |
+
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
| 292 |
if query_param and result:
|
| 293 |
self.log_research_activity(calling_model_name, function_name, query_param, result, session_log_function)
|
| 294 |
+
|
| 295 |
# Add function result to conversation
|
| 296 |
messages.append({
|
| 297 |
"role": "tool",
|
|
|
|
| 359 |
print(f"Error in follow-up completion for {calling_model}: {str(e)}")
|
| 360 |
return message.content or "Analysis completed with research integration."
|
| 361 |
|
| 362 |
+
|
| 363 |
def _execute_research_function(self, function_name: str, arguments: dict) -> str:
|
| 364 |
+
"""Execute research function with REAL-TIME visual feedback and progress indicators"""
|
| 365 |
+
|
| 366 |
+
query_param = arguments.get("query") or arguments.get("topic") or arguments.get("technology") or arguments.get("company")
|
| 367 |
+
|
| 368 |
+
# Phase 1: Show research STARTING
|
| 369 |
+
if query_param:
|
| 370 |
+
self.show_research_starting(function_name, query_param)
|
| 371 |
+
|
| 372 |
try:
|
| 373 |
+
# Actually execute the research with detailed progress indicators
|
| 374 |
+
result = ""
|
| 375 |
+
|
| 376 |
if function_name == "search_web":
|
| 377 |
+
self.update_research_progress("Initializing web search engines...")
|
| 378 |
depth = arguments.get("depth", "standard")
|
| 379 |
+
|
| 380 |
+
if depth == "deep":
|
| 381 |
+
self.update_research_progress("Performing deep web search (multiple sources)...")
|
| 382 |
+
else:
|
| 383 |
+
self.update_research_progress("Searching web databases...")
|
| 384 |
+
|
| 385 |
+
result = self.search_agent.search(arguments["query"], depth)
|
| 386 |
+
self.update_research_progress(f"Web search complete - found {len(result)} characters of data")
|
| 387 |
|
| 388 |
elif function_name == "search_wikipedia":
|
| 389 |
+
self.update_research_progress("Connecting to Wikipedia API...")
|
| 390 |
+
self.update_research_progress("Searching Wikipedia articles...")
|
| 391 |
+
result = self.search_agent.search_wikipedia(arguments["topic"])
|
| 392 |
+
self.update_research_progress(f"Wikipedia search complete - found {len(result)} characters")
|
| 393 |
|
| 394 |
elif function_name == "search_academic":
|
| 395 |
source = arguments.get("source", "both")
|
| 396 |
+
|
| 397 |
if source == "arxiv":
|
| 398 |
+
self.update_research_progress("Connecting to arXiv preprint server...")
|
| 399 |
+
self.update_research_progress("Searching academic papers on arXiv...")
|
| 400 |
+
result = self.search_agent.tools['arxiv'].search(arguments["query"])
|
| 401 |
+
self.update_research_progress(f"arXiv search complete - found {len(result)} characters")
|
| 402 |
+
|
| 403 |
elif source == "scholar":
|
| 404 |
+
self.update_research_progress("Connecting to Google Scholar...")
|
| 405 |
+
self.update_research_progress("Searching peer-reviewed research...")
|
| 406 |
+
result = self.search_agent.tools['scholar'].search(arguments["query"])
|
| 407 |
+
self.update_research_progress(f"Google Scholar search complete - found {len(result)} characters")
|
| 408 |
+
|
| 409 |
+
else: # both sources
|
| 410 |
+
self.update_research_progress("Connecting to arXiv preprint server...")
|
| 411 |
+
self.update_research_progress("Searching academic papers on arXiv...")
|
| 412 |
arxiv_result = self.search_agent.tools['arxiv'].search(arguments["query"])
|
| 413 |
+
self.update_research_progress(f"arXiv complete ({len(arxiv_result)} chars) - now searching Google Scholar...")
|
| 414 |
+
|
| 415 |
+
self.update_research_progress("Connecting to Google Scholar...")
|
| 416 |
+
self.update_research_progress("Searching peer-reviewed research...")
|
| 417 |
scholar_result = self.search_agent.tools['scholar'].search(arguments["query"])
|
| 418 |
+
self.update_research_progress("Combining arXiv and Google Scholar results...")
|
| 419 |
+
|
| 420 |
+
result = f"{arxiv_result}\n\n{scholar_result}"
|
| 421 |
+
self.update_research_progress(f"Academic search complete - combined {len(result)} characters")
|
| 422 |
|
| 423 |
elif function_name == "search_technology_trends":
|
| 424 |
+
self.update_research_progress("Connecting to GitHub API...")
|
| 425 |
+
self.update_research_progress("Analyzing technology trends and repository data...")
|
| 426 |
+
result = self.search_agent.tools['github'].search(arguments["technology"])
|
| 427 |
+
self.update_research_progress(f"Technology trends analysis complete - found {len(result)} characters")
|
| 428 |
|
| 429 |
elif function_name == "search_financial_data":
|
| 430 |
+
self.update_research_progress("Connecting to SEC EDGAR database...")
|
| 431 |
+
self.update_research_progress("Searching financial filings and reports...")
|
| 432 |
+
result = self.search_agent.tools['sec'].search(arguments["company"])
|
| 433 |
+
self.update_research_progress(f"Financial data search complete - found {len(result)} characters")
|
| 434 |
|
| 435 |
elif function_name == "multi_source_research":
|
| 436 |
+
self.update_research_progress("Initializing multi-source deep research...")
|
| 437 |
+
self.update_research_progress("Phase 1: Web search...")
|
| 438 |
+
|
| 439 |
+
# Show progress for each source in deep research
|
| 440 |
+
result = ""
|
| 441 |
+
try:
|
| 442 |
+
# Simulate the deep research process with progress updates
|
| 443 |
+
self.update_research_progress("Phase 1: Comprehensive web search...")
|
| 444 |
+
web_result = self.search_agent.search(arguments["query"], "standard")
|
| 445 |
+
self.update_research_progress(f"Web search complete ({len(web_result)} chars) - Phase 2: Academic sources...")
|
| 446 |
+
|
| 447 |
+
self.update_research_progress("Phase 2: Searching academic databases...")
|
| 448 |
+
# Add small delay to show progress
|
| 449 |
+
time.sleep(1)
|
| 450 |
+
|
| 451 |
+
self.update_research_progress("Phase 3: Analyzing and synthesizing results...")
|
| 452 |
+
result = self.search_agent.search(arguments["query"], "deep")
|
| 453 |
+
self.update_research_progress(f"Multi-source research complete - synthesized {len(result)} characters")
|
| 454 |
+
|
| 455 |
+
except Exception as e:
|
| 456 |
+
self.update_research_progress(f"Multi-source research error: {str(e)}")
|
| 457 |
+
result = f"Multi-source research encountered an error: {str(e)}"
|
| 458 |
|
| 459 |
else:
|
| 460 |
+
self.update_research_progress(f"Unknown research function: {function_name}")
|
| 461 |
+
result = f"Unknown research function: {function_name}"
|
| 462 |
+
|
| 463 |
+
# Phase 3: Show research ACTUALLY complete (after execution)
|
| 464 |
+
if query_param:
|
| 465 |
+
self.show_research_complete(function_name, query_param, len(result))
|
| 466 |
|
| 467 |
+
return result
|
| 468 |
+
|
| 469 |
except Exception as e:
|
| 470 |
+
error_msg = str(e)
|
| 471 |
+
if query_param:
|
| 472 |
+
self.show_research_error(function_name, query_param, error_msg)
|
| 473 |
+
return f"Research function error: {error_msg}"
|
| 474 |
|
| 475 |
+
def show_research_starting(self, function: str, query: str):
|
| 476 |
+
"""Show research request initiation with enhanced messaging"""
|
| 477 |
+
session = get_or_create_session_state(self.session_id)
|
| 478 |
+
current_state = session["roundtable_state"]
|
| 479 |
+
all_messages = list(current_state.get("messages", []))
|
| 480 |
+
participants = current_state.get("participants", [])
|
| 481 |
+
|
| 482 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 483 |
+
# Ensure both Research Agent AND the calling model stay visible
|
| 484 |
+
if "Research Agent" not in existing_bubbles:
|
| 485 |
+
existing_bubbles.append("Research Agent")
|
| 486 |
+
# Keep the current speaker (the one who requested research) visible
|
| 487 |
+
current_speaker = current_state.get("currentSpeaker")
|
| 488 |
+
if current_speaker and current_speaker not in existing_bubbles and current_speaker != "Research Agent":
|
| 489 |
+
existing_bubbles.append(current_speaker)
|
| 490 |
+
|
| 491 |
+
# Enhanced messages based on function type
|
| 492 |
+
function_descriptions = {
|
| 493 |
+
"search_web": "π Web Search - Real-time information",
|
| 494 |
+
"search_wikipedia": "π Wikipedia - Authoritative encyclopedia",
|
| 495 |
+
"search_academic": "π Academic Research - Peer-reviewed papers",
|
| 496 |
+
"search_technology_trends": "π» Technology Trends - GitHub analysis",
|
| 497 |
+
"search_financial_data": "π° Financial Data - SEC filings",
|
| 498 |
+
"multi_source_research": "π¬ Deep Research - Multiple sources"
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
function_desc = function_descriptions.get(function, function.replace('_', ' ').title())
|
| 502 |
+
|
| 503 |
+
estimated_time = self.estimate_research_time(function)
|
| 504 |
+
message = {
|
| 505 |
+
"speaker": "Research Agent",
|
| 506 |
+
"text": f"π **Initiating Research**\n{function_desc}\nπ Query: \"{query}\"\nβ° Estimated time: {estimated_time}\nβ³ Connecting to data sources...",
|
| 507 |
+
"type": "research_starting"
|
| 508 |
+
}
|
| 509 |
+
all_messages.append(message)
|
| 510 |
+
|
| 511 |
+
self.update_visual_state({
|
| 512 |
+
"participants": participants,
|
| 513 |
+
"messages": all_messages,
|
| 514 |
+
"currentSpeaker": None,
|
| 515 |
+
"thinking": [],
|
| 516 |
+
"showBubbles": existing_bubbles + ["Research Agent"]
|
| 517 |
+
})
|
| 518 |
+
time.sleep(0.5)
|
| 519 |
+
|
| 520 |
+
def show_research_complete(self, function: str, query: str, result_length: int):
|
| 521 |
+
"""Show research ACTUALLY completed with data quality indicators"""
|
| 522 |
+
session = get_or_create_session_state(self.session_id)
|
| 523 |
+
current_state = session["roundtable_state"]
|
| 524 |
+
all_messages = list(current_state.get("messages", []))
|
| 525 |
+
participants = current_state.get("participants", [])
|
| 526 |
+
|
| 527 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 528 |
+
# Ensure both Research Agent AND the calling model stay visible
|
| 529 |
+
if "Research Agent" not in existing_bubbles:
|
| 530 |
+
existing_bubbles.append("Research Agent")
|
| 531 |
+
# Keep the current speaker (the one who requested research) visible
|
| 532 |
+
current_speaker = current_state.get("currentSpeaker")
|
| 533 |
+
if current_speaker and current_speaker not in existing_bubbles and current_speaker != "Research Agent":
|
| 534 |
+
existing_bubbles.append(current_speaker)
|
| 535 |
+
|
| 536 |
+
# Determine data quality based on result length
|
| 537 |
+
if result_length > 2000:
|
| 538 |
+
quality_indicator = "π High-quality data (comprehensive)"
|
| 539 |
+
quality_emoji = "π―"
|
| 540 |
+
elif result_length > 800:
|
| 541 |
+
quality_indicator = "π Good data (substantial)"
|
| 542 |
+
quality_emoji = "β
"
|
| 543 |
+
elif result_length > 200:
|
| 544 |
+
quality_indicator = "π Moderate data (basic)"
|
| 545 |
+
quality_emoji = "β οΈ"
|
| 546 |
+
else:
|
| 547 |
+
quality_indicator = "π Limited data (minimal)"
|
| 548 |
+
quality_emoji = "β‘"
|
| 549 |
+
|
| 550 |
+
# Function-specific completion messages
|
| 551 |
+
function_summaries = {
|
| 552 |
+
"search_web": "Live web data retrieved",
|
| 553 |
+
"search_wikipedia": "Encyclopedia articles found",
|
| 554 |
+
"search_academic": "Academic papers analyzed",
|
| 555 |
+
"search_technology_trends": "Tech trends mapped",
|
| 556 |
+
"search_financial_data": "Financial reports accessed",
|
| 557 |
+
"multi_source_research": "Multi-source synthesis complete"
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
function_summary = function_summaries.get(function, "Research complete")
|
| 561 |
+
|
| 562 |
+
message = {
|
| 563 |
+
"speaker": "Research Agent",
|
| 564 |
+
"text": f"β
**Research Complete**\nπ¬ {function.replace('_', ' ').title()}\nπ Query: \"{query}\"\n{quality_emoji} {function_summary}\n{quality_indicator}\nπ {result_length:,} characters analyzed\nπ― Data ready for expert analysis",
|
| 565 |
+
"type": "research_complete"
|
| 566 |
+
}
|
| 567 |
+
all_messages.append(message)
|
| 568 |
+
|
| 569 |
+
self.update_visual_state({
|
| 570 |
+
"participants": participants,
|
| 571 |
+
"messages": all_messages,
|
| 572 |
+
"currentSpeaker": None,
|
| 573 |
+
"thinking": [],
|
| 574 |
+
"showBubbles": existing_bubbles + ["Research Agent"]
|
| 575 |
+
})
|
| 576 |
+
time.sleep(1.5) # Longer pause to show the detailed completion
|
| 577 |
+
|
| 578 |
+
def estimate_research_time(self, function_name: str) -> str:
|
| 579 |
+
"""Provide time estimates for different research functions"""
|
| 580 |
+
time_estimates = {
|
| 581 |
+
"search_web": "30-60 seconds",
|
| 582 |
+
"search_wikipedia": "15-30 seconds",
|
| 583 |
+
"search_academic": "2-5 minutes",
|
| 584 |
+
"search_technology_trends": "1-2 minutes",
|
| 585 |
+
"search_financial_data": "1-3 minutes",
|
| 586 |
+
"multi_source_research": "3-7 minutes"
|
| 587 |
+
}
|
| 588 |
+
return time_estimates.get(function_name, "1-3 minutes")
|
| 589 |
+
|
| 590 |
+
def show_research_error(self, function: str, query: str, error: str):
|
| 591 |
+
"""Show research error"""
|
| 592 |
+
session = get_or_create_session_state(self.session_id)
|
| 593 |
+
current_state = session["roundtable_state"]
|
| 594 |
+
all_messages = list(current_state.get("messages", []))
|
| 595 |
+
participants = current_state.get("participants", [])
|
| 596 |
+
|
| 597 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 598 |
+
# Ensure both Research Agent AND the calling model stay visible
|
| 599 |
+
if "Research Agent" not in existing_bubbles:
|
| 600 |
+
existing_bubbles.append("Research Agent")
|
| 601 |
+
# Keep the current speaker (the one who requested research) visible
|
| 602 |
+
current_speaker = current_state.get("currentSpeaker")
|
| 603 |
+
if current_speaker and current_speaker not in existing_bubbles and current_speaker != "Research Agent":
|
| 604 |
+
existing_bubbles.append(current_speaker)
|
| 605 |
+
|
| 606 |
+
message = {
|
| 607 |
+
"speaker": "Research Agent",
|
| 608 |
+
"text": f"β **Research Error**: {function.replace('_', ' ').title()}\nπ Query: \"{query}\"\nβ οΈ Error: {error}\nπ Continuing with available data",
|
| 609 |
+
"type": "research_error"
|
| 610 |
+
}
|
| 611 |
+
all_messages.append(message)
|
| 612 |
+
|
| 613 |
+
self.update_visual_state({
|
| 614 |
+
"participants": participants,
|
| 615 |
+
"messages": all_messages,
|
| 616 |
+
"currentSpeaker": None,
|
| 617 |
+
"thinking": [],
|
| 618 |
+
"showBubbles": existing_bubbles + ["Research Agent"]
|
| 619 |
+
})
|
| 620 |
+
time.sleep(1)
|
| 621 |
+
|
| 622 |
+
def update_research_progress(self, progress_text: str):
|
| 623 |
+
"""Update research progress in real-time - ALWAYS REMOVE RESEARCH AGENT FROM THINKING"""
|
| 624 |
+
session = get_or_create_session_state(self.session_id)
|
| 625 |
+
current_state = session["roundtable_state"]
|
| 626 |
+
all_messages = list(current_state.get("messages", []))
|
| 627 |
+
participants = current_state.get("participants", [])
|
| 628 |
+
|
| 629 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 630 |
+
if "Research Agent" not in existing_bubbles:
|
| 631 |
+
existing_bubbles.append("Research Agent")
|
| 632 |
+
|
| 633 |
+
progress_message = {
|
| 634 |
+
"speaker": "Research Agent",
|
| 635 |
+
"text": f"π {progress_text}",
|
| 636 |
+
"type": "research_progress"
|
| 637 |
+
}
|
| 638 |
+
all_messages.append(progress_message)
|
| 639 |
+
|
| 640 |
+
# Get current thinking and ALWAYS remove Research Agent
|
| 641 |
+
current_thinking = list(current_state.get("thinking", []))
|
| 642 |
+
if "Research Agent" in current_thinking:
|
| 643 |
+
current_thinking.remove("Research Agent")
|
| 644 |
+
|
| 645 |
+
self.update_visual_state({
|
| 646 |
+
"participants": participants,
|
| 647 |
+
"messages": all_messages,
|
| 648 |
+
"currentSpeaker": None,
|
| 649 |
+
"thinking": current_thinking, # Research Agent NEVER in thinking
|
| 650 |
+
"showBubbles": existing_bubbles
|
| 651 |
+
})
|
| 652 |
+
time.sleep(0.3)
|
| 653 |
+
|
| 654 |
def call_model(self, model: str, prompt: str, context: str = "") -> Optional[str]:
|
| 655 |
"""Enhanced model calling with native function calling support"""
|
| 656 |
if not self.models[model]['available']:
|
|
|
|
| 696 |
|
| 697 |
# Check if model supports function calling
|
| 698 |
supports_functions = sambanova_model in [
|
| 699 |
+
'DeepSeek-V3-0324',
|
| 700 |
'Meta-Llama-3.1-8B-Instruct',
|
| 701 |
'Meta-Llama-3.1-405B-Instruct',
|
| 702 |
'Meta-Llama-3.3-70B-Instruct'
|
|
|
|
| 907 |
# Log and set thinking state - PRESERVE BUBBLES
|
| 908 |
log_event('thinking', speaker=self.models[model]['name'])
|
| 909 |
|
| 910 |
+
session = get_or_create_session_state(self.session_id)
|
| 911 |
+
current_state = session["roundtable_state"]
|
| 912 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 913 |
|
| 914 |
self.update_visual_state({
|
| 915 |
"participants": visual_participant_names,
|
|
|
|
| 957 |
log_event('speaking', speaker=self.models[model]['name'])
|
| 958 |
|
| 959 |
# Calculate existing bubbles
|
| 960 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 961 |
|
| 962 |
self.update_visual_state({
|
| 963 |
"participants": visual_participant_names,
|
|
|
|
| 1034 |
# Log thinking with preserved bubbles
|
| 1035 |
log_event('thinking', speaker=self.models[model]['name'])
|
| 1036 |
|
| 1037 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 1038 |
|
| 1039 |
self.update_visual_state({
|
| 1040 |
"participants": visual_participant_names,
|
|
|
|
| 1083 |
# Log speaking with preserved bubbles
|
| 1084 |
log_event('speaking', speaker=self.models[model]['name'])
|
| 1085 |
|
| 1086 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 1087 |
|
| 1088 |
self.update_visual_state({
|
| 1089 |
"participants": visual_participant_names,
|
|
|
|
| 1160 |
expert_names = [self.models[model]['name'] for model in available_models]
|
| 1161 |
|
| 1162 |
# Preserve existing bubbles during final thinking
|
| 1163 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 1164 |
|
| 1165 |
self.update_visual_state({
|
| 1166 |
"participants": visual_participant_names,
|
|
|
|
| 1238 |
log_event('speaking', speaker=moderator_title, content="Synthesizing expert analysis into final recommendation...")
|
| 1239 |
|
| 1240 |
# Preserve existing bubbles during final speaking
|
| 1241 |
+
existing_bubbles = list(current_state.get("showBubbles", []))
|
| 1242 |
|
| 1243 |
self.update_visual_state({
|
| 1244 |
"participants": visual_participant_names,
|