a2a-lite 0.2.2__tar.gz → 0.2.3__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.2 → a2a_lite-0.2.3}/PKG-INFO +37 -92
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/README.md +36 -89
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/06_pydantic_models.py +1 -1
- a2a_lite-0.2.2/examples/12_file_handling.py → a2a_lite-0.2.3/examples/10_file_handling.py +1 -1
- a2a_lite-0.2.2/examples/13_task_tracking.py → a2a_lite-0.2.3/examples/11_task_tracking.py +1 -1
- a2a_lite-0.2.2/examples/14_with_auth.py → a2a_lite-0.2.3/examples/12_with_auth.py +1 -1
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/pyproject.toml +1 -3
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/__init__.py +7 -36
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/agent.py +2 -64
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/cli.py +2 -43
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/decorators.py +0 -3
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/executor.py +1 -9
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/streaming.py +0 -29
- a2a_lite-0.2.2/examples/10_webhooks.py +0 -91
- a2a_lite-0.2.2/examples/11_human_in_the_loop.py +0 -78
- a2a_lite-0.2.2/src/a2a_lite/discovery.py +0 -152
- a2a_lite-0.2.2/src/a2a_lite/human_loop.py +0 -284
- a2a_lite-0.2.2/src/a2a_lite/webhooks.py +0 -228
- a2a_lite-0.2.2/tests/test_discovery.py +0 -55
- a2a_lite-0.2.2/tests/test_human_loop.py +0 -134
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/.claude/settings.local.json +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/.gitignore +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/01_hello_world.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/02_calculator.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/03_async_agent.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/04_multi_agent/finance_agent.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/04_multi_agent/reporter_agent.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/04_multi_agent/run_demo.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/05_with_llm.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/07_middleware.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/08_streaming.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/examples/09_testing.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/auth.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/middleware.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/parts.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/tasks.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/testing.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/src/a2a_lite/utils.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/__init__.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_agent.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_auth.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_decorators.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_integration.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_middleware.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_parts.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_pydantic.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_tasks.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/tests/test_testing.py +0 -0
- {a2a_lite-0.2.2 → a2a_lite-0.2.3}/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.3
|
|
4
4
|
Summary: Simplified wrapper for Google's A2A Protocol SDK
|
|
5
5
|
Author: A2A Lite Contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,8 +21,6 @@ Requires-Dist: rich>=13.0
|
|
|
21
21
|
Requires-Dist: starlette>=0.40.0
|
|
22
22
|
Requires-Dist: typer>=0.9.0
|
|
23
23
|
Requires-Dist: uvicorn>=0.30.0
|
|
24
|
-
Requires-Dist: watchfiles>=0.20.0
|
|
25
|
-
Requires-Dist: zeroconf>=0.80.0
|
|
26
24
|
Provides-Extra: dev
|
|
27
25
|
Requires-Dist: httpx>=0.25; extra == 'dev'
|
|
28
26
|
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
@@ -33,7 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
33
31
|
|
|
34
32
|
# A2A Lite - Python
|
|
35
33
|
|
|
36
|
-
**Build A2A agents in 8 lines. Add
|
|
34
|
+
**Build A2A agents in 8 lines. Add features when you need them.**
|
|
37
35
|
|
|
38
36
|
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple, intuitive API.
|
|
39
37
|
|
|
@@ -149,7 +147,6 @@ class User(BaseModel):
|
|
|
149
147
|
|
|
150
148
|
@agent.skill("create_user")
|
|
151
149
|
async def create_user(user: User) -> dict:
|
|
152
|
-
# 'user' is already a User instance — auto-converted from dict!
|
|
153
150
|
return {"id": 1, "name": user.name}
|
|
154
151
|
```
|
|
155
152
|
|
|
@@ -188,28 +185,13 @@ Built-in middleware:
|
|
|
188
185
|
```python
|
|
189
186
|
from a2a_lite import logging_middleware, timing_middleware, retry_middleware, rate_limit_middleware
|
|
190
187
|
|
|
191
|
-
agent.
|
|
192
|
-
agent.
|
|
193
|
-
agent.
|
|
194
|
-
agent.
|
|
188
|
+
agent.add_middleware(logging_middleware)
|
|
189
|
+
agent.add_middleware(timing_middleware)
|
|
190
|
+
agent.add_middleware(rate_limit_middleware(max_per_minute=60))
|
|
191
|
+
agent.add_middleware(retry_middleware(max_retries=3))
|
|
195
192
|
```
|
|
196
193
|
|
|
197
|
-
### Level 5:
|
|
198
|
-
|
|
199
|
-
```python
|
|
200
|
-
from a2a_lite import InteractionContext
|
|
201
|
-
|
|
202
|
-
@agent.skill("wizard")
|
|
203
|
-
async def wizard(ctx: InteractionContext) -> dict:
|
|
204
|
-
name = await ctx.ask("What's your name?")
|
|
205
|
-
role = await ctx.ask("Role?", options=["Dev", "Manager"])
|
|
206
|
-
|
|
207
|
-
if await ctx.confirm(f"Create {name} as {role}?"):
|
|
208
|
-
return {"created": name}
|
|
209
|
-
return {"cancelled": True}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Level 6: File Handling
|
|
194
|
+
### Level 5: File Handling
|
|
213
195
|
|
|
214
196
|
```python
|
|
215
197
|
from a2a_lite import FilePart
|
|
@@ -220,7 +202,7 @@ async def summarize(doc: FilePart) -> str:
|
|
|
220
202
|
return f"Summary: {content[:100]}..."
|
|
221
203
|
```
|
|
222
204
|
|
|
223
|
-
### Level
|
|
205
|
+
### Level 6: Task Tracking
|
|
224
206
|
|
|
225
207
|
```python
|
|
226
208
|
from a2a_lite import TaskContext
|
|
@@ -237,7 +219,7 @@ async def process(data: str, task: TaskContext) -> str:
|
|
|
237
219
|
return "Done!"
|
|
238
220
|
```
|
|
239
221
|
|
|
240
|
-
### Level
|
|
222
|
+
### Level 7: Authentication
|
|
241
223
|
|
|
242
224
|
```python
|
|
243
225
|
from a2a_lite import Agent, APIKeyAuth
|
|
@@ -262,14 +244,24 @@ agent = Agent(
|
|
|
262
244
|
auth=BearerAuth(secret="your-jwt-secret"),
|
|
263
245
|
)
|
|
264
246
|
|
|
265
|
-
# OAuth2
|
|
247
|
+
# OAuth2 (requires: pip install a2a-lite[oauth])
|
|
266
248
|
agent = Agent(
|
|
267
249
|
name="Bot", description="A bot",
|
|
268
250
|
auth=OAuth2Auth(issuer="https://auth.example.com", audience="my-api"),
|
|
269
251
|
)
|
|
270
252
|
```
|
|
271
253
|
|
|
272
|
-
|
|
254
|
+
Skills can receive auth results by type-hinting a parameter as `AuthResult`:
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
from a2a_lite.auth import AuthResult
|
|
258
|
+
|
|
259
|
+
@agent.skill("whoami")
|
|
260
|
+
async def whoami(auth: AuthResult) -> dict:
|
|
261
|
+
return {"user": auth.identity, "scheme": auth.scheme}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Level 8: CORS and Production Mode
|
|
273
265
|
|
|
274
266
|
```python
|
|
275
267
|
agent = Agent(
|
|
@@ -280,11 +272,11 @@ agent = Agent(
|
|
|
280
272
|
)
|
|
281
273
|
```
|
|
282
274
|
|
|
283
|
-
### Level
|
|
275
|
+
### Level 9: Completion Hooks
|
|
284
276
|
|
|
285
277
|
```python
|
|
286
278
|
@agent.on_complete
|
|
287
|
-
async def notify(skill_name, result):
|
|
279
|
+
async def notify(skill_name, result, ctx):
|
|
288
280
|
print(f"Skill {skill_name} completed with: {result}")
|
|
289
281
|
```
|
|
290
282
|
|
|
@@ -313,25 +305,16 @@ async def info(name: str, age: int) -> dict:
|
|
|
313
305
|
def test_simple_result():
|
|
314
306
|
client = AgentTestClient(agent)
|
|
315
307
|
result = client.call("greet", name="World")
|
|
316
|
-
# Simple values support direct equality
|
|
317
308
|
assert result == "Hello, World!"
|
|
318
309
|
|
|
319
310
|
|
|
320
311
|
def test_dict_result():
|
|
321
312
|
client = AgentTestClient(agent)
|
|
322
313
|
result = client.call("info", name="Alice", age=30)
|
|
323
|
-
# Access dict results via .data
|
|
324
314
|
assert result.data["name"] == "Alice"
|
|
325
315
|
assert result.data["age"] == 30
|
|
326
316
|
|
|
327
317
|
|
|
328
|
-
def test_text_access():
|
|
329
|
-
client = AgentTestClient(agent)
|
|
330
|
-
result = client.call("greet", name="World")
|
|
331
|
-
# .text gives the raw string
|
|
332
|
-
assert result.text == '"Hello, World!"'
|
|
333
|
-
|
|
334
|
-
|
|
335
318
|
def test_list_skills():
|
|
336
319
|
client = AgentTestClient(agent)
|
|
337
320
|
skills = client.list_skills()
|
|
@@ -379,59 +362,19 @@ def test_streaming():
|
|
|
379
362
|
|
|
380
363
|
---
|
|
381
364
|
|
|
382
|
-
## Task Store
|
|
383
|
-
|
|
384
|
-
The `TaskStore` provides async-safe task lifecycle management:
|
|
385
|
-
|
|
386
|
-
```python
|
|
387
|
-
from a2a_lite.tasks import TaskStore, TaskStatus
|
|
388
|
-
|
|
389
|
-
store = TaskStore()
|
|
390
|
-
|
|
391
|
-
# All operations are async and thread-safe
|
|
392
|
-
task = await store.create(task_id="task-1", skill="process")
|
|
393
|
-
task = await store.get("task-1")
|
|
394
|
-
await store.update("task-1", status=TaskStatus.WORKING, progress=0.5)
|
|
395
|
-
tasks = await store.list()
|
|
396
|
-
await store.delete("task-1")
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
---
|
|
400
|
-
|
|
401
|
-
## Agent Discovery
|
|
402
|
-
|
|
403
|
-
Find agents on your local network via mDNS:
|
|
404
|
-
|
|
405
|
-
```python
|
|
406
|
-
from a2a_lite import AgentDiscovery
|
|
407
|
-
|
|
408
|
-
# Advertise your agent
|
|
409
|
-
agent.run(port=8787, enable_discovery=True)
|
|
410
|
-
|
|
411
|
-
# Discover other agents
|
|
412
|
-
discovery = AgentDiscovery()
|
|
413
|
-
agents = await discovery.discover(timeout=5.0)
|
|
414
|
-
for a in agents:
|
|
415
|
-
print(f"{a.name} at {a.url}")
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
---
|
|
419
|
-
|
|
420
365
|
## CLI
|
|
421
366
|
|
|
422
367
|
```bash
|
|
423
368
|
a2a-lite init my-agent # Create new project
|
|
424
369
|
a2a-lite serve agent.py # Run agent from file
|
|
425
|
-
a2a-lite serve agent.py -r # Run with hot reload
|
|
426
370
|
a2a-lite inspect http://... # View agent capabilities
|
|
427
371
|
a2a-lite test http://... skill # Test a skill
|
|
428
|
-
a2a-lite discover # Find local agents
|
|
429
372
|
a2a-lite version # Show version
|
|
430
373
|
```
|
|
431
374
|
|
|
432
375
|
---
|
|
433
376
|
|
|
434
|
-
##
|
|
377
|
+
## API Reference
|
|
435
378
|
|
|
436
379
|
### Agent
|
|
437
380
|
|
|
@@ -445,7 +388,6 @@ Agent(
|
|
|
445
388
|
task_store: str | TaskStore = None, # "memory" or custom TaskStore
|
|
446
389
|
cors_origins: List[str] = None, # CORS allowed origins
|
|
447
390
|
production: bool = False, # Enable production warnings
|
|
448
|
-
enable_discovery: bool = False, # mDNS discovery
|
|
449
391
|
)
|
|
450
392
|
```
|
|
451
393
|
|
|
@@ -455,8 +397,11 @@ Agent(
|
|
|
455
397
|
|--------|-------------|
|
|
456
398
|
| `@agent.skill(name, **config)` | Register a skill via decorator |
|
|
457
399
|
| `@agent.middleware` | Register middleware via decorator |
|
|
458
|
-
| `agent.
|
|
400
|
+
| `agent.add_middleware(fn)` | Register middleware function |
|
|
459
401
|
| `@agent.on_complete` | Register completion hook |
|
|
402
|
+
| `@agent.on_startup` | Register startup hook |
|
|
403
|
+
| `@agent.on_shutdown` | Register shutdown hook |
|
|
404
|
+
| `@agent.on_error` | Register error handler |
|
|
460
405
|
| `agent.run(port=8787)` | Start the server |
|
|
461
406
|
| `agent.get_app()` | Get the ASGI app (for custom deployment) |
|
|
462
407
|
|
|
@@ -464,7 +409,7 @@ Agent(
|
|
|
464
409
|
|
|
465
410
|
```python
|
|
466
411
|
@agent.skill(
|
|
467
|
-
name: str,
|
|
412
|
+
name: str = None, # Skill name (defaults to function name)
|
|
468
413
|
description: str = None, # Human-readable description
|
|
469
414
|
tags: List[str] = None, # Categorization tags
|
|
470
415
|
streaming: bool = False, # Enable streaming
|
|
@@ -477,18 +422,19 @@ Agent(
|
|
|
477
422
|
|----------|-------|
|
|
478
423
|
| `APIKeyAuth(keys=[...])` | API key auth (keys hashed with SHA-256) |
|
|
479
424
|
| `BearerAuth(secret=...)` | JWT/Bearer token auth |
|
|
480
|
-
| `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth |
|
|
425
|
+
| `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth (requires `a2a-lite[oauth]`) |
|
|
481
426
|
| `NoAuth()` | No auth (default) |
|
|
482
427
|
|
|
483
428
|
### Special Parameter Types
|
|
484
429
|
|
|
485
|
-
These are auto-injected when detected in skill signatures:
|
|
430
|
+
These are auto-injected when detected in skill function signatures:
|
|
486
431
|
|
|
487
432
|
| Type | Description |
|
|
488
433
|
|------|-------------|
|
|
489
434
|
| `TaskContext` | Task lifecycle management (requires `task_store`) |
|
|
490
|
-
| `
|
|
435
|
+
| `AuthResult` | Authentication result injection |
|
|
491
436
|
| `FilePart` | File upload handling |
|
|
437
|
+
| `DataPart` | Structured data handling |
|
|
492
438
|
|
|
493
439
|
---
|
|
494
440
|
|
|
@@ -501,10 +447,9 @@ These are auto-injected when detected in skill signatures:
|
|
|
501
447
|
| [06_pydantic_models.py](examples/06_pydantic_models.py) | Auto Pydantic conversion |
|
|
502
448
|
| [08_streaming.py](examples/08_streaming.py) | Streaming responses |
|
|
503
449
|
| [09_testing.py](examples/09_testing.py) | Testing your agents |
|
|
504
|
-
| [
|
|
505
|
-
| [
|
|
506
|
-
| [
|
|
507
|
-
| [14_with_auth.py](examples/14_with_auth.py) | Authentication |
|
|
450
|
+
| [10_file_handling.py](examples/10_file_handling.py) | Handle files |
|
|
451
|
+
| [11_task_tracking.py](examples/11_task_tracking.py) | Progress updates |
|
|
452
|
+
| [12_with_auth.py](examples/12_with_auth.py) | Authentication |
|
|
508
453
|
|
|
509
454
|
---
|
|
510
455
|
|
|
@@ -516,9 +461,9 @@ A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A proto
|
|
|
516
461
|
|----------|--------------|
|
|
517
462
|
| `@agent.skill()` | Agent Skills |
|
|
518
463
|
| `streaming=True` | SSE Streaming |
|
|
519
|
-
| `InteractionContext.ask()` | `input-required` state |
|
|
520
464
|
| `TaskContext.update()` | Task lifecycle states |
|
|
521
465
|
| `FilePart` | A2A File parts |
|
|
466
|
+
| `DataPart` | A2A Data parts |
|
|
522
467
|
| `APIKeyAuth` / `BearerAuth` | Security schemes |
|
|
523
468
|
|
|
524
469
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# A2A Lite - Python
|
|
2
2
|
|
|
3
|
-
**Build A2A agents in 8 lines. Add
|
|
3
|
+
**Build A2A agents in 8 lines. Add features when you need them.**
|
|
4
4
|
|
|
5
5
|
Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple, intuitive API.
|
|
6
6
|
|
|
@@ -116,7 +116,6 @@ class User(BaseModel):
|
|
|
116
116
|
|
|
117
117
|
@agent.skill("create_user")
|
|
118
118
|
async def create_user(user: User) -> dict:
|
|
119
|
-
# 'user' is already a User instance — auto-converted from dict!
|
|
120
119
|
return {"id": 1, "name": user.name}
|
|
121
120
|
```
|
|
122
121
|
|
|
@@ -155,28 +154,13 @@ Built-in middleware:
|
|
|
155
154
|
```python
|
|
156
155
|
from a2a_lite import logging_middleware, timing_middleware, retry_middleware, rate_limit_middleware
|
|
157
156
|
|
|
158
|
-
agent.
|
|
159
|
-
agent.
|
|
160
|
-
agent.
|
|
161
|
-
agent.
|
|
157
|
+
agent.add_middleware(logging_middleware)
|
|
158
|
+
agent.add_middleware(timing_middleware)
|
|
159
|
+
agent.add_middleware(rate_limit_middleware(max_per_minute=60))
|
|
160
|
+
agent.add_middleware(retry_middleware(max_retries=3))
|
|
162
161
|
```
|
|
163
162
|
|
|
164
|
-
### Level 5:
|
|
165
|
-
|
|
166
|
-
```python
|
|
167
|
-
from a2a_lite import InteractionContext
|
|
168
|
-
|
|
169
|
-
@agent.skill("wizard")
|
|
170
|
-
async def wizard(ctx: InteractionContext) -> dict:
|
|
171
|
-
name = await ctx.ask("What's your name?")
|
|
172
|
-
role = await ctx.ask("Role?", options=["Dev", "Manager"])
|
|
173
|
-
|
|
174
|
-
if await ctx.confirm(f"Create {name} as {role}?"):
|
|
175
|
-
return {"created": name}
|
|
176
|
-
return {"cancelled": True}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Level 6: File Handling
|
|
163
|
+
### Level 5: File Handling
|
|
180
164
|
|
|
181
165
|
```python
|
|
182
166
|
from a2a_lite import FilePart
|
|
@@ -187,7 +171,7 @@ async def summarize(doc: FilePart) -> str:
|
|
|
187
171
|
return f"Summary: {content[:100]}..."
|
|
188
172
|
```
|
|
189
173
|
|
|
190
|
-
### Level
|
|
174
|
+
### Level 6: Task Tracking
|
|
191
175
|
|
|
192
176
|
```python
|
|
193
177
|
from a2a_lite import TaskContext
|
|
@@ -204,7 +188,7 @@ async def process(data: str, task: TaskContext) -> str:
|
|
|
204
188
|
return "Done!"
|
|
205
189
|
```
|
|
206
190
|
|
|
207
|
-
### Level
|
|
191
|
+
### Level 7: Authentication
|
|
208
192
|
|
|
209
193
|
```python
|
|
210
194
|
from a2a_lite import Agent, APIKeyAuth
|
|
@@ -229,14 +213,24 @@ agent = Agent(
|
|
|
229
213
|
auth=BearerAuth(secret="your-jwt-secret"),
|
|
230
214
|
)
|
|
231
215
|
|
|
232
|
-
# OAuth2
|
|
216
|
+
# OAuth2 (requires: pip install a2a-lite[oauth])
|
|
233
217
|
agent = Agent(
|
|
234
218
|
name="Bot", description="A bot",
|
|
235
219
|
auth=OAuth2Auth(issuer="https://auth.example.com", audience="my-api"),
|
|
236
220
|
)
|
|
237
221
|
```
|
|
238
222
|
|
|
239
|
-
|
|
223
|
+
Skills can receive auth results by type-hinting a parameter as `AuthResult`:
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from a2a_lite.auth import AuthResult
|
|
227
|
+
|
|
228
|
+
@agent.skill("whoami")
|
|
229
|
+
async def whoami(auth: AuthResult) -> dict:
|
|
230
|
+
return {"user": auth.identity, "scheme": auth.scheme}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Level 8: CORS and Production Mode
|
|
240
234
|
|
|
241
235
|
```python
|
|
242
236
|
agent = Agent(
|
|
@@ -247,11 +241,11 @@ agent = Agent(
|
|
|
247
241
|
)
|
|
248
242
|
```
|
|
249
243
|
|
|
250
|
-
### Level
|
|
244
|
+
### Level 9: Completion Hooks
|
|
251
245
|
|
|
252
246
|
```python
|
|
253
247
|
@agent.on_complete
|
|
254
|
-
async def notify(skill_name, result):
|
|
248
|
+
async def notify(skill_name, result, ctx):
|
|
255
249
|
print(f"Skill {skill_name} completed with: {result}")
|
|
256
250
|
```
|
|
257
251
|
|
|
@@ -280,25 +274,16 @@ async def info(name: str, age: int) -> dict:
|
|
|
280
274
|
def test_simple_result():
|
|
281
275
|
client = AgentTestClient(agent)
|
|
282
276
|
result = client.call("greet", name="World")
|
|
283
|
-
# Simple values support direct equality
|
|
284
277
|
assert result == "Hello, World!"
|
|
285
278
|
|
|
286
279
|
|
|
287
280
|
def test_dict_result():
|
|
288
281
|
client = AgentTestClient(agent)
|
|
289
282
|
result = client.call("info", name="Alice", age=30)
|
|
290
|
-
# Access dict results via .data
|
|
291
283
|
assert result.data["name"] == "Alice"
|
|
292
284
|
assert result.data["age"] == 30
|
|
293
285
|
|
|
294
286
|
|
|
295
|
-
def test_text_access():
|
|
296
|
-
client = AgentTestClient(agent)
|
|
297
|
-
result = client.call("greet", name="World")
|
|
298
|
-
# .text gives the raw string
|
|
299
|
-
assert result.text == '"Hello, World!"'
|
|
300
|
-
|
|
301
|
-
|
|
302
287
|
def test_list_skills():
|
|
303
288
|
client = AgentTestClient(agent)
|
|
304
289
|
skills = client.list_skills()
|
|
@@ -346,59 +331,19 @@ def test_streaming():
|
|
|
346
331
|
|
|
347
332
|
---
|
|
348
333
|
|
|
349
|
-
## Task Store
|
|
350
|
-
|
|
351
|
-
The `TaskStore` provides async-safe task lifecycle management:
|
|
352
|
-
|
|
353
|
-
```python
|
|
354
|
-
from a2a_lite.tasks import TaskStore, TaskStatus
|
|
355
|
-
|
|
356
|
-
store = TaskStore()
|
|
357
|
-
|
|
358
|
-
# All operations are async and thread-safe
|
|
359
|
-
task = await store.create(task_id="task-1", skill="process")
|
|
360
|
-
task = await store.get("task-1")
|
|
361
|
-
await store.update("task-1", status=TaskStatus.WORKING, progress=0.5)
|
|
362
|
-
tasks = await store.list()
|
|
363
|
-
await store.delete("task-1")
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
## Agent Discovery
|
|
369
|
-
|
|
370
|
-
Find agents on your local network via mDNS:
|
|
371
|
-
|
|
372
|
-
```python
|
|
373
|
-
from a2a_lite import AgentDiscovery
|
|
374
|
-
|
|
375
|
-
# Advertise your agent
|
|
376
|
-
agent.run(port=8787, enable_discovery=True)
|
|
377
|
-
|
|
378
|
-
# Discover other agents
|
|
379
|
-
discovery = AgentDiscovery()
|
|
380
|
-
agents = await discovery.discover(timeout=5.0)
|
|
381
|
-
for a in agents:
|
|
382
|
-
print(f"{a.name} at {a.url}")
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
334
|
## CLI
|
|
388
335
|
|
|
389
336
|
```bash
|
|
390
337
|
a2a-lite init my-agent # Create new project
|
|
391
338
|
a2a-lite serve agent.py # Run agent from file
|
|
392
|
-
a2a-lite serve agent.py -r # Run with hot reload
|
|
393
339
|
a2a-lite inspect http://... # View agent capabilities
|
|
394
340
|
a2a-lite test http://... skill # Test a skill
|
|
395
|
-
a2a-lite discover # Find local agents
|
|
396
341
|
a2a-lite version # Show version
|
|
397
342
|
```
|
|
398
343
|
|
|
399
344
|
---
|
|
400
345
|
|
|
401
|
-
##
|
|
346
|
+
## API Reference
|
|
402
347
|
|
|
403
348
|
### Agent
|
|
404
349
|
|
|
@@ -412,7 +357,6 @@ Agent(
|
|
|
412
357
|
task_store: str | TaskStore = None, # "memory" or custom TaskStore
|
|
413
358
|
cors_origins: List[str] = None, # CORS allowed origins
|
|
414
359
|
production: bool = False, # Enable production warnings
|
|
415
|
-
enable_discovery: bool = False, # mDNS discovery
|
|
416
360
|
)
|
|
417
361
|
```
|
|
418
362
|
|
|
@@ -422,8 +366,11 @@ Agent(
|
|
|
422
366
|
|--------|-------------|
|
|
423
367
|
| `@agent.skill(name, **config)` | Register a skill via decorator |
|
|
424
368
|
| `@agent.middleware` | Register middleware via decorator |
|
|
425
|
-
| `agent.
|
|
369
|
+
| `agent.add_middleware(fn)` | Register middleware function |
|
|
426
370
|
| `@agent.on_complete` | Register completion hook |
|
|
371
|
+
| `@agent.on_startup` | Register startup hook |
|
|
372
|
+
| `@agent.on_shutdown` | Register shutdown hook |
|
|
373
|
+
| `@agent.on_error` | Register error handler |
|
|
427
374
|
| `agent.run(port=8787)` | Start the server |
|
|
428
375
|
| `agent.get_app()` | Get the ASGI app (for custom deployment) |
|
|
429
376
|
|
|
@@ -431,7 +378,7 @@ Agent(
|
|
|
431
378
|
|
|
432
379
|
```python
|
|
433
380
|
@agent.skill(
|
|
434
|
-
name: str,
|
|
381
|
+
name: str = None, # Skill name (defaults to function name)
|
|
435
382
|
description: str = None, # Human-readable description
|
|
436
383
|
tags: List[str] = None, # Categorization tags
|
|
437
384
|
streaming: bool = False, # Enable streaming
|
|
@@ -444,18 +391,19 @@ Agent(
|
|
|
444
391
|
|----------|-------|
|
|
445
392
|
| `APIKeyAuth(keys=[...])` | API key auth (keys hashed with SHA-256) |
|
|
446
393
|
| `BearerAuth(secret=...)` | JWT/Bearer token auth |
|
|
447
|
-
| `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth |
|
|
394
|
+
| `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth (requires `a2a-lite[oauth]`) |
|
|
448
395
|
| `NoAuth()` | No auth (default) |
|
|
449
396
|
|
|
450
397
|
### Special Parameter Types
|
|
451
398
|
|
|
452
|
-
These are auto-injected when detected in skill signatures:
|
|
399
|
+
These are auto-injected when detected in skill function signatures:
|
|
453
400
|
|
|
454
401
|
| Type | Description |
|
|
455
402
|
|------|-------------|
|
|
456
403
|
| `TaskContext` | Task lifecycle management (requires `task_store`) |
|
|
457
|
-
| `
|
|
404
|
+
| `AuthResult` | Authentication result injection |
|
|
458
405
|
| `FilePart` | File upload handling |
|
|
406
|
+
| `DataPart` | Structured data handling |
|
|
459
407
|
|
|
460
408
|
---
|
|
461
409
|
|
|
@@ -468,10 +416,9 @@ These are auto-injected when detected in skill signatures:
|
|
|
468
416
|
| [06_pydantic_models.py](examples/06_pydantic_models.py) | Auto Pydantic conversion |
|
|
469
417
|
| [08_streaming.py](examples/08_streaming.py) | Streaming responses |
|
|
470
418
|
| [09_testing.py](examples/09_testing.py) | Testing your agents |
|
|
471
|
-
| [
|
|
472
|
-
| [
|
|
473
|
-
| [
|
|
474
|
-
| [14_with_auth.py](examples/14_with_auth.py) | Authentication |
|
|
419
|
+
| [10_file_handling.py](examples/10_file_handling.py) | Handle files |
|
|
420
|
+
| [11_task_tracking.py](examples/11_task_tracking.py) | Progress updates |
|
|
421
|
+
| [12_with_auth.py](examples/12_with_auth.py) | Authentication |
|
|
475
422
|
|
|
476
423
|
---
|
|
477
424
|
|
|
@@ -483,9 +430,9 @@ A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A proto
|
|
|
483
430
|
|----------|--------------|
|
|
484
431
|
| `@agent.skill()` | Agent Skills |
|
|
485
432
|
| `streaming=True` | SSE Streaming |
|
|
486
|
-
| `InteractionContext.ask()` | `input-required` state |
|
|
487
433
|
| `TaskContext.update()` | Task lifecycle states |
|
|
488
434
|
| `FilePart` | A2A File parts |
|
|
435
|
+
| `DataPart` | A2A Data parts |
|
|
489
436
|
| `APIKeyAuth` / `BearerAuth` | Security schemes |
|
|
490
437
|
|
|
491
438
|
---
|
|
@@ -6,7 +6,7 @@ This is the SIMPLEST way to handle complex data - just use Pydantic!
|
|
|
6
6
|
Run: python examples/06_pydantic_models.py
|
|
7
7
|
Test: a2a-lite test http://localhost:8787 create_user -p '{"user": {"name": "Alice", "email": "alice@example.com", "age": 30}}'
|
|
8
8
|
"""
|
|
9
|
-
from pydantic import BaseModel
|
|
9
|
+
from pydantic import BaseModel
|
|
10
10
|
from typing import List, Optional
|
|
11
11
|
from a2a_lite import Agent
|
|
12
12
|
|
|
@@ -3,7 +3,7 @@ Example: Authentication (optional).
|
|
|
3
3
|
|
|
4
4
|
Add auth when you need it - skip it when you don't.
|
|
5
5
|
|
|
6
|
-
Run: python examples/
|
|
6
|
+
Run: python examples/12_with_auth.py
|
|
7
7
|
Test: curl -H "X-API-Key: secret-key" http://localhost:8787/...
|
|
8
8
|
"""
|
|
9
9
|
from a2a_lite import Agent, APIKeyAuth
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "a2a-lite"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
description = "Simplified wrapper for Google's A2A Protocol SDK"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -24,8 +24,6 @@ dependencies = [
|
|
|
24
24
|
"pydantic>=2.0",
|
|
25
25
|
"typer>=0.9.0",
|
|
26
26
|
"rich>=13.0",
|
|
27
|
-
"watchfiles>=0.20.0",
|
|
28
|
-
"zeroconf>=0.80.0",
|
|
29
27
|
"uvicorn>=0.30.0",
|
|
30
28
|
"httpx>=0.25.0",
|
|
31
29
|
"starlette>=0.40.0",
|