Merge #487 — analyst execution planning and timing hooks

refactor(graph): add analyst execution planning and timing hooks
This commit is contained in:
Yijia Xiao
2026-05-17 00:01:46 -07:00
committed by GitHub
6 changed files with 271 additions and 57 deletions

View File

@@ -21,6 +21,12 @@ from rich.align import Align
from rich.rule import Rule
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.graph.analyst_execution import (
AnalystWallTimeTracker,
build_analyst_execution_plan,
get_initial_analyst_node,
sync_analyst_tracker_from_chunk,
)
from tradingagents.default_config import DEFAULT_CONFIG
from cli.models import AnalystType
from cli.utils import *
@@ -844,7 +850,7 @@ ANALYST_REPORT_MAP = {
}
def update_analyst_statuses(message_buffer, chunk):
def update_analyst_statuses(message_buffer, chunk, wall_time_tracker=None):
"""Update analyst statuses based on accumulated report state.
Logic:
@@ -858,6 +864,9 @@ def update_analyst_statuses(message_buffer, chunk):
selected = message_buffer.selected_analysts
found_active = False
if wall_time_tracker is not None:
sync_analyst_tracker_from_chunk(wall_time_tracker, chunk)
for analyst_key in ANALYST_ORDER:
if analyst_key not in selected:
continue
@@ -985,6 +994,11 @@ def run_analysis(checkpoint: bool = False):
# Normalize analyst selection to predefined order (selection is a 'set', order is fixed)
selected_set = {analyst.value for analyst in selections["analysts"]}
selected_analyst_keys = [a for a in ANALYST_ORDER if a in selected_set]
analyst_execution_plan = build_analyst_execution_plan(
selected_analyst_keys,
concurrency_limit=config["analyst_concurrency_limit"],
)
analyst_wall_time_tracker = AnalystWallTimeTracker(analyst_execution_plan)
# Initialize the graph with callbacks bound to LLMs
graph = TradingAgentsGraph(
@@ -1067,8 +1081,9 @@ def run_analysis(checkpoint: bool = False):
update_display(layout, stats_handler=stats_handler, start_time=start_time)
# Update agent status to in_progress for the first analyst
first_analyst = f"{selections['analysts'][0].value.capitalize()} Analyst"
first_analyst = get_initial_analyst_node(analyst_execution_plan)
message_buffer.update_agent_status(first_analyst, "in_progress")
analyst_wall_time_tracker.mark_started(selected_analyst_keys[0])
update_display(layout, stats_handler=stats_handler, start_time=start_time)
# Create spinner text
@@ -1108,7 +1123,11 @@ def run_analysis(checkpoint: bool = False):
message_buffer.add_tool_call(tool_call.name, tool_call.args)
# Update analyst statuses based on report state (runs on every chunk)
update_analyst_statuses(message_buffer, chunk)
update_analyst_statuses(
message_buffer,
chunk,
wall_time_tracker=analyst_wall_time_tracker,
)
# Research Team - Handle Investment Debate State
if chunk.get("investment_debate_state"):
@@ -1200,6 +1219,7 @@ def run_analysis(checkpoint: bool = False):
message_buffer.add_message(
"System", f"Completed analysis for {selections['analysis_date']}"
)
message_buffer.add_message("System", analyst_wall_time_tracker.format_summary())
# Update final report sections
for section in message_buffer.report_sections.keys():
@@ -1210,6 +1230,7 @@ def run_analysis(checkpoint: bool = False):
# Post-analysis prompts (outside Live context for clean interaction)
console.print("\n[bold cyan]Analysis Complete![/bold cyan]\n")
console.print(f"[dim]{analyst_wall_time_tracker.format_summary()}[/dim]")
# Prompt to save report
save_choice = typer.prompt("Save report?", default="Y").strip().upper()