a2a-lite 0.2.4__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/PKG-INFO +57 -30
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/README.md +56 -29
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/pyproject.toml +1 -1
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/.claude/settings.local.json +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/.gitignore +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/01_hello_world.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/02_calculator.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/03_async_agent.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/04_multi_agent/finance_agent.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/04_multi_agent/reporter_agent.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/04_multi_agent/run_demo.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/05_with_llm.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/06_pydantic_models.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/07_middleware.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/08_streaming.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/09_testing.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/10_file_handling.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/11_task_tracking.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/examples/12_with_auth.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/__init__.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/agent.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/auth.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/cli.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/decorators.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/executor.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/middleware.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/parts.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/streaming.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/tasks.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/testing.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/src/a2a_lite/utils.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/__init__.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_agent.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_auth.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_decorators.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_integration.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_middleware.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_parts.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_pydantic.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_tasks.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_testing.py +0 -0
- {a2a_lite-0.2.4 → a2a_lite-0.2.5}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: a2a-lite
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Simplified wrapper for Google's A2A Protocol SDK
|
|
5
5
|
Author: A2A Lite Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -29,11 +29,14 @@ Provides-Extra: oauth
|
|
|
29
29
|
Requires-Dist: pyjwt[crypto]>=2.0; extra == 'oauth'
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
|
-
# A2A Lite
|
|
32
|
+
# A2A Lite — Python
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/a2a-lite/)
|
|
35
|
+
[](https://github.com/xvierd/a2a-lite)
|
|
33
36
|
|
|
34
37
|
**Build A2A agents in 8 lines. Add features when you need them.**
|
|
35
38
|
|
|
36
|
-
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple,
|
|
39
|
+
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple, decorator-based API. 100% protocol-compatible.
|
|
37
40
|
|
|
38
41
|
```python
|
|
39
42
|
from a2a_lite import Agent
|
|
@@ -81,7 +84,7 @@ async def multiply(a: int, b: int) -> int:
|
|
|
81
84
|
agent.run(port=8787)
|
|
82
85
|
```
|
|
83
86
|
|
|
84
|
-
### 2. Test it
|
|
87
|
+
### 2. Test it (no HTTP needed)
|
|
85
88
|
|
|
86
89
|
```python
|
|
87
90
|
from a2a_lite import Agent, AgentTestClient
|
|
@@ -97,7 +100,7 @@ result = client.call("add", a=2, b=3)
|
|
|
97
100
|
assert result == 5
|
|
98
101
|
```
|
|
99
102
|
|
|
100
|
-
### 3. Call it
|
|
103
|
+
### 3. Call it over the network
|
|
101
104
|
|
|
102
105
|
```bash
|
|
103
106
|
curl -X POST http://localhost:8787/ \
|
|
@@ -120,7 +123,7 @@ curl -X POST http://localhost:8787/ \
|
|
|
120
123
|
|
|
121
124
|
## Progressive Complexity
|
|
122
125
|
|
|
123
|
-
### Level 1
|
|
126
|
+
### Level 1 — Basic Skills
|
|
124
127
|
|
|
125
128
|
```python
|
|
126
129
|
from a2a_lite import Agent
|
|
@@ -134,7 +137,7 @@ async def greet(name: str) -> str:
|
|
|
134
137
|
agent.run()
|
|
135
138
|
```
|
|
136
139
|
|
|
137
|
-
### Level 2
|
|
140
|
+
### Level 2 — Pydantic Models
|
|
138
141
|
|
|
139
142
|
Pass dicts from callers — they're auto-converted to Pydantic models:
|
|
140
143
|
|
|
@@ -160,7 +163,9 @@ async def count_users(users: List[User]) -> int:
|
|
|
160
163
|
return len(users)
|
|
161
164
|
```
|
|
162
165
|
|
|
163
|
-
### Level 3
|
|
166
|
+
### Level 3 — Streaming
|
|
167
|
+
|
|
168
|
+
Just `yield` instead of `return`:
|
|
164
169
|
|
|
165
170
|
```python
|
|
166
171
|
@agent.skill("chat", streaming=True)
|
|
@@ -169,7 +174,9 @@ async def chat(message: str):
|
|
|
169
174
|
yield word + " "
|
|
170
175
|
```
|
|
171
176
|
|
|
172
|
-
### Level 4
|
|
177
|
+
### Level 4 — Middleware
|
|
178
|
+
|
|
179
|
+
Cross-cutting concerns without touching skill code:
|
|
173
180
|
|
|
174
181
|
```python
|
|
175
182
|
@agent.middleware
|
|
@@ -191,7 +198,9 @@ agent.add_middleware(rate_limit_middleware(max_per_minute=60))
|
|
|
191
198
|
agent.add_middleware(retry_middleware(max_retries=3))
|
|
192
199
|
```
|
|
193
200
|
|
|
194
|
-
### Level 5
|
|
201
|
+
### Level 5 — File Handling
|
|
202
|
+
|
|
203
|
+
Accept and return files through the A2A protocol:
|
|
195
204
|
|
|
196
205
|
```python
|
|
197
206
|
from a2a_lite import FilePart
|
|
@@ -202,7 +211,9 @@ async def summarize(doc: FilePart) -> str:
|
|
|
202
211
|
return f"Summary: {content[:100]}..."
|
|
203
212
|
```
|
|
204
213
|
|
|
205
|
-
### Level 6
|
|
214
|
+
### Level 6 — Task Tracking
|
|
215
|
+
|
|
216
|
+
Long-running operations with progress updates:
|
|
206
217
|
|
|
207
218
|
```python
|
|
208
219
|
from a2a_lite import TaskContext
|
|
@@ -212,14 +223,14 @@ agent = Agent(name="Bot", description="A bot", task_store="memory")
|
|
|
212
223
|
@agent.skill("process")
|
|
213
224
|
async def process(data: str, task: TaskContext) -> str:
|
|
214
225
|
await task.update("working", "Starting...", progress=0.0)
|
|
215
|
-
|
|
216
226
|
for i in range(10):
|
|
217
227
|
await task.update("working", f"Step {i}/10", progress=i/10)
|
|
218
|
-
|
|
219
228
|
return "Done!"
|
|
220
229
|
```
|
|
221
230
|
|
|
222
|
-
### Level 7
|
|
231
|
+
### Level 7 — Authentication
|
|
232
|
+
|
|
233
|
+
API keys are hashed in memory using SHA-256 — plaintext keys are never stored.
|
|
223
234
|
|
|
224
235
|
```python
|
|
225
236
|
from a2a_lite import Agent, APIKeyAuth
|
|
@@ -231,8 +242,6 @@ agent = Agent(
|
|
|
231
242
|
)
|
|
232
243
|
```
|
|
233
244
|
|
|
234
|
-
API keys are hashed in memory using SHA-256 — plaintext keys are never stored.
|
|
235
|
-
|
|
236
245
|
Other auth providers:
|
|
237
246
|
|
|
238
247
|
```python
|
|
@@ -261,7 +270,7 @@ async def whoami(auth: AuthResult) -> dict:
|
|
|
261
270
|
return {"user": auth.identity, "scheme": auth.scheme}
|
|
262
271
|
```
|
|
263
272
|
|
|
264
|
-
### Level 8
|
|
273
|
+
### Level 8 — CORS & Production Mode
|
|
265
274
|
|
|
266
275
|
```python
|
|
267
276
|
agent = Agent(
|
|
@@ -272,12 +281,24 @@ agent = Agent(
|
|
|
272
281
|
)
|
|
273
282
|
```
|
|
274
283
|
|
|
275
|
-
### Level 9
|
|
284
|
+
### Level 9 — Lifecycle Hooks
|
|
276
285
|
|
|
277
286
|
```python
|
|
287
|
+
@agent.on_startup
|
|
288
|
+
async def startup():
|
|
289
|
+
print("Agent starting...")
|
|
290
|
+
|
|
291
|
+
@agent.on_shutdown
|
|
292
|
+
async def shutdown():
|
|
293
|
+
print("Agent stopping...")
|
|
294
|
+
|
|
278
295
|
@agent.on_complete
|
|
279
296
|
async def notify(skill_name, result, ctx):
|
|
280
297
|
print(f"Skill {skill_name} completed with: {result}")
|
|
298
|
+
|
|
299
|
+
@agent.on_error
|
|
300
|
+
async def handle_error(error: Exception):
|
|
301
|
+
return {"error": str(error), "type": type(error).__name__}
|
|
281
302
|
```
|
|
282
303
|
|
|
283
304
|
---
|
|
@@ -286,7 +307,7 @@ async def notify(skill_name, result, ctx):
|
|
|
286
307
|
|
|
287
308
|
### AgentTestClient
|
|
288
309
|
|
|
289
|
-
|
|
310
|
+
Synchronous test client for pytest:
|
|
290
311
|
|
|
291
312
|
```python
|
|
292
313
|
from a2a_lite import Agent, AgentTestClient
|
|
@@ -324,7 +345,7 @@ def test_list_skills():
|
|
|
324
345
|
|
|
325
346
|
### TestResult
|
|
326
347
|
|
|
327
|
-
Every `client.call()` returns a `TestResult
|
|
348
|
+
Every `client.call()` returns a `TestResult`:
|
|
328
349
|
|
|
329
350
|
| Property | Description |
|
|
330
351
|
|----------|-------------|
|
|
@@ -333,7 +354,7 @@ Every `client.call()` returns a `TestResult` with:
|
|
|
333
354
|
| `.json()` | Parse text as JSON (raises on invalid JSON) |
|
|
334
355
|
| `.raw_response` | Full A2A response dict |
|
|
335
356
|
|
|
336
|
-
`TestResult` supports direct equality
|
|
357
|
+
`TestResult` supports direct equality for simple values (`result == 5`), but use `.data` for subscripting (`result.data["key"]`).
|
|
337
358
|
|
|
338
359
|
### AsyncAgentTestClient
|
|
339
360
|
|
|
@@ -365,10 +386,11 @@ def test_streaming():
|
|
|
365
386
|
## CLI
|
|
366
387
|
|
|
367
388
|
```bash
|
|
368
|
-
a2a-lite init my-agent #
|
|
369
|
-
a2a-lite serve agent.py # Run agent from file
|
|
370
|
-
a2a-lite inspect http://... # View agent
|
|
371
|
-
a2a-lite test http://... skill #
|
|
389
|
+
a2a-lite init my-agent # Scaffold a new project
|
|
390
|
+
a2a-lite serve agent.py # Run an agent from file
|
|
391
|
+
a2a-lite inspect http://... # View agent card & skills
|
|
392
|
+
a2a-lite test http://... skill # Smoke-test a skill
|
|
393
|
+
a2a-lite discover # Find agents on the local network (mDNS)
|
|
372
394
|
a2a-lite version # Show version
|
|
373
395
|
```
|
|
374
396
|
|
|
@@ -427,7 +449,7 @@ Agent(
|
|
|
427
449
|
|
|
428
450
|
### Special Parameter Types
|
|
429
451
|
|
|
430
|
-
|
|
452
|
+
Auto-injected when detected in skill function signatures:
|
|
431
453
|
|
|
432
454
|
| Type | Description |
|
|
433
455
|
|------|-------------|
|
|
@@ -444,18 +466,22 @@ These are auto-injected when detected in skill function signatures:
|
|
|
444
466
|
|---------|---------------|
|
|
445
467
|
| [01_hello_world.py](examples/01_hello_world.py) | Simplest agent (8 lines) |
|
|
446
468
|
| [02_calculator.py](examples/02_calculator.py) | Multiple skills |
|
|
469
|
+
| [03_async_agent.py](examples/03_async_agent.py) | Async operations & lifecycle hooks |
|
|
470
|
+
| [04_multi_agent/](examples/04_multi_agent) | Two agents communicating |
|
|
471
|
+
| [05_with_llm.py](examples/05_with_llm.py) | OpenAI / Anthropic integration |
|
|
447
472
|
| [06_pydantic_models.py](examples/06_pydantic_models.py) | Auto Pydantic conversion |
|
|
473
|
+
| [07_middleware.py](examples/07_middleware.py) | Middleware pipeline |
|
|
448
474
|
| [08_streaming.py](examples/08_streaming.py) | Streaming responses |
|
|
449
|
-
| [09_testing.py](examples/09_testing.py) |
|
|
450
|
-
| [10_file_handling.py](examples/10_file_handling.py) |
|
|
475
|
+
| [09_testing.py](examples/09_testing.py) | Built-in TestClient |
|
|
476
|
+
| [10_file_handling.py](examples/10_file_handling.py) | File upload & processing |
|
|
451
477
|
| [11_task_tracking.py](examples/11_task_tracking.py) | Progress updates |
|
|
452
478
|
| [12_with_auth.py](examples/12_with_auth.py) | Authentication |
|
|
453
479
|
|
|
454
480
|
---
|
|
455
481
|
|
|
456
|
-
##
|
|
482
|
+
## A2A Protocol Mapping
|
|
457
483
|
|
|
458
|
-
|
|
484
|
+
Everything maps directly to the underlying protocol — no magic, no lock-in.
|
|
459
485
|
|
|
460
486
|
| A2A Lite | A2A Protocol |
|
|
461
487
|
|----------|--------------|
|
|
@@ -464,6 +490,7 @@ A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A proto
|
|
|
464
490
|
| `TaskContext.update()` | Task lifecycle states |
|
|
465
491
|
| `FilePart` | A2A File parts |
|
|
466
492
|
| `DataPart` | A2A Data parts |
|
|
493
|
+
| `Artifact` | A2A Artifacts |
|
|
467
494
|
| `APIKeyAuth` / `BearerAuth` | Security schemes |
|
|
468
495
|
|
|
469
496
|
---
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
# A2A Lite
|
|
1
|
+
# A2A Lite — Python
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/a2a-lite/)
|
|
4
|
+
[](https://github.com/xvierd/a2a-lite)
|
|
2
5
|
|
|
3
6
|
**Build A2A agents in 8 lines. Add features when you need them.**
|
|
4
7
|
|
|
5
|
-
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple,
|
|
8
|
+
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple, decorator-based API. 100% protocol-compatible.
|
|
6
9
|
|
|
7
10
|
```python
|
|
8
11
|
from a2a_lite import Agent
|
|
@@ -50,7 +53,7 @@ async def multiply(a: int, b: int) -> int:
|
|
|
50
53
|
agent.run(port=8787)
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
### 2. Test it
|
|
56
|
+
### 2. Test it (no HTTP needed)
|
|
54
57
|
|
|
55
58
|
```python
|
|
56
59
|
from a2a_lite import Agent, AgentTestClient
|
|
@@ -66,7 +69,7 @@ result = client.call("add", a=2, b=3)
|
|
|
66
69
|
assert result == 5
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
### 3. Call it
|
|
72
|
+
### 3. Call it over the network
|
|
70
73
|
|
|
71
74
|
```bash
|
|
72
75
|
curl -X POST http://localhost:8787/ \
|
|
@@ -89,7 +92,7 @@ curl -X POST http://localhost:8787/ \
|
|
|
89
92
|
|
|
90
93
|
## Progressive Complexity
|
|
91
94
|
|
|
92
|
-
### Level 1
|
|
95
|
+
### Level 1 — Basic Skills
|
|
93
96
|
|
|
94
97
|
```python
|
|
95
98
|
from a2a_lite import Agent
|
|
@@ -103,7 +106,7 @@ async def greet(name: str) -> str:
|
|
|
103
106
|
agent.run()
|
|
104
107
|
```
|
|
105
108
|
|
|
106
|
-
### Level 2
|
|
109
|
+
### Level 2 — Pydantic Models
|
|
107
110
|
|
|
108
111
|
Pass dicts from callers — they're auto-converted to Pydantic models:
|
|
109
112
|
|
|
@@ -129,7 +132,9 @@ async def count_users(users: List[User]) -> int:
|
|
|
129
132
|
return len(users)
|
|
130
133
|
```
|
|
131
134
|
|
|
132
|
-
### Level 3
|
|
135
|
+
### Level 3 — Streaming
|
|
136
|
+
|
|
137
|
+
Just `yield` instead of `return`:
|
|
133
138
|
|
|
134
139
|
```python
|
|
135
140
|
@agent.skill("chat", streaming=True)
|
|
@@ -138,7 +143,9 @@ async def chat(message: str):
|
|
|
138
143
|
yield word + " "
|
|
139
144
|
```
|
|
140
145
|
|
|
141
|
-
### Level 4
|
|
146
|
+
### Level 4 — Middleware
|
|
147
|
+
|
|
148
|
+
Cross-cutting concerns without touching skill code:
|
|
142
149
|
|
|
143
150
|
```python
|
|
144
151
|
@agent.middleware
|
|
@@ -160,7 +167,9 @@ agent.add_middleware(rate_limit_middleware(max_per_minute=60))
|
|
|
160
167
|
agent.add_middleware(retry_middleware(max_retries=3))
|
|
161
168
|
```
|
|
162
169
|
|
|
163
|
-
### Level 5
|
|
170
|
+
### Level 5 — File Handling
|
|
171
|
+
|
|
172
|
+
Accept and return files through the A2A protocol:
|
|
164
173
|
|
|
165
174
|
```python
|
|
166
175
|
from a2a_lite import FilePart
|
|
@@ -171,7 +180,9 @@ async def summarize(doc: FilePart) -> str:
|
|
|
171
180
|
return f"Summary: {content[:100]}..."
|
|
172
181
|
```
|
|
173
182
|
|
|
174
|
-
### Level 6
|
|
183
|
+
### Level 6 — Task Tracking
|
|
184
|
+
|
|
185
|
+
Long-running operations with progress updates:
|
|
175
186
|
|
|
176
187
|
```python
|
|
177
188
|
from a2a_lite import TaskContext
|
|
@@ -181,14 +192,14 @@ agent = Agent(name="Bot", description="A bot", task_store="memory")
|
|
|
181
192
|
@agent.skill("process")
|
|
182
193
|
async def process(data: str, task: TaskContext) -> str:
|
|
183
194
|
await task.update("working", "Starting...", progress=0.0)
|
|
184
|
-
|
|
185
195
|
for i in range(10):
|
|
186
196
|
await task.update("working", f"Step {i}/10", progress=i/10)
|
|
187
|
-
|
|
188
197
|
return "Done!"
|
|
189
198
|
```
|
|
190
199
|
|
|
191
|
-
### Level 7
|
|
200
|
+
### Level 7 — Authentication
|
|
201
|
+
|
|
202
|
+
API keys are hashed in memory using SHA-256 — plaintext keys are never stored.
|
|
192
203
|
|
|
193
204
|
```python
|
|
194
205
|
from a2a_lite import Agent, APIKeyAuth
|
|
@@ -200,8 +211,6 @@ agent = Agent(
|
|
|
200
211
|
)
|
|
201
212
|
```
|
|
202
213
|
|
|
203
|
-
API keys are hashed in memory using SHA-256 — plaintext keys are never stored.
|
|
204
|
-
|
|
205
214
|
Other auth providers:
|
|
206
215
|
|
|
207
216
|
```python
|
|
@@ -230,7 +239,7 @@ async def whoami(auth: AuthResult) -> dict:
|
|
|
230
239
|
return {"user": auth.identity, "scheme": auth.scheme}
|
|
231
240
|
```
|
|
232
241
|
|
|
233
|
-
### Level 8
|
|
242
|
+
### Level 8 — CORS & Production Mode
|
|
234
243
|
|
|
235
244
|
```python
|
|
236
245
|
agent = Agent(
|
|
@@ -241,12 +250,24 @@ agent = Agent(
|
|
|
241
250
|
)
|
|
242
251
|
```
|
|
243
252
|
|
|
244
|
-
### Level 9
|
|
253
|
+
### Level 9 — Lifecycle Hooks
|
|
245
254
|
|
|
246
255
|
```python
|
|
256
|
+
@agent.on_startup
|
|
257
|
+
async def startup():
|
|
258
|
+
print("Agent starting...")
|
|
259
|
+
|
|
260
|
+
@agent.on_shutdown
|
|
261
|
+
async def shutdown():
|
|
262
|
+
print("Agent stopping...")
|
|
263
|
+
|
|
247
264
|
@agent.on_complete
|
|
248
265
|
async def notify(skill_name, result, ctx):
|
|
249
266
|
print(f"Skill {skill_name} completed with: {result}")
|
|
267
|
+
|
|
268
|
+
@agent.on_error
|
|
269
|
+
async def handle_error(error: Exception):
|
|
270
|
+
return {"error": str(error), "type": type(error).__name__}
|
|
250
271
|
```
|
|
251
272
|
|
|
252
273
|
---
|
|
@@ -255,7 +276,7 @@ async def notify(skill_name, result, ctx):
|
|
|
255
276
|
|
|
256
277
|
### AgentTestClient
|
|
257
278
|
|
|
258
|
-
|
|
279
|
+
Synchronous test client for pytest:
|
|
259
280
|
|
|
260
281
|
```python
|
|
261
282
|
from a2a_lite import Agent, AgentTestClient
|
|
@@ -293,7 +314,7 @@ def test_list_skills():
|
|
|
293
314
|
|
|
294
315
|
### TestResult
|
|
295
316
|
|
|
296
|
-
Every `client.call()` returns a `TestResult
|
|
317
|
+
Every `client.call()` returns a `TestResult`:
|
|
297
318
|
|
|
298
319
|
| Property | Description |
|
|
299
320
|
|----------|-------------|
|
|
@@ -302,7 +323,7 @@ Every `client.call()` returns a `TestResult` with:
|
|
|
302
323
|
| `.json()` | Parse text as JSON (raises on invalid JSON) |
|
|
303
324
|
| `.raw_response` | Full A2A response dict |
|
|
304
325
|
|
|
305
|
-
`TestResult` supports direct equality
|
|
326
|
+
`TestResult` supports direct equality for simple values (`result == 5`), but use `.data` for subscripting (`result.data["key"]`).
|
|
306
327
|
|
|
307
328
|
### AsyncAgentTestClient
|
|
308
329
|
|
|
@@ -334,10 +355,11 @@ def test_streaming():
|
|
|
334
355
|
## CLI
|
|
335
356
|
|
|
336
357
|
```bash
|
|
337
|
-
a2a-lite init my-agent #
|
|
338
|
-
a2a-lite serve agent.py # Run agent from file
|
|
339
|
-
a2a-lite inspect http://... # View agent
|
|
340
|
-
a2a-lite test http://... skill #
|
|
358
|
+
a2a-lite init my-agent # Scaffold a new project
|
|
359
|
+
a2a-lite serve agent.py # Run an agent from file
|
|
360
|
+
a2a-lite inspect http://... # View agent card & skills
|
|
361
|
+
a2a-lite test http://... skill # Smoke-test a skill
|
|
362
|
+
a2a-lite discover # Find agents on the local network (mDNS)
|
|
341
363
|
a2a-lite version # Show version
|
|
342
364
|
```
|
|
343
365
|
|
|
@@ -396,7 +418,7 @@ Agent(
|
|
|
396
418
|
|
|
397
419
|
### Special Parameter Types
|
|
398
420
|
|
|
399
|
-
|
|
421
|
+
Auto-injected when detected in skill function signatures:
|
|
400
422
|
|
|
401
423
|
| Type | Description |
|
|
402
424
|
|------|-------------|
|
|
@@ -413,18 +435,22 @@ These are auto-injected when detected in skill function signatures:
|
|
|
413
435
|
|---------|---------------|
|
|
414
436
|
| [01_hello_world.py](examples/01_hello_world.py) | Simplest agent (8 lines) |
|
|
415
437
|
| [02_calculator.py](examples/02_calculator.py) | Multiple skills |
|
|
438
|
+
| [03_async_agent.py](examples/03_async_agent.py) | Async operations & lifecycle hooks |
|
|
439
|
+
| [04_multi_agent/](examples/04_multi_agent) | Two agents communicating |
|
|
440
|
+
| [05_with_llm.py](examples/05_with_llm.py) | OpenAI / Anthropic integration |
|
|
416
441
|
| [06_pydantic_models.py](examples/06_pydantic_models.py) | Auto Pydantic conversion |
|
|
442
|
+
| [07_middleware.py](examples/07_middleware.py) | Middleware pipeline |
|
|
417
443
|
| [08_streaming.py](examples/08_streaming.py) | Streaming responses |
|
|
418
|
-
| [09_testing.py](examples/09_testing.py) |
|
|
419
|
-
| [10_file_handling.py](examples/10_file_handling.py) |
|
|
444
|
+
| [09_testing.py](examples/09_testing.py) | Built-in TestClient |
|
|
445
|
+
| [10_file_handling.py](examples/10_file_handling.py) | File upload & processing |
|
|
420
446
|
| [11_task_tracking.py](examples/11_task_tracking.py) | Progress updates |
|
|
421
447
|
| [12_with_auth.py](examples/12_with_auth.py) | Authentication |
|
|
422
448
|
|
|
423
449
|
---
|
|
424
450
|
|
|
425
|
-
##
|
|
451
|
+
## A2A Protocol Mapping
|
|
426
452
|
|
|
427
|
-
|
|
453
|
+
Everything maps directly to the underlying protocol — no magic, no lock-in.
|
|
428
454
|
|
|
429
455
|
| A2A Lite | A2A Protocol |
|
|
430
456
|
|----------|--------------|
|
|
@@ -433,6 +459,7 @@ A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A proto
|
|
|
433
459
|
| `TaskContext.update()` | Task lifecycle states |
|
|
434
460
|
| `FilePart` | A2A File parts |
|
|
435
461
|
| `DataPart` | A2A Data parts |
|
|
462
|
+
| `Artifact` | A2A Artifacts |
|
|
436
463
|
| `APIKeyAuth` / `BearerAuth` | Security schemes |
|
|
437
464
|
|
|
438
465
|
---
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|