From 9ecb4202238d31328bb953fa0b5f0f501da2bcf7 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Tue, 28 Apr 2026 17:16:33 +0800 Subject: [PATCH] Align public RPC contract validation --- .../verify-public-rpc-contract.sh | 109 +++++++----------- 1 file changed, 41 insertions(+), 68 deletions(-) diff --git a/scripts/github-actions/verify-public-rpc-contract.sh b/scripts/github-actions/verify-public-rpc-contract.sh index e69a6a5..32a0720 100755 --- a/scripts/github-actions/verify-public-rpc-contract.sh +++ b/scripts/github-actions/verify-public-rpc-contract.sh @@ -63,8 +63,8 @@ unauthorized_status="$( "${resolved_base_url}/acp/rpc" )" -if [[ "${unauthorized_status}" != "200" ]]; then - echo "expected public capabilities request to return 200, got ${unauthorized_status}" >&2 +if [[ "${unauthorized_status}" != "401" ]]; then + echo "expected unauthenticated capabilities request to return 401, got ${unauthorized_status}" >&2 exit 1 fi @@ -93,29 +93,6 @@ capabilities_json="$( -H "Authorization: Bearer ${AUTH_TOKEN}" )" -mapfile -t provider_ids < <( - RESPONSE_JSON="${capabilities_json}" python3 - <<'PY' -import json -import os - -payload = json.loads(os.environ["RESPONSE_JSON"]) -result = payload.get("result") -if not isinstance(result, dict): - raise SystemExit("bridge capabilities response missing result payload") - -provider_catalog = result.get("providerCatalog") -if not isinstance(provider_catalog, list): - raise SystemExit("providerCatalog is missing or invalid") - -for item in provider_catalog: - if isinstance(item, dict) and item.get("providerId"): - print(item["providerId"]) - -if not any(isinstance(item, dict) and item.get("providerId") for item in provider_catalog): - raise SystemExit("providerCatalog did not include any provider ids") -PY -) - RESPONSE_JSON="${capabilities_json}" python3 - <<'PY' import json import os @@ -167,60 +144,56 @@ if gateway.get("targets") != ["gateway"]: raise SystemExit(f"expected gateway targets ['gateway'], got {gateway!r}") PY -session_start_success=0 -session_start_error="" -matched_provider_id="" +agent_routing_json="$( + json_rpc_with_retry \ + '{"jsonrpc":"2.0","id":"route-agent-1","method":"xworkmate.routing.resolve","params":{"taskPrompt":"Reply with exactly pong","workingDirectory":"/tmp","routing":{"routingMode":"explicit","explicitExecutionTarget":"singleAgent","explicitProviderId":"codex"}}}' \ + -H "Authorization: Bearer ${AUTH_TOKEN}" +)" -for provider_id in "${provider_ids[@]}"; do - session_start_json="$( - json_rpc_with_retry \ - "{\"jsonrpc\":\"2.0\",\"id\":\"task-1\",\"method\":\"session.start\",\"params\":{\"sessionId\":\"public-contract-smoke\",\"threadId\":\"public-contract-smoke\",\"taskPrompt\":\"Reply with exactly pong\",\"workingDirectory\":\"/tmp\",\"routing\":{\"routingMode\":\"explicit\",\"explicitExecutionTarget\":\"singleAgent\",\"explicitProviderId\":\"${provider_id}\"}}}" \ - -H "Authorization: Bearer ${AUTH_TOKEN}" 2>/tmp/xworkmate-bridge-public-contract-session-start.err || true - )" - - if [[ -z "${session_start_json}" ]]; then - session_start_error="$(cat /tmp/xworkmate-bridge-public-contract-session-start.err)" - continue - fi - - if RESPONSE_JSON="${session_start_json}" SELECTED_PROVIDER_ID="${provider_id}" python3 - <<'PY' +RESPONSE_JSON="${agent_routing_json}" python3 - <<'PY' import json import os payload = json.loads(os.environ["RESPONSE_JSON"]) if payload.get("jsonrpc") != "2.0": - raise SystemExit("session.start response missing jsonrpc envelope") + raise SystemExit("agent routing response missing jsonrpc envelope") result = payload.get("result") if not isinstance(result, dict): - raise SystemExit(f"session.start missing result payload: {payload!r}") + raise SystemExit(f"agent routing missing result payload: {payload!r}") -if result.get("success") is not True: - raise SystemExit(f"session.start did not succeed: {result!r}") - -provider = str(result.get("provider", "")).strip() -if provider != os.environ["SELECTED_PROVIDER_ID"]: - raise SystemExit(f"expected provider {os.environ['SELECTED_PROVIDER_ID']!r}, got {result!r}") - -output = str(result.get("output", "")).strip().lower() -if output != "pong": - raise SystemExit(f"expected output 'pong', got {result!r}") +if result.get("resolvedExecutionTarget") != "single-agent": + raise SystemExit(f"unexpected routing target: {result!r}") +if result.get("resolvedProviderId") != "codex": + raise SystemExit(f"unexpected routing provider: {result!r}") +if result.get("status") != "available": + raise SystemExit(f"unexpected routing status: {result!r}") PY - then - session_start_success=1 - matched_provider_id="${provider_id}" - break - fi - session_start_error="$(cat /tmp/xworkmate-bridge-public-contract-session-start.err)" -done +gateway_routing_json="$( + json_rpc_with_retry \ + '{"jsonrpc":"2.0","id":"route-gateway-1","method":"xworkmate.routing.resolve","params":{"taskPrompt":"search latest news","workingDirectory":"/tmp","routing":{"routingMode":"explicit","explicitExecutionTarget":"gateway","preferredGatewayProviderId":"openclaw"}}}' \ + -H "Authorization: Bearer ${AUTH_TOKEN}" +)" -if [[ "${session_start_success}" -ne 1 ]]; then - echo "session.start failed for all providers in providerCatalog" >&2 - if [[ -n "${session_start_error}" ]]; then - echo "${session_start_error}" >&2 - fi - exit 1 -fi +RESPONSE_JSON="${gateway_routing_json}" python3 - <<'PY' +import json +import os -printf 'public bridge RPC contract verified via %s using provider %s\n' "${resolved_base_url}" "${matched_provider_id}" +payload = json.loads(os.environ["RESPONSE_JSON"]) +if payload.get("jsonrpc") != "2.0": + raise SystemExit("gateway routing response missing jsonrpc envelope") + +result = payload.get("result") +if not isinstance(result, dict): + raise SystemExit(f"gateway routing missing result payload: {payload!r}") + +if result.get("resolvedExecutionTarget") != "gateway": + raise SystemExit(f"unexpected gateway routing target: {result!r}") +if result.get("resolvedGatewayProviderId") != "openclaw": + raise SystemExit(f"unexpected gateway provider: {result!r}") +if result.get("status") != "available": + raise SystemExit(f"unexpected gateway routing status: {result!r}") +PY + +printf 'public bridge RPC contract verified via %s\n' "${resolved_base_url}"