Files
sorrow404null bc0b92bcdc docs: add agent handoff docs, verification guide, and repair evidence
Add docs/agent-handoff (backlog, execution state, verification, platform plan, per-task evidence), repo AGENTS.md, and architecture notes updated for the dual-renderer design.
2026-09-17 16:40:06 +08:00

75 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P1-02 证据:Windows/Linux shell 与进程树终止
日期:2026-07-09(无人值守轮次)
状态:**完成(Windows 侧自动化全绿;Linux 侧逻辑已实现并单测覆盖参数/提示词,进程组用例在 Linux 上运行时生效)**
## 目标(摘自 REPAIR_BACKLOG.md
- Windows 明确通过 `cmd.exe` 执行;Linux 明确通过 `/bin/bash -lc` 执行,不依赖 `shell=True` 的平台默认值。
- 超时与主动中止都终止完整子进程树(Windows `taskkill /F /T`Linux 独立 POSIX 进程组,SIGTERM→宽限→SIGKILL 整组)。
- 只保留一份通用 `SYSTEM_PROMPT.md`,运行时插入**短**平台 shell/path 段;两平台互不串段。
- 保留输出流、超时、截断、工具结果结构;不加命令审批/沙箱/路径限制。
## 改动文件
| 文件 | 改动 |
|---|---|
| `core/platform_shell.py` | **新增**窄平台适配:`shell_command()``popen_flags()``kill_process_tree()``shell_prompt_section()``apply_platform_section()`、占位符 `{{SHELL_PLATFORM_SECTION}}` |
| `core/agent/tools.py` | `tool_bash` 的 Popen 改 `shell_command(command) + popen_flags()``_kill_tree` 委托 `kill_process_tree`;移除 `ctx["shell"]` 隐式开关 |
| `core/llm_engine.py` | `load_system_prompt()` 读文件后过 `apply_platform_section()`(每次请求仍重读,既有行为不变) |
| `SYSTEM_PROMPT.md` | 通用正文化:第 1 节去 Windows 路径/conda 环境名;原 1.1「shell 真相」cmd 表整体移入运行时 Windows 段;工具表与 3.2 去掉 `cmd.exe`/`dir`/`findstr` 字样;占位符落在原 1.1 位置 |
| `tests/test_cross_platform_shell.py` | **新增** 20 项断言(A 平台参数 / B 提示词 / C 进程树 / D 安全边界) |
## 关键设计决策
1. **Windows 用字符串命令行,不用 argv 列表。**
`["cmd.exe","/d","/c",cmd]` 列表形态会被 CPython `list2cmdline` 把内部引号转义成 `\"`cmd 不认,
带引号路径直接 `'...\python.exe"' is not recognized`(实测复现)。最终契约:
`cmd.exe /d /s /c "<command>"` 作为**字符串**交给 CreateProcessWcmd 按 /s 规则解析 /c 参数
(外层引号剥离、内部引号保留)。实测矩阵:引号 Python 路径 `rc=0``echo a && echo b` 正确;
`%USERPROFILE%` 展开;`;`/单引号行为与旧文档一致。
注:旧 `shell=True` 之所以能跑,是因为 CPython 对带引号程序名直接 CreateProcess(不经 cmd);
新契约统一显式过 cmd,行为更可预测且与提示词一致。
2. **POSIX 安全不变量**`kill_process_tree` 仅当 `os.getpgid(pid) == pid`(确认 `start_new_session`
生效、子进程是组首)才 `killpg`,否则退化单进程 `kill`,绝不误杀调用方所在组。
流程:SIGTERM 整组 → 轮询至 `grace_s=3.0s` → SIGKILL 整组。
3. **提示词单一来源**`SYSTEM_PROMPT.md` 唯一;`apply_platform_section` 只做占位符替换,
无占位符(兜底提示词)原样返回。`load_system_prompt()` 每请求重读 → 平台段永远对应当前平台。
## 验证结果(本机 Windows 11 x64CPython 3.10.21,全部显式超时)
| 命令 | 结果 |
|---|---|
| `python tests/test_cross_platform_shell.py` | **20/20 PASS**EXIT=0 |
| `python tests/test_bash_stream.py` | **30/30 PASS**EXIT=0 |
| `python tests/test_tool_params.py` | **35/35 PASS**EXIT=0 |
| `python tests/run_tests.py`agent core,含 test_agent_core | **41/41**EXIT=0 |
| `python tests/smoke_mode.py`(完整 agent 回合,走 tool_bash | ALL PASSEXIT=0 |
| P0-03 一致性检查(AGENTS.md 指针 / ARCHITECTURE 历史资料标记 / 无第三方任务书正文) | 3/3 PASS |
### 测试点明细(test_cross_platform_shell.py
- **A 平台参数**Windows 命令 == `cmd.exe /d /s /c "echo hi"`Linux argv == `["/bin/bash","-lc","echo hi"]`
Linux `popen_flags() == {"start_new_session": True}`Windows 为空。
- **B 提示词**:通用正文含占位符且无平台泄漏(无 `cmd.exe`/`/bin/bash`);Windows 段含 `cmd.exe`
`/bin/bash`,Linux 段反之;替换后通用正文逐字节相同(B6);`load_system_prompt()` == 文件+当前平台段。
- **C 进程树(真实进程,父挂 30s + 孙每 0.2s 写心跳文件)**:
- C1 超时 3s → 错误结果含「超时」,耗时 <15s,**父与孙都不存在**(心跳静默 >0.6s 且无完成标记);
- C2 主动中止 1.5s → 错误结果含「中止」,**父与孙都不存在**;
- C3 Linux 独立进程组(Windows 上 SKIP`pgid==pid` 断言 + killpg 后子进程消失,Linux 运行即生效)。
- **D 安全边界**:已退出进程、`None` 输入均不抛异常。
### 调试过程记录(铁律:所有调试命令显式超时)
1. 首跑 C1 失败:`'...\python.exe"' is not recognized` → 定位为 `list2cmdline` 引号转义;
读 CPython 3.10 `subprocess.py` 确认 `shell=True` 实为直接 CreateProcessW(带引号程序名不经 cmd)。
2. 尝试 `["cmd.exe","/d","/s","/c", '"'+cmd+'"']` 列表 → 仍失败(同样被转义)。
3. 改**字符串**命令行 + 实测矩阵(引号路径/&&/管道/%VAR%)→ 全过,定稿。
4. 首跑进程树用例 `hb_last=None`:父脚本模板漏传 `child.py` 脚本路径(把心跳路径当脚本)→
手动 `subprocess.run` 复现(超时 6s/3s 探针)→ 修模板,20/20 通过。
## Linux 侧待办(不阻塞本任务)
- 在 Linux 环境跑一次 `python tests/test_cross_platform_shell.py`C3 生效)+ `test_bash_stream.py`
即可闭环;代码路径与 Windows 共用同一套 `kill_process_tree`/`shell_command` 分派。