通读 @/Users/pencil/Desktop/learning cluade code/coding agent/ 包之后,按"严重 → 一般"列出真正影响功能/正确性的问题(不算注释和命名风格)。
严重 Bug
1. auto_compact 会丢掉 system prompt
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/agent.py:14-18:
microcompact(messages)
if estimate_tokens(messages) > TOKEN_THRESHOLD:
print("[auto-compact triggered]")
auto_compact 返回的是 [{"role": "user", ...}],messages[:] = auto_compact(messages) 之后 system 消息不见了 。main.py 用 /compact 时是 [history[0]] + compressed,自动触发的这条路径却没保留 system,下一轮起 Lead 就失去身份与技能描述。
修复 :跟 main.py 一样把 messages[0] 单独拎出来保留。
2. plan_approval 协议是断的
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/protocols.py:6 定义了 plan_requests = {},但 整个代码库里没有任何地方往里写 。队员侧没有 submit_plan 工具、Lead 也不会从 inbox 抽出 plan 提交事件登记到这个表。结果 plan_approval 工具永远只能回 Error: Unknown plan request_id。
3. run_bash 黑名单形同虚设
上一轮已经提过:只挡 rm -rf / 这一种文本,rm -r /...、rm -rf ./xx、find -delete 全能绕过。run_write/_edit 走 safe_path,但 run_bash 没做任何路径限制。
4. 多线程 race condition
任务认领 :@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/team.py:185-193 多个 idle 队员同时扫到同一条 pending 任务,unclaimed[0] + claim 之间没有原子检查 → 同一个 task 可能被两个队员都标成 in_progress,owner 互相覆盖。
邮箱 :@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/messaging.py:33-35 read_text() 和 write_text("") 之间投递的新消息会被一起清掉、彻底丢失。
TaskManager._load → 改 → _save 也没有锁。
修复 :在 TaskManager.claim 里用 threading.Lock 包住"读 → 校验 owner 仍为空 → 写";MessageBus 类似(最简单:用 os.rename 把邮箱移走再读)。
5. WORKDIR = Path.cwd() 依赖启动目录
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/config.py:11。.tasks/、.team/、.transcripts/、skills/ 都挂在 cwd 上。在 coding agent/ 里跑和在仓库根跑会得到两套完全不同的状态目录,已有的看板/邮箱/技能都"看不见"。模块化项目应该锚到 Path(__file__).resolve().parent.parent.parent 这种相对包的固定根。
中等问题
6. registry.py 顶层副作用过强
import coding_agent.registry 就会立刻 TaskManager()/MessageBus()/TeammateManager()/SkillLoader(),触发 mkdir 与磁盘扫描。任何想单独 import 某个工具/做单测都被迫创建一堆目录。建议改成懒加载工厂或 get_registry()。
7. microcompact 只清 tool 消息,不清 assistant 的 tool_calls
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/compression.py:21-29。如果 LLM 一次性 write_file 写大文件,巨量内容是塞在 assistant 消息的 tool_calls[].function.arguments 里——这块永远不会被清。"微压缩"对真实场景下最大的体积来源没作用。
8. BUS.send 不校验 msg_type
config.py 定义了 VALID_MSG_TYPES,并在 send_message 工具的 schema 里 enum 限制;但 MessageBus.send 自身没校验,protocol 层任意字符串都能写进 JSONL。LLM 拼错或恶意自定义 type 不会报错,导致下游消费方分支走漏。
9. assistant_msg.model_dump(exclude_unset=True) 兼容性坑
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/agent.py:35 与 team.py:125、subagent.py:76 都这么写。exclude_unset=True 在很多 OpenAI 兼容网关(DeepSeek/Qwen/Doubao 等)下会让 content=None 字段直接消失,下一轮请求被网关判 400 "missing content"。更稳的写法:
messages .append ({
"role" : "assistant" ,
"content" : assistant_msg .content ,
"tool_calls" : [tc .model_dump () for tc in assistant_msg .tool_calls or []] or None ,
})
或者干脆 model_dump() 不加 exclude_unset。
10. 队员永远不会触发自身压缩
team.py._loop 没有调 microcompact / auto_compact,但 @/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/team.py:195 又靠 len(messages) <= 4 来判断"是否被压缩过"决定是否重注入身份。这段身份重注入逻辑在当前实现里永远走不进 ,等于死代码。要么给队员也接上压缩,要么删掉这个判断。
11. run_subagent 30 轮 + 截断细节
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/subagent.py:67-100:
子代理整 30 轮都只调工具不出文本,last_text 始终为空,最后只能返回 (no summary)。建议在跑满时主动追一句 "Please summarize what you did." 再调一次 LLM。
out = h(**args) 之后再 str(out)[:50000],但 h 抛 KeyError/TypeError(args 缺字段)会冒到外层 except 变成 Error: ...,这是 OK 的;但 str(out) 是按 50000 字符截,比 base.py 的 50000 已经做过的截多一层,浪费但无害。
小问题
init .py 的 __all__ = ["agent", "config", ...] 只对 from coding_agent import * 有意义,模块名就在那放着,作用很弱。
run_edit 只替换首个匹配但不告诉调用方"还存在多少处未替换",LLM 可能误以为已全替换。
TaskManager.list_all 用 [✓],TodoManager 也用 [✓],但你 tasks.py 里写的是 [x](在 step_full.py 老版本里也用 [x])—— 注意你贴的 tasks.py 是 [✓],看你想统一成哪个。
compress 工具 handler 返回 "Compressing...",但真正压缩在 for 循环结束后异步进行;LLM 看到的工具结果其实没意义,可以直接在 handler 里返回 "Will compress after this turn." 让模型清楚状态。
建议优先级
ascii -> mermaid #1 system prompt 丢失 (一压缩就废)
Add navigation links to skills mechanism documentation #4 race condition (多队员场景必现)
Add uv support to README files #5 WORKDIR (不同目录跑数据完全分裂)
Update navigation links in v3-subagent-mechanism.md #3 / Fix bug and improve error handling in todo agent #8 安全/校验
Update SKILL.md #2 plan 协议 (功能死链路,要么补完要么删工具)
其他按需
要我先把 #1 / #5 这两个最致命的修了吗?
通读
@/Users/pencil/Desktop/learning cluade code/coding agent/包之后,按"严重 → 一般"列出真正影响功能/正确性的问题(不算注释和命名风格)。严重 Bug
1. auto_compact 会丢掉 system prompt
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/agent.py:14-18:auto_compact 返回的是
[{"role": "user", ...}],messages[:] = auto_compact(messages)之后 system 消息不见了。main.py 用/compact时是[history[0]] + compressed,自动触发的这条路径却没保留 system,下一轮起 Lead 就失去身份与技能描述。修复:跟 main.py 一样把
messages[0]单独拎出来保留。2. plan_approval 协议是断的
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/protocols.py:6定义了plan_requests = {},但 整个代码库里没有任何地方往里写。队员侧没有submit_plan工具、Lead 也不会从 inbox 抽出 plan 提交事件登记到这个表。结果plan_approval工具永远只能回Error: Unknown plan request_id。3. run_bash 黑名单形同虚设
上一轮已经提过:只挡
rm -rf /这一种文本,rm -r /...、rm -rf ./xx、find -delete全能绕过。run_write/_edit走 safe_path,但 run_bash 没做任何路径限制。4. 多线程 race condition
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/team.py:185-193多个 idle 队员同时扫到同一条 pending 任务,unclaimed[0]+ claim 之间没有原子检查 → 同一个 task 可能被两个队员都标成in_progress,owner 互相覆盖。@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/messaging.py:33-35read_text()和write_text("")之间投递的新消息会被一起清掉、彻底丢失。TaskManager._load → 改 → _save也没有锁。修复:在 TaskManager.claim 里用
threading.Lock包住"读 → 校验 owner 仍为空 → 写";MessageBus 类似(最简单:用os.rename把邮箱移走再读)。5.
WORKDIR = Path.cwd()依赖启动目录@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/config.py:11。.tasks/、.team/、.transcripts/、skills/都挂在 cwd 上。在coding agent/里跑和在仓库根跑会得到两套完全不同的状态目录,已有的看板/邮箱/技能都"看不见"。模块化项目应该锚到Path(__file__).resolve().parent.parent.parent这种相对包的固定根。中等问题
6. registry.py 顶层副作用过强
import
coding_agent.registry就会立刻 TaskManager()/MessageBus()/TeammateManager()/SkillLoader(),触发mkdir与磁盘扫描。任何想单独 import 某个工具/做单测都被迫创建一堆目录。建议改成懒加载工厂或get_registry()。7. microcompact 只清 tool 消息,不清 assistant 的
tool_calls@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/compression.py:21-29。如果 LLM 一次性write_file写大文件,巨量内容是塞在 assistant 消息的tool_calls[].function.arguments里——这块永远不会被清。"微压缩"对真实场景下最大的体积来源没作用。8. BUS.send 不校验
msg_typeconfig.py 定义了
VALID_MSG_TYPES,并在send_message工具的 schema 里 enum 限制;但 MessageBus.send 自身没校验,protocol 层任意字符串都能写进 JSONL。LLM 拼错或恶意自定义 type 不会报错,导致下游消费方分支走漏。9.
assistant_msg.model_dump(exclude_unset=True)兼容性坑@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/agent.py:35与team.py:125、subagent.py:76都这么写。exclude_unset=True在很多 OpenAI 兼容网关(DeepSeek/Qwen/Doubao 等)下会让content=None字段直接消失,下一轮请求被网关判 400 "missing content"。更稳的写法:或者干脆
model_dump()不加exclude_unset。10. 队员永远不会触发自身压缩
team.py._loop 没有调
microcompact / auto_compact,但@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/team.py:195又靠len(messages) <= 4来判断"是否被压缩过"决定是否重注入身份。这段身份重注入逻辑在当前实现里永远走不进,等于死代码。要么给队员也接上压缩,要么删掉这个判断。11. run_subagent 30 轮 + 截断细节
@/Users/pencil/Desktop/learning cluade code/coding agent/coding_agent/tools/subagent.py:67-100:last_text始终为空,最后只能返回(no summary)。建议在跑满时主动追一句"Please summarize what you did."再调一次 LLM。out = h(**args)之后再str(out)[:50000],但h抛KeyError/TypeError(args 缺字段)会冒到外层 except 变成Error: ...,这是 OK 的;但str(out)是按 50000 字符截,比 base.py 的 50000 已经做过的截多一层,浪费但无害。小问题
__all__ = ["agent", "config", ...]只对from coding_agent import *有意义,模块名就在那放着,作用很弱。[✓],TodoManager 也用[✓],但你 tasks.py 里写的是[x](在 step_full.py 老版本里也用[x])—— 注意你贴的 tasks.py 是[✓],看你想统一成哪个。compress工具 handler 返回"Compressing...",但真正压缩在 for 循环结束后异步进行;LLM 看到的工具结果其实没意义,可以直接在 handler 里返回 "Will compress after this turn." 让模型清楚状态。建议优先级
要我先把 #1 / #5 这两个最致命的修了吗?