Files
tradingagents/tradingagents/graph/propagation.py
Yijia-Xiao d7b40a2a5c fix(graph): resolve instrument identity to stop wrong-company hallucination
Agents had no ground-truth ticker→company mapping, so the market analyst
could pattern-match a price chart to the wrong company (e.g. TOTDY read as
"TotalEnergies"), and every downstream agent inherited the bad framing.

Resolve identity once at run start via a cached, fail-open yfinance lookup
and inject company/sector/exchange into the shared instrument context that
all twelve agents consume, with an explicit do-not-substitute instruction.
Resolution runs on both the propagate() and CLI entry points.

Also replaces the bare "Continue" message-clear placeholder, which some
OpenAI-compatible providers interpreted as the user task, with a
context-anchored placeholder carrying the resolved identity and date.

#814 #888
2026-05-30 23:56:32 +00:00

85 lines
2.8 KiB
Python

# TradingAgents/graph/propagation.py
from typing import Dict, Any, List, Optional
from tradingagents.agents.utils.agent_states import (
AgentState,
InvestDebateState,
RiskDebateState,
)
class Propagator:
"""Handles state initialization and propagation through the graph."""
def __init__(self, max_recur_limit=100):
"""Initialize with configuration parameters."""
self.max_recur_limit = max_recur_limit
def create_initial_state(
self,
company_name: str,
trade_date: str,
asset_type: str = "stock",
past_context: str = "",
instrument_context: str = "",
) -> Dict[str, Any]:
"""Create the initial state for the agent graph.
``instrument_context`` is the deterministic ticker-identity string
resolved once at run start (see
``TradingAgentsGraph.resolve_instrument_context``). When empty, agents
fall back to ticker-only context via
``get_instrument_context_from_state``.
"""
return {
"messages": [("human", company_name)],
"company_of_interest": company_name,
"asset_type": asset_type,
"instrument_context": instrument_context,
"trade_date": str(trade_date),
"past_context": past_context,
"investment_debate_state": InvestDebateState(
{
"bull_history": "",
"bear_history": "",
"history": "",
"current_response": "",
"judge_decision": "",
"count": 0,
}
),
"risk_debate_state": RiskDebateState(
{
"aggressive_history": "",
"conservative_history": "",
"neutral_history": "",
"history": "",
"latest_speaker": "",
"current_aggressive_response": "",
"current_conservative_response": "",
"current_neutral_response": "",
"judge_decision": "",
"count": 0,
}
),
"market_report": "",
"fundamentals_report": "",
"sentiment_report": "",
"news_report": "",
}
def get_graph_args(self, callbacks: Optional[List] = None) -> Dict[str, Any]:
"""Get arguments for the graph invocation.
Args:
callbacks: Optional list of callback handlers for tool execution tracking.
Note: LLM callbacks are handled separately via LLM constructor.
"""
config = {"recursion_limit": self.max_recur_limit}
if callbacks:
config["callbacks"] = callbacks
return {
"stream_mode": "values",
"config": config,
}