Skip to main content

Bridge between smolagents and the A2A (Agent2Agent) protocol

Project description

A2A-Smol-Adapter

Python 3.10+ License: MIT Tests Ruff

Bridge between smolagents (HuggingFace) and the A2A protocol (Google).

Expose any smolagents CodeAgent as an A2A-compliant server, or delegate tasks from a CodeAgent to remote A2A agents — in a few lines of Python.

Why?

The Agent2Agent (A2A) protocol is an open standard for agent interoperability. smolagents is HuggingFace's lightweight agent framework. This library bridges both, enabling:

  • Your smolagents agents to be discoverable and callable by any A2A-compatible client
  • Your agents to delegate work to any remote A2A agent (LangChain, CrewAI, Google ADK, etc.)
  • Multi-agent systems where agents from different frameworks collaborate seamlessly

Features

Feature Description
A2A Server Wrap a CodeAgent in a FastAPI server that speaks JSON-RPC 2.0
A2A Client Tool smolagents.Tool to delegate work to any remote A2A agent
Agent Card Auto-generated discovery endpoint at /.well-known/agent-card.json
API Key Auth Optional Bearer token authentication on server and client
SSE Streaming Intermediate progress events via message/stream
Retry with Backoff Exponential backoff on transient network errors (client)
Configurable Timeout Server-side agent execution timeout with proper failure events
Health Endpoint GET /health for Kubernetes liveness/readiness probes

Installation

pip install a2a-smol-adapter

Or from source:

git clone https://github.com/billyboy06/a2a-smol-adapter.git
cd a2a-smol-adapter
pip install -e ".[dev]"

Quick Start

Expose an agent as A2A server

import os
from smolagents import CodeAgent, InferenceClientModel
from a2a_smol_adapter import SmolA2AServer

agent = CodeAgent(tools=[], model=InferenceClientModel())

server = SmolA2AServer(
    agent,
    name="my-agent",
    host="0.0.0.0",             # listen on all interfaces (default: 127.0.0.1)
    port=5001,
    api_key=os.environ.get("A2A_API_KEY"),  # optional auth via env var
    agent_timeout=60.0,         # optional timeout (default: 120s)
)
server.run()
# Agent card → http://localhost:5001/.well-known/agent-card.json
# Health     → http://localhost:5001/health

Delegate to a remote A2A agent

import os
from smolagents import CodeAgent, InferenceClientModel
from a2a_smol_adapter import SmolA2ADelegateTool

delegate = SmolA2ADelegateTool(
    remote_url="http://remote-agent:5001/",
    api_key=os.environ.get("A2A_API_KEY"),  # optional, matches server auth
    max_retries=2,              # retry on network errors (default: 2)
)

agent = CodeAgent(tools=[delegate], model=InferenceClientModel())
result = agent.run("Ask the remote agent to compute pi to 50 digits")

Architecture

┌──────────────────┐          ┌──────────────────────────────────────┐
│  Any A2A Client  │          │  SmolA2AServer                      │
│  (LangChain,     │  JSON-   │  ┌──────────┐  ┌────────────────┐  │
│   CrewAI,        │  RPC 2.0 │  │ FastAPI   │  │ SmolAgent      │  │
│   Google ADK,    │ ────────►│  │ + Auth    │─►│ Executor       │  │
│   curl...)       │          │  │ + Health  │  │ (async bridge) │  │
└──────────────────┘          │  └──────────┘  └───────┬────────┘  │
                              │                        │           │
                              │                ┌───────▼────────┐  │
                              │                │ smolagents     │  │
                              │                │ CodeAgent.run()│  │
                              │                └────────────────┘  │
                              └──────────────────────────────────────┘

┌──────────────────────────────────────┐          ┌──────────────────┐
│  Your smolagents CodeAgent           │          │  Any A2A Server  │
│  ┌────────────────────────────────┐  │  JSON-   │  (this lib,      │
│  │ SmolA2ADelegateTool            │  │  RPC 2.0 │   Google ADK,    │
│  │ (auto-retry, auth, timeout)   │──│─────────►│   LangChain...)  │
│  └────────────────────────────────┘  │          └──────────────────┘
└──────────────────────────────────────┘

