fix: switch copaw-worker runtime entrypoint to qwenpaw#950
Conversation
📊 CI Metrics ReportSummary
By Role
Per-Test Breakdown
Trends✅ 1 test(s) improved (fewer LLM calls) Generated by HiClaw CI on 2026-07-07 17:48:55 UTC |
|
这个迁移方向是合理的,但当前实现还有几个合并前需要补齐的运行时接线问题。
建议二选一:
Dockerfile 已经把 Matrix channel 覆盖到
PR 描述里说 TeamHarness adapter 会调用
现在用的是
这个 PR 修改了 另外,CI 评论里有旧提交上的集成测试失败,以及 最后,@maplefeng-a 也在做相关的工作,可以看看是否存在逻辑上不一致的地方。 This migration direction is reasonable, but the current implementation still has several runtime wiring issues that need to be patched before merging.
It is recommended to choose one of the two:
The Dockerfile has overwritten the Matrix channel to
The PR description says that the TeamHarness adapter will call
Currently,
This PR modifies the content that will enter the image under In addition, there are integration test failures on old commits in the CI comments, and the token/call of Finally, @mapplefeng-a is also doing related work to see if there are any logical inconsistencies. |
1. Working dir: export QWENPAW_WORKING_DIR alongside COPAW_WORKING_DIR so qwenpaw.constant resolves the runtime dir without relying on legacy COPAW_ fallback alone. 2. Dockerfile: add qwenpaw CLI symlink to PATH for TeamHarness adapter compatibility. 3. bridge.py: change agents.profiles injection from shallow setdefault() to nested merge. Previously, if config.json already had an 'agents' key, profiles/active_agent/workspace_dir were not injected. Now each sub-key is setdefault'd individually. 4. chanhelog: add PR agentscope-ai#950 entries for copaw/ image-affecting changes. Note on Matrix config overlay: the maintainer asked about potential inconsistency between the config.py overlay (copied to copaw/config/) and qwenpaw.config.config. Analysis confirms no inconsistency: - Matrix channel.py (overlaid to qwenpaw/app/channels/matrix/) does not import from config.py at all — it only depends on BaseChannel and agentscope_runtime, both available via the dual fallback. - The HiClaw config overlay (copaw/src/matrix/config.py) adds HiClaw-specific channel types to copaw.config.config and is only needed by copaw.app. qwenpaw.app loads qwenpaw.config.config (its own module), and the channel layer is config-agnostic.
maplefeng-a
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. I checked the latest head, and this PR still has conflicts with main (copaw/Dockerfile, copaw/scripts/copaw-worker-entrypoint.sh, copaw/src/copaw_worker/bridge.py, and copaw/src/copaw_worker/worker.py).
Please rebase or merge main and resolve those conflicts first. Once the branch is clean again, I can continue the code review on the updated diff.
我看了最新 head,目前这个 PR 仍然和 main 有冲突,涉及 copaw/Dockerfile、copaw/scripts/copaw-worker-entrypoint.sh、copaw/src/copaw_worker/bridge.py 和 copaw/src/copaw_worker/worker.py。
请先 rebase 或 merge main 并解决冲突;分支干净后我再继续基于最新 diff 做代码 review。
1. Working dir: export QWENPAW_WORKING_DIR alongside COPAW_WORKING_DIR so qwenpaw.constant resolves the runtime dir without relying on legacy COPAW_ fallback alone. 2. Dockerfile: add qwenpaw CLI symlink to PATH for TeamHarness adapter compatibility. 3. bridge.py: change agents.profiles injection from shallow setdefault() to nested merge. Previously, if config.json already had an 'agents' key, profiles/active_agent/workspace_dir were not injected. Now each sub-key is setdefault'd individually. 4. chanhelog: add PR agentscope-ai#950 entries for copaw/ image-affecting changes. Note on Matrix config overlay: the maintainer asked about potential inconsistency between the config.py overlay (copied to copaw/config/) and qwenpaw.config.config. Analysis confirms no inconsistency: - Matrix channel.py (overlaid to qwenpaw/app/channels/matrix/) does not import from config.py at all — it only depends on BaseChannel and agentscope_runtime, both available via the dual fallback. - The HiClaw config overlay (copaw/src/matrix/config.py) adds HiClaw-specific channel types to copaw.config.config and is only needed by copaw.app. qwenpaw.app loads qwenpaw.config.config (its own module), and the channel layer is config-agnostic.
3014704 to
9911d12
Compare
… logging (agentscope-ai#950) - Replace qwenpaw health API (false positive: token check != sync complete) with Matrix /_matrix/client/v3/joined_rooms polling in background task. Marker file written when >= 1 room joined → true readiness signal. - Add logger output to build_worker_readiness() model check to eliminate diagnostic blind spot (previously model check was silent during probes). - test-helpers.sh: print last readyz JSON on probe timeout; increase docker logs --tail from 100 to 200 to preserve startup diagnostics.
833b17c to
59782d5
Compare
… logging (agentscope-ai#950) - Replace qwenpaw health API (false positive: token check != sync complete) with Matrix /_matrix/client/v3/joined_rooms polling in background task. Marker file written when >= 1 room joined -> true readiness signal. - Add logger output to build_worker_readiness() model check to eliminate diagnostic blind spot (previously model check was silent during probes). - test-helpers.sh: print last readyz JSON on probe timeout; increase docker logs --tail from 100 to 200 to preserve startup diagnostics.
1. Working dir: export QWENPAW_WORKING_DIR alongside COPAW_WORKING_DIR so qwenpaw.constant resolves the runtime dir without relying on legacy COPAW_ fallback alone. 2. Dockerfile: add qwenpaw CLI symlink to PATH for TeamHarness adapter compatibility. 3. bridge.py: change agents.profiles injection from shallow setdefault() to nested merge. Previously, if config.json already had an 'agents' key, profiles/active_agent/workspace_dir were not injected. Now each sub-key is setdefault'd individually. 4. chanhelog: add PR agentscope-ai#950 entries for copaw/ image-affecting changes. Note on Matrix config overlay: the maintainer asked about potential inconsistency between the config.py overlay (copied to copaw/config/) and qwenpaw.config.config. Analysis confirms no inconsistency: - Matrix channel.py (overlaid to qwenpaw/app/channels/matrix/) does not import from config.py at all — it only depends on BaseChannel and agentscope_runtime, both available via the dual fallback. - The HiClaw config overlay (copaw/src/matrix/config.py) adds HiClaw-specific channel types to copaw.config.config and is only needed by copaw.app. qwenpaw.app loads qwenpaw.config.config (its own module), and the channel layer is config-agnostic.
… logging (agentscope-ai#950) - Replace qwenpaw health API (false positive: token check != sync complete) with Matrix /_matrix/client/v3/joined_rooms polling in background task. Marker file written when >= 1 room joined -> true readiness signal. - Add logger output to build_worker_readiness() model check to eliminate diagnostic blind spot (previously model check was silent during probes). - test-helpers.sh: print last readyz JSON on probe timeout; increase docker logs --tail from 100 to 200 to preserve startup diagnostics.
e69bcea to
b791cd6
Compare
9898301 to
9bd3cb2
Compare
Worker changes: - copaw/Dockerfile: install qwenpaw after copaw-worker (standard venv) - entrypoint.sh: set QWENPAW_WORKING_DIR for qwenpaw config path - worker.py: switch copaw.app._app → qwenpaw.app._app (console + headless) - bridge.py: inject agents.profiles into config.json (required by qwenpaw) - matrix_channel.py: dual fallback — try qwenpaw BaseChannel first, then copaw - health.py: update docstring reference Manager changes: - Dockerfile.copaw: install qwenpaw after copaw-worker overlay (agentscope 1.0.20) - start-copaw-manager.sh: export QWENPAW_WORKING_DIR + launch python3 -m qwenpaw app CI health check changes: - test-helpers.sh: pgrep checks for 'copaw app' OR 'qwenpaw app' - test-01-manager-boot.sh: same dual pgrep pattern
87e6087 to
b3d1e5b
Compare
…e, qwenpaw symlink - changelog/current.md: add copaw→qwenpaw migration entry - copaw/Dockerfile: ln -sf qwenpaw to /usr/local/bin for CLI PATH - bridge.py: nested setdefault merge for agents.profiles (handle partially-populated blocks instead of only top-level setdefault)
The worker Dockerfile has two venvs: standard (console mode) and lite (headless mode, default when no CONSOLE_PORT is set). Both worker.py code paths (_run_copaw_with_console and _run_copaw_headless) now import from qwenpaw, but qwenpaw was only installed in the standard venv. Lite mode would crash with ImportError on startup. CI only tests standard mode (with console port), so this bug was invisible in CI. Production Workers without console ports would be affected.
HiClaw copaw→qwenpaw 全量迁移
一、本质HiClaw Docker 镜像里装着两套框架: 不是"升级 copaw",是换框架。 二、PR #950 改动清单11 文件,+90/-23 行。
Worker 侧(6 文件)
Manager 侧(2 文件)
CI 侧(2 文件)
三、关键架构决策3.1 为什么
|
| venv | 触发条件 | worker.py 入口 |
|---|---|---|
/opt/venv/standard |
HICLAW_CONSOLE_PORT 已设置 |
_run_copaw_with_console() |
/opt/venv/lite |
默认(无 console port) | _run_copaw_headless() |
两个入口函数都改为从 qwenpaw import。CI 只测标准模式(带 console port),lite 模式未经 CI 覆盖。如果只在标准 venv 装 qwenpaw,lite 模式生产部署会 ImportError 崩溃。因此两个 venv 都要装。
四、线 A:生产部署(已全部完成)
线 A 是容器内直接修改——不改源码,不重新构建镜像,立即可用。线 B(PR #950)的改动在源码层实现相同效果。
操作概要
| 阶段 | Worker | 数量 | 状态 |
|---|---|---|---|
| Phase 1 | biz-team(金丝雀) | 4 | ✅ |
| Phase 2 | daily-luo + doc-reader | 2 | ✅ |
| Phase 3 | sysdev + embedded 全员 | 12 | ✅ |
| 合计 | 18 | ✅ 全量完成 |
每个 Worker 的操作
# 1. 装 qwenpaw
docker exec hiclaw-worker-<name> pip install qwenpaw --no-deps
# 2. 改入口点
docker exec hiclaw-worker-<name> sed -i \
's|copaw.app._app:app|qwenpaw.app._app:app|g' \
$(docker exec hiclaw-worker-<name> python3 -c "import copaw_worker.worker; print(copaw_worker.worker.__file__)")
# 3. 写 config.json(agents.profiles)
# 4. docker restart与线 B 的对应关系
线 A 的 sed 改 worker.py 和手写 config.json,在线 B 中变为 worker.py 源码改 + bridge.py 自动注入。效果完全相同。
五、已知副作用
5.1 pip console_scripts 覆盖 Dockerfile symlink
pip install 带 [project.scripts] 的包时,会在 /usr/local/bin/ 写入实体文件。如果 Dockerfile 之前创建了同名 symlink(如 /usr/local/bin/copaw → /opt/venv/copaw/bin/copaw),symlink 会被 pip 覆盖为实体文件,shebang 变成系统 Python。CLI 脱离 venv → 报一连串 ModuleNotFoundError。
这是 pip 的通用行为,任何带 console_scripts 的包都可能触发。不是 qwenpaw 特有的问题。
影响范围:三个 Leader 容器(sysdev-lead、embedded-lead、sunzong)——它们在迁移期间被 pip 写入实体文件。Worker 不受影响(Worker 不调用 CLI)。
修复(一行恢复 symlink):
docker exec <leader> ln -sf /opt/venv/copaw/bin/copaw /usr/local/bin/copaw预防:可在 Dockerfile 最后加防御:
RUN ln -sf /opt/venv/copaw/bin/copaw /usr/local/bin/copaw \
&& ln -sf /opt/venv/copaw/bin/qwenpaw /usr/local/bin/qwenpaw5.2 copaw 残留
以下模块在磁盘上存在但不被 qwenpaw runtime 使用:
copawCLI entrypoint- Matrix channel overlay(Manager Dockerfile.copaw L95-101)
- copaw 1.0.2 包本身
这些将在后续独立 PR 中清理。
六、test-spawn E2E 证据(2026-06-17)
- 环境:Node1,独立容器
hiclaw-worker-test-spawn(不入 Team) - 配置:qwenpaw 1.1.12,worker.py 改两行,config.json agents.profiles 预种
- 测试:Agent 推理 → 调用
spawn_subagent→ 创建临时 subagent(SESSION:sub-6a2df2bc)→ 执行echo hello world→ 返回 "hello world" → 销毁 - SSE 流证据:
plugin_call帧name=spawn_subagent,plugin_call_output帧output="hello world" - 结论:spawn_subagent 功能完整可用
七、后续清理 PR(PR #950 合入后)
当前 PR 是一份桥接层——同时兼容 qwenpaw 和 copaw。桥是暂时的。
| 文件 | 改动 | 原因 |
|---|---|---|
copaw/Dockerfile |
删除 pip install copaw==1.0.2 |
不再需要 copaw runtime |
copaw/src/copaw_worker/matrix_channel.py |
删除 copaw fallback 分支 | 全链 qwenpaw,不再需要 legacy 兼容 |
copaw/src/copaw_worker/health.py |
移除 copaw 相关 docstring | 清理 |
manager/Dockerfile.copaw |
删除 Matrix overlay + copaw pip install | 全链 qwenpaw,不再需要 overlay 和 copaw 残留 |
manager/Dockerfile.openclaw |
同上 | openclaw Manager 也切 qwenpaw |
manager/scripts/init/start-copaw-manager.sh |
移除 COPAW_WORKING_DIR |
只保留 QWENPAW_WORKING_DIR |
八、CI 轮次记录
| Round | Commit | 结果 | 备注 |
|---|---|---|---|
| 21 | b3d1e5b |
✅ 10/10 全过 | 核心迁移,首次全绿 |
| 22 | 9d7f67a |
❌ SHARD_A copaw/hermes test-06 FAIL | copaw guard 非确定性拦截 execute_shell_command(TOOL_CMD_DANGEROUS_RM)。Manager 镜像在 R21→R22 间零改动 → flaky test |
| 23 | f34fff3 |
✅ 10/10 全过 | 空 commit 触发 re-run,同镜像通过 |
关于 copaw/hermes flaky test
copaw Manager 内置 guard 系统偶尔把 execute_shell_command 判定为危险操作(TOOL_CMD_DANGEROUS_RM)→ 等人类审批 → CI 无人审批 → 超时 → Worker Bob 未创建。这是 copaw 的非确定性行为(LLM 输出差异触发不同的 guard 规则匹配),与本次 PR 无关。
证据:R21 和 R22 的 Manager 镜像是同一个(Manager Dockerfile.copaw 在 b3d1e5b 和 9d7f67a 之间零改动)。R21 不触发 guard → 全过。R22 触发 guard → test-06 失败。R23 同一镜像 re-run → 全过。
Summary
Switch copaw-worker from copaw.app to qwenpaw.app as the runtime
entrypoint. qwenpaw is already present in the image as a dependency
of copaw; this change makes Workers use it directly, enabling
spawn_subagent and the full qwenpaw multi-agent feature set.
Changes (6 files, +31/-12)
Validation
Relation to TeamHarness
This PR is a prerequisite for TeamHarness Phase 4 (QwenPaw Worker
integration). The adapter code in
plugins/teamharness/adapters/qwenpaw/already imports from
qwenpaw.*modules and callsqwenpaw plugin install,but those can't work until Workers actually start
qwenpaw.app.The
agents.profilesinjection inbridge.pyfeeds directly intoTeamHarness's
_iter_qwenpaw_agents().What this does NOT change
HICLAW_COPAW_WORKER_IMAGEdefault value