Files
mnote/.codex/reasonix-tasks/results/batch-j-worker-a-http-proxy-fallback.md
T

6.9 KiB
Raw Blame History

Batch J Worker A:旧 HTTP proxy / page AI fallback 调用链审查

创建时间:2026-05-21

只读审查,不修改代码。

1. 读取过的关键文件

文件 行数 内容
rust/crates/mnote-web/src/routes/hermes_client.rs 8202 首页面 AI Hermes 路由:session/run/tool 的 proxy 和 ACP 双路径
rust/crates/mnote-web/src/page_ai_workflow.rs 不存在(不在根目录,在 routes/ 下)
rust/crates/mnote-web/src/routes/page_ai_workflow.rs 500+ 页面 AI block-edit fast path
rust/crates/mnote-web/src/acp_runtime.rs 500+ ACP runtime manager
rust/crates/mnote-web/src/acp_session_manager.rs 700+ ACP session lifecycle
rust/crates/mnote-web/src/routes/mod.rs 200+ 全路线由注册
rust/crates/mnote-web/src/routes/compat.rs 200+ /api/ai-agent/run 退役 guard

2. 调用链分析

2.1 旧 HTTP proxy 路径

判断函数: hermes_client.rs:2844 hermes_http_proxy_enabled()

fn hermes_http_proxy_enabled() -> bool {
    ["MNOTE_WEB_ENABLE_HERMES_HTTP_PROXY", "MNOTE_ENABLE_HERMES_HTTP_PROXY"]
        .into_iter().find_map(env_or_dotenv)
        .map(|v| matches!(v.trim().to_ascii_lowercase(), "1" | "true" | "yes"))
        .unwrap_or(false)
}

默认关闭unwrap_or(false))。HTTP proxy 仅在显式设 MNOTE_WEB_ENABLE_HERMES_HTTP_PROXY=true 时启用。

上游 URL 来源: configured_upstream()hermes_client.rs:2813

  • 检查 MNOTE_WEB_HERMES_UPSTREAM_URLMNOTE_HERMES_UPSTREAM_URLMNOTE_HERMES_API_BASE_URL
  • 均不存在时返回 None

is_acp_profile() 路由逻辑hermes_client.rs:2871):

fn is_acp_profile(profile: &str) -> bool {
    if !hermes_http_proxy_enabled() { return true; }  // 默认全走 ACP
    if profile == "reasonix" || profile == "hermes" { return true; }
    // 还可通过 MNOTE_WEB_{PROFILE}_RUNTIME_TYPE=acp 环境变量控制
    ...
}

2.2 各路由入口分类

Route Handler HTTP proxy 条件 默认走 分类
GET /client/sessions list_sessions !is_acp_profile(profile) && configured_upstream_for_profile(profile).is_some() ACP compat
GET /client/sessions/search search_sessions 同上 ACP compat
GET /client/gateway/health gateway_health !is_acp_profile(&profile) → HTTP proxy ACP(对于非 ACP profile 走 HTTP proxy compat
POST /client/runs create_run configured_upstream_for_profile(&registration.profile).is_some() ACP compat
GET /client/events/{run_id} stream_events 先查 acp_runtime_for_run(),再 fallback configured_upstream_for_profile() ACP compat
POST /client/runs/{run_id}/abort abort_run 同上 ACP compat
GET /client/models list_models 直接 configured_upstream() HTTP proxy(与 ACP 无关的 model 列表) compat
队列自动处理 auto_start_next_queued_runline 5377 configured_upstream_for_profile(queued.profile) ACP compat
POST /api/ai-agent/run compat::next_ai_agent_run 始终返回 410 GONE retired
POST /api/page-ai/block-edit-workflow page_ai_workflow::block_edit_workflow 绕过 ACP,直接调模型 API + execute_mnote_tool_call debug-only fast path debug-only

2.3 page_ai_workflow 是否绕过 ACP / tool executor

调用链:

POST /api/page-ai/block-edit-workflow
  → looks_like_block_edit(message)     ← 中文关键词匹配
  → call_block_edit_model()            ← 直调 DeepSeek/etc APIHTTP
  → extract_markdown_plan_from_model_text()
  → 构造 ToolCallInput { tool_name: "mnote.doc.markdown_edit", capability_scope: ["block.write","page.write"], ... }
  → hermes_tools::execute_mnote_tool_call()  ← 共享 tool executor
    → is_mnote_tool_disabled() & ensure_write_authorized() & 实际执行

结论:

  1. 不经过旧 HTTP proxy ✓ — 没有调用 configured_upstream_for_profile
  2. 不经过 ACP session manager — 直接调用 execute_mnote_tool_call,没有 session/new + session/prompt 生命周期
  3. 但经过共享 tool executor — 受 is_mnote_tool_disabled()ensure_write_authorized()is_shared_read_scope() 等守卫保护
  4. 设计意图7-15 设计文档说明 "local-first 普通正文编辑默认不经过它",该路径是给合模型快速做 search/replace 块编辑的 fast path,不是常规 AI 执行路径

2.4 compat::next_ai_agent_run 状态

routes/compat.rs:10next_ai_agent_run() 始终返回 410 GONE + 消息"旧 /api/ai-agent/run 页面 AI 主链已退场"。已确认退役,无 P0 风险。

3. 各入口分类汇总

分类 条目 说明
default HTTP proxy 默认关闭;ACP 是默认 runtime
compat list_sessions, search_sessions, gateway_health, create_run, stream_events, abort_run, list_models, 队列处理 仅当 MNOTE_WEB_ENABLE_HERMES_HTTP_PROXY=true 时激活;不影响正常用户
debug-only page_ai_workflow::block_edit_workflow bypass ACP session,但受工具 executor 守卫保护
retired compat::next_ai_agent_run 已返回 410,无降级路径
未被调用 configured_runtime_for_profile()line 3368 标记 #[allow(dead_code)]

4. P0 缺口评估

当前没有 P0 必须修复的缺口。

理由:

  1. HTTP proxy 默认关闭(hermes_http_proxy_enabled() = false
  2. compat::next_ai_agent_run 已正确返回 410
  3. page_ai_workflow 经过共享 tool executor 守卫,不绕过权限检查
  4. 所有路由的第一分支都是 ACP

5. 建议的后续修改范围

建议 紧急程度
HTTP proxy 完整退役 删除 configured_upstream() / configured_upstream_for_profile() / proxy_json() 相关代码 P2cleanup
list_models 从 HTTP proxy 迁移 改为 ACP 的 session/initialize 返回 model 信息 P2(依赖 ACP 协议增强)
page_ai_workflow 检查驱动 确保测试覆盖其 bypass ACP session 的行为的非期望路径(task-page-block-ai-smoke.js → 已存在) 已有
旧环境变量清理 文档标记 MNOTE_WEB_HERMES_UPSTREAM_URL 等为退役 P2

6. 建议测试

# 确认 HTTP proxy 默认关闭(infra 测试)
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web hermes_http_proxy -- --test-threads=1

# 确认 compat 路由返回 410(已存在)
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web direct_ai_agent_run_returns_legacy_retired_guard -- --test-threads=1

# 确认 page_ai_workflow 受守卫保护(已存在)
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web block_edit_workflow_respects_disabled_markdown_edit_tool -- --test-threads=1