Skip to content
Merged
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
16 changes: 16 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,19 @@ jobs:
run: pip install pytest pydantic pydantic-settings httpx python-dotenv
- name: Run tests
run: python -m pytest -v

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Good use of SHA-pinned actions with version comments. The timeout-minutes: 15 is a sensible guardrail.

# Make sure all of the examples start up successfully by running their `test_startup.exp` scripts, which use `expect` to verify the agent starts and responds to a simple input.
test-startup:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6
- name: Install expect
run: sudo apt-get update && sudo apt-get install -y expect
- name: Verify agents start
run: make test-startup-all
27 changes: 26 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.PHONY: lint fmt test-docker test-a2a test-mcp sync-all-uv sync-a2a sync-mcp
SHELL := /bin/bash

.PHONY: lint fmt test-docker test-a2a test-mcp sync-all-uv sync-a2a sync-mcp test-startup-all test-startup-a2a test-startup-mcp

lint:
pre-commit run --all-files
Expand Down Expand Up @@ -48,3 +50,26 @@ sync-mcp:
uv sync --no-dev || exit; \
popd; \
done

test-startup-all: test-startup-a2a test-startup-mcp

# Run the test_startup.exp script for each A2A example that has one to verify it starts successfully.
test-startup-a2a:
@for f in $(shell find a2a -mindepth 1 -maxdepth 1 -type d); do \
pushd $${f} || exit; \
if [ -f test_startup.exp ]; then \
echo "Testing startup for $${f}..."; \
expect -f test_startup.exp || exit; \
fi; \
popd; \
done

test-startup-mcp:
@for f in $(shell find mcp -mindepth 1 -maxdepth 1 -type d); do \
pushd $${f} || exit; \
if [ -f test_startup.exp ]; then \
echo "Testing startup for $${f}..."; \
expect -f test_startup.exp || exit; \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: test-startup-a2a and test-startup-mcp are nearly identical — the only difference is the top-level directory (a2a vs mcp). Could collapse into a shared pattern to reduce duplication, but not blocking since it's only ~10 lines each.

fi; \
popd; \
done
5 changes: 4 additions & 1 deletion a2a/a2a_contact_extractor/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/a2a_contact_extractor/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked . --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
3 changes: 3 additions & 0 deletions a2a/a2a_currency_converter/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.venv
deployment

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/a2a_currency_converter/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked app --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
3 changes: 3 additions & 0 deletions a2a/cheerup_agent/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ __pycache__
*.pyc
.venv
.git

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/cheerup_agent/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion a2a/file_organizer/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/file_organizer/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion a2a/generic_agent/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/generic_agent/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
4 changes: 4 additions & 0 deletions a2a/git_issue_agent/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.venv

# `expect` scripts
test_startup.exp
23 changes: 23 additions & 0 deletions a2a/git_issue_agent/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
set child_pid [spawn env HOST=localhost PORT=8001 uv run --locked server]

expect {
"Uvicorn running on" {
# Unlike the other servers, this one opens a child process.
# Without the explicit `pkill -P` it would leave a `uv` process running.
puts "Spawned pid was $child_pid"
exec pkill -P $child_pid
puts "Success"; exit 0
}
timeout {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The pkill -P $child_pid cleanup in the success branch is good. In the timeout branch you use kill -9 directly on the parent — if the child also spawns its own children, those grandchildren may survive. Consider using pkill -P in the timeout branch too for consistency.

exec pkill -P $child_pid
puts "Timed out waiting for startup"; exit 1
}
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion a2a/image_service/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/image_service/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
3 changes: 3 additions & 0 deletions a2a/recipe_agent/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ __pycache__
*.pyc
.venv
.git

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/recipe_agent/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
3 changes: 3 additions & 0 deletions a2a/reservation_service/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ build
.git
.gitignore
.DS_Store

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/reservation_service/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked python -c "from src.reservation_service.agent import run; run()" --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion a2a/simple_generalist/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ README.md
tests
.pytest_cache
.coverage
htmlcov
htmlcov

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/simple_generalist/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked python -c "from src.simple_generalist.main import run; run()" --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion a2a/slack_researcher/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/slack_researcher/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
3 changes: 3 additions & 0 deletions a2a/trivia_agent/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ __pycache__
*.pyc
.venv
.git

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/trivia_agent/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked python -c "from src.trivia_agent.agent import run; run()" --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
2 changes: 2 additions & 0 deletions a2a/weather_service/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

deployment

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions a2a/weather_service/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked server --host localhost --port 8001

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion mcp/cloud_storage_tool/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions mcp/cloud_storage_tool/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked cloud_storage_tool.py

expect {
"Uvicorn running on" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
4 changes: 4 additions & 0 deletions mcp/flight_tool/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.venv

# `expect` scripts
test_startup.exp
14 changes: 14 additions & 0 deletions mcp/flight_tool/test_startup.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This script tests if the server has dependencies and reaches the point of starting its server.

# Run with `expect -f test_startup.exp`

set timeout 120

# This is similar the Dockerfile CMD
spawn env HOST=localhost PORT=8001 uv run --locked flight_tool.py

expect {
"http://localhost:8001/mcp" { puts "Success"; exit 0 }
timeout { puts "Timed out waiting for startup"; exit 1 }
eof { puts "Process exited early"; exit 2 }
}
5 changes: 4 additions & 1 deletion mcp/image_tool/.dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.venv
.venv

# `expect` scripts
test_startup.exp
Loading
Loading