Simplified wrapper for Google's A2A Protocol SDK
Project description
A2A Lite - Python
Build A2A agents in 8 lines. Add features when you need them.
Wraps the official A2A Python SDK with a simple, intuitive API.
from a2a_lite import Agent
agent = Agent(name="Bot", description="My bot")
@agent.skill("greet")
async def greet(name: str) -> str:
return f"Hello, {name}!"
agent.run()
Installation
pip install a2a-lite
# or
uv add a2a-lite
Requirements: Python 3.10+
Quick Start
1. Create an agent
from a2a_lite import Agent
agent = Agent(name="Calculator", description="Does math")
@agent.skill("add")
async def add(a: int, b: int) -> int:
return a + b
@agent.skill("multiply")
async def multiply(a: int, b: int) -> int:
return a * b
agent.run(port=8787)
2. Test it
from a2a_lite import Agent, AgentTestClient
agent = Agent(name="Calculator", description="Does math")
@agent.skill("add")
async def add(a: int, b: int) -> int:
return a + b
client = AgentTestClient(agent)
result = client.call("add", a=2, b=3)
assert result == 5
3. Call it
curl -X POST http://localhost:8787/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "message/send",
"id": "1",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "{\"skill\": \"add\", \"params\": {\"a\": 2, \"b\": 3}}"}],
"messageId": "msg-1"
}
}
}'
Progressive Complexity
Level 1: Basic Skills
from a2a_lite import Agent
agent = Agent(name="Bot", description="A bot")
@agent.skill("greet")
async def greet(name: str) -> str:
return f"Hello, {name}!"
agent.run()
Level 2: Pydantic Models (Just Works)
Pass dicts from callers — they're auto-converted to Pydantic models:
from pydantic import BaseModel
class User(BaseModel):
name: str
email: str
@agent.skill("create_user")
async def create_user(user: User) -> dict:
return {"id": 1, "name": user.name}
Lists of models work too:
from typing import List
@agent.skill("count_users")
async def count_users(users: List[User]) -> int:
return len(users)
Level 3: Streaming (Just Yield)
@agent.skill("chat", streaming=True)
async def chat(message: str):
for word in message.split():
yield word + " "
Level 4: Middleware
@agent.middleware
async def log_requests(ctx, next):
print(f"Calling: {ctx.skill}")
result = await next()
print(f"Result: {result}")
return result
Built-in middleware:
from a2a_lite import logging_middleware, timing_middleware, retry_middleware, rate_limit_middleware
agent.add_middleware(logging_middleware)
agent.add_middleware(timing_middleware)
agent.add_middleware(rate_limit_middleware(max_per_minute=60))
agent.add_middleware(retry_middleware(max_retries=3))
Level 5: File Handling
from a2a_lite import FilePart
@agent.skill("summarize")
async def summarize(doc: FilePart) -> str:
content = await doc.read_text()
return f"Summary: {content[:100]}..."
Level 6: Task Tracking
from a2a_lite import TaskContext
agent = Agent(name="Bot", description="A bot", task_store="memory")
@agent.skill("process")
async def process(data: str, task: TaskContext) -> str:
await task.update("working", "Starting...", progress=0.0)
for i in range(10):
await task.update("working", f"Step {i}/10", progress=i/10)
return "Done!"
Level 7: Authentication
from a2a_lite import Agent, APIKeyAuth
agent = Agent(
name="SecureBot",
description="A secure bot",
auth=APIKeyAuth(keys=["secret-key-1", "secret-key-2"]),
)
API keys are hashed in memory using SHA-256 — plaintext keys are never stored.
Other auth providers:
from a2a_lite.auth import BearerAuth, OAuth2Auth
# Bearer/JWT
agent = Agent(
name="Bot", description="A bot",
auth=BearerAuth(secret="your-jwt-secret"),
)
# OAuth2 (requires: pip install a2a-lite[oauth])
agent = Agent(
name="Bot", description="A bot",
auth=OAuth2Auth(issuer="https://auth.example.com", audience="my-api"),
)
Skills can receive auth results by type-hinting a parameter as AuthResult:
from a2a_lite.auth import AuthResult
@agent.skill("whoami")
async def whoami(auth: AuthResult) -> dict:
return {"user": auth.identity, "scheme": auth.scheme}
Level 8: CORS and Production Mode
agent = Agent(
name="Bot",
description="A bot",
cors_origins=["https://myapp.com", "https://admin.myapp.com"],
production=True, # Warns if running over HTTP
)
Level 9: Completion Hooks
@agent.on_complete
async def notify(skill_name, result, ctx):
print(f"Skill {skill_name} completed with: {result}")
Testing
AgentTestClient
The synchronous test client for use with pytest:
from a2a_lite import Agent, AgentTestClient
agent = Agent(name="Bot", description="Test")
@agent.skill("greet")
async def greet(name: str) -> str:
return f"Hello, {name}!"
@agent.skill("info")
async def info(name: str, age: int) -> dict:
return {"name": name, "age": age}
def test_simple_result():
client = AgentTestClient(agent)
result = client.call("greet", name="World")
assert result == "Hello, World!"
def test_dict_result():
client = AgentTestClient(agent)
result = client.call("info", name="Alice", age=30)
assert result.data["name"] == "Alice"
assert result.data["age"] == 30
def test_list_skills():
client = AgentTestClient(agent)
skills = client.list_skills()
assert "greet" in skills
assert "info" in skills
TestResult
Every client.call() returns a TestResult with:
| Property | Description |
|---|---|
.data |
Parsed Python object (dict, list, int, str, etc.) |
.text |
Raw text string from the response |
.json() |
Parse text as JSON (raises on invalid JSON) |
.raw_response |
Full A2A response dict |
TestResult supports direct equality comparison for simple values (result == 5), but use .data for subscripting (result.data["key"]).
AsyncAgentTestClient
For async test frameworks:
import pytest
from a2a_lite import AsyncAgentTestClient
@pytest.mark.asyncio
async def test_async():
client = AsyncAgentTestClient(agent)
result = await client.call("greet", name="World")
assert result == "Hello, World!"
await client.close()
Streaming Tests
def test_streaming():
client = AgentTestClient(agent)
results = client.stream("chat", message="hello world")
assert len(results) == 2
CLI
a2a-lite init my-agent # Create new project
a2a-lite serve agent.py # Run agent from file
a2a-lite inspect http://... # View agent capabilities
a2a-lite test http://... skill # Test a skill
a2a-lite version # Show version
API Reference
Agent
Agent(
name: str, # Required
description: str, # Required
version: str = "1.0.0",
url: str = None, # Override auto-detected URL
auth: AuthProvider = None, # Authentication provider
task_store: str | TaskStore = None, # "memory" or custom TaskStore
cors_origins: List[str] = None, # CORS allowed origins
production: bool = False, # Enable production warnings
)
Methods:
| Method | Description |
|---|---|
@agent.skill(name, **config) |
Register a skill via decorator |
@agent.middleware |
Register middleware via decorator |
agent.add_middleware(fn) |
Register middleware function |
@agent.on_complete |
Register completion hook |
@agent.on_startup |
Register startup hook |
@agent.on_shutdown |
Register shutdown hook |
@agent.on_error |
Register error handler |
agent.run(port=8787) |
Start the server |
agent.get_app() |
Get the ASGI app (for custom deployment) |
Skill Decorator
@agent.skill(
name: str = None, # Skill name (defaults to function name)
description: str = None, # Human-readable description
tags: List[str] = None, # Categorization tags
streaming: bool = False, # Enable streaming
)
Auth Providers
| Provider | Usage |
|---|---|
APIKeyAuth(keys=[...]) |
API key auth (keys hashed with SHA-256) |
BearerAuth(secret=...) |
JWT/Bearer token auth |
OAuth2Auth(issuer=..., audience=...) |
OAuth2 auth (requires a2a-lite[oauth]) |
NoAuth() |
No auth (default) |
Special Parameter Types
These are auto-injected when detected in skill function signatures:
| Type | Description |
|---|---|
TaskContext |
Task lifecycle management (requires task_store) |
AuthResult |
Authentication result injection |
FilePart |
File upload handling |
DataPart |
Structured data handling |
Examples
| Example | What it shows |
|---|---|
| 01_hello_world.py | Simplest agent (8 lines) |
| 02_calculator.py | Multiple skills |
| 06_pydantic_models.py | Auto Pydantic conversion |
| 08_streaming.py | Streaming responses |
| 09_testing.py | Testing your agents |
| 10_file_handling.py | Handle files |
| 11_task_tracking.py | Progress updates |
| 12_with_auth.py | Authentication |
100% A2A Protocol Compatible
A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A protocol concepts:
| A2A Lite | A2A Protocol |
|---|---|
@agent.skill() |
Agent Skills |
streaming=True |
SSE Streaming |
TaskContext.update() |
Task lifecycle states |
FilePart |
A2A File parts |
DataPart |
A2A Data parts |
APIKeyAuth / BearerAuth |
Security schemes |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file a2a_lite-0.2.4.tar.gz.
File metadata
- Download URL: a2a_lite-0.2.4.tar.gz
- Upload date:
- Size: 40.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81e0b2294121c977b7fcb9cf5f7e59fe0911b05ff4ce9f684a887992f5a3c203
|
|
| MD5 |
87421cc6e9c4b3fc8fa9f8186352f22e
|
|
| BLAKE2b-256 |
db9a5eeeced27658902e01564f294ebf787ee3c133368ac1c25021e115b31e0c
|
File details
Details for the file a2a_lite-0.2.4-py3-none-any.whl.
File metadata
- Download URL: a2a_lite-0.2.4-py3-none-any.whl
- Upload date:
- Size: 31.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4af61910ab8d42b12ceccdad31271a90efd593c61cc103fa0d2158c14adfeb4
|
|
| MD5 |
77b715b59251a2aa4f63eb3be5e37fb6
|
|
| BLAKE2b-256 |
246b6248da704cb5adc968780231647050683625a4d368beea2b13fab065fcb9
|