mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 10:53:33 +08:00
feat: add Codex App Server agent prototype (#2004)
This commit is contained in:
@@ -38,6 +38,7 @@ GENERATION_BACKEND_MAX_CONCURRENCY=1
|
||||
LOCAL_CLI_BACKEND_MAX_CONCURRENCY=1
|
||||
# 可选:留空时使用本机 OpenCode 默认模型;配置时作为 --model 覆盖值传给 OpenCode。
|
||||
# OPENCODE_CLI_MODEL=provider/model
|
||||
AGENT_BACKEND=auto
|
||||
AGENT_GENERATION_BACKEND=auto
|
||||
```
|
||||
|
||||
@@ -45,7 +46,7 @@ AGENT_GENERATION_BACKEND=auto
|
||||
- `GENERATION_BACKEND=opencode_cli` 时默认不传 `--model`,由本机 OpenCode 使用自身默认模型配置;`OPENCODE_CLI_MODEL` 只是可选覆盖值,配置时才作为单个 `--model` 参数传给 OpenCode。provider 认证、账号和模型可用性由本机 OpenCode 自身配置负责;DSA 不接管这些配置。
|
||||
- `GENERATION_FALLBACK_BACKEND` 未配置时默认 `litellm`;本地 `.env` 显式空值 `GENERATION_FALLBACK_BACKEND=` 表示禁用 backend-level fallback;primary 与 fallback 相同时解析为 no-op。仓库自带 GitHub Actions workflow 未配置该变量时会显式导出 `litellm`,如果要在 Actions 中禁用 backend fallback,请把 fallback 设为 primary backend,例如 `GENERATION_BACKEND=codex_cli` + `GENERATION_FALLBACK_BACKEND=codex_cli`。
|
||||
- `GENERATION_BACKEND=codex_cli|claude_code_cli` 且没有 Gemini/OpenAI/Anthropic/DeepSeek API Key 时,普通分析和大盘复盘仍会尝试本地 CLI backend;如果对应 executable 不存在,会返回结构化 `command_not_found`,不会报“API Key 未配置”。
|
||||
- 当前 `codex_cli` preset 使用 `codex exec --output-last-message <temp-file> -` 读取最终响应;Codex CLI 仍会把同一最终响应打印到 stdout,DSA 会从 stdout 诊断预览和输出大小统计中剔除这份重复内容,不参与主分析 JSON 解析。官方依据见 [Codex non-interactive mode](https://developers.openai.com/codex/noninteractive) 与 [Codex CLI command line options](https://developers.openai.com/codex/cli/reference)。本仓库当前只验证 `codex-cli 0.142.0`,不声明更宽最低版本;如果 CLI 版本不支持 preset 参数,DSA 会返回结构化 `capability_unsupported` / `cli_contract_unsupported` 诊断,并在配置 backend fallback 时回退到 `litellm`。
|
||||
- 当前 `codex_cli` preset 使用 `codex --ask-for-approval never exec --sandbox read-only --output-last-message <temp-file> -`:普通分析是无人值守生成任务,固定 `never` 可避免非交互运行停在人工批准请求,同时仍由 `read-only` 保持只读边界。DSA 从临时文件读取最终响应;Codex CLI 同时打印到 stdout 的重复内容会从诊断预览和输出大小统计中剔除,不参与主分析 JSON 解析。官方依据见 [Codex non-interactive mode](https://developers.openai.com/codex/noninteractive) 与 [Codex CLI command line options](https://developers.openai.com/codex/cli/reference)。本仓库当前真实验证 `codex-cli 0.144.3`,不声明更宽最低版本;如果 CLI 版本不支持 preset 参数,DSA 会返回结构化 `capability_unsupported` / `cli_contract_unsupported` 诊断,并在配置 backend fallback 时回退到 `litellm`。
|
||||
- 当前 `claude_code_cli` preset 使用 `claude --safe-mode --tools "" --disallowedTools "mcp__*" --strict-mcp-config --no-session-persistence --output-format json -p <static instruction>`,完整 DSA prompt 通过 stdin 传入。DSA 只从 Claude JSON envelope 的 `result/success` 最终字段提取文本;如果后续启用 `--json-schema`,schema mode 必须提取 `structured_output`,并且仍会继续经过 DSA 现有 JSON validator、minimal parser contract、`_parse_response()`、integrity retry、placeholder fill 和 usage telemetry。参数依据见 [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference);本 PR smoke 验证版本为 `claude 2.1.177 (Claude Code)`,不声明更宽最低版本。
|
||||
- 当前 `opencode_cli` preset 使用 `opencode --pure run --format json [--model <OPENCODE_CLI_MODEL>] <static instruction> --file <temp prompt file>`;只有显式配置 `OPENCODE_CLI_MODEL` 时才追加 `--model`,完整 DSA prompt 写入权限受控的临时文件,不进入 argv。DSA 只解析 OpenCode JSON event 输出中无工具事件的 `text` 内容,并要求正常 `step_finish`;出现 `tool_use`、`error`、`question`、`permission` 等事件会结构化失败。参数依据见 [OpenCode CLI reference](https://opencode.ai/docs/cli),项目配置合并语义见 [OpenCode config reference](https://opencode.ai/docs/config);本 PR smoke 验证版本为 `opencode 1.17.11`,不声明更宽最低版本。
|
||||
- 本地 CLI backend 不支持 streaming。请求 stream 时会自动降级为 non-stream,不会因此返回 `capability_unsupported`。
|
||||
@@ -53,10 +54,37 @@ AGENT_GENERATION_BACKEND=auto
|
||||
- 本地 CLI 执行上限有硬边界:`GENERATION_BACKEND_TIMEOUT_SECONDS` 最大 `3600`,`GENERATION_BACKEND_MAX_OUTPUT_BYTES` 最大 `33554432`,`GENERATION_BACKEND_MAX_CONCURRENCY` 最大 `16`,`LOCAL_CLI_BACKEND_MAX_CONCURRENCY` 最大 `4`。诊断 stdout/stderr 与最终响应合计超过输出上限时会返回结构化 `output_too_large`;对 `--output-last-message` preset,stdout 中重复打印的最终响应不会重复计入,也不会作为 `stdout_preview` 暴露。
|
||||
- 本地 CLI 默认并发为 1;有效并发为 `min(LOCAL_CLI_BACKEND_MAX_CONCURRENCY, GENERATION_BACKEND_MAX_CONCURRENCY)`,不继承 `MAX_WORKERS`。
|
||||
- `AGENT_GENERATION_BACKEND=auto` 不会继承 `GENERATION_BACKEND` 的 local CLI 值;Agent 工具调用继续使用 LiteLLM。Web 设置页仅暴露 `auto|litellm`;手写 `AGENT_GENERATION_BACKEND=codex_cli|claude_code_cli|opencode_cli` 不实现 text-only Agent mode,会返回明确 unsupported tool-calling 诊断。
|
||||
- Phase 6a 的 DSA Tool Surface 只是内部工具 schema、权限元数据、scope guard、结构化错误和审计/脱敏边界,用于后续 AgentBackend 统一消费;stock-scoped 工具调用必须显式传入 `ToolAccessContext.stock_scope`,有 `stock_code` 参数但未声明 stock scope 的工具会 fail-closed。它不新增外部 runtime adapter、MCP server、REST API、Web UI 或 `.env` 配置,也不改变 generation backend / Agent backend 路由。Codex / Claude / OpenCode / Hermes 在完成 wire-level tool call / tool result roundtrip probe 前仍不能绕过 Tool Surface 直接拼 provider-specific tool schema,`codex_cli` / `claude_code_cli` / `opencode_cli` 仍保持 generation-only,`supports_tools=false`。
|
||||
- Phase 6a 的 DSA Tool Surface 仍是唯一工具 schema、权限元数据、scope guard、结构化错误和审计/脱敏边界;Phase 6 的 Codex AgentBackend 只能通过该 Tool Surface 执行工具。`codex_cli` / `claude_code_cli` / `opencode_cli` 仍是 generation-only,不能作为 Agent tool fallback。
|
||||
- Web 设置页的生成后端快速检查只读取已保存的 `.env`、运行时兜底值和未保存草稿;它不会写配置、重载运行时,也不会发起真实模型请求。`available` 只表示当前配置具备尝试运行的条件。JSON 冒烟测试是单独的显式操作,会使用服务端固定的 JSON 提示词和 schema 发起一次真实的生成后端请求,用于验证提取器、JSON 契约、超时、输出限制和 usage-unavailable 语义。
|
||||
- `GET /api/v1/system/config/generation-backends/status` 只读取已保存配置;未保存草稿需调用 `POST /api/v1/system/config/generation-backends/status/preview` 或 `POST /api/v1/system/config/generation-backends/smoke-test`。被遮罩的密钥字段会继续沿用已保存值。`health_status` 与 `last_error_code/message` 只代表本次计算结果,不是历史持久健康状态。
|
||||
|
||||
### Codex 本地 Agent(Phase 6 实验原型)
|
||||
|
||||
`AGENT_BACKEND` 只决定现有问股 Chat 的运行方式,不影响普通报告、定时分析、大盘复盘、普通 Agent 分析 pipeline、LiteLLM Multi Agent 或 Deep Research:
|
||||
|
||||
```env
|
||||
# auto(推荐)不会自动启用实验性的 Codex;auto 与 litellm 均保持原有默认模型路径。
|
||||
AGENT_BACKEND=auto
|
||||
# 显式启用时:
|
||||
# AGENT_BACKEND=codex_app_server
|
||||
# AGENT_ARCH=single
|
||||
```
|
||||
|
||||
Web 启用步骤:打开「设置 → Agent 设置 → 问股生成方式」,选择「Codex 本地 Agent(实验)」,确认架构为「单 Agent」,并将 Agent 整体时限设置为大于 0 后保存。设置页只检查当前配置、本机 Codex 命令和所需 App Server 协议是否允许尝试,不登录、不调用模型,也不读取股票数据。保存后可直接回到问股页提问;第一次问题就是第一次真实执行。要恢复原有行为,选择「自动(推荐)」并保存。
|
||||
|
||||
- Codex 必须安装并登录在**运行 DSA 后端的设备**上;DSA 不读取或保存 Codex 凭据,App Server 进程使用 Codex 自身登录态。Docker、远程服务器和 Desktop 的 PATH / 登录态彼此独立。在 Desktop 中从 Finder/Dock 启动时,后端只继承 Desktop 构造的真实 PATH;若状态提示找不到 Codex,请将 Codex CLI 安装到后端 PATH 可见位置并完全重启 DSA,不要只在另一个终端窗口验证。
|
||||
- Phase 6 的 Codex App Server Agent 当前支持 macOS、Linux,以及 DSA 后端完整运行于 WSL 的环境;原生 Windows 后端会在状态检查和 transport 启动前明确拒绝。此限制不影响 Phase 2 `GENERATION_BACKEND=codex_cli` 已有的 Windows 生成能力。
|
||||
- Codex 当前只开放已保存分析上下文、全局回测汇总和策略回测汇总的只读查询。本期只验证并承诺这三个工具的独立进程、停止、超时和回收闭环;实时行情、新闻、市场热点、技术指标重算、个股回测明细和持仓工具未纳入本期验证,因此不会出现在 Codex 的工具列表中。需要这些能力时,请在 Web 中选择「默认模型」。明确股票代码或 Web 已选择的唯一股票只会为已开放的历史分析上下文工具建立股票范围;遇到同名歧义时不会猜测。
|
||||
- 该能力不是离线模型。股票代码、问题、新闻、持仓上下文和脱敏后的工具结果可能由 Codex 自身配置的服务处理。
|
||||
- 当前只支持 single-agent Chat;不支持 Codex Multi Agent 或 Codex Deep Research。现有 LiteLLM Multi Agent 与 Deep Research 不受影响。
|
||||
- 每次 Chat 都创建新的 ephemeral App Server thread;DSA 继续保存原有可见会话历史,并在下一轮注入,但不会注入 LiteLLM provider trace。Web 客户端不会收到 chain-of-thought、原始 JSON-RPC、stderr 或完整工具参数/结果;Codex 只接收完成该轮分析所需的脱敏工具结果。
|
||||
- 用户停止问股时,页面会先显示“正在停止”。DSA 会中断 Codex turn,并结束、回收本轮独立运行的工具进程;只有确认 Codex 与工具进程均已退出后,原问股请求才返回最终“已停止”。超时和客户端断开也遵守同一清理边界,不会在后台仍有本轮任务时提前宣告结束。该契约仅作用于 Codex,不改变默认 LiteLLM Agent 的执行方式。
|
||||
- Codex 必须使用大于 0 的 `AGENT_ORCHESTRATOR_TIMEOUT_S`,以保证成功、失败、超时或停止都在明确时间内结束;`0` 关闭时限的旧语义只保留给默认 LiteLLM 路径,选择 Codex 时会在保存与运行前明确拒绝,不会静默替换成 600 秒。
|
||||
- 快速状态只检查配置、可执行文件、版本和生产路径实际依赖的 App Server schema 能力,不发模型请求,也不证明 Codex 已登录、模型可用或真实工具闭环。状态只表达“可以尝试”;真实命令、协议、登录、模型和工具错误在用户发送问题时按原始类别返回。Chat 每次加载检查一次,失败后由用户手动重新检查,不自动重试。
|
||||
- 正式 Chat 由服务端选择实际 backend。服务端完成上下文准备并保存用户问题后,SSE 才发出唯一 `accepted` 事件,然后开始模型执行。Web 在 `accepted` 前保留输入、股票范围、追问上下文和技能选择;因此环境或保存失败不会产生页面中的幽灵消息。`accepted` 返回的实际 backend 决定停止方式。
|
||||
- 每次问股共享一份整轮资源预算:App Server 的累计输出和事件数有界,工具调用总数服从现有 `AGENT_MAX_STEPS`,完成后立即清理本轮状态。工具进程按原始 UTF-8 结果字节计量,不会因 JSON 转义把合法结果误报为 handler 崩溃;超限统一返回明确错误并回收本轮进程,不重试或切换后端。
|
||||
- 当前依据 [Codex App Server v2 文档](https://developers.openai.com/codex/app-server/) 使用 JSONL stdio、ephemeral `thread/start`、`turn/start` / `turn/interrupt` 与 experimental dynamic tools。2026-07-15 的本地验收版本为 `codex-cli 0.144.3`;本项目不据此猜测通用最低版本。设置页兼容性检查只决定是否允许尝试,最终可用性以用户问题的真实执行结果为准。
|
||||
|
||||
### Local CLI 本地 backend 隐私与边界
|
||||
|
||||
- 本地 CLI Backend 不等于离线模型;Codex / Claude Code / OpenCode 背后的服务可能处理股票代码、新闻、持仓上下文、分析 prompt、报告草稿等内容。
|
||||
@@ -247,9 +275,9 @@ Hermes 是保留渠道名,只支持本机 loopback `/v1` OpenAI-compatible gen
|
||||
- 如果你通过 OpenAI Compatible 渠道接 MiniMax,请在渠道模型里直接填写 `minimax/<模型名>`,例如 `minimax/MiniMax-M1`。
|
||||
- Web 设置页里的主模型、Agent 主模型、Fallback、Vision 下拉会保留这个值原样展示,不会再错误改写成 `openai/minimax/<模型名>`。
|
||||
|
||||
### 问股 Agent / LiteLLM 配置兼容说明
|
||||
### 默认模型问股 / LiteLLM 配置兼容说明
|
||||
|
||||
- 问股 Agent 运行时沿用与普通分析相同的三层优先级:`LITELLM_CONFIG`(LiteLLM YAML)> `LLM_CHANNELS` > legacy provider keys。只要上层配置有效生效,下层配置就不会再参与本次请求。
|
||||
- `AGENT_BACKEND=auto|litellm` 时,问股 Agent 沿用与普通分析相同的三层优先级:`LITELLM_CONFIG`(LiteLLM YAML)> `LLM_CHANNELS` > legacy provider keys。只要上层配置有效生效,下层配置就不会再参与本次请求;Codex 不使用这套模型路由。
|
||||
- YAML 模式下,Agent 直接复用 LiteLLM `model_list` / `model_name` 路由语义;渠道模式下,优先读取 `AGENT_LITELLM_MODEL`,留空时继承 `LITELLM_MODEL`,再按 `LITELLM_FALLBACK_MODELS` 继续 fallback。
|
||||
- 如果你没有启用 YAML / Channels,且 `AGENT_LITELLM_MODEL` 也留空,但本地仍保留 legacy 环境变量,问股 Agent 依然会继承旧配置:`GEMINI_API_KEY + GEMINI_MODEL` -> `gemini/<model>`,`OPENAI_API_KEY + OPENAI_MODEL` -> `openai/<model>`,`ANTHROPIC_API_KEY + ANTHROPIC_MODEL` -> `anthropic/<model>`。
|
||||
- 该兼容逻辑只增强“失败时保留后端真实错误原因”和“未配置 LLM 时给出更具体诊断”,**不会**静默删除、清空、迁移或改写你现有的 `GEMINI_*` / `OPENAI_*` / `ANTHROPIC_*` / `LITELLM_*` 配置。
|
||||
@@ -258,7 +286,7 @@ Hermes 是保留渠道名,只支持本机 loopback `/v1` OpenAI-compatible gen
|
||||
|
||||
### 问股可见对话上下文压缩
|
||||
|
||||
默认情况下,问股仍按历史行为只注入最近 20 条可见对话。需要长会话省 token 时,可开启:
|
||||
默认情况下,问股仍按历史行为只注入最近 20 条可见对话。以下 LLM 压缩只适用于「默认模型」问股:Codex Agent 始终使用最近 20 条用户可见对话,不会调用 `AGENT_LITELLM_MODEL` 生成历史摘要。切换到 Codex 不会清空已保存的压缩配置,切回「默认模型」后会继续生效。需要为默认模型长会话省 token 时,可开启:
|
||||
|
||||
```env
|
||||
AGENT_CONTEXT_COMPRESSION_ENABLED=true
|
||||
|
||||
Reference in New Issue
Block a user