Files
auto_control/doc/backlog/TODO.md
T
butubb 46e6ea1f37 feat(AI 建任务): AI 自己在真机探索 → 写出可调度任务 → 人工确认入库
AI 控制台下新增子分栏「🧭 AI 建任务」:描述要做什么(例:建一个跑 2 小时的任务、自动刷
某 App、随机点赞),AI 用 de_* 工具自己在设备上探索(看屏/读元素树/点按验证),把走通的
路径写成一条任务草稿,经服务端校验后交人在步骤编辑器里核对/手改/试跑,保存才入库。

链路:POST /api/agent/run{mode:"designer", settings}
  → Agent 自探 → 本地工具 submit_task(draft)
  → core/task_draft 校验(失败把 errors 回灌模型让它改)
  → 只暂存(运行态 + app_meta.agent_task_draft,**不落库**)
  → SSE done{mode,draft,warnings} → 页面草稿预览 → openTaskModal(null, prefill) 预填

关键实现
- core/task_draft.py(新):把执行器的"静默跳过点"(未知 type/空 selector/空 children/
  嵌套>5/节点>60/cron 非法/必填缺失)前移成显式 error——POST /api/jobs 对 params 是盲存的,
  执行器又静默跳过错误步骤,没有这道闸门就是"任务建好了、跑起来什么都没做"。
  归一化兜底任务名/target/schedule/retry/时长;页面填的设置以 overrides 优先于模型。
  故意**不比执行器更严**:loop_mode 近义值归一(count→rounds)、缺 max_iterations 补默认 10
  (执行器本来就默认)——实测卡太死会把一轮探索耗在改字段上。
  有副作用的步骤(评论/发送/购买/删除…)只警告并把触发概率压到 30%(编辑器可改回)。
- mcp_agent/agent.py:双系统提示词(CHAT/DESIGNER)+ 平台级本地工具
  (LOCAL_TOOL_SPECS,不进 MCP)+ 每工具调用上限 40 + designer 输出上限 8192 +
  **json.loads 容错**(草稿被截断时给模型可读错误,而不是整轮失败)。
- web/agent_api.py:mode/settings 透传、submit_task 处理器(app_context 内校验+暂存)、
  done 带 draft、GET /api/agent/task_draft{,+POST,/clear}(草稿走 app_meta,不新建表)。
- 前端:static/admin/taskgen.js + #agent-sub-taskgen 子面板(showSubTab 机制);
  tasks.js 的 openTaskModal(jobId, prefill) + 信封归一化 + 唯一 draftKey;
  agent.js 按 mode 门控(一个 run 只有一个事件队列,两个 EventSource 会互相瓜分事件)。

顺带修掉一个 chat 也踩的协议 bug:一轮里同时调 de_screenshot 与别的工具时,截图图像会被
插在两条 tool 消息之间 → 模型侧判"工具回应不足"直接 400。改为本轮 tool 消息发完再附图像,
_repair_tool_messages 也改成只数**连续**的 tool 消息。

真机实测(Redmi 22120RN86C,设置页):8 步探索(含 tap_text 验证)→ submit_task 一次通过 →
草稿 8 个顶层步骤(screen_on/open_app/wait_el/click/wait/key_event…)、max_duration 1800、
无 click_xy、3 条 evidence;页面恢复草稿 + 预填编辑器 + 提示块渲染均正常,无 JS 报错。
自测数据已清理(草稿已丢弃、未创建任何任务)。

文档:AI_TASK_GEN.md 状态改「P0 已实现」+ §10 实现记录(差异/护栏/未做项)、AI_CONSOLE.md
(子分栏、designer 分支、SSE done 负载、app_meta 键)、API.md、DATA_MODEL.md、ARCHITECTURE.md、
DEVELOPMENT.md(自测入口)、README.md 索引、backlog 勾掉 P0。
2026-09-13 23:08:59 +08:00

9.9 KiB
Raw Blame History

待完成项 / 已知问题(Backlog)

用途:记录已确认但暂缓的功能、优化与已知缺陷,避免丢线索。完成时移出本文件,并按「doc 同步红线」更新对应文档。 维护:新条目写清 背景 / 期望 / 涉及文件 / 验收;缺陷写清 现象 / 复现 / 影响。 相关:doc/README.md(文档索引与维护约定)。


A. 已知缺陷(尚未修)

A1. GET /locate 返回 500(设备定位大字页打不开)

  • 现象:访问 /locate?serial=… 直接 500。
  • 原因:web/monitor.py 的 locate_page() 用了 render_template_string 与 _esc,但该文件只导入了 render_template,也没有 _esc 定义。
  • 复现:curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:18050/locate?serial=1.2.3.4:5555" → 500(路由扫描脚本已确认)。
  • 影响:「工具 → 设备池管理 → 定位」在设备上打开的大字页不可用(亮屏那半仍生效)。
  • 涉及:web/monitor.py(补 import / 补转义实现,或改用 render_template + 模板文件)。
  • 验收:/locate 返回 200 且页面正确显示 serial/IP;纳入回归脚本。

