Skip to content

Latest commit

 

History

History
114 lines (90 loc) · 5.11 KB

File metadata and controls

114 lines (90 loc) · 5.11 KB

Stock availability over A2A

This is a deterministic inventory demo using the official A2A Python SDK HTTP+JSON 1.0 binding. The client discovers the public Agent Card, then calls SendMessage with POST /message:send. WIDGET-001 always has 42 units.

From this repository's python/ directory, with Python 3.11 or newer:

uv sync --extra demo
uv run --extra demo pytest tests/test_stock_demo.py

The tests use HTTPS ASGI requests, generated keys, temporary SQLite databases and a simulated registry.

Local TLS demo

Use one shell to configure a local test identity, then run the server. The generator creates a buyer key, its public key, and a separate localhost TLS key/certificate valid for two days. It refuses to write credentials inside this repository or overwrite existing files.

stock_demo_dir="$(mktemp -d)"
uv run --extra demo python -m examples.stock.local_setup "$stock_demo_dir"

export AITHOS_STOCK_MODE=local
export AITHOS_STOCK_BASE_URL=https://localhost:8443
export AITHOS_STOCK_LOCAL_PUBLIC_KEY="$stock_demo_dir/buyer.pub.pem"
export AITHOS_STOCK_NONCE_DB="$stock_demo_dir/nonces.sqlite3"
export AITHOS_STOCK_REQUIRED_DOMAINS=supplier.example
export AITHOS_STOCK_KEY_ID=local-stock-buyer
export AITHOS_STOCK_PRIVATE_KEY="$stock_demo_dir/buyer.key.pem"
export AITHOS_STOCK_CA_FILE="$stock_demo_dir/server.cert.pem"

uv run --extra demo uvicorn examples.stock.server:app_from_env --factory \
  --host 127.0.0.1 --port 8443 --no-proxy-headers \
  --ssl-keyfile "$stock_demo_dir/server.key.pem" \
  --ssl-certfile "$stock_demo_dir/server.cert.pem"

In another shell, set AITHOS_STOCK_PRIVATE_KEY and AITHOS_STOCK_CA_FILE to the paths printed above and AITHOS_STOCK_KEY_ID=local-stock-buyer, then:

uv run --extra demo python -m examples.stock.client --sku WIDGET-001

The response is an SDK-parsed A2A SendMessageResponse whose message contains {"sku": "WIDGET-001", "quantity": 42, "mock": true, ...}. TLS is verified against the explicitly trusted test certificate. The local resolver asserts supplier.example only as a fixture; it is not a registry domain certification.

The local files are throwaway development credentials. Retain the nonce database while the same keys/server remain in use, including across server restarts.

Aithos Registry mode

The default server mode is registry, using AithosResolver() and https://registry.aithos.world. Configure your own registered buyer's key without copying a real private key into this repository:

export AITHOS_STOCK_MODE=registry
export AITHOS_STOCK_BASE_URL=https://your-stock-server.example
export AITHOS_STOCK_ALLOWED_AGENTS='YOUR_REGISTERED_AGENT_ID'
export AITHOS_STOCK_REQUIRED_DOMAINS=your-verified-domain.example
export AITHOS_STOCK_NONCE_DB=/persistent/shared/stock-nonces.sqlite3
export AITHOS_STOCK_KEY_ID='YOUR_REGISTERED_AGENT_ID:YOUR_KEY_THUMBPRINT'
export AITHOS_STOCK_PRIVATE_KEY=/secure/path/to/your-buyer-key.pem
unset AITHOS_STOCK_CA_FILE

Run the same Uvicorn factory with your server TLS certificate and key. AITHOS_STOCK_BASE_URL is trusted deployment configuration and must match the externally visible HTTPS origin. This example serves at the origin root; it does not configure proxy path rewriting. Set it on the client too. Do not expose the explicit local fixture mode as a public identity service.

Optional server settings:

Variable Default / effect
AITHOS_STOCK_REGISTRY_ORIGIN The official registry; can be another HTTPS registry origin
AITHOS_STOCK_ALLOWED_AGENTS *, or comma-separated agent identifiers
AITHOS_STOCK_REQUIRED_DOMAINS supplier.example; comma-separated required domains
AITHOS_STOCK_DOMAIN_OPERATOR or, or and
AITHOS_STOCK_NONCE_DB .aithos-auth/stock-nonces.sqlite3

All instances accepting the same signed requests must share durable replay state. A SQLite file on one host can serve multiple workers; deployments across hosts need a shared atomic nonce store satisfying the library contract.

Integration boundaries

server.py serves /.well-known/agent-card.json publicly and mounts every SDK operation behind the A2A activation adapter and AithosAuthMiddleware. The adapter uses the SDK's ExtensionSupportRequiredError serialization for missing activation (400), then the middleware enforces identity, domain policy and replay protection (401/403). Successful responses include A2A-Extensions, preserving other extensions already activated by the server. Unsupported operations still pass through activation and authentication.

client.py uses the SDK's A2ACardResolver and RestTransport. Its HTTPX request hook adds A2A-Extensions, A2A-Version and the A2A media type before signing the final request.content bytes. It refuses another origin and disables redirects. The exact prepared request is then sent by HTTPX, with no JSON reserialization after signing.

The end-to-end tests cover public discovery, SDK SendMessage, signed body and header tampering, unknown keys, replay across a server restart, domain denial, missing activation, extension response headers and registry key withdrawal.