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
This commit is contained in:
Yijia-Xiao committed 2026-05-30 23:56:32 +00:00
1 parent 61522e103e
commit d7b40a2a5c
18 files changed
+390 -44

No files matched your search

+10 -1
View File
@@ -21,12 +21,21 @@ class Propagator:
trade_date: str,
asset_type: str = "stock",
past_context: str = "",
instrument_context: str = "",
) -> Dict[str, Any]:
"""Create the initial state for the agent graph."""
"""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(
+22 -2
View File
@@ -28,6 +28,8 @@ from tradingagents.dataflows.config import set_config
# Import the new abstract tool methods from agent_utils
from tradingagents.agents.utils.agent_utils import (
build_instrument_context,
resolve_instrument_identity,
get_stock_data,
get_indicators,
get_fundamentals,
@@ -292,6 +294,18 @@ class TradingAgentsGraph:
if updates:
self.memory_log.batch_update_with_outcomes(updates)
def resolve_instrument_context(self, ticker: str, asset_type: str = "stock") -> str:
"""Resolve ticker identity once and return the full instrument context.
Deterministic yfinance lookup (cached, fail-open) injected into a
context string so every agent anchors to the real company instead of
hallucinating one from the price chart (#814). Both the propagate()
path and the CLI call this so the resolved identity reaches the whole
graph regardless of entry point.
"""
identity = resolve_instrument_identity(ticker)
return build_instrument_context(ticker, asset_type, identity)
def propagate(self, company_name, trade_date, asset_type: str = "stock"):
"""Run the trading agents graph for a company on a specific date.
@@ -335,10 +349,16 @@ class TradingAgentsGraph:
def _run_graph(self, company_name, trade_date, asset_type: str = "stock"):
"""Execute the graph and write the resulting state to disk and memory log."""
# Initialize state — inject memory log context for PM.
# Initialize state — inject memory log context for PM and the
# deterministically resolved instrument identity for all agents.
past_context = self.memory_log.get_past_context(company_name)
instrument_context = self.resolve_instrument_context(company_name, asset_type)
init_agent_state = self.propagator.create_initial_state(
company_name, trade_date, asset_type=asset_type, past_context=past_context
company_name,
trade_date,
asset_type=asset_type,
past_context=past_context,
instrument_context=instrument_context,
)
args = self.propagator.get_graph_args()