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
1 change: 1 addition & 0 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Record image-affecting changes to `manager/`, `worker/`, `copaw/`, `openclaw-bas

---

- fix(manager): reject unsupported MCP overrides during Worker runtime switches and document the separate authorization step ([8241cf7](https://github.com/agentscope-ai/AgentTeams/commit/8241cf7bb1cefc6c10748dd5dfd83e966083e77b)).
- feat(qwenpaw): add the QwenPaw worker runtime Python package baseline with runtime config sync, storage sync, heartbeat reporting, Matrix channel overlay, and focused unit tests.
- fix(controller): surface Kubernetes Pod container failures in Worker backend status and status API responses.
- feat(controller): expose low-cardinality AgentTeams controller metrics and optional Helm ServiceMonitor.
Expand Down
4 changes: 2 additions & 2 deletions manager/agent/skills/worker-management/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ To migrate a Worker between runtimes (e.g. openclaw → copaw, copaw → hermes)
bash /opt/hiclaw/agent/skills/worker-management/scripts/update-worker-config.sh \
--name <NAME> \
--runtime <openclaw|copaw|hermes|openhuman> \
[--model <MODEL>] [--skills s1,s2] [--mcp-servers s1,s2]
[--model <MODEL>] [--skills s1,s2]
```

What happens behind the scenes:
Expand All @@ -98,5 +98,5 @@ What happens behind the scenes:

Constraints:

- `--package-dir` and `--channel-policy` cannot be combined with `--runtime` — apply those separately after the runtime switch settles
- `--package-dir`, `--channel-policy`, and `--mcp-servers` cannot be combined with `--runtime` — apply those separately after the runtime switch settles
- The wrapper preserves Matrix account/room/credentials/MinIO data but loses container-local ephemeral state — see the runtime gotcha above
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#
# Usage:
# update-worker-config.sh --name <NAME> [--model <MODEL_ID>] [--skills s1,s2] [--mcp-servers s1,s2] [--package-dir <DIR>]
# update-worker-config.sh --name <NAME> --runtime <openclaw|copaw|hermes|openhuman> [--model <MODEL_ID>] [--skills s1,s2] [--mcp-servers s1,s2]
# update-worker-config.sh --name <NAME> --runtime <openclaw|copaw|hermes|openhuman> [--model <MODEL_ID>] [--skills s1,s2]
#
# Prerequisites:
# - Worker must already exist (created via create-worker.sh)
Expand Down Expand Up @@ -65,7 +65,7 @@ done

if [ -z "${WORKER_NAME}" ]; then
echo "Usage: update-worker-config.sh --name <NAME> [--model <MODEL>] [--skills s1,s2] [--mcp-servers s1,s2] [--package-dir <DIR>]"
echo " update-worker-config.sh --name <NAME> --runtime <openclaw|copaw|hermes|openhuman> [--model <MODEL>] [--skills s1,s2] [--mcp-servers s1,s2]"
echo " update-worker-config.sh --name <NAME> --runtime <openclaw|copaw|hermes|openhuman> [--model <MODEL>] [--skills s1,s2]"
exit 1
fi

Expand All @@ -92,6 +92,9 @@ if [ -n "${RUNTIME}" ]; then
if [ -n "${CHANNEL_POLICY_JSON}" ]; then
_fail "--channel-policy cannot be combined with --runtime. Apply the channel-policy separately (without --runtime) after the runtime switch settles."
fi
if [ -n "${MCP_SERVERS}" ]; then
_fail "--mcp-servers cannot be combined with --runtime. Reauthorize MCP servers separately (without --runtime) after the runtime switch settles."
fi

log "=== Switching runtime for Worker: ${WORKER_NAME} -> ${RUNTIME} ==="
log " WARNING: existing container will be destroyed and recreated."
Expand All @@ -101,7 +104,6 @@ if [ -n "${RUNTIME}" ]; then
CLI_ARGS=(update worker --name "${WORKER_NAME}" --runtime "${RUNTIME}")
[ -n "${MODEL_ID}" ] && CLI_ARGS+=(--model "${MODEL_ID}")
[ -n "${WORKER_SKILLS}" ] && CLI_ARGS+=(--skills "${WORKER_SKILLS}")
[ -n "${MCP_SERVERS}" ] && CLI_ARGS+=(--mcp-servers "${MCP_SERVERS}")

