a2a-lite 0.2.1__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.
Files changed (49) hide show
  1. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/PKG-INFO +39 -92
  2. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/README.md +36 -89
  3. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/06_pydantic_models.py +1 -1
  4. a2a_lite-0.2.1/examples/12_file_handling.py → a2a_lite-0.2.3/examples/10_file_handling.py +1 -1
  5. a2a_lite-0.2.1/examples/13_task_tracking.py → a2a_lite-0.2.3/examples/11_task_tracking.py +1 -1
  6. a2a_lite-0.2.1/examples/14_with_auth.py → a2a_lite-0.2.3/examples/12_with_auth.py +1 -1
  7. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/pyproject.toml +4 -3
  8. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/__init__.py +7 -36
  9. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/agent.py +31 -74
  10. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/auth.py +2 -2
  11. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/cli.py +2 -43
  12. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/decorators.py +2 -3
  13. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/executor.py +22 -23
  14. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/streaming.py +0 -29
  15. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/testing.py +10 -1
  16. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/utils.py +5 -1
  17. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_auth.py +86 -0
  18. a2a_lite-0.2.1/examples/10_webhooks.py +0 -91
  19. a2a_lite-0.2.1/examples/11_human_in_the_loop.py +0 -78
  20. a2a_lite-0.2.1/src/a2a_lite/discovery.py +0 -152
  21. a2a_lite-0.2.1/src/a2a_lite/human_loop.py +0 -284
  22. a2a_lite-0.2.1/src/a2a_lite/webhooks.py +0 -232
  23. a2a_lite-0.2.1/tests/test_discovery.py +0 -55
  24. a2a_lite-0.2.1/tests/test_human_loop.py +0 -134
  25. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/.claude/settings.local.json +0 -0
  26. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/.gitignore +0 -0
  27. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/01_hello_world.py +0 -0
  28. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/02_calculator.py +0 -0
  29. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/03_async_agent.py +0 -0
  30. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/04_multi_agent/finance_agent.py +0 -0
  31. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/04_multi_agent/reporter_agent.py +0 -0
  32. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/04_multi_agent/run_demo.py +0 -0
  33. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/05_with_llm.py +0 -0
  34. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/07_middleware.py +0 -0
  35. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/08_streaming.py +0 -0
  36. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/examples/09_testing.py +0 -0
  37. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/middleware.py +0 -0
  38. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/parts.py +0 -0
  39. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/src/a2a_lite/tasks.py +0 -0
  40. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/__init__.py +0 -0
  41. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_agent.py +0 -0
  42. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_decorators.py +0 -0
  43. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_integration.py +0 -0
  44. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_middleware.py +0 -0
  45. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_parts.py +0 -0
  46. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_pydantic.py +0 -0
  47. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_tasks.py +0 -0
  48. {a2a_lite-0.2.1 → a2a_lite-0.2.3}/tests/test_testing.py +0 -0
  49. {a2a_lite-0.2.1 → 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.1
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,17 +21,17 @@ 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'
29
27
  Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Provides-Extra: oauth
29
+ Requires-Dist: pyjwt[crypto]>=2.0; extra == 'oauth'
30
30
  Description-Content-Type: text/markdown
31
31
 
32
32
  # A2A Lite - Python
33
33
 
34
- **Build A2A agents in 8 lines. Add enterprise features when you need them.**
34
+ **Build A2A agents in 8 lines. Add features when you need them.**
35
35
 
36
36
  Wraps the official [A2A Python SDK](https://github.com/a2aproject/a2a-python) with a simple, intuitive API.
37
37
 
@@ -147,7 +147,6 @@ class User(BaseModel):
147
147
 
148
148
  @agent.skill("create_user")
149
149
  async def create_user(user: User) -> dict:
150
- # 'user' is already a User instance — auto-converted from dict!
151
150
  return {"id": 1, "name": user.name}
152
151
  ```
153
152
 
@@ -186,28 +185,13 @@ Built-in middleware:
186
185
  ```python
187
186
  from a2a_lite import logging_middleware, timing_middleware, retry_middleware, rate_limit_middleware
188
187
 
189
- agent.use(logging_middleware)
190
- agent.use(timing_middleware)
191
- agent.use(rate_limit_middleware(max_per_minute=60))
192
- agent.use(retry_middleware(max_retries=3))
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))
193
192
  ```
194
193
 
195
- ### Level 5: Human-in-the-Loop
196
-
197
- ```python
198
- from a2a_lite import InteractionContext
199
-
200
- @agent.skill("wizard")
201
- async def wizard(ctx: InteractionContext) -> dict:
202
- name = await ctx.ask("What's your name?")
203
- role = await ctx.ask("Role?", options=["Dev", "Manager"])
204
-
205
- if await ctx.confirm(f"Create {name} as {role}?"):
206
- return {"created": name}
207
- return {"cancelled": True}
208
- ```
209
-
210
- ### Level 6: File Handling
194
+ ### Level 5: File Handling
211
195
 
212
196
  ```python
