From 730cf80c99afb3e9f89b3da5c9d1d140fb456e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 10:59:29 +0800 Subject: [PATCH 01/12] =?UTF-8?q?feat(auth):=20=E6=B7=BB=E5=8A=A0ChatGPT?= =?UTF-8?q?=20OAuth=E8=AE=A4=E8=AF=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加auth子命令用于管理ChatGPT OAuth认证,包含登录、状态查看和登出功能 支持浏览器自动登录和手动输入授权码两种方式 --- cli/main.py | 119 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/cli/main.py b/cli/main.py index fb97d189..13188654 100644 --- a/cli/main.py +++ b/cli/main.py @@ -23,8 +23,6 @@ from rich import box from rich.align import Align from rich.rule import Rule -from tradingagents.graph.trading_graph import TradingAgentsGraph -from tradingagents.default_config import DEFAULT_CONFIG from cli.models import AnalystType from cli.utils import * from cli.announcements import fetch_announcements, display_announcements @@ -37,6 +35,8 @@ app = typer.Typer( help="TradingAgents CLI: Multi-Agents LLM Financial Trading Framework", add_completion=True, # Enable shell completion ) +auth_app = typer.Typer(help="Manage ChatGPT OAuth credentials for codex_oauth.") +app.add_typer(auth_app, name="auth") # Create a deque to store recent messages with a maximum length @@ -536,10 +536,10 @@ def get_user_selections(): ) selected_research_depth = select_research_depth() - # Step 5: OpenAI backend + # Step 5: LLM backend console.print( create_question_box( - "Step 5: OpenAI backend", "Select which service to talk to" + "Step 5: LLM backend", "Select which service to talk to" ) ) selected_llm_provider, backend_url = select_llm_provider() @@ -566,11 +566,11 @@ def get_user_selections(): ) ) thinking_level = ask_gemini_thinking_config() - elif provider_lower == "openai": + elif provider_lower in ("openai", "codex_oauth"): console.print( create_question_box( "Step 7: Reasoning Effort", - "Configure OpenAI reasoning effort level" + "Configure reasoning effort level" ) ) reasoning_effort = ask_openai_reasoning_effort() @@ -897,6 +897,9 @@ def format_tool_args(args, max_length=80) -> str: return result def run_analysis(): + from tradingagents.default_config import DEFAULT_CONFIG + from tradingagents.graph.trading_graph import TradingAgentsGraph + # First get all user selections selections = get_user_selections() @@ -1167,6 +1170,110 @@ def run_analysis(): display_complete_report(final_state) +def _format_ms(ms: int) -> str: + if not ms: + return "unknown" + return datetime.datetime.fromtimestamp(ms / 1000, tz=datetime.timezone.utc).isoformat() + + +def _load_codex_oauth_modules(): + try: + from codex_oauth.auth import ( + decode_jwt_payload, + exchange_authorization_code, + extract_chatgpt_account_id, + login_manual, + login_via_browser, + ) + from codex_oauth.exceptions import NotAuthenticatedError, OAuthFlowError + from codex_oauth.store import AuthStore, OAuthCredentials + except ModuleNotFoundError as exc: + console.print( + "[red]Missing dependency `langchain-codex-oauth`. " + "Install project dependencies first.[/red]" + ) + raise typer.Exit(code=1) from exc + + return { + "decode_jwt_payload": decode_jwt_payload, + "exchange_authorization_code": exchange_authorization_code, + "extract_chatgpt_account_id": extract_chatgpt_account_id, + "login_manual": login_manual, + "login_via_browser": login_via_browser, + "NotAuthenticatedError": NotAuthenticatedError, + "OAuthFlowError": OAuthFlowError, + "AuthStore": AuthStore, + "OAuthCredentials": OAuthCredentials, + } + + +@auth_app.command("login") +def auth_login( + manual: bool = typer.Option(False, "--manual", help="Paste redirect URL/code manually."), + timeout_s: int = typer.Option(180, "--timeout-s", min=30, help="Browser callback timeout in seconds."), +): + """Login via ChatGPT OAuth and save local credentials.""" + modules = _load_codex_oauth_modules() + try: + if manual: + code, verifier = modules["login_manual"]() + else: + result = modules["login_via_browser"](timeout_s=timeout_s) + if not result: + raise modules["OAuthFlowError"]( + "OAuth callback timed out. Retry with --manual or try again." + ) + code, verifier = result + + token = modules["exchange_authorization_code"](code=code, verifier=verifier) + payload = modules["decode_jwt_payload"](token.access) + if not payload: + raise modules["OAuthFlowError"]("Received invalid access token.") + account_id = modules["extract_chatgpt_account_id"](payload) + if not account_id: + raise modules["OAuthFlowError"]( + "Failed to extract chatgpt_account_id from access token." + ) + + modules["AuthStore"]().save( + modules["OAuthCredentials"]( + access=token.access, + refresh=token.refresh, + expires=token.expires_at_ms, + account_id=account_id, + ) + ) + except modules["OAuthFlowError"] as exc: + console.print(f"[red]{exc}[/red]") + raise typer.Exit(code=2) + + console.print("[green]Login successful. OAuth credentials saved.[/green]") + + +@auth_app.command("status") +def auth_status(): + """Show current OAuth credential status.""" + modules = _load_codex_oauth_modules() + store = modules["AuthStore"]() + try: + creds = store.load() + except modules["NotAuthenticatedError"] as exc: + console.print(f"[red]{exc}[/red]") + raise typer.Exit(code=1) + + console.print("[green]Logged in: yes[/green]") + console.print(f"Account id: {creds.account_id}") + console.print(f"Expires (UTC): {_format_ms(creds.expires)}") + + +@auth_app.command("logout") +def auth_logout(): + """Delete local OAuth credentials.""" + modules = _load_codex_oauth_modules() + modules["AuthStore"]().delete() + console.print("[green]Logged out.[/green]") + + @app.command() def analyze(): run_analysis() From 22d9d8a64aab2c278ca08f0352e5f2ab15f8c78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 10:59:39 +0800 Subject: [PATCH 02/12] =?UTF-8?q?feat(cli):=20=E6=B7=BB=E5=8A=A0Codex=20OA?= =?UTF-8?q?uth=E6=94=AF=E6=8C=81=E5=B9=B6=E9=87=8D=E6=9E=84LLM=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E5=95=86=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在shallow和deep思考代理选项中添加Codex OAuth模型 - 重构select_llm_provider函数以返回提供商名称和URL - 更新错误消息以使用更通用的LLM术语 --- cli/utils.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/cli/utils.py b/cli/utils.py index aa097fb5..08d01ad6 100644 --- a/cli/utils.py +++ b/cli/utils.py @@ -127,6 +127,12 @@ def select_shallow_thinking_agent(provider) -> str: # Define shallow thinking llm engine options with their corresponding model names SHALLOW_AGENT_OPTIONS = { + "codex_oauth": [ + ("GPT-5.4", "gpt-5.4"), + ("GPT-5.2", "gpt-5.2"), + ("GPT-5.3-Codex", "gpt-5.3-codex"), + ("GPT-5.2-Codex", "gpt-5.2-codex"), + ], "openai": [ ("GPT-5 Mini - Cost-optimized reasoning", "gpt-5-mini"), ("GPT-5 Nano - Ultra-fast, high-throughput", "gpt-5-nano"), @@ -192,6 +198,12 @@ def select_deep_thinking_agent(provider) -> str: # Define deep thinking llm engine options with their corresponding model names DEEP_AGENT_OPTIONS = { + "codex_oauth": [ + ("GPT-5.4", "gpt-5.4"), + ("GPT-5.2", "gpt-5.2"), + ("GPT-5.3-Codex", "gpt-5.3-codex"), + ("GPT-5.2-Codex", "gpt-5.2-codex"), + ], "openai": [ ("GPT-5.2 - Latest flagship", "gpt-5.2"), ("GPT-5.1 - Flexible reasoning", "gpt-5.1"), @@ -253,22 +265,22 @@ def select_deep_thinking_agent(provider) -> str: return choice def select_llm_provider() -> tuple[str, str]: - """Select the OpenAI api url using interactive selection.""" - # Define OpenAI api options with their corresponding endpoints + """Select LLM provider and backend URL using interactive selection.""" BASE_URLS = [ - ("OpenAI", "https://api.openai.com/v1"), - ("Google", "https://generativelanguage.googleapis.com/v1"), - ("Anthropic", "https://api.anthropic.com/"), - ("xAI", "https://api.x.ai/v1"), - ("Openrouter", "https://openrouter.ai/api/v1"), - ("Ollama", "http://localhost:11434/v1"), + ("Codex OAuth (ChatGPT Plus/Pro)", "codex_oauth", "https://chatgpt.com/backend-api"), + ("OpenAI", "openai", "https://api.openai.com/v1"), + ("Google", "google", "https://generativelanguage.googleapis.com/v1"), + ("Anthropic", "anthropic", "https://api.anthropic.com/"), + ("xAI", "xai", "https://api.x.ai/v1"), + ("Openrouter", "openrouter", "https://openrouter.ai/api/v1"), + ("Ollama", "ollama", "http://localhost:11434/v1"), ] choice = questionary.select( "Select your LLM Provider:", choices=[ - questionary.Choice(display, value=(display, value)) - for display, value in BASE_URLS + questionary.Choice(display, value=(display, provider, value)) + for display, provider, value in BASE_URLS ], instruction="\n- Use arrow keys to navigate\n- Press Enter to select", style=questionary.Style( @@ -281,13 +293,13 @@ def select_llm_provider() -> tuple[str, str]: ).ask() if choice is None: - console.print("\n[red]no OpenAI backend selected. Exiting...[/red]") + console.print("\n[red]No LLM backend selected. Exiting...[/red]") exit(1) - display_name, url = choice + display_name, provider_name, url = choice print(f"You selected: {display_name}\tURL: {url}") - return display_name, url + return provider_name, url def ask_openai_reasoning_effort() -> str: From b89dabca89cf4338f1e28d94a3b5e17738895a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 10:59:48 +0800 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E9=BB=98?= =?UTF-8?q?=E8=AE=A4LLM=E9=85=8D=E7=BD=AE=E4=B8=BAcodex=5Foauth=E5=B9=B6?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E6=A8=A1=E5=9E=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将默认的LLM提供商从openai更改为codex_oauth,同时升级deep_think_llm和quick_think_llm的模型版本,并更新backend_url以匹配新的提供商 --- tradingagents/default_config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tradingagents/default_config.py b/tradingagents/default_config.py index ecf0dc29..8c7de36e 100644 --- a/tradingagents/default_config.py +++ b/tradingagents/default_config.py @@ -8,10 +8,10 @@ DEFAULT_CONFIG = { "dataflows/data_cache", ), # LLM settings - "llm_provider": "openai", - "deep_think_llm": "gpt-5.2", - "quick_think_llm": "gpt-5-mini", - "backend_url": "https://api.openai.com/v1", + "llm_provider": "codex_oauth", + "deep_think_llm": "gpt-5.4", + "quick_think_llm": "gpt-5.2", + "backend_url": "https://chatgpt.com/backend-api", # Provider-specific thinking configuration "google_thinking_level": None, # "high", "minimal", etc. "openai_reasoning_effort": None, # "medium", "high", "low" From c6d89aeb429b43ccb32f4917eb1ec6f85dcf89fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 10:59:56 +0800 Subject: [PATCH 04/12] =?UTF-8?q?fix(graph):=20=E6=94=AF=E6=8C=81=20codex?= =?UTF-8?q?=5Foauth=20=E4=BD=9C=E4=B8=BA=20provider=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 codex_oauth 作为有效的 provider 参数,使其与 openai 共享相同的配置逻辑 --- tradingagents/graph/trading_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tradingagents/graph/trading_graph.py b/tradingagents/graph/trading_graph.py index 44ecca0c..4adc6851 100644 --- a/tradingagents/graph/trading_graph.py +++ b/tradingagents/graph/trading_graph.py @@ -140,7 +140,7 @@ class TradingAgentsGraph: if thinking_level: kwargs["thinking_level"] = thinking_level - elif provider == "openai": + elif provider in ("openai", "codex_oauth"): reasoning_effort = self.config.get("openai_reasoning_effort") if reasoning_effort: kwargs["reasoning_effort"] = reasoning_effort From 7d9e07bd192e4eec43c09856d1346548d11d7103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:00:07 +0800 Subject: [PATCH 05/12] =?UTF-8?q?feat(llm=5Fclients):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?CodexOAuthClient=E6=94=AF=E6=8C=81OAuth=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E7=9A=84Codex=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm_clients/codex_oauth_client.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tradingagents/llm_clients/codex_oauth_client.py diff --git a/tradingagents/llm_clients/codex_oauth_client.py b/tradingagents/llm_clients/codex_oauth_client.py new file mode 100644 index 00000000..68a89709 --- /dev/null +++ b/tradingagents/llm_clients/codex_oauth_client.py @@ -0,0 +1,43 @@ +from typing import Any, Optional + +from .base_client import BaseLLMClient +from .validators import validate_model + + +class CodexOAuthClient(BaseLLMClient): + """Client for ChatGPT OAuth Codex models.""" + + def __init__(self, model: str, base_url: Optional[str] = None, **kwargs): + super().__init__(model, base_url, **kwargs) + + def get_llm(self) -> Any: + """Return configured ChatCodexOAuth instance.""" + try: + from langchain_codex_oauth import ChatCodexOAuth + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "langchain-codex-oauth is required for llm_provider='codex_oauth'. " + "Install dependencies and run `tradingagents auth login`." + ) from exc + + llm_kwargs = {"model": self.model} + + if self.base_url: + llm_kwargs["base_url"] = self.base_url + + for key in ( + "timeout", + "max_retries", + "reasoning_effort", + "max_tokens", + "temperature", + "callbacks", + ): + if key in self.kwargs: + llm_kwargs[key] = self.kwargs[key] + + return ChatCodexOAuth(**llm_kwargs) + + def validate_model(self) -> bool: + """Validate model for codex_oauth.""" + return validate_model("codex_oauth", self.model) From 24f53bc237c6e992782232aa35e275597911a251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:00:17 +0800 Subject: [PATCH 06/12] =?UTF-8?q?refactor(llm=5Fclients):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=B7=A5=E5=8E=82=E6=A8=A1=E5=BC=8F=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=8A=A8=E6=80=81=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E5=92=8C=E4=BE=9D=E8=B5=96=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将硬编码的导入改为动态导入,并添加对缺失依赖的检查 为codex_oauth添加新的客户端支持 更新provider参数文档说明 --- tradingagents/llm_clients/factory.py | 47 +++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tradingagents/llm_clients/factory.py b/tradingagents/llm_clients/factory.py index 028c88a2..27cc424d 100644 --- a/tradingagents/llm_clients/factory.py +++ b/tradingagents/llm_clients/factory.py @@ -1,9 +1,6 @@ from typing import Optional from .base_client import BaseLLMClient -from .openai_client import OpenAIClient -from .anthropic_client import AnthropicClient -from .google_client import GoogleClient def create_llm_client( @@ -15,7 +12,7 @@ def create_llm_client( """Create an LLM client for the specified provider. Args: - provider: LLM provider (openai, anthropic, google, xai, ollama, openrouter) + provider: LLM provider (openai, codex_oauth, anthropic, google, xai, ollama, openrouter) model: Model name/identifier base_url: Optional base URL for API endpoint **kwargs: Additional provider-specific arguments @@ -29,15 +26,57 @@ def create_llm_client( provider_lower = provider.lower() if provider_lower in ("openai", "ollama", "openrouter"): + try: + from .openai_client import OpenAIClient + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "Missing dependency for OpenAI-compatible providers. " + "Install `langchain-openai`." + ) from exc + return OpenAIClient(model, base_url, provider=provider_lower, **kwargs) + if provider_lower == "codex_oauth": + try: + from .codex_oauth_client import CodexOAuthClient + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "Missing dependency for codex_oauth provider. " + "Install `langchain-codex-oauth`." + ) from exc + + return CodexOAuthClient(model, base_url, **kwargs) + if provider_lower == "xai": + try: + from .openai_client import OpenAIClient + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "Missing dependency for xAI provider. Install `langchain-openai`." + ) from exc + return OpenAIClient(model, base_url, provider="xai", **kwargs) if provider_lower == "anthropic": + try: + from .anthropic_client import AnthropicClient + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "Missing dependency for Anthropic provider. " + "Install `langchain-anthropic`." + ) from exc + return AnthropicClient(model, base_url, **kwargs) if provider_lower == "google": + try: + from .google_client import GoogleClient + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + "Missing dependency for Google provider. " + "Install `langchain-google-genai`." + ) from exc + return GoogleClient(model, base_url, **kwargs) raise ValueError(f"Unsupported LLM provider: {provider}") From e784cddb62527b368cec1892d6e5d85c43b6134f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:00:47 +0800 Subject: [PATCH 07/12] =?UTF-8?q?feat(llm=5Fclients):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?codex=5Foauth=E6=A8=A1=E5=9E=8B=E5=88=B0=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=99=A8=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tradingagents/llm_clients/validators.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tradingagents/llm_clients/validators.py b/tradingagents/llm_clients/validators.py index 3c0f2290..dd8ba049 100644 --- a/tradingagents/llm_clients/validators.py +++ b/tradingagents/llm_clients/validators.py @@ -26,6 +26,13 @@ VALID_MODELS = { "gpt-4o", "gpt-4o-mini", ], + "codex_oauth": [ + # Codex chat models via ChatGPT OAuth backend + "gpt-5.4", + "gpt-5.2", + "gpt-5.3-codex", + "gpt-5.2-codex", + ], "anthropic": [ # Claude 4.5 series (2025) "claude-opus-4-5", From b8f56186e711cb6a8d4ce98e3d686a283d0915b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:00:58 +0800 Subject: [PATCH 08/12] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0.gitignore?= =?UTF-8?q?=E6=96=87=E4=BB=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0reports=E3=80=81re?= =?UTF-8?q?sults=E5=92=8Ctests=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9a2904a9..3d76faa6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +reports +results +tests # Byte-compiled / optimized / DLL files __pycache__/ *.py[codz] From 5abaf297ef5b6fbd693b38600f7c7bb68f5c4431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:02:32 +0800 Subject: [PATCH 09/12] =?UTF-8?q?build:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E9=A1=B9=E4=B8=AD=E7=9A=84langchain-experimental?= =?UTF-8?q?=E4=B8=BAlangchain-codex-oauth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9e51ed98..c3f28e45 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ typing-extensions langchain-core langchain-openai -langchain-experimental +langchain-codex-oauth pandas yfinance stockstats From f517cc06eed75dbcd4137202f3ee3d8723144d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:03:47 +0800 Subject: [PATCH 10/12] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0README=E4=BB=A5?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0Codex=20OAuth=E8=AE=A4=E8=AF=81=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加ChatGPT Plus/Pro账户的Codex OAuth认证方式说明 更新支持的LLM提供商列表和默认配置参数 --- README.md | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 34310010..55264e26 100644 --- a/README.md +++ b/README.md @@ -116,9 +116,32 @@ Install dependencies: pip install -r requirements.txt ``` -### Required APIs +### Authentication / APIs -TradingAgents supports multiple LLM providers. Set the API key for your chosen provider: +TradingAgents supports multiple LLM providers. + +#### Option A (Default): ChatGPT OAuth for Codex models (no `OPENAI_API_KEY`) + +If you have a ChatGPT Plus/Pro account, login once: + +```bash +tradingagents auth login +# If local callback port 1455 is busy: +tradingagents auth login --manual +``` + +Check status / logout: + +```bash +tradingagents auth status +tradingagents auth logout +``` + +`codex_oauth` currently uses a Codex model whitelist: +- `gpt-5.2-codex` +- `gpt-5.2` + +#### Option B: API keys for other providers ```bash export OPENAI_API_KEY=... # OpenAI (GPT) @@ -162,7 +185,7 @@ An interface will appear showing results as they load, letting you track the age ### Implementation Details -We built TradingAgents with LangGraph to ensure flexibility and modularity. The framework supports multiple LLM providers: OpenAI, Google, Anthropic, xAI, OpenRouter, and Ollama. +We built TradingAgents with LangGraph to ensure flexibility and modularity. The framework supports multiple LLM providers: Codex OAuth (ChatGPT Plus/Pro), OpenAI, Google, Anthropic, xAI, OpenRouter, and Ollama. ### Python Usage @@ -186,9 +209,9 @@ from tradingagents.graph.trading_graph import TradingAgentsGraph from tradingagents.default_config import DEFAULT_CONFIG config = DEFAULT_CONFIG.copy() -config["llm_provider"] = "openai" # openai, google, anthropic, xai, openrouter, ollama -config["deep_think_llm"] = "gpt-5.2" # Model for complex reasoning -config["quick_think_llm"] = "gpt-5-mini" # Model for quick tasks +config["llm_provider"] = "codex_oauth" # codex_oauth, openai, google, anthropic, xai, openrouter, ollama +config["deep_think_llm"] = "gpt-5.4" +config["quick_think_llm"] = "gpt-5.2" config["max_debate_rounds"] = 2 ta = TradingAgentsGraph(debug=True, config=config) From 31abb735c62891a3ac36c922b488a2b572bb5125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:04:06 +0800 Subject: [PATCH 11/12] =?UTF-8?q?build:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E7=89=88=E6=9C=AC=E5=B9=B6=E6=B7=BB=E5=8A=A0pytest?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将langchain相关依赖升级至1.x版本并添加版本范围限制 添加pytest的pythonpath和testpaths配置 --- pyproject.toml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9213d7f6..3ef437b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,13 +9,13 @@ description = "TradingAgents: Multi-Agents LLM Financial Trading Framework" readme = "README.md" requires-python = ">=3.10" dependencies = [ - "langchain-core>=0.3.81", + "langchain-core>=1.0.0,<2.0.0", "backtrader>=1.9.78.123", "chainlit>=2.5.5", - "langchain-anthropic>=0.3.15", - "langchain-experimental>=0.3.4", + "langchain-anthropic>=1.0.0,<2.0.0", "langchain-google-genai>=2.1.5", - "langchain-openai>=0.3.23", + "langchain-openai>=1.0.0,<2.0.0", + "langchain-codex-oauth>=1.0,<1.1", "langgraph>=0.4.8", "pandas>=2.3.0", "parsel>=1.10.0", @@ -38,3 +38,7 @@ tradingagents = "cli.main:app" [tool.setuptools.packages.find] include = ["tradingagents*", "cli*"] + +[tool.pytest.ini_options] +pythonpath = ["."] +testpaths = ["tests"] From c9408db34a69b5a10e961143c12d9461f02cb62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E5=BC=A0=E5=BC=9B?= Date: Sat, 14 Mar 2026 11:04:15 +0800 Subject: [PATCH 12/12] =?UTF-8?q?docs(env):=20=E6=9B=B4=E6=96=B0=20.env.ex?= =?UTF-8?q?ample=20=E4=B8=AD=E7=9A=84=E6=B3=A8=E9=87=8A=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加关于默认提供商的注释说明,明确 codex_oauth 为默认且不需要 OPENAI_API_KEY --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index 1328b838..a7c0259f 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ +# Default provider is `codex_oauth` and does not require OPENAI_API_KEY. # LLM Providers (set the one you use) OPENAI_API_KEY= GOOGLE_API_KEY=