API Reference

SmolA2AServer

SmolA2AServer(
    agent: CodeAgent,
    *,
    name: str = "smol-agent",
    description: str = "...",
    version: str = "0.1.0",
    host: str = "127.0.0.1",
    port: int = 5000,
    skills: list[dict] | None = None,
    api_key: str | None = None,        # Bearer token auth
    agent_timeout: float = 120.0,      # seconds before timeout
)
Method Description
run() Start the uvicorn server
build_app() Return the FastAPI app (for custom deployments, ASGI)
agent_card The A2A AgentCard with name, skills, capabilities

SmolA2ADelegateTool

SmolA2ADelegateTool(
    remote_url: str = "",
    timeout: float = 120.0,
    api_key: str | None = None,        # Bearer token for remote server
    max_retries: int = 2,              # retries on ConnectError/Timeout
    http_client: httpx.Client | None = None,  # injectable for testing
)

Usable as a standard smolagents.Tool — add it to your agent's tool list and call via delegate_to_a2a(url, task).

Testing

pip install -e ".[dev]"

# Run all 69 tests
pytest -v

# Lint
ruff check src/ tests/

Test coverage includes:

  • Unit tests for server executor, client tool, auth middleware, healthcheck
  • Integration tests with full cycle: discovery → send task → receive artifact
  • Auth scenarios: valid key, invalid key, missing key, exempt paths
  • Retry behavior: exponential backoff, exhausted retries, no retry on 4xx/5xx
  • Timeout: agent execution timeout with proper failure events
  • Streaming: intermediate working events from agent steps

Project Structure

src/a2a_smol_adapter/
├── __init__.py         # Public API: SmolA2AServer, SmolA2ADelegateTool
├── server.py           # A2A server, executor, auth middleware, healthcheck
└── client_tool.py      # A2A client tool with retry, auth, DI

tests/
├── test_server.py      # 38 tests — executor, auth, streaming, health
├── test_client_tool.py # 23 tests — retry, auth header, DI, extraction
└── integration/
    └── test_end_to_end.py  # 8 tests — full cycle with ASGI transport

examples/
├── basic_server.py     # Minimal server setup
└── basic_client.py     # Minimal client delegation

Security Considerations

  • API key comparison uses hmac.compare_digest (timing-safe) to prevent side-channel attacks
  • Default host is 127.0.0.1 (localhost only) — use host="0.0.0.0" explicitly for network-facing deployments
  • Prompt size is capped at 100KB to prevent abuse
  • No rate limiting built-in — use a reverse proxy (nginx, Traefik) for rate limiting in production
  • Security headers (HSTS, CSP, etc.) are the responsibility of your reverse proxy
  • Prompt injection: CodeAgent generates and executes Python code from user prompts. Use smolagents' sandboxing features (LocalPythonExecutor restrictions) when exposing to untrusted users
  • Consumer responsibility: error messages from remote agents are returned as-is — escape them before rendering in HTML contexts
  • API keys should be loaded from environment variables, never hardcoded (see examples)

Built With

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

a2a_smol_adapter-0.1.0.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

a2a_smol_adapter-0.1.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file a2a_smol_adapter-0.1.0.tar.gz.

File metadata

  • Download URL: a2a_smol_adapter-0.1.0.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for a2a_smol_adapter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0ade61f5dcba7e7f5678b7c27ee49cff9cf88e68d6c261d052699a8539fe8a87
MD5 8515c24d622a9362f0075808f3d23c59
BLAKE2b-256 8ed194fa5e345ff262d6a5e5f00dda786956dfe5efedd7d7fd2977b85d6760e8

See more details on using hashes here.

File details

Details for the file a2a_smol_adapter-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for a2a_smol_adapter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 addf7cded22f6c4063d133a90b644a665ad79f319f7ec478c581c0efd53a9788
MD5 7e22822d7541127e999831470ce77438
BLAKE2b-256 3a718746e1101f0fb8d36218638c336be4929a722a003ad0e08f0d753924d050

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page