213
197
  from a2a_lite import FilePart
@@ -218,7 +202,7 @@ async def summarize(doc: FilePart) -> str:
218
202
  return f"Summary: {content[:100]}..."
219
203
  ```
220
204
 
221
- ### Level 7: Task Tracking
205
+ ### Level 6: Task Tracking
222
206
 
223
207
  ```python
224
208
  from a2a_lite import TaskContext
@@ -235,7 +219,7 @@ async def process(data: str, task: TaskContext) -> str:
235
219
  return "Done!"
236
220
  ```
237
221
 
238
- ### Level 8: Authentication
222
+ ### Level 7: Authentication
239
223
 
240
224
  ```python
241
225
  from a2a_lite import Agent, APIKeyAuth
@@ -260,14 +244,24 @@ agent = Agent(
260
244
  auth=BearerAuth(secret="your-jwt-secret"),
261
245
  )
262
246
 
263
- # OAuth2
247
+ # OAuth2 (requires: pip install a2a-lite[oauth])
264
248
  agent = Agent(
265
249
  name="Bot", description="A bot",
266
250
  auth=OAuth2Auth(issuer="https://auth.example.com", audience="my-api"),
267
251
  )
268
252
  ```
269
253
 
270
- ### Level 9: CORS and Production Mode
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
271
265
 
272
266
  ```python