log "Step 1: Calling: hiclaw ${CLI_ARGS[*]}"
if ! CLI_OUT=$(hiclaw "${CLI_ARGS[@]}" 2>&1); then
Expand Down
114 changes: 114 additions & 0 deletions manager/tests/test-update-worker-runtime.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/bin/bash
# Regression tests for runtime-switch arguments in update-worker-config.sh.

set -uo pipefail

PASS=0
FAIL=0
TMPDIR_ROOT=$(mktemp -d)
trap 'rm -rf "${TMPDIR_ROOT}"' EXIT

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
UPDATE_SCRIPT="${PROJECT_ROOT}/manager/agent/skills/worker-management/scripts/update-worker-config.sh"
TEST_SCRIPT="${TMPDIR_ROOT}/update-worker-config.sh"
MOCK_BIN="${TMPDIR_ROOT}/bin"
HICLAW_LOG="${TMPDIR_ROOT}/hiclaw.log"

pass() {
echo " PASS: $1"
PASS=$((PASS + 1))
}

fail() {
echo " FAIL: $1"
echo " expected: $2"
echo " got: $3"
FAIL=$((FAIL + 1))
}

assert_eq() {
local description="$1" expected="$2" actual="$3"
if [ "${expected}" = "${actual}" ]; then
pass "${description}"
else
fail "${description}" "${expected}" "${actual}"
fi
}

assert_contains() {
local description="$1" needle="$2" actual="$3"
if printf '%s\n' "${actual}" | grep -qF -- "${needle}"; then
pass "${description}"
else
fail "${description}" "contains ${needle}" "${actual}"
fi
}

# The production source only exports shared environment helpers. Runtime mode
# does not need them, so replace that source line in the isolated test copy.
sed 's|^source /opt/hiclaw/scripts/lib/hiclaw-env.sh$|: # environment supplied by test|' \
"${UPDATE_SCRIPT}" > "${TEST_SCRIPT}"
chmod +x "${TEST_SCRIPT}"

mkdir -p "${MOCK_BIN}"
cat > "${MOCK_BIN}/hiclaw" <<'EOF'
#!/bin/sh
case "$1 $2" in
"update worker")
printf '%s\n' "$@" > "${TEST_HICLAW_LOG:?}"
echo "worker updated"
;;
"get workers")
printf '%s\n' '{"workers":[{"name":"alice","phase":"Running","runtime":"hermes"}]}'
;;
*)
echo "unexpected hiclaw command: $*" >&2
exit 2
;;
esac
EOF
chmod +x "${MOCK_BIN}/hiclaw"

echo "=== Runtime switch rejects the unsupported MCP combination ==="
if REJECT_OUTPUT=$(PATH="${MOCK_BIN}:${PATH}" \
TEST_HICLAW_LOG="${HICLAW_LOG}" \
bash "${TEST_SCRIPT}" --name alice --runtime hermes --mcp-servers github 2>&1); then
fail "runtime and MCP options are rejected before the CLI call" \
"non-zero exit" "exit 0"
else
assert_contains "rejection explains the incompatible options" \
"--mcp-servers cannot be combined with --runtime" "${REJECT_OUTPUT}"
fi

if [ -e "${HICLAW_LOG}" ]; then
fail "rejected options do not invoke hiclaw" "no command log" "$(cat "${HICLAW_LOG}")"
else
pass "rejected options do not invoke hiclaw"
fi

echo "=== Runtime switch forwards supported update flags unchanged ==="
RUNTIME_OUTPUT=$(PATH="${MOCK_BIN}:${PATH}" \
TEST_HICLAW_LOG="${HICLAW_LOG}" \
bash "${TEST_SCRIPT}" \
--name alice \
--runtime hermes \
--model qwen3.6-plus \
--skills code-review)

EXPECTED_ARGS=$(printf '%s\n' \
update worker \
--name alice \
--runtime hermes \
--model qwen3.6-plus \
--skills code-review)
assert_eq "supported runtime arguments match hiclaw update worker" \
"${EXPECTED_ARGS}" "$(cat "${HICLAW_LOG}")"
assert_contains "runtime switch still reports completion" \
'"status": "runtime_switched"' "${RUNTIME_OUTPUT}"

echo ""
echo "Results: ${PASS} passed, ${FAIL} failed"
if [ "${FAIL}" -gt 0 ]; then
exit 1
fi
Loading