跳转至

Web 控制台

本地 Web 控制台(NiceGUI)用于实时监看与操控,是可选观察层:不启动它,CLI / headless 用法的全部 机制不受影响。启动:

.venv/bin/python -m phone_agent.web --device-id "$SERIAL" --port 8080

默认地址是 http://127.0.0.1:8080。CLI 只有 --device-id / --model(模型 ID,等价 PHONE_AGENT_MODEL)/ --port 三个参数;监听地址固定在 127.0.0.1,没有 --host。

控制台默认只监听 127.0.0.1;任务由独立 runner 子进程执行,页面通过 PHONE_AGENT_RUNS_DIR 下每个 run 目录的 追加式文件观察(读写方向见下)。重启后只有仍存活的任务会被重连;已有终局 run_end 的 run 目录既不回放也不展示。

投影边界

控制台是纯观察层,边界如下:

边界 契约
设备与工具 Web 进程不持有设备访问、不执行工具、不做工作流路由;通过 PHONE_AGENT_RUNS_DIR 下每个 run 目录的文件监督任务——读 events.jsonl 投影状态,写 spec.json 与 runner.pid,向 control.jsonl 追加 stop / hitl 指令(runner 读);终局正常由 runner 写,Web 只在 runner 无法自己收尾时补写(见「终局合成」)
浏览器出站 浏览器只收到投影后的事件,收不到 API key、认证头或完整配置
被动读取 App-KB 表的定时刷新只读 kb.json 快照:文件缺失、不可读或顶层不是列表时显示空表,坏行跳过;不构造 store、不重放、不改写、不触碰文件。手动整理(「立即整理」按钮)是用户显式操作,会构造 store 并写回快照
状态推进 状态只由真实事件推进:已请求停止 是中间态,不等于已停止;只有终局 run_end 才转为结束态
模型身份 首选模型 只来自实际发出的请求绑定,实际模型 只取 provider 返回的元数据;缺失显示「未上报」,绝不用首选或配置的备用名顶替
参考帧 帧按事件自带的 reference / screen_ref 标记判定为参考帧并标注「参考帧未验证」,不靠帧序缺失推断;各帧保留独立身份,不互相覆盖、不冒充新观测
配置抽屉 设备 serial 留空或纯空白 = 显式自动(解析为 None 后进入序列化与指纹);省略该 override 才继承环境变量
终局合成 runner 启动失败 / runner 死亡 / 重连到无终局的死 run:Web 进程合成终局 run_end(error: runner_start_failed / error: runner_died)并同步写 run.json
裁决字段 run.json 的 finish_verifier(pass / fail / skipped)与 finish_verifier_verdict(approve / status / reason / latency_ms / usage,未产出裁决时为 null)由 runner 在终局写入:验收器已把 reason 脱敏并截断,控制台只从 run.json 读 usage,不渲染裁决,也不替它解读
App-KB generation run spec 的可选 generation 以显式 generation / version 标识,否则取内容摘要;run 启动时发现漂移只写一条 memory_generation_drift 审计事件(captured / actual),绝不阻止启动

布局

固定顶栏(品牌、运行状态、设置、演示标识)+ 视口高度内的两栏工作台:

区域 内容
顶栏(52px) 品牌与一句说明、当前运行状态 pill(含“在等什么”的提示)、设置抽屉入口;演示标识只是一个小 badge,只出现在 fake 预览页
设备栏(336px) 当前画面按剩余视口高度等比 contain 完整显示;下方一条紧凑历史缩略条,只渲染最近 14 帧
右栏 紧凑 composer(多行任务、运行/停止)+ 一行运行元数据 + 次级页签工作区

桌面整页不滚动(重内容各自区域内滚动),最大宽度约 1440px 居中;窄屏回落为单列自然滚动。

右栏页签

页签 内容
步骤 顶部“当前步骤”窄条只在该 running 步骤已带工具或回执时出现,模型调用在途期间隐藏;历史每步含状态图标、意图、工具/目标芯片与耗时,展开看参数、回执与耗时拆分;模型收尾的伪步骤显示“模型收尾”与“收尾”徽标;有截图的步骤可把左侧画面钉到该步;顶部另有一行按角色拆分的 token 用量条;启用模型流式时上方出现“模型流式输出”面板
任务板 TaskDoc 结构化渲染:目标、路线项(状态图标 + 证据)、最近步骤流程线
应用库 App-KB 条目表(名称/包名/类型/成功/状态;类型映射 设备/别名/学习/用户,状态显示 有效/已失效);定时刷新只读 kb.json 快照,不构造 store、不写回;「立即整理」按钮做手动整理
记忆 能力状态(生效/影子/关闭/待岗,缺依赖时附「缺 …」)、回想统计(任务档案/回想评估/Hit@1/污染率/卡片抑制/规则抑制)与当前回想模式、历次任务档案表
产出 agent 写出的 HTML 文档列表(攻略/计划/报告):沙箱预览、新窗口打开、删除(仅用户可操作,需确认);列表由 /api/deliverables 提供,删除走独立路由

状态与真实性

运行状态只由真实事件推进,待命/结束与中间态不靠动画伪装:

