From e9e1aa8e0fcd2b1f65a0ab0eb00c70c21745977f Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 12 Sep 2026 12:50:22 +0800 Subject: [PATCH] fix(agent): clarify browser and subagent states --- app/agent/middleware/subagents.py | 4 ++++ app/agent/tools/impl/browse_webpage.py | 9 +++++++-- docs/refactor/agent-codex-parity-plan.md | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/agent/middleware/subagents.py b/app/agent/middleware/subagents.py index 09d26e4d9..b35f48dd4 100644 --- a/app/agent/middleware/subagents.py +++ b/app/agent/middleware/subagents.py @@ -733,8 +733,12 @@ class SubAgentTaskControlMiddleware(AgentMiddleware): "finished_at": _format_datetime(record.finished_at), } if not record.task.done(): + payload["execution_outcome"] = "pending" + payload["recovery"] = "使用 action=wait 或 action=status 继续观察,不要重复启动同一任务。" return payload if record.task.cancelled(): + payload["execution_outcome"] = "failed" + payload["recovery"] = "任务已取消;检查其他任务结果,只有在需要时用新的 task_id 重新派发。" return payload error = record.task.exception() diff --git a/app/agent/tools/impl/browse_webpage.py b/app/agent/tools/impl/browse_webpage.py index 145d9520a..81aa06de6 100644 --- a/app/agent/tools/impl/browse_webpage.py +++ b/app/agent/tools/impl/browse_webpage.py @@ -536,8 +536,13 @@ class BrowseWebpageTool(MoviePilotTool): @staticmethod def _json_response(payload: dict[str, Any]) -> str: - """返回格式化 JSON 字符串""" - return json.dumps(payload, ensure_ascii=False, indent=2) + """返回带明确执行状态的格式化 JSON 字符串。""" + normalized = dict(payload) + if isinstance(normalized.get("success"), bool): + normalized.setdefault( + "execution_outcome", "succeeded" if normalized["success"] else "failed" + ) + return json.dumps(normalized, ensure_ascii=False, indent=2) @staticmethod def _action_goto( diff --git a/docs/refactor/agent-codex-parity-plan.md b/docs/refactor/agent-codex-parity-plan.md index e74605ca7..e3ec50304 100644 --- a/docs/refactor/agent-codex-parity-plan.md +++ b/docs/refactor/agent-codex-parity-plan.md @@ -112,4 +112,5 @@ uv run --locked --no-sync python -m scripts.evaluation \ - CLI 环境复核:现有用户配置把 provider 指向自定义兼容端点,直接追加 `--use-codex-auth` 会被评测入口拒绝。已用隔离的官方 OAuth 配置 `/tmp/moviepilot-codex-official.toml` 重跑,原生模型真实完成 21 次调用,证明 CLI 登录与模型权限正常;`subagent_terminal_share` 仍由原生 `write_stdin failed: Unknown process id` 结束,`thread/read` 也被 app-server 拒绝,故该差异属于终端句柄生命周期,不能通过 CLI 配置或评分器改判通过。 - 生产工具错误合同阶段:`MoviePilotTool` 统一入口现在将浏览器、文件读写和 Shell 等旧工具返回的裸错误转换为 `execution_outcome=failed`、脱敏错误和恢复提示;子代理控制器对失败批次和失败任务同样返回结构化状态及“修正任务描述/参数、不要重复在途任务”的恢复路径。该阶段覆盖 108 项浏览器、文件、Shell、子代理和工具结果回归,下一轮真实场景应验证模型是否利用这些提示完成纠错。 - Shell 会话恢复阶段:一次性命令和后台会话的失败、未知、作用域拒绝、输出游标错误现在都返回对应恢复动作;未知退出状态优先要求读取现有 session,失败命令要求检查 `output/exit_code` 后修正,避免把输出文字当成功或重复启动副作用命令。文件工具的行号与版本冲突保护已在上一阶段验证;本阶段相关回归共 122 项通过。 +- 浏览器与子代理状态阶段:浏览器所有成功/失败 JSON 统一带 `execution_outcome`;子代理任务的 running/cancelled 状态带明确的 `pending/failed` 语义和继续观察、取消后重新派发的恢复建议。当前阶段与文件、Shell、浏览器回归共 112 项通过;真实浏览器仍受用户保存权限限制,子代理终端共享仍需原生句柄闭环。 - 浏览器环境复核:启动本机 Chrome 后用同一官方 OAuth 配置重跑 `/tmp/moviepilot-agent-round-luna-oauth-native-browser-chrome-20260912.json`,原生已加载 Browser plugin、node_repl 并选择 Chrome;真实回环导航仍被保存的浏览器权限拒绝。该结果排除了“CLI 未登录或未启动 Chrome”的解释,下一次只有在用户允许对应回环地址后才继续导航、点击和 oracle 配对。