mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-19 11:15:24 +03:00
fix(agents): stop conflict alone from defaulting the verdict to Hold
- both manager prompts and both rating fields listed "materially conflicting" as a Hold condition, and every bull/bear and risk debate is conflicting, so a modest directional edge collapsed to Hold - state one rule at all four sites: conflict alone is not a reason to Hold, commit to the stronger side sized by how decisively it wins, and Hold only when the evidence is still balanced after weighing or too thin for a call - a modest bull edge now resolves to Overweight; a genuinely balanced debate still resolves to Hold #1321
This commit is contained in:
@@ -7,12 +7,14 @@ behavior we added for the Trader, Research Manager, and Sentiment Analyst
|
||||
so they share the same deterministic output shape.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from tradingagents.agents.analysts.sentiment_analyst import create_sentiment_analyst
|
||||
from tradingagents.agents.managers.portfolio_manager import create_portfolio_manager
|
||||
from tradingagents.agents.managers.research_manager import create_research_manager
|
||||
from tradingagents.agents.schemas import (
|
||||
PortfolioDecision,
|
||||
@@ -484,3 +486,20 @@ class TestSentimentAnalystAgent:
|
||||
llm.with_structured_output.return_value = structured
|
||||
llm.invoke.return_value = MagicMock(content=plain)
|
||||
assert create_sentiment_analyst(llm)(_make_sentiment_state())["sentiment_report"] == plain
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.parametrize("source", [
|
||||
pytest.param(lambda: ResearchPlan.model_fields["recommendation"].description, id="ResearchPlan.recommendation"),
|
||||
pytest.param(lambda: PortfolioDecision.model_fields["rating"].description, id="PortfolioDecision.rating"),
|
||||
pytest.param(lambda: inspect.getsource(create_research_manager), id="research_manager prompt"),
|
||||
pytest.param(lambda: inspect.getsource(create_portfolio_manager), id="portfolio_manager prompt"),
|
||||
])
|
||||
def test_conflict_alone_is_not_a_hold_trigger(source):
|
||||
# The debate always contains conflicting arguments, so a Hold condition that
|
||||
# conflict satisfies fires on every run and swallows directional calls
|
||||
# (#1321). All four decision sites must state the same rule.
|
||||
text = " ".join(source().split())
|
||||
assert "conflict alone is not a reason to Hold" in text or \
|
||||
"Conflicting arguments alone are not a reason to Hold" in text
|
||||
assert "materially conflicting" not in text
|
||||
|
||||
Reference in New Issue
Block a user