273
267
  agent = Agent(
@@ -278,11 +272,11 @@ agent = Agent(
278
272
  )
279
273
  ```
280
274
 
281
- ### Level 10: Webhooks
275
+ ### Level 9: Completion Hooks
282
276
 
283
277
  ```python
284
278
  @agent.on_complete
285
- async def notify(skill_name, result):
279
+ async def notify(skill_name, result, ctx):
286
280
  print(f"Skill {skill_name} completed with: {result}")
287
281
  ```
288
282
 
@@ -311,25 +305,16 @@ async def info(name: str, age: int) -> dict:
311
305
  def test_simple_result():
312
306
  client = AgentTestClient(agent)
313
307
  result = client.call("greet", name="World")
314
- # Simple values support direct equality
315
308
  assert result == "Hello, World!"
316
309
 
317
310
 
318
311
  def test_dict_result():
319
312
  client = AgentTestClient(agent)
320
313
  result = client.call("info", name="Alice", age=30)
321
- # Access dict results via .data
322
314
  assert result.data["name"] == "Alice"
323
315
  assert result.data["age"] == 30
324
316
 
325
317
 
326
- def test_text_access():
327
- client = AgentTestClient(agent)
328
- result = client.call("greet", name="World")
329
- # .text gives the raw string
330
- assert result.text == '"Hello, World!"'
331
-
332
-
333
318
  def test_list_skills():
334
319
  client = AgentTestClient(agent)
335
320
  skills = client.list_skills()
@@ -377,59 +362,19 @@ def test_streaming():
377
362
 
378
363
  ---
379
364
 
380
- ## Task Store
381
-
382
- The `TaskStore` provides async-safe task lifecycle management:
383
-
384
- ```python
385
- from a2a_lite.tasks import TaskStore, TaskStatus
386
-
387
- store = TaskStore()
388
-
389
- # All operations are async and thread-safe
390
- task = await store.create(task_id="task-1", skill="process")
391
- task = await store.get("task-1")
392
- await store.update("task-1", status=TaskStatus.WORKING, progress=0.5)
393
- tasks = await store.list()
394
- await store.delete("task-1")
395
- ```
396
-
397
- ---
398
-
399
- ## Agent Discovery
400
-
401
- Find agents on your local network via mDNS:
402
-
403
- ```python
404
- from a2a_lite import AgentDiscovery
405
-
406
- # Advertise your agent
407
- agent.run(port=8787, enable_discovery=True)
408
-
409
- # Discover other agents
410
- discovery = AgentDiscovery()
411
- agents = await discovery.discover(timeout=5.0)
412
- for a in agents:
413
- print(f"{a.name} at {a.url}")
414
- ```
415
-
416
- ---
417
-
418
365
  ## CLI
419
366
 
420
367
  ```bash
421
368
  a2a-lite init my-agent # Create new project
422
369
  a2a-lite serve agent.py # Run agent from file
423
- a2a-lite serve agent.py -r # Run with hot reload
424
370
  a2a-lite inspect http://... # View agent capabilities
425
371
  a2a-lite test http://... skill # Test a skill
426
- a2a-lite discover # Find local agents
427
372
  a2a-lite version # Show version
428
373
  ```
429
374
 
430
375
  ---
431
376
 
432
- ## Full API Reference
377
+ ## API Reference
433
378
 
434
379
  ### Agent
435
380
 
@@ -443,7 +388,6 @@ Agent(
443
388
  task_store: str | TaskStore = None, # "memory" or custom TaskStore
444
389
  cors_origins: List[str] = None, # CORS allowed origins
445
390
  production: bool = False, # Enable production warnings
446
- enable_discovery: bool = False, # mDNS discovery
447
391
  )
448
392
  ```
449
393
 
@@ -453,8 +397,11 @@ Agent(
453
397
  |--------|-------------|
454
398
  | `@agent.skill(name, **config)` | Register a skill via decorator |
455
399
  | `@agent.middleware` | Register middleware via decorator |
456
- | `agent.use(middleware)` | Register middleware function |
400
+ | `agent.add_middleware(fn)` | Register middleware function |
457
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 |
458
405
  | `agent.run(port=8787)` | Start the server |
459
406
  | `agent.get_app()` | Get the ASGI app (for custom deployment) |
460
407
 
@@ -462,7 +409,7 @@ Agent(
462
409
 
463
410
  ```python
464
411
  @agent.skill(
465
- name: str, # Skill name (required)
412
+ name: str = None, # Skill name (defaults to function name)
466
413
  description: str = None, # Human-readable description
467
414
  tags: List[str] = None, # Categorization tags
468
415
  streaming: bool = False, # Enable streaming
@@ -475,18 +422,19 @@ Agent(
475
422
  |----------|-------|
476
423
  | `APIKeyAuth(keys=[...])` | API key auth (keys hashed with SHA-256) |
477
424
  | `BearerAuth(secret=...)` | JWT/Bearer token auth |
478
- | `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth |
425
+ | `OAuth2Auth(issuer=..., audience=...)` | OAuth2 auth (requires `a2a-lite[oauth]`) |
479
426
  | `NoAuth()` | No auth (default) |
480
427
 
481
428
  ### Special Parameter Types
482
429
 
483
- These are auto-injected when detected in skill signatures:
430
+ These are auto-injected when detected in skill function signatures:
484
431
 
485
432
  | Type | Description |
486
433
  |------|-------------|
487
434
  | `TaskContext` | Task lifecycle management (requires `task_store`) |
488
- | `InteractionContext` | Human-in-the-loop interactions |
435
+ | `AuthResult` | Authentication result injection |
489
436
  | `FilePart` | File upload handling |
437
+ | `DataPart` | Structured data handling |
490
438
 
491
439
  ---
492
440
 
@@ -499,10 +447,9 @@ These are auto-injected when detected in skill signatures:
499
447
  | [06_pydantic_models.py](examples/06_pydantic_models.py) | Auto Pydantic conversion |
500
448
  | [08_streaming.py](examples/08_streaming.py) | Streaming responses |
501
449
  | [09_testing.py](examples/09_testing.py) | Testing your agents |
502
- | [11_human_in_the_loop.py](examples/11_human_in_the_loop.py) | Ask user questions |
503
- | [12_file_handling.py](examples/12_file_handling.py) | Handle files |
504
- | [13_task_tracking.py](examples/13_task_tracking.py) | Progress updates |
505
- | [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 |
506
453
 
507
454
  ---
508
455
 
@@ -514,9 +461,9 @@ A2A Lite wraps the official A2A Python SDK. Every feature maps to real A2A proto
514
461
  |----------|--------------|
515
462
  | `@agent.skill()` | Agent Skills |
516
463
  | `streaming=True` | SSE Streaming |
517
- | `InteractionContext.ask()` | `input-required` state |
518
464
  | `TaskContext.update()` | Task lifecycle states |
519
465
  | `FilePart` | A2A File parts |
466
+ | `DataPart` | A2A Data parts |
520
467
  | `APIKeyAuth` / `BearerAuth` | Security schemes |
521
468
 
522
469
  ---
@@ -1,6 +1,6 @@
1
1
  # A2A Lite - Python
2
2
 
3
- **Build A2A agents in 8 lines. Add enterprise features when you need them.**
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.use(logging_middleware)
159
- agent.use(timing_middleware)
160
- agent.use(rate_limit_middleware(max_per_minute=60))
161
- agent.use(retry_middleware(max_retries=3))
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: Human-in-the-Loop
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 7: Task Tracking
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 8: Authentication
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
- ### Level 9: CORS and Production Mode
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 10: Webhooks
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
- ## Full API Reference
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.use(middleware)` | Register middleware function |
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, # Skill name (required)
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
- | `InteractionContext` | Human-in-the-loop interactions |
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
- | [11_human_in_the_loop.py](examples/11_human_in_the_loop.py) | Ask user questions |
472
- | [12_file_handling.py](examples/12_file_handling.py) | Handle files |
473
- | [13_task_tracking.py](examples/13_task_tracking.py) | Progress updates |
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, EmailStr
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: Multi-modal file handling.
3
3
 
4
4
  Handle files, images, documents - not just text!
5
5
 
6
- Run: python examples/12_file_handling.py
6
+ Run: python examples/10_file_handling.py
7
7
  """
8
8
  from a2a_lite import Agent, FilePart, DataPart, Artifact
9
9
 
@@ -3,7 +3,7 @@ Example: Task lifecycle and progress tracking.
3
3
 
4
4
  Show users real-time progress for long-running tasks.
5
5
 
6
- Run: python examples/13_task_tracking.py
6
+ Run: python examples/11_task_tracking.py
7
7
  """
8
8
  import asyncio
9
9
  from a2a_lite import Agent, TaskContext
@@ -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/14_with_auth.py
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.1"
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,14 +24,15 @@ 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",
32
30
  ]
33
31
 
34
32
  [project.optional-dependencies]
33
+ oauth = [
34
+ "pyjwt[crypto]>=2.0",
35
+ ]
35
36
  dev = [
36
37
  "pytest>=7.0",
37
38
  "pytest-asyncio>=0.21",