mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-27 15:02:39 +03:00
refactor(cli): split the interactive choices and the run loop out of cli/main.py
- selections.py asks what to run; run.py builds the graph, streams it to the live view and saves the report - main.py keeps the Typer app and its two commands
This commit is contained in:
+46
-47
@@ -11,6 +11,8 @@ from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
import cli.selections as cli_selections
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestProviderDefaultUrl(unittest.TestCase):
|
||||
@@ -33,7 +35,6 @@ class TestProviderDefaultUrl(unittest.TestCase):
|
||||
@pytest.mark.unit
|
||||
class TestCliSkipsPromptsFromEnv(unittest.TestCase):
|
||||
def test_env_config_skips_llm_prompts(self):
|
||||
import cli.main as m
|
||||
|
||||
env = {
|
||||
"TRADINGAGENTS_LLM_PROVIDER": "openai",
|
||||
@@ -42,7 +43,7 @@ class TestCliSkipsPromptsFromEnv(unittest.TestCase):
|
||||
"TRADINGAGENTS_LLM_BACKEND_URL": "https://opencode.ai/zen/go/v1",
|
||||
"TRADINGAGENTS_OUTPUT_LANGUAGE": "Japanese",
|
||||
}
|
||||
fake_cfg = dict(m.DEFAULT_CONFIG)
|
||||
fake_cfg = dict(cli_selections.DEFAULT_CONFIG)
|
||||
fake_cfg.update({
|
||||
"llm_provider": "openai",
|
||||
"backend_url": "https://opencode.ai/zen/go/v1",
|
||||
@@ -52,19 +53,19 @@ class TestCliSkipsPromptsFromEnv(unittest.TestCase):
|
||||
})
|
||||
|
||||
with mock.patch.dict(os.environ, env, clear=False), \
|
||||
mock.patch.object(m, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(m, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(m, "display_announcements"), \
|
||||
mock.patch.object(m, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(m, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(m, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(m, "select_research_depth", return_value=1), \
|
||||
mock.patch.object(m, "ensure_api_key") as ensure_key, \
|
||||
mock.patch.object(m, "select_llm_provider") as prompt_provider, \
|
||||
mock.patch.object(m, "ask_output_language") as prompt_lang, \
|
||||
mock.patch.object(m, "select_shallow_thinking_agent") as prompt_quick, \
|
||||
mock.patch.object(m, "select_deep_thinking_agent") as prompt_deep:
|
||||
sel = m.get_user_selections()
|
||||
mock.patch.object(cli_selections, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(cli_selections, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(cli_selections, "display_announcements"), \
|
||||
mock.patch.object(cli_selections, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(cli_selections, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(cli_selections, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(cli_selections, "select_research_depth", return_value=1), \
|
||||
mock.patch.object(cli_selections, "ensure_api_key") as ensure_key, \
|
||||
mock.patch.object(cli_selections, "select_llm_provider") as prompt_provider, \
|
||||
mock.patch.object(cli_selections, "ask_output_language") as prompt_lang, \
|
||||
mock.patch.object(cli_selections, "select_shallow_thinking_agent") as prompt_quick, \
|
||||
mock.patch.object(cli_selections, "select_deep_thinking_agent") as prompt_deep:
|
||||
sel = cli_selections.get_user_selections()
|
||||
|
||||
# None of the LLM selection prompts should have been shown.
|
||||
prompt_provider.assert_not_called()
|
||||
@@ -85,30 +86,29 @@ class TestCliSkipsPromptsFromEnv(unittest.TestCase):
|
||||
@pytest.mark.unit
|
||||
class TestResearchDepthSkippedFromEnv(unittest.TestCase):
|
||||
def test_both_round_envs_skip_depth_prompt(self):
|
||||
import cli.main as m
|
||||
|
||||
env = {
|
||||
"TRADINGAGENTS_MAX_DEBATE_ROUNDS": "2",
|
||||
"TRADINGAGENTS_MAX_RISK_ROUNDS": "4",
|
||||
}
|
||||
fake_cfg = dict(m.DEFAULT_CONFIG)
|
||||
fake_cfg = dict(cli_selections.DEFAULT_CONFIG)
|
||||
fake_cfg.update({"max_debate_rounds": 2, "max_risk_discuss_rounds": 4})
|
||||
|
||||
with mock.patch.dict(os.environ, env, clear=False), \
|
||||
mock.patch.object(m, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(m, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(m, "display_announcements"), \
|
||||
mock.patch.object(m, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(m, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(m, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(m, "select_research_depth") as prompt_depth, \
|
||||
mock.patch.object(m, "ensure_api_key"), \
|
||||
mock.patch.object(m, "select_llm_provider", return_value=("openai", None)), \
|
||||
mock.patch.object(m, "ask_output_language", return_value="English"), \
|
||||
mock.patch.object(m, "select_shallow_thinking_agent", return_value="gpt-5.4-mini"), \
|
||||
mock.patch.object(m, "select_deep_thinking_agent", return_value="gpt-5.5"), \
|
||||
mock.patch.object(m, "ask_openai_reasoning_effort", return_value=None):
|
||||
sel = m.get_user_selections()
|
||||
mock.patch.object(cli_selections, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(cli_selections, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(cli_selections, "display_announcements"), \
|
||||
mock.patch.object(cli_selections, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(cli_selections, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(cli_selections, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(cli_selections, "select_research_depth") as prompt_depth, \
|
||||
mock.patch.object(cli_selections, "ensure_api_key"), \
|
||||
mock.patch.object(cli_selections, "select_llm_provider", return_value=("openai", None)), \
|
||||
mock.patch.object(cli_selections, "ask_output_language", return_value="English"), \
|
||||
mock.patch.object(cli_selections, "select_shallow_thinking_agent", return_value="gpt-5.4-mini"), \
|
||||
mock.patch.object(cli_selections, "select_deep_thinking_agent", return_value="gpt-5.5"), \
|
||||
mock.patch.object(cli_selections, "ask_openai_reasoning_effort", return_value=None):
|
||||
sel = cli_selections.get_user_selections()
|
||||
|
||||
# The research-depth prompt is skipped; the value comes from the env config.
|
||||
prompt_depth.assert_not_called()
|
||||
@@ -118,27 +118,26 @@ class TestResearchDepthSkippedFromEnv(unittest.TestCase):
|
||||
@pytest.mark.unit
|
||||
class TestReasoningEffortSkippedFromEnv(unittest.TestCase):
|
||||
def test_effort_env_skips_step8_prompt(self):
|
||||
import cli.main as m
|
||||
|
||||
env = {"TRADINGAGENTS_OPENAI_REASONING_EFFORT": "high"}
|
||||
fake_cfg = dict(m.DEFAULT_CONFIG)
|
||||
fake_cfg = dict(cli_selections.DEFAULT_CONFIG)
|
||||
fake_cfg.update({"openai_reasoning_effort": "high"})
|
||||
|
||||
with mock.patch.dict(os.environ, env, clear=False), \
|
||||
mock.patch.object(m, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(m, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(m, "display_announcements"), \
|
||||
mock.patch.object(m, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(m, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(m, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(m, "select_research_depth", return_value=1), \
|
||||
mock.patch.object(m, "ensure_api_key"), \
|
||||
mock.patch.object(m, "select_llm_provider", return_value=("openai", None)), \
|
||||
mock.patch.object(m, "ask_output_language", return_value="English"), \
|
||||
mock.patch.object(m, "select_shallow_thinking_agent", return_value="gpt-5.4-mini"), \
|
||||
mock.patch.object(m, "select_deep_thinking_agent", return_value="gpt-5.5"), \
|
||||
mock.patch.object(m, "ask_openai_reasoning_effort") as prompt_effort:
|
||||
sel = m.get_user_selections()
|
||||
mock.patch.object(cli_selections, "DEFAULT_CONFIG", fake_cfg), \
|
||||
mock.patch.object(cli_selections, "fetch_announcements", return_value=None), \
|
||||
mock.patch.object(cli_selections, "display_announcements"), \
|
||||
mock.patch.object(cli_selections, "get_ticker", return_value="AAPL"), \
|
||||
mock.patch.object(cli_selections, "get_analysis_date", return_value="2026-05-29"), \
|
||||
mock.patch.object(cli_selections, "select_analysts", return_value=[]), \
|
||||
mock.patch.object(cli_selections, "select_research_depth", return_value=1), \
|
||||
mock.patch.object(cli_selections, "ensure_api_key"), \
|
||||
mock.patch.object(cli_selections, "select_llm_provider", return_value=("openai", None)), \
|
||||
mock.patch.object(cli_selections, "ask_output_language", return_value="English"), \
|
||||
mock.patch.object(cli_selections, "select_shallow_thinking_agent", return_value="gpt-5.4-mini"), \
|
||||
mock.patch.object(cli_selections, "select_deep_thinking_agent", return_value="gpt-5.5"), \
|
||||
mock.patch.object(cli_selections, "ask_openai_reasoning_effort") as prompt_effort:
|
||||
sel = cli_selections.get_user_selections()
|
||||
|
||||
# The reasoning-effort prompt is skipped; the value comes from env config.
|
||||
prompt_effort.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user