状态 含义
启动中 / 运行中 运行进程拉起中 / 模型已返回、正在处理;两者都是活动态
等待模型调用返回 请求在途;界面只写“网络 / 队列 / 推理无法区分”,不把它说成网关纯推理耗时
执行工具 工具正在设备上执行
等待人工 HITL 横幅出现在主要工作区顶部(不是页尾),原文显示问题,可输入或同意/拒绝
已请求停止 软停止请求已发出但尚未收到终局事件;不会冒充“已停止”,收到终局才转为结束态
待命 / 已完成 / 未完成 / 已接管/停止 / 预算耗尽 / 保险丝触发 / 运行错误 状态 pill 的全部标签;终局只由 run_end 决定,界面不另行渲染原因文本(result.reason 只参与渲染去重)
  • 模型身份:“首选模型”来自实际发出的请求绑定;“实际模型”只取 provider 返回的元数据,缺失时显示 未上报,绝不用首选或配置的备用名顶替。
  • 参考图:帧带 reference / screen_ref 标记即标注“参考帧未验证”(判定不靠帧序缺失);多个参考帧各有独立 身份,不互相覆盖,也不冒充新观测。
  • 可选记忆:App-KB 快照按内容(显式 generation/version,否则内容摘要)标识;run 启动时发现漂移只写 一条 memory_generation_drift 审计事件(captured/actual),绝不阻止手机任务。
  • 模型流式(PHONE_AGENT_STREAMING 默认 off,抽屉可覆盖;调用侧契约见配置参考): 增量显示模型正文与 SDK 上报的推理文本(Responses 的 summary_text、Anthropic 的 thinking、reasoning_content), 没有上报就不编造。面板默认跟随最新尝试,点历史尝试芯片即钉住并出现“回到最新”按钮;新 run 清空并隐藏旧面板。每次 尝试(首选与备用调用)各有独立身份:失败/中断的尝试保留已收到的部分文本并标注“中断 + 原因”,绝不把备用文本拼进 首选半截回复,备用是否流式由备用自身的声明决定。实时头部显示“尝试 a · 第 s 步 · N 字”,正文只留末尾 2400 字、 每次尝试最多 20000 字、同时保留最近 6 次尝试,截断时另注“仅显示末尾 2400 字(已接收 N 字)”,完整文本以最终消息为准。 抽屉开关显示的是生效值:模型条目/roles.actor.streaming 覆盖开关时会明确提示,不会出现开关写 off 而实际仍在流式。
  • 一行元数据收敛 run id、首选/实际模型、token、已持续与最近事件时间;不为每个字段做大卡片。

操控

操作 行为
运行 多行任务目标;Ctrl / ⌘ + Enter 运行,单独回车换行,避免多行任务误提交
停止 软停止:向当前 run 发送停止请求,页面提示“已请求停止(等待当前调用/步骤返回后收尾)”;runner 让当前步收尾,run 以 takeover 终局结束
人工中断 ask_user / take_over / hard 档确认时横幅置顶,原文显示问题,输入框回车即提交,或点同意/拒绝
历史钉选 点击缩略图钉住该帧,再点一次、或点设备栏标题右侧的无文字定位图标按钮(my_location)恢复跟随;带文字的「回到最新」按钮只出现在模型流式面板,两者都只在已钉住时可见
配置抽屉 下一轮运行的覆盖配置:设备 serial / 主模型 / 备用模型 / 安全模式 / 语言 / 最大步数(保险丝)/ Token 预算 / Grounding / App-KB 记忆 / 模型流式;只对下一轮运行生效,不写回 .env;模型流式一项显示生效值与来源(模型/角色声明可覆盖开关);设备 serial 留空/纯空白 = 显式自动(不继承 .env 的 serial);抽屉下方另有只读的「当前生效」区(脱敏后的网关地址、图片保留张数与 compact 比例)与「恢复默认」按钮

浏览器只接收投影后的事件,不发送 API key、认证头或完整配置。

本地合成预览

scripts/fake_console_preview.py 提供隔离的合成预览:只使用内存状态、生成的安卓风格画面与临时产物目录, 不构造真实 bridge / runner / 设备 / 模型客户端 / 记忆存储;状态切换入口藏在小 badge 的菜单里, 不占用工作台。用于本地看版式,不作为真实运行证据。

.venv/bin/python scripts/fake_console_preview.py --root /tmp/tw-console-preview --port 8091

另见回放面。

回放面

同一次 run 的四个观侧面:

  • trace:每次 run 的脱敏事件流落 .traces/<run_id>.jsonl(64 字截断、敏感子串脱敏、base64 不落盘);语义见 Trace 与脱敏。
  • 经验 replay:phone_agent/v2/replay.py 离线重放 episode 日志,评估先例通道三闸与过程卡指标:
.venv/bin/python -m phone_agent.v2.replay --channel exemplar

语义见通道离线评估(replay)。 - 合成控制台预览:纯内存 FakeBridge 合成画面,不触设备/模型/记忆;命令见本地合成预览。 - 真机诊断回放:.agents/skills/phone-agent-live-diagnosis/SKILL.md 把真机 run 渲染为离线中文 HTML 回放与证据包;下列命令为离线冒烟入口(合成数据,不代表真机能力):

.venv/bin/python .agents/skills/phone-agent-live-diagnosis/scripts/run_diagnosis.py dry-run

验收说明

  • 本页描述的是用户手动看版式后接受的界面(2026-09-10,基于 fake 预览)。
  • 验收按手动结论填写,不要求浏览器自动化截图;公开页不使用真实设备或账号画面。
  • 控制台只在 fake 预览与合成数据上验证,未在真机上运行;真机行为以 live-diagnosis 流程结果为准。