A2. POST /api/device/locate(show=true)失败

  • 现象:带 show=true 调用时抛异常 → 502。
  • 原因:web/monitor.py 用了 urllib.parse.quote 但未 import urllib。
  • 影响:无法远程把设备浏览器打开到定位页。
  • 涉及:web/monitor.py。验收:show=true 时设备浏览器打开定位页且返回 200。

A3. CSRF 实际未启用

  • 现象:/api/csrf 会签发 token、前端所有非 GET 请求都会带 X-CSRF-Token,但服务端从不校验。
  • 原因:web_server.py 只 from web.auth import _csrf_protect,没有注册 app.before_request(_csrf_protect);而 web/auth.py 的 docstring 声称"由 web_server 注册"。
  • 影响:CSRF 防护形同虚设(同网段内可伪造写请求)。
  • 涉及:web_server.py(注册钩子)+ 需要回归所有写接口(前端、脚本、MCP 的 platform_client 都已带 token,风险点是第三方直接调 API)。
  • 验收:注册后所有写接口在缺 token 时返回 403,且前端/MCP 全链路正常。

A5. 前端 --card-line 变量未定义

  • 现象:AI 控制台的会话/经验/动作模态框边框失效(border:1px solid var(--card-line) 解析为无效值)。
  • 原因:该变量只在 templates/admin/wall.html 的 :root 定义,monitor.html 的 :root 里没有,但被引用了 5 处。
  • 涉及:templates/admin/monitor.html(:root 补 --card-line:#232936)。

A6. monitor.js 引用了未定义变量 countParts

  • 现象:进度为 0 的边界分支会抛 ReferenceError(被外层 try/catch 吞掉,用户无感)。
  • 涉及:static/admin/monitor.js(该分支的进度渲染)。

A7. 其它小问题(低优先)

  • static/admin/custom.css 是死文件(无任何引用)。
  • templates/admin/monitor.html 里 .agent-shell 有完全重复的 CSS 声明(后者覆盖前者的 min-height)。
  • 设备表空态 colspan="11" 与实际列数(10)不符。
  • core/device_worker.py 的 _u2_connect_remote 有两个结构相同的 except Exception,后者是死代码。
  • core/ssh_client.py 全项目无人 import(STF_SSH_* 配置也只被它读取);要么接上用途,要么删除。
  • 若干按功能域拆包时留下的重复函数定义:_merged_device_list(web/common.py / apks_api.py / tools_api.py 各一份)、tools_api.py 的三个辅助函数、monitor.py 的屏相关函数、tasks_api.py 的 _job_next_run(各定义两次)。

B. 设备与连接

  • adb 远程终端加「目标切换」(本机 / 220)

    • 背景:终端默认走 .env 的 ANDROID_ADB_SERVER_ADDRESS=192.168.20.220(adb 客户端生效,非本项目代码读取),因此终端里看不到本机 USB 设备。
    • 期望:/api/adb/devices、/api/adb/cmd 支持 target=local|remote;前端 tools.js 加下拉。
    • 涉及:web/tools_api.py、static/admin/tools.js、doc/API.md、doc/DEVELOPMENT.md(配置速查)。
    • 验收:切「本机」能列本机 USB + 已连 IP:5555;切「220」列 220 侧设备;adb cmd 同样生效。
  • .env 的 adb 路由键要在文档里说明(或去掉)

    • ANDROID_ADB_SERVER_ADDRESS/HOST/PORT 会被 .env 注入 os.environ,adb 客户端据此把所有调用指向 220;ANDROID_ADB_SERVER_HOST 是非标准键(adb 不认)。
    • 期望:在配置速查里写明该行为与取舍,或本地去掉这三行改走本机 adb。
  • .gitignore 漏项:data/mcp_audit.log 已补(data/*.log,2026-09-13);data/uiauto.pid 仍未忽略(git status 会显示为未跟踪);data/apks/ 目录无占位文件。

  • 220 的 Tailscale / adb server(5037) 可达性巡检(曾出现连不通超时)。


C. 编辑器 / 元素抓取

  • 未命中要「明确提示」,别混成「执行了这步」

    • 背景(2026-09-10):click/long_click/wait_el/swipe_until/if_el 未命中时只写 [WARNING] ... 未找到元素,前端进度仍按"执行了一步"计数 → 用户看到像"成功",实际没点(db03f16e 案例就是这么误判的)。
    • 期望:执行器把未命中作为该步结果(✗)返回并计入统计;前端标红 ✗ 并给出所用选择器;任务结束汇总未命中步骤数。
    • 涉及:tasks/generic/task.py、static/admin/{tasks,monitor}.js、doc/TASK_DEV.md。
  • 元素抓取超时——部分设备 dump 慢于平台超时

    • 背景(2026-09-10 实测):core/uiauto_helper.py 的 _TIMEOUT=(1,8);某设备 dump ~18s → 平台报「uiauto2 请求超时」,编辑器抓不到元素(设备本身正常)。
    • 期望:读超时提到 (2, 30) + 前端加载中有明确提示;可选"同界面短时缓存"。
    • 涉及:core/uiauto_helper.py、web/tasks_api.py、static/admin/editor.js、doc/ARCHITECTURE.md。
  • 序号型 XPath / 界面就绪 的防呆(2026-09-10 db03f16e 案例)

    • 背景:(//*[@resource-id="…"])[6] 依赖"抓取那一刻该属性有 ≥6 个实例";运行时界面不同(App 仍在闪屏页)→ 序号必然失配。
    • 期望:① open_app 提示勾选「等待首页」;② 抓取器对带序号的选择器加醒目提示(✅ 2026-09-13 已完成,且更进一步:抓取器优先产出语义选择器再去掉序号,见 research/U2_ELEMENT_SELECTORS.md §五);③ 抓取弹窗提醒"请先把设备停在任务运行到该步时的同一界面再抓"。
    • 涉及:core/uiauto_helper.py、static/admin/editor.js、tasks/generic/task.py、doc/TASK_DEV.md。
  • 自定义动作支持 action_ref 引用型节点(现状:拖入画布会展开成 group,改动需同步执行器 + 编辑器)。


D. AI 控制台 / 经验与动作

  • 「🧠 经验库 / 🎬 动作库」合为一个面板(标签页切换)。
  • AI 建任务 P0(✅ 2026-09-13:独立子页「AI 建任务」+ submit_task 校验 + 草稿预览/预填,见 AI_TASK_GEN.md §10)。
    • 仍未做:平台级 MCP 只读清单(task_types/groups/pool)、把动作库当 generic_steps 预制件复用、draft→经验/动作沉淀、「探索完直接创建」接口。
  • 新增 MCP de_screen_text(文本化看屏:前台包名 + screen_state + 可点元素文本 + OCR),并把操作纪律写进工具 description。
  • 经验召回改进:现为 bigram + ORDER BY hits(候选只看 top50、hits 对所有命中行回写 → 马太效应);改为对称相似度 / 更合理候选集,hits 仅在真正注入时 +1。
  • 经验/动作入库依赖模型蒸馏成功:加失败重试与可视化观测(现在只在日志里)。

E. 工程化 / 文档

  • MCP 白名单语义缺口:MCP_ALLOWED_SERIALS 为空时并未按设计限制为"平台设备池内"(当前只校验非空),见 MCP.md;如需收紧需补实现。
  • MCP_DESIGN.md 里的"演进备选"(独立 mcp-server 容器)未落地:已在文中标注,若确定不做可删除该节,避免后续误读。
  • STF 容器状态确认:doc/DEVELOPMENT.md(已停用)与 doc/STF_REMOVAL.md(待人工确认)说法矛盾,需以 220 实际为准后统一。
  • DISCOVERY_SUBNETS 无 env 支持:config.py 里是硬编码列表,其余发现配置走 app_meta;若要支持 .env 覆盖需补实现。

F. 已完成(留档,便于追溯)

  • platform-tools → auto_control 命名统一(2026-09-10:文档/README/scripts/pack.py 产物名)。
  • 删除抖音养号任务类型(douyin_nurture),平台只保留 generic_steps;残留旧类型任务改为启动告警 + 执行时明确报错。
  • generic_steps 去掉默认步骤;空步骤任务执行时明确报错(不再静默空跑)。
  • 重试耗尽时的 last_error 带上真实失败原因(不再只有"重试 N 次失败")。
  • 监控页任务卡去掉「编辑/删除」,只留执行/停用 + 显示覆盖设备。
  • 备份覆盖清单补 agent_action / app_meta + 导出/导入双向自检。
  • AI 控制台:Markdown 渲染、推理链可折叠、token 用量显示。
  • 路由回归脚本 Windows 可用(2026-09-13:signal.alarm 加 hasattr 守卫)+ 新增安全闸: 配置或目标库被标为 prod 时拒绝运行(脚本会发真实写请求,不能拿生产数据做实验)。
  • 数据库从 SQLite 迁到 MySQL:连接层多环境配置 + 防混库校验、schema 收敛到 ORM metadata、 备份/恢复改为「SQLite 归档 + 单事务整库替换」、迁移脚本(2026-09-13)。