Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 18 additions & 40 deletions tests/test-06-multi-worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/test-18-team-config-verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ assert_eq "worker" "${W2_ROLE}" "Worker 2 has role=worker"
# ============================================================
log_section "Verify Leader AGENTS.md"

# TeamReconciler injects the leader context after member provisioning and room
# IDs are available. Avoid a single early MinIO read racing that async write.
wait_agent_file_contains "${TEST_LEADER}" "AGENTS.md" "hiclaw-team-context-start" 120 || true

LEADER_AGENTS=$(exec_in_manager mc cat "${STORAGE_PREFIX}/agents/${TEST_LEADER}/AGENTS.md" 2>/dev/null || echo "")
assert_not_empty "${LEADER_AGENTS}" "Leader AGENTS.md exists in MinIO"

Expand Down
7 changes: 7 additions & 0 deletions tests/test-21-team-project-dag.sh
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ MAX_DM_ONLY_POLLS="${MAX_DM_ONLY_POLLS:-1}"

LEADER_RESPONDED=false
TEAM_COORDINATED=false
LEADER_COORDINATION_NUDGE_SENT=false
RUNTIME_ERROR=false
DM_ONLY_POLLS=0
for i in $(seq 1 "${MAX_COORDINATION_POLLS}"); do
Expand Down Expand Up @@ -394,6 +395,12 @@ for i in $(seq 1 "${MAX_COORDINATION_POLLS}"); do
if echo "${DM_MSGS}" | grep -qi "Error:\\|No active model configured"; then
RUNTIME_ERROR=true
fi
if [ "${LEADER_COORDINATION_NUDGE_SENT}" != "true" ] && [ "${TEAM_COORDINATED}" != "true" ]; then
log_info "Leader is active in DM but not coordinating in Team Room; sending one corrective Team Room nudge"
matrix_send_message "${ADMIN_LOGIN_TOKEN}" "${TEAM_ROOM}" \
"@${TEST_LEADER}:${TEST_MATRIX_DOMAIN} You are the Team Leader, not the implementer. Stop doing the API work yourself. In this Team Room, create/delegate tasks and @mention ${TEST_W1} for API design/implementation and ${TEST_W2} for QA/test cases. Workers only process task assignments addressed to them in this Team Room."
LEADER_COORDINATION_NUDGE_SENT=true
fi
fi

if [ "${LEADER_RESPONDED}" = "true" ] && [ "${TEAM_COORDINATED}" != "true" ]; then
Expand Down
Loading