From 3e77ce3c66cba377aeddb8d7a36ff9b13160ec10 Mon Sep 17 00:00:00 2001 From: JakubWorek Date: Tue, 25 Aug 2026 11:02:57 +0000 Subject: [PATCH 1/2] feat(itk): use shared scenarios --- itk/run_itk.sh | 203 ++++----------------- itk/scenarios.json | 64 ------- itk/scenarios_full.json | 392 ---------------------------------------- 3 files changed, 37 insertions(+), 622 deletions(-) delete mode 100644 itk/scenarios.json delete mode 100644 itk/scenarios_full.json diff --git a/itk/run_itk.sh b/itk/run_itk.sh index 4490f9119..79f9d3c15 100755 --- a/itk/run_itk.sh +++ b/itk/run_itk.sh @@ -1,174 +1,45 @@ #!/bin/bash -set -ex - -# Set default log level -export ITK_LOG_LEVEL="${ITK_LOG_LEVEL:-INFO}" - -# Initialize default exit code -RESULT=1 - -# Cleanup function to be called on exit -cleanup() { - set +x - echo "Cleaning up artifacts..." - docker stop itk-service > /dev/null 2>&1 || true - docker rm itk-service > /dev/null 2>&1 || true - docker rmi itk_service > /dev/null 2>&1 || true - rm -rf a2a-itk > /dev/null 2>&1 || true - rm -rf pyproto > /dev/null 2>&1 || true - rm -f instruction.proto > /dev/null 2>&1 || true - echo "Done. Final exit code: $RESULT" +# ITK harness for a2a-python — a thin shim over a2a-itk's shared driver. +# +# Everything that used to live here (clone, image build, container start, +# readiness poll, POST /run, result reporting, nightly metrics) is now in +# a2a-itk/scripts/run_itk_shared.sh, which all five SDK repos share. Only the +# genuinely python-specific part stays: generating the proto stubs. +# +# Scenarios come from the shared role-based set in a2a-itk rather than a +# scenarios.json in this repo — see a2a-itk/scenarios/traversal/. +set -e +cd "$(dirname "${BASH_SOURCE[0]}")" + +ITK_SDK_NAME=python +ITK_SCENARIO_SET=shared + +itk_generate_protos() { + mkdir -p pyproto + touch pyproto/__init__.py + uv run --with grpcio-tools python -m grpc_tools.protoc \ + -I. \ + --python_out=pyproto \ + --grpc_python_out=pyproto \ + instruction.proto + # Generated code imports its sibling as a top-level module; make it relative + # so `pyproto` works as a package. + sed -i 's/^import instruction_pb2 as instruction__pb2/from . import instruction_pb2 as instruction__pb2/' \ + pyproto/instruction_pb2_grpc.py } -# Register cleanup function to run on script exit -trap cleanup EXIT +itk_extra_cleanup() { + rm -rf pyproto +} -# 1. Pull a2a-itk and checkout revision +# --- bootstrap ------------------------------------------------------------- +# The shared driver lives in a2a-itk, so the checkout has to exist before it +# can be sourced. CI has already placed it here via actions/checkout; locally +# we clone it from a2aproject/a2a-itk. : "${A2A_ITK_REVISION:?A2A_ITK_REVISION environment variable must be set}" - -if [ ! -d "a2a-itk" ]; then +if [ ! -d a2a-itk ]; then git clone https://github.com/a2aproject/a2a-itk.git a2a-itk + git -C a2a-itk checkout "$A2A_ITK_REVISION" fi -cd a2a-itk -git fetch origin -git checkout "$A2A_ITK_REVISION" - -# Only pull if it's a branch (not a detached HEAD) -if git symbolic-ref -q HEAD > /dev/null; then - git pull origin "$A2A_ITK_REVISION" -fi -cd .. - -# 2. Copy instruction.proto from a2a-itk -cp a2a-itk/protos/instruction.proto ./instruction.proto - -# 3. Build pyproto library -mkdir -p pyproto -touch pyproto/__init__.py -uv run --with grpcio-tools python -m grpc_tools.protoc \ - -I. \ - --python_out=pyproto \ - --grpc_python_out=pyproto \ - instruction.proto - -# Fix imports in generated file -sed -i 's/^import instruction_pb2 as instruction__pb2/from . import instruction_pb2 as instruction__pb2/' pyproto/instruction_pb2_grpc.py - -# 4. Build jit itk_service docker image from root of a2a-itk (skipped in CI -# where the workflow builds via docker/build-push-action for GHA caching). -if [ "${ITK_SKIP_BUILD:-0}" != "1" ]; then - docker build -t itk_service a2a-itk -fi - -# 5. Start docker service -# Mounting a2a-python as repo and itk as current agent -A2A_PYTHON_ROOT=$(cd .. && pwd) -ITK_DIR=$(pwd) - -# Stop existing container if any -docker rm -f itk-service || true - -# Create logs directory if debug -if [ "${ITK_LOG_LEVEL^^}" = "DEBUG" ]; then - mkdir -p "$ITK_DIR/logs" -fi - -DOCKER_MOUNT_LOGS="" -if [ "${ITK_LOG_LEVEL^^}" = "DEBUG" ]; then - DOCKER_MOUNT_LOGS="-v $ITK_DIR/logs:/app/logs" -fi - -mkdir -p "$HOME/.cache/a2a-itk-launcher" - -docker run -d --name itk-service \ - -v "$A2A_PYTHON_ROOT:/app/agents/repo" \ - -v "$ITK_DIR:/app/agents/repo/itk" \ - -v "$HOME/.cache/a2a-itk-launcher:/root/.cache/a2a-itk" \ - $DOCKER_MOUNT_LOGS \ - -e ITK_LOG_LEVEL="$ITK_LOG_LEVEL" \ - -e ITK_ENTRYPOINT="${ITK_ENTRYPOINT:-itk_service_v2.py}" \ - -e ITK_READINESS_TIMEOUT="${ITK_READINESS_TIMEOUT:-180}" \ - -e ITK_MAX_WORKERS="${ITK_MAX_WORKERS:-2}" \ - -p 8000:8000 \ - itk_service - -# 5.1. Fix dubious ownership for git (needed for uv-dynamic-versioning) -docker exec -u root itk-service git config --system --add safe.directory /app/agents/repo -docker exec -u root itk-service git config --system --add safe.directory /app/agents/repo/itk -docker exec -u root itk-service git config --system core.multiPackIndex false -# Launcher's peer checkouts under /root/.cache/a2a-itk are host-owned; trust -# only repos under the launcher cache dir so container-side git accepts them. -docker exec -u root itk-service bash -lc 'while IFS= read -r -d "" d; do git config --system --add safe.directory "${d%/.git}"; done < <(find /root/.cache/a2a-itk -type d -name .git -print0)' - -# 6. Verify service is up and send post request -MAX_RETRIES=30 -echo "Waiting for ITK service to start on 127.0.0.1:8000..." -set +e -for i in $(seq 1 $MAX_RETRIES); do - if curl -s http://127.0.0.1:8000/ > /dev/null; then - echo "Service is up!" - break - fi - echo "Still waiting... ($i/$MAX_RETRIES)" - sleep 2 -done - -# If we reached the end of the loop without success -if ! curl -s http://127.0.0.1:8000/ > /dev/null; then - echo "Error: ITK service failed to start on port 8000" - docker logs itk-service - exit 1 -fi - -SCENARIO_FILE="scenarios.json" -if [ "${ITK_NIGHTLY_RUN^^}" = "TRUE" ]; then - SCENARIO_FILE="scenarios_full.json" -fi - -echo "ITK Service is up! Sending compatibility test request using $SCENARIO_FILE..." -RESPONSE=$(curl -s -X POST http://127.0.0.1:8000/run \ - -H "Content-Type: application/json" \ - -d "@$SCENARIO_FILE") - -if [ "${ITK_NIGHTLY_RUN^^}" = "TRUE" ]; then - echo "Nightly run detected. Saving raw results and running process_results.py..." - echo "$RESPONSE" > raw_results.json - python3 a2a-itk/scripts/process_results.py \ - --history_output_file itk_python.json \ - --history_url https://github.com/a2aproject/a2a-python/releases/download/nightly-metrics/itk_python.json - RESULT=$? -else - echo "--------------------------------------------------------" - echo "ITK TEST RESULTS:" - echo "--------------------------------------------------------" - echo "$RESPONSE" | python3 -c " -import sys, json -try: - data = json.load(sys.stdin) - all_passed = data.get('all_passed', False) - results = data.get('results', {}) - for test, passed in results.items(): - status = 'PASSED' if passed else 'FAILED' - print(f'{test}: {status}') - print('--------------------------------------------------------') - print(f'OVERALL STATUS: {\"PASSED\" if all_passed else \"FAILED\"}') - if not all_passed: - sys.exit(1) -except Exception as e: - print(f'Error parsing results: {e}') - print(f'Raw response: {data if \"data\" in locals() else \"no data\"}') - sys.exit(1) -" - RESULT=$? -fi -set -e - -if [ $RESULT -ne 0 ]; then - echo "Tests failed. Container logs:" - docker logs itk-service -fi -echo "--------------------------------------------------------" - -# Final exit result will be captured by trap cleanup -exit $RESULT +source a2a-itk/scripts/run_itk_shared.sh diff --git a/itk/scenarios.json b/itk/scenarios.json deleted file mode 100644 index 90a44de43..000000000 --- a/itk/scenarios.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "tests": [ - { - "name": "Star Topology (Full) - JSONRPC & GRPC", - "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], - "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], - "protocols": ["jsonrpc", "grpc"], - "behavior": "send_message" - }, - { - "name": "Star Topology (No Go v03) - HTTP_JSON", - "sdks": ["current", "python_v10", "python_v03", "go_v10"], - "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], - "protocols": ["http_json"], - "behavior": "send_message" - }, - { - "name": "Star Topology (Full) - JSONRPC & GRPC (Streaming)", - "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], - "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], - "protocols": ["jsonrpc", "grpc"], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Star Topology (No Go v03) - HTTP_JSON (Streaming)", - "sdks": ["current", "python_v10", "python_v03", "go_v10"], - "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], - "protocols": ["http_json"], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Push Notification Test - JSONRPC & GRPC", - "sdks": ["current", "python_v10", "python_v03", "go_v03"], - "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], - "protocols": ["jsonrpc", "grpc"], - "behavior": "push_notification" - }, - { - "name": "Push Notification Test - HTTP_JSON", - "sdks": ["current", "python_v10", "python_v03"], - "edges": ["0->1", "0->2", "1->0", "2->0"], - "protocols": ["http_json"], - "behavior": "push_notification" - }, - { - "name": "Resubscribe Test - JSONRPC", - "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], - "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], - "protocols": ["jsonrpc"], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Resubscribe Test - Python & Go Non-JSONRPC Protocols", - "sdks": ["current", "python_v10", "python_v03", "go_v10"], - "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], - "protocols": ["grpc", "http_json"], - "streaming": true, - "behavior": "resubscribe" - } - ] -} diff --git a/itk/scenarios_full.json b/itk/scenarios_full.json deleted file mode 100644 index 8ab5a1434..000000000 --- a/itk/scenarios_full.json +++ /dev/null @@ -1,392 +0,0 @@ -{ - "tests": [ - { - "name": "Current vs Python v10 - Send Message (Non-Streaming)", - "sdks": ["current", "python_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Python v10 - Send Message (Streaming)", - "sdks": ["current", "python_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Python v10 - Push Notification", - "sdks": ["current", "python_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Python v10 - Resubscribe", - "sdks": ["current", "python_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs Python v03 - Send Message (Non-Streaming)", - "sdks": ["current", "python_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Python v03 - Send Message (Streaming)", - "sdks": ["current", "python_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Python v03 - Push Notification", - "sdks": ["current", "python_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Python v03 - Resubscribe", - "sdks": ["current", "python_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs Go v10 - Send Message (Non-Streaming)", - "sdks": ["current", "go_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Go v10 - Send Message (Streaming)", - "sdks": ["current", "go_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Go v10 - Push Notification", - "sdks": ["current", "go_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Go v10 - Resubscribe", - "sdks": ["current", "go_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs Go v03 - Send Message (Non-Streaming)", - "sdks": ["current", "go_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Go v03 - Send Message (Streaming)", - "sdks": ["current", "go_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Go v03 - Push Notification", - "sdks": ["current", "go_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Go v03 - Resubscribe", - "sdks": ["current", "go_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs TS v10 - Send Message (Non-Streaming)", - "sdks": ["current", "ts_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs TS v10 - Send Message (Streaming)", - "sdks": ["current", "ts_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs TS v10 - Push Notification", - "sdks": ["current", "ts_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs TS v10 - Resubscribe", - "sdks": ["current", "ts_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs TS v03 - Send Message (Non-Streaming)", - "sdks": ["current", "ts_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc" - ], - "behavior": "send_message" - }, - { - "name": "Current vs TS v03 - Send Message (Streaming)", - "sdks": ["current", "ts_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs TS v03 - Push Notification", - "sdks": ["current", "ts_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs TS v03 - Resubscribe", - "sdks": ["current", "ts_v03"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs Rust v10 - Send Message (Non-Streaming)", - "sdks": ["current", "rust_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Rust v10 - Send Message (Streaming)", - "sdks": ["current", "rust_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Rust v10 - Push Notification", - "sdks": ["current", "rust_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Rust v10 - Resubscribe", - "sdks": ["current", "rust_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - }, - { - "name": "Current vs Java v10 - Send Message (Non-Streaming)", - "sdks": ["current", "java_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "send_message" - }, - { - "name": "Current vs Java v10 - Send Message (Streaming)", - "sdks": ["current", "java_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "send_message" - }, - { - "name": "Current vs Java v10 - Push Notification", - "sdks": ["current", "java_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "behavior": "push_notification" - }, - { - "name": "Current vs Java v10 - Resubscribe", - "sdks": ["current", "java_v10"], - "traversal": "euler", - "edges": ["0->1", "1->0"], - "protocols": [ - "jsonrpc", - "grpc", - "http_json" - ], - "streaming": true, - "behavior": "resubscribe" - } - ] -} From db97d72ba50fd94a8517966142ef44206743049a Mon Sep 17 00:00:00 2001 From: JakubWorek Date: Tue, 25 Aug 2026 14:41:35 +0000 Subject: [PATCH 2/2] Update check-spelling metadata --- .github/actions/spelling/allow.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index dc1b6831a..cba8a880d 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -139,6 +139,7 @@ SECP256R1 SFIXED SLF socio +sourced sse starlette Starlette