From 43d10487e0604af697f7f1b60e331c98e8119c73 Mon Sep 17 00:00:00 2001 From: Ziyang Guo <121015044+RunMarshal@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:10:41 +0800 Subject: [PATCH 1/2] test: make multi-worker bob setup deterministic --- tests/test-06-multi-worker.sh | 58 +++++++++++------------------------ 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/tests/test-06-multi-worker.sh b/tests/test-06-multi-worker.sh index e73f77388..fa09a8b6f 100755 --- a/tests/test-06-multi-worker.sh +++ b/tests/test-06-multi-worker.sh @@ -35,53 +35,31 @@ wait_for_manager_agent_ready 300 "${DM_ROOM}" "${ADMIN_TOKEN}" || { exit 1 } -# test-05 can leave CoPaw Manager finishing heartbeat / pending-worker cleanup -# replies in the admin DM. Let that prior turn go quiet before measuring Bob's -# create-worker ack/provisioning SLA; the post-request waits below stay strict. -if ! matrix_wait_for_sender_quiet "${ADMIN_TOKEN}" "${DM_ROOM}" "@manager" 20 180; then - log_fail "Manager DM did not become quiet before Bob create request" - test_teardown "06-multi-worker" - test_summary - exit 1 -fi - # Alice is running from previous tests; bob will be created below (offset=0 is correct for new workers) wait_for_worker_container "alice" 60 METRICS_BASELINE=$(snapshot_baseline "alice" "bob") TEST_WORKER_RUNTIME="${HICLAW_DEFAULT_WORKER_RUNTIME:-openclaw}" -# worker-management/SKILL.md tells Manager to ask admin for FOUR inputs -# (name / runtime / SOUL / skills) before running `hiclaw create worker` -# and not to invent defaults. A vague prompt that only names the worker is -# therefore a coin flip — sometimes Manager replies with a confirmation -# request, never calls the CLI, and the consumer/SOUL.md polls below -# silently time out. Spell out all four inputs and tell Manager to skip -# confirmation so this test exercises actual Worker creation. -# -# The runtime is explicit because the CI matrix runtime is the source of truth; -# rendered Manager workspace text may contain fallback defaults. -matrix_send_message "${ADMIN_TOKEN}" "${DM_ROOM}" \ - "Please create a new Worker now using these exact values — do not ask me to confirm any of them: -- name: bob -- runtime: ${TEST_WORKER_RUNTIME} (use this exact runtime; do not reinterpret it as the install default) -- SOUL/role: Backend developer specializing in REST APIs, server-side logic, and data persistence -- skills: github-operations (file-sync / task-progress / project-participation are auto-included, no need to ask) - -Proceed immediately and tell me when he is created." - -log_info "Waiting for Manager to create Worker Bob..." -REPLY=$(matrix_wait_for_reply_matching "${ADMIN_TOKEN}" "${DM_ROOM}" "@manager" \ - "bob.*(accepted|created|creating|pending|running|ready)" 300 \ - "${ADMIN_TOKEN}" "${DM_ROOM}" "Please check if the request to create worker bob has been processed.") - -assert_not_empty "${REPLY}" "Manager replied to create bob request" -assert_contains_i "${REPLY}" "bob" "Reply mentions worker name 'bob'" +# This test verifies multi-worker collaboration after Alice and Bob exist. Bob +# creation must be deterministic setup: asking the Manager to create him via DM +# is flaky under CI because the Manager may still be processing heartbeat/task +# follow-ups from earlier shard-A tests, or may hit a tool-guard prompt before +# calling `hiclaw create worker`. Use the controller CLI directly here so the +# collaboration assertions below measure the multi-worker flow, not LLM timing. +BOB_SOUL="Backend developer specializing in REST APIs, server-side logic, and data persistence" +log_info "Creating Worker Bob via hiclaw CLI (runtime: ${TEST_WORKER_RUNTIME})..." +CREATE_OUTPUT=$(exec_in_agent hiclaw apply worker --name bob \ + --runtime "${TEST_WORKER_RUNTIME}" \ + --soul "${BOB_SOUL}" \ + --skills github-operations 2>&1) +if echo "${CREATE_OUTPUT}" | grep -qiE "worker/bob (created|configured)"; then + log_pass "hiclaw apply worker bob accepted" +else + log_fail "hiclaw apply worker bob failed: ${CREATE_OUTPUT}" +fi # Verify Bob's infrastructure. Worker creation is asynchronous, so wait on # persisted provisioning state and gateway side effects instead of sleeping. -BOB_PROVISION_TIMEOUT=60 -if echo "${REPLY}" | grep -qiE "bob.*(accepted|creating|pending)" 2>/dev/null; then - BOB_PROVISION_TIMEOUT=180 -fi +BOB_PROVISION_TIMEOUT=180 if wait_worker_provisioned "bob" "${BOB_PROVISION_TIMEOUT}"; then log_pass "Worker Bob provisioned (roomID + matrixUserID populated)" else From 316f8312be6c74c80d5641d5be3dd601cc4540d3 Mon Sep 17 00:00:00 2001 From: Ziyang Guo <121015044+RunMarshal@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:20:55 +0800 Subject: [PATCH 2/2] docs(team-leader): simplify worker name guidance --- changelog/current.md | 1 + .../skills/project-management/SKILL.md | 21 ++++---------- .../references/dag-execution.md | 5 +--- .../skills/task-management/SKILL.md | 29 ++++--------------- 4 files changed, 13 insertions(+), 43 deletions(-) diff --git a/changelog/current.md b/changelog/current.md index f3ae6b4eb..1d67e8bba 100644 --- a/changelog/current.md +++ b/changelog/current.md @@ -30,6 +30,7 @@ Record image-affecting changes to `manager/`, `worker/`, `copaw/`, `openclaw-bas - **Legacy Team channel policy**: Legacy Team reconciliation now writes final Matrix channel allow-lists to member runtime config and re-adds the Team Leader to the Manager allow-list so controller integration tests observe durable policy state. - **Sandbox worker-deps hardening**: Sandbox-backed Workers now prepare controller-owned worker-deps env/token/data material before claim creation, recycle stale SandboxClaims and bound Sandboxes on runtime-affecting changes, and use bounded ServiceAccount token projection for built-in SandboxClaim mounts. - **CLI AgentTeams auth env**: The `hiclaw` CLI now discovers `AGENTTEAMS_CONTROLLER_URL`, `AGENTTEAMS_AUTH_TOKEN`, `AGENTTEAMS_AUTH_TOKEN_FILE`, and `AGENTTEAMS_CLUSTER_ID` while preserving legacy `HICLAW_*` fallbacks, so Manager and Worker containers can use the terminal env names for controller calls. +- **Team Leader task routing guidance**: Leader project/task skills now describe Worker `assignedTo` values with a concise Matrix-localpart rule instead of long defensive warning blocks. - **CoPaw worker runtime environment**: CoPaw workers now prefer AgentTeams storage/runtime environment variables while preserving legacy HiClaw fallbacks, and Qwen-style model health preflights disable thinking for lightweight readiness checks. - **CoPaw Worker heartbeat**: CoPaw worker templates now seed heartbeat at a 10-minute interval so Team Leader agents created from the worker template can run heartbeat turns without requiring an explicit Team CR heartbeat spec. - **Helm CRDs**: Removed unsupported `propertyNames` schema fields from Worker and Team CRDs so Kubernetes API servers accept the chart CRDs. diff --git a/manager/agent/team-leader-agent/skills/project-management/SKILL.md b/manager/agent/team-leader-agent/skills/project-management/SKILL.md index c9ef40a2e..f54888b3a 100644 --- a/manager/agent/team-leader-agent/skills/project-management/SKILL.md +++ b/manager/agent/team-leader-agent/skills/project-management/SKILL.md @@ -151,21 +151,10 @@ Each node uses: - `assignedTo` - `dependsOn` -For `assignedTo`, use the Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract it mechanically — never guess, strip, or transform. - -**Lookup steps (mandatory before every `plan_dag` / `plan_loop` call):** -1. Run `hiclaw get workers --team "$TEAM_CR" -o json` -2. For each Worker, extract the localpart from `.matrixUserID`: e.g. `@worker-issue-resolver:domain` → `worker-issue-resolver` -3. Use that localpart verbatim as `assignedTo` - -❌ Do NOT use CLI `.name` field directly (it may include deployment prefixes like `magic-cn-...-worker-issue-resolver`) -❌ Do NOT strip prefixes yourself — you will incorrectly remove legitimate name components -❌ Do NOT infer worker names from memory, AGENTS.md, or display names - -| CLI `.name` | `matrixUserID` | ✅ `assignedTo` | ❌ Wrong | -|---|---|---|---| -| `magic-cn-x0a4t4pr201-worker-issue-resolver` | `@worker-issue-resolver:domain` | `worker-issue-resolver` | `issue-resolver` | -| `magic-cn-plt4s29va0r-worker-dev-worker` | `@dev-worker:domain` | `dev-worker` | `worker` | +For `assignedTo`, use the Worker's **Matrix localpart**: the part between +`@` and `:` in `matrixUserID`. Run `hiclaw get workers --team "$TEAM_CR" -o +json`, read each Worker's `matrixUserID`, and copy that localpart verbatim. +Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`. Do not use `worker`, `owner`, `dependencies`, or standalone short IDs. @@ -222,7 +211,7 @@ Optional inputs: - `status` - `tasks` -For every Loop task, `assignedTo` follows the same rule as DAG tasks: extract the Matrix localpart from `hiclaw get workers` output. Never strip or transform. +For every Loop task, `assignedTo` follows the same Matrix localpart rule as DAG tasks. Use `ready_loop_nodes` to find pending nodes in the current iteration whose dependencies are satisfied by accepted `[x]` nodes. Delegate returned nodes with `task-management`. diff --git a/manager/agent/team-leader-agent/skills/project-management/references/dag-execution.md b/manager/agent/team-leader-agent/skills/project-management/references/dag-execution.md index 2174ff5da..70fa1800b 100644 --- a/manager/agent/team-leader-agent/skills/project-management/references/dag-execution.md +++ b/manager/agent/team-leader-agent/skills/project-management/references/dag-execution.md @@ -39,10 +39,7 @@ Each task node uses: - `taskId`: stable node ID. Use `{projectId}-{seq}`. - `title`: short human-readable work unit. -- `assignedTo`: Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract mechanically from `hiclaw get workers --team "$TEAM_CR" -o json` output. Never strip, guess, or transform. - - ❌ Do NOT use CLI `.name` field directly (may include deployment prefixes) - - ❌ Do NOT strip prefixes yourself - - Example: `@worker-issue-resolver:domain` → `worker-issue-resolver` +- `assignedTo`: Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Get it from `hiclaw get workers --team "$TEAM_CR" -o json` and copy it verbatim. Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`. - `dependsOn`: list of task IDs that must produce accepted upstream results first. Do not use `worker`, `owner`, `dependencies`, or short standalone IDs like `st-01`. diff --git a/manager/agent/team-leader-agent/skills/task-management/SKILL.md b/manager/agent/team-leader-agent/skills/task-management/SKILL.md index efcc41c39..9e36c31f5 100644 --- a/manager/agent/team-leader-agent/skills/task-management/SKILL.md +++ b/manager/agent/team-leader-agent/skills/task-management/SKILL.md @@ -111,36 +111,19 @@ Keep machine-facing identifiers and protocol tokens unchanged: ## Worker Name Canonicality -`assigned_to`, Matrix @mention, and all task tracking fields must use the Worker's **Matrix localpart** (the part between `@` and `:` in `matrixUserID`). Extract it mechanically — never guess, strip, or transform. +`assigned_to`, Matrix @mentions, and task tracking fields use the Worker's +**Matrix localpart**: the part between `@` and `:` in `matrixUserID`. Get team +workers with `hiclaw get workers --team "$TEAM_CR" -o json`, read +`matrixUserID`, and copy the localpart verbatim. -### Lookup (mandatory before assigning any task) +Example: `@worker-issue-resolver:domain` -> `worker-issue-resolver`. -```bash -# 1. Resolve team CR name -TEAM_CR="$(hiclaw get workers "${AGENTTEAMS_WORKER_CR_NAME:-$AGENTTEAMS_WORKER_NAME}" -o json | jq -r '.team')" - -# 2. Get all team workers -hiclaw get workers --team "$TEAM_CR" -o json - -# 3. Extract localpart from matrixUserID for each worker -# @worker-issue-resolver:domain → worker-issue-resolver -``` - -Use the extracted localpart verbatim everywhere: +Use that value everywhere: - `manage-team-state.sh --assigned-to ` - Matrix @mention: `@:` - `meta.json` `assigned_to` field -### Common mistake - -CLI `.name` may include a deployment prefix (e.g. `magic-cn-x0a4t4pr201-worker-issue-resolver`). **Do NOT use `.name` directly and do NOT manually strip prefixes.** Always extract the localpart from `.matrixUserID` instead. - -| CLI `.name` | `matrixUserID` | ✅ `assigned_to` | ❌ Wrong | -|---|---|---|---| -| `magic-cn-...-worker-issue-resolver` | `@worker-issue-resolver:domain` | `worker-issue-resolver` | `issue-resolver` | -| `magic-cn-...-dev-worker` | `@dev-worker:domain` | `dev-worker` | `worker` | - ## Delegate A Ready Node Delegate only nodes returned by: