From dc93d025fb30a68200fc19b3f1ff3f1917e547c7 Mon Sep 17 00:00:00 2001 From: Tomortec Date: Tue, 1 Jul 2025 23:53:46 +0800 Subject: [PATCH] feat: import external reports --- cli/main.py | 32 ++++++++++++++++--- .../agents/managers/research_manager.py | 5 ++- tradingagents/agents/managers/risk_manager.py | 5 ++- tradingagents/agents/trader/trader.py | 4 ++- tradingagents/agents/utils/agent_states.py | 1 + tradingagents/graph/propagation.py | 3 +- tradingagents/i18n/interface/en.py | 6 ++-- tradingagents/i18n/interface/zh.py | 6 ++-- tradingagents/i18n/prompts/zh.py | 8 ++++- 9 files changed, 56 insertions(+), 14 deletions(-) diff --git a/cli/main.py b/cli/main.py index 4559a699..45e29d95 100644 --- a/cli/main.py +++ b/cli/main.py @@ -459,20 +459,28 @@ def get_user_selections(): ) selected_research_depth = select_research_depth() - # Step 5: OpenAI backend + # Step 5: External Reports console.print( create_question_box( get_lang("step5_title"), get_lang("step5_prompt") ) ) - selected_llm_provider, backend_url = select_llm_provider() - - # Step 6: Thinking agents + external_reports = get_external_reports() + + # Step 6: OpenAI backend console.print( create_question_box( get_lang("step6_title"), get_lang("step6_prompt") ) ) + selected_llm_provider, backend_url = select_llm_provider() + + # Step 7: Thinking agents + console.print( + create_question_box( + get_lang("step7_title"), get_lang("step7_prompt") + ) + ) selected_shallow_thinker = select_shallow_thinking_agent(selected_llm_provider) selected_deep_thinker = select_deep_thinking_agent(selected_llm_provider) @@ -483,6 +491,7 @@ def get_user_selections(): "research_depth": selected_research_depth, "llm_provider": selected_llm_provider.lower(), "backend_url": backend_url, + "external_reports": external_reports, "shallow_thinker": selected_shallow_thinker, "deep_thinker": selected_deep_thinker, } @@ -511,6 +520,15 @@ def get_analysis_date(): "[red]Error: Invalid date format. Please use YYYY-MM-DD[/red]" ) +def get_external_reports(): + """Get external reports from user input.""" + need_external = typer.confirm( + get_lang("step5_prompt"), default=False + ) + if need_external: + reports = typer.edit(require_save=False) + return reports.replace("\n", "").split("") if reports else [] + return [] def display_complete_report(final_state): """Display the complete analysis report with team-based panels.""" @@ -761,6 +779,10 @@ def run_analysis(): "System", f"Selected analysts: {', '.join(analyst.value for analyst in selections['analysts'])}", ) + message_buffer.add_message( + "User", + f"External reports: {'\n'.join(selections['external_reports']) if selections['external_reports'] else 'None'}", + ) update_display(layout) # Reset agent statuses @@ -786,7 +808,7 @@ def run_analysis(): # Initialize state and get graph args init_agent_state = graph.propagator.create_initial_state( - selections["ticker"], selections["analysis_date"] + selections["ticker"], selections["analysis_date"], selections["external_reports"] ) args = graph.propagator.get_graph_args() diff --git a/tradingagents/agents/managers/research_manager.py b/tradingagents/agents/managers/research_manager.py index 532598f2..ad959fbe 100644 --- a/tradingagents/agents/managers/research_manager.py +++ b/tradingagents/agents/managers/research_manager.py @@ -10,6 +10,7 @@ def create_research_manager(llm, memory): sentiment_report = state["sentiment_report"] news_report = state["news_report"] fundamentals_report = state["fundamentals_report"] + external_reports = state.get("external_reports", []) investment_debate_state = state["investment_debate_state"] @@ -23,7 +24,9 @@ def create_research_manager(llm, memory): prompt = get_prompts("managers", "research_manager") \ .replace("{max_tokens}", str(DEFAULT_CONFIG["max_tokens"])) \ .replace("{past_memory_str}", past_memory_str) \ - .replace("{history}", history) + .replace("{history}", history) \ + .replace("{external_reports}", "\n".join(external_reports)) + response = llm.invoke(prompt) new_investment_debate_state = { diff --git a/tradingagents/agents/managers/risk_manager.py b/tradingagents/agents/managers/risk_manager.py index 989641da..08ef910a 100644 --- a/tradingagents/agents/managers/risk_manager.py +++ b/tradingagents/agents/managers/risk_manager.py @@ -14,6 +14,7 @@ def create_risk_manager(llm, memory): news_report = state["news_report"] fundamentals_report = state["news_report"] sentiment_report = state["sentiment_report"] + external_reports = state.get("external_reports", []) trader_plan = state["investment_plan"] curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}" @@ -27,7 +28,9 @@ def create_risk_manager(llm, memory): .replace("{max_tokens}", str(DEFAULT_CONFIG["max_tokens"])) \ .replace("{trader_plan}", trader_plan) \ .replace("{past_memory_str}", past_memory_str) \ - .replace("{history}", history) + .replace("{history}", history) \ + .replace("{external_reports}", "\n".join(external_reports)) + response = llm.invoke(prompt) new_risk_debate_state = { diff --git a/tradingagents/agents/trader/trader.py b/tradingagents/agents/trader/trader.py index 3e95054a..3d9598a1 100644 --- a/tradingagents/agents/trader/trader.py +++ b/tradingagents/agents/trader/trader.py @@ -11,6 +11,7 @@ def create_trader(llm, memory): sentiment_report = state["sentiment_report"] news_report = state["news_report"] fundamentals_report = state["fundamentals_report"] + external_reports = state.get("external_reports", []) curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}" past_memories = memory.get_memories(curr_situation, n_matches=2) @@ -23,7 +24,8 @@ def create_trader(llm, memory): "role": "user", "content": get_prompts("trader", "user_message") \ .replace("{company_name}", company_name) \ - .replace("{investment_plan}", investment_plan) + .replace("{investment_plan}", investment_plan) \ + .replace("{external_reports}", "\n".join(external_reports)) } messages = [ diff --git a/tradingagents/agents/utils/agent_states.py b/tradingagents/agents/utils/agent_states.py index 3a859ea1..6280c080 100644 --- a/tradingagents/agents/utils/agent_states.py +++ b/tradingagents/agents/utils/agent_states.py @@ -54,6 +54,7 @@ class AgentState(MessagesState): sender: Annotated[str, "Agent that sent this message"] # research step + external_reports: Annotated[list[str], "Reports from the External Expert Researcher"] market_report: Annotated[str, "Report from the Market Analyst"] sentiment_report: Annotated[str, "Report from the Social Media Analyst"] news_report: Annotated[ diff --git a/tradingagents/graph/propagation.py b/tradingagents/graph/propagation.py index 90427598..d4931da4 100644 --- a/tradingagents/graph/propagation.py +++ b/tradingagents/graph/propagation.py @@ -16,7 +16,7 @@ class Propagator: self.max_recur_limit = max_recur_limit def create_initial_state( - self, company_name: str, trade_date: str + self, company_name: str, trade_date: str, external_reports: list[str] = [] ) -> Dict[str, Any]: """Create the initial state for the agent graph.""" return { @@ -39,6 +39,7 @@ class Propagator: "fundamentals_report": "", "sentiment_report": "", "news_report": "", + "external_reports": external_reports, } def get_graph_args(self) -> Dict[str, Any]: diff --git a/tradingagents/i18n/interface/en.py b/tradingagents/i18n/interface/en.py index c4b2a810..3a5920ee 100644 --- a/tradingagents/i18n/interface/en.py +++ b/tradingagents/i18n/interface/en.py @@ -51,10 +51,12 @@ LANG = { "step3_prompt": "Select your LLM analyst agents for the analysis", "step4_title": "Step 4: Research Depth", "step4_prompt": "Select your research depth level", - "step5_title": "Step 5: Thinking Agents", - "step5_prompt": "Select your thinking agents for analysis", + "step5_title": "Step 5: External Reports", + "step5_prompt": "Do you need to import external reports?", "step6_title": "Step 6: Thinking Agents", "step6_prompt": "Select your thinking agents for analysis", + "step7_title": "Step 7: Thinking Agents", + "step7_prompt": "Select your thinking agents for analysis", "default_ticker": "SPY", "ticker_validate": "Please enter a valid ticker symbol.", "date_validate": "Please enter a valid date in YYYY-MM-DD format.", diff --git a/tradingagents/i18n/interface/zh.py b/tradingagents/i18n/interface/zh.py index 99f7bf0f..791e8d8f 100644 --- a/tradingagents/i18n/interface/zh.py +++ b/tradingagents/i18n/interface/zh.py @@ -51,10 +51,12 @@ LANG = { "step3_prompt": "请选择用于分析的LLM分析师代理", "step4_title": "步骤4:研究深度", "step4_prompt": "请选择研究深度等级", - "step5_title": "步骤5:思考代理", - "step5_prompt": "请选择用于分析的思考代理", + "step5_title": "步骤5:外部报告", + "step5_prompt": "需要导入外部报告吗?", "step6_title": "步骤6:思考代理", "step6_prompt": "请选择用于分析的思考代理", + "step7_title": "步骤7:思考代理", + "step7_prompt": "请选择用于分析的思考代理", "default_ticker": "SPY", "ticker_validate": "请输入有效的资产代码。", "date_validate": "请输入有效的日期,格式为YYYY-MM-DD。", diff --git a/tradingagents/i18n/prompts/zh.py b/tradingagents/i18n/prompts/zh.py index 19161116..bddd6fe6 100644 --- a/tradingagents/i18n/prompts/zh.py +++ b/tradingagents/i18n/prompts/zh.py @@ -86,6 +86,9 @@ PROMPTS = { 考虑你过去在类似情况下的错误。利用这些见解来完善你的决策,并确保你正在学习和改进。以对话的方式呈现你的分析,就像自然地说话一样,无需特殊的格式。 +必须认真考虑外部分析师报告: +{external_reports} + 你在过去的错误和反思: \"{past_memory_str}\" @@ -107,6 +110,9 @@ PROMPTS = { - 基于辩论与反思的详细理由 - 务必不超过{max_tokens}tokens +必须认真考虑外部分析师报告: +{external_reports} + 分析师辩论历史: {history}""" #endregion @@ -199,7 +205,7 @@ Here is the current conversation history: {history} Here is the last response fr }, "trader": { #region Trader - "user_message": "以下是针对 {company_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:\n\n建议方案:{investment_plan}\n\n请基于此作出合理而有策略的判断。", + "user_message": "以下是针对 {company_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:\n\n建议方案:{investment_plan}\n\n外部专家分析:{external_reports}\n\n请基于此作出合理而有策略的判断。", "system_message": "你是一名交易代理,负责根据市场数据做出买入、卖出或持有的明确投资决策。分析结束后,请以 “最终投资建议:BUY/HOLD/SELL” 结尾,明确表达立场。请结合历史经验做出更优判断。以下为你在类似情况中总结的教训:{past_memory_str}" #endregion },