Skip to content

Commit e1bd992

Browse files
authored
Merge branch 'main' into doc/helper-utils
2 parents 19e48d9 + 79e577d commit e1bd992

File tree

9 files changed

+104
-123
lines changed

9 files changed

+104
-123
lines changed

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: 'uv'
4+
directory: '/'
5+
schedule:
6+
interval: 'monthly'
7+
- package-ecosystem: 'github-actions'
8+
directory: '/'
9+
schedule:
10+
interval: 'monthly'

.github/workflows/conventional-commits.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020
steps:
2121
- name: semantic-pull-request
22-
uses: amannn/action-semantic-pull-request@v5.5.3
22+
uses: amannn/action-semantic-pull-request@v6.1.1
2323
env:
2424
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2525
with:

.github/workflows/linter.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
if: github.repository == 'a2aproject/a2a-python'
1313
steps:
1414
- name: Checkout Code
15-
uses: actions/checkout@v4
15+
uses: actions/checkout@v5
1616
- name: Set up Python
1717
uses: actions/setup-python@v5
1818
with:

.github/workflows/python-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
steps:
15-
- uses: actions/checkout@v4
15+
- uses: actions/checkout@v5
1616

1717
- name: Install uv
1818
uses: astral-sh/setup-uv@v5

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
python-version: ['3.10', '3.13']
4040
steps:
4141
- name: Checkout code
42-
uses: actions/checkout@v4
42+
uses: actions/checkout@v5
4343
- name: Set up test environment variables
4444
run: |
4545
echo "POSTGRES_TEST_DSN=postgresql+asyncpg://a2a:a2a_password@localhost:5432/a2a_test" >> $GITHUB_ENV

.github/workflows/update-a2a-types.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
pull-requests: write
1313
steps:
1414
- name: Checkout code
15-
uses: actions/checkout@v4
15+
uses: actions/checkout@v5
1616
- name: Set up Python
1717
uses: actions/setup-python@v5
1818
with:
@@ -42,7 +42,7 @@ jobs:
4242
uv run scripts/grpc_gen_post_processor.py
4343
echo "Buf generate finished."
4444
- name: Create Pull Request with Updates
45-
uses: peter-evans/create-pull-request@v6
45+
uses: peter-evans/create-pull-request@v7
4646
with:
4747
token: ${{ secrets.A2A_BOT_PAT }}
4848
committer: a2a-bot <[email protected]>

README.md

Lines changed: 54 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,110 +4,63 @@
44
[![PyPI version](https://img.shields.io/pypi/v/a2a-sdk)](https://pypi.org/project/a2a-sdk/)
55
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/a2a-sdk)
66
[![PyPI - Downloads](https://img.shields.io/pypi/dw/a2a-sdk)](https://pypistats.org/packages/a2a-sdk)
7+
[![Python Unit Tests](https://github.com/a2aproject/a2a-python/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/a2aproject/a2a-python/actions/workflows/unit-tests.yml)
8+
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/a2aproject/a2a-python)
79

810
<!-- markdownlint-disable no-inline-html -->
911

10-
<html>
11-
<h2 align="center">
12+
<div align="center">
1213
<img src="https://raw.githubusercontent.com/a2aproject/A2A/refs/heads/main/docs/assets/a2a-logo-black.svg" width="256" alt="A2A Logo"/>
13-
</h2>
14-
<h3 align="center">A Python library that helps run agentic applications as A2AServers following the <a href="https://a2a-protocol.org">Agent2Agent (A2A) Protocol</a>.</h3>
15-
</html>
14+
<h3>
15+
A Python library for running agentic applications as A2A Servers, following the <a href="https://a2a-protocol.org">Agent2Agent (A2A) Protocol</a>.
16+
</h3>
17+
</div>
1618

1719
<!-- markdownlint-enable no-inline-html -->
1820

19-
## Installation
21+
---
2022

21-
You can install the A2A SDK using either `uv` or `pip`.
23+
## ✨ Features
2224

23-
## Prerequisites
25+
- **A2A Protocol Compliant:** Build agentic applications that adhere to the Agent2Agent (A2A) Protocol.
26+
- **Extensible:** Easily add support for different communication protocols and database backends.
27+
- **Asynchronous:** Built on modern async Python for high performance.
28+
- **Optional Integrations:** Includes optional support for:
29+
- HTTP servers ([FastAPI](https://fastapi.tiangolo.com/), [Starlette](https://www.starlette.io/))
30+
- [gRPC](https://grpc.io/)
31+
- [OpenTelemetry](https://opentelemetry.io/) for tracing
32+
- SQL databases ([PostgreSQL](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://sqlite.org/))
2433

25-
- Python 3.10+
26-
- `uv` (optional, but recommended) or `pip`
27-
28-
### Using `uv`
29-
30-
When you're working within a uv project or a virtual environment managed by uv, the preferred way to add packages is using uv add.
31-
32-
```bash
33-
uv add a2a-sdk
34-
```
35-
36-
To include the optional HTTP server components (FastAPI, Starlette), install the `http-server` extra:
37-
38-
```bash
39-
uv add a2a-sdk[http-server]
40-
```
41-
42-
To install with gRPC support:
43-
44-
```bash
45-
uv add "a2a-sdk[grpc]"
46-
```
47-
48-
To install with OpenTelemetry tracing support:
49-
50-
```bash
51-
uv add "a2a-sdk[telemetry]"
52-
```
53-
54-
To install with database support:
55-
56-
```bash
57-
# PostgreSQL support
58-
uv add "a2a-sdk[postgresql]"
59-
60-
# MySQL support
61-
uv add "a2a-sdk[mysql]"
34+
---
6235

63-
# SQLite support
64-
uv add "a2a-sdk[sqlite]"
36+
## 🚀 Getting Started
6537

66-
# All database drivers
67-
uv add "a2a-sdk[sql]"
68-
```
38+
### Prerequisites
6939

70-
### Using `pip`
71-
72-
If you prefer to use pip, the standard Python package installer, you can install `a2a-sdk` as follows
73-
74-
```bash
75-
pip install a2a-sdk
76-
```
77-
78-
To include the optional HTTP server components (FastAPI, Starlette), install the `http-server` extra:
79-
80-
```bash
81-
pip install a2a-sdk[http-server]
82-
```
83-
84-
To install with gRPC support:
85-
86-
```bash
87-
pip install "a2a-sdk[grpc]"
88-
```
89-
90-
To install with OpenTelemetry tracing support:
40+
- Python 3.10+
41+
- `uv` (recommended) or `pip`
9142

92-
```bash
93-
pip install "a2a-sdk[telemetry]"
94-
```
43+
### 🔧 Installation
9544

96-
To install with database support:
45+
Install the core SDK and any desired extras using your preferred package manager.
9746

98-
```bash
99-
# PostgreSQL support
100-
pip install "a2a-sdk[postgresql]"
47+
| Feature | `uv` Command | `pip` Command |
48+
| ------------------------ | ------------------------------------------ | -------------------------------------------- |
49+
| **Core SDK** | `uv add a2a-sdk` | `pip install a2a-sdk` |
50+
| **HTTP Server** | `uv add "a2a-sdk[http-server]"` | `pip install "a2a-sdk[http-server]"` |
51+
| **gRPC Support** | `uv add "a2a-sdk[grpc]"` | `pip install "a2a-sdk[grpc]"` |
52+
| **OpenTelemetry Tracing**| `uv add "a2a-sdk[telemetry]"` | `pip install "a2a-sdk[telemetry]"` |
10153

102-
# MySQL support
103-
pip install "a2a-sdk[mysql]"
54+
#### Database Support
10455

105-
# SQLite support
106-
pip install "a2a-sdk[sqlite]"
56+
Install the necessary drivers for your chosen SQL database.
10757

108-
# All database drivers
109-
pip install "a2a-sdk[sql]"
110-
```
58+
| Database | `uv` Command | `pip` Command |
59+
| ------------- | ---------------------------------- | ------------------------------------ |
60+
| **PostgreSQL**| `uv add "a2a-sdk[postgresql]"` | `pip install "a2a-sdk[postgresql]"` |
61+
| **MySQL** | `uv add "a2a-sdk[mysql]"` | `pip install "a2a-sdk[mysql]"` |
62+
| **SQLite** | `uv add "a2a-sdk[sqlite]"` | `pip install "a2a-sdk[sqlite]"` |
63+
| **All SQL Drivers** | `uv add "a2a-sdk[sql]"` | `pip install "a2a-sdk[sql]"` |
11164

11265
## Examples
11366

@@ -130,12 +83,23 @@ pip install "a2a-sdk[sql]"
13083

13184
3. You can validate your agent using the agent inspector. Follow the instructions at the [a2a-inspector](https://github.com/a2aproject/a2a-inspector) repo.
13285

133-
You can also find more Python samples [here](https://github.com/a2aproject/a2a-samples/tree/main/samples/python) and JavaScript samples [here](https://github.com/a2aproject/a2a-samples/tree/main/samples/js).
86+
---
87+
88+
## 🌐 More Examples
89+
90+
You can find a variety of more detailed examples in the [a2a-samples](https://github.com/a2aproject/a2a-samples) repository:
91+
92+
- **[Python Examples](https://github.com/a2aproject/a2a-samples/tree/main/samples/python)**
93+
- **[JavaScript Examples](https://github.com/a2aproject/a2a-samples/tree/main/samples/js)**
94+
95+
---
96+
97+
## 🤝 Contributing
13498

135-
## License
99+
Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines on how to get involved.
136100

137-
This project is licensed under the terms of the [Apache 2.0 License](https://raw.githubusercontent.com/a2aproject/a2a-python/refs/heads/main/LICENSE).
101+
---
138102

139-
## Contributing
103+
## 📄 License
140104

141-
See [CONTRIBUTING.md](https://github.com/a2aproject/a2a-python/blob/main/CONTRIBUTING.md) for contribution guidelines.
105+
This project is licensed under the Apache 2.0 License. See the [LICENSE](LICENSE) file for more details.

src/a2a/server/request_handlers/default_request_handler.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,15 +344,6 @@ async def push_notification_callback() -> None:
344344
blocking=blocking,
345345
event_callback=push_notification_callback,
346346
)
347-
if not result:
348-
raise ServerError(error=InternalError()) # noqa: TRY301
349-
350-
if isinstance(result, Task):
351-
self._validate_task_id_match(task_id, result.id)
352-
353-
await self._send_push_notification_if_needed(
354-
task_id, result_aggregator
355-
)
356347

357348
except Exception:
358349
logger.exception('Agent execution failed')
@@ -367,6 +358,14 @@ async def push_notification_callback() -> None:
367358
else:
368359
await self._cleanup_producer(producer_task, task_id)
369360

361+
if not result:
362+
raise ServerError(error=InternalError())
363+
364+
if isinstance(result, Task):
365+
self._validate_task_id_match(task_id, result.id)
366+
367+
await self._send_push_notification_if_needed(task_id, result_aggregator)
368+
370369
return result
371370

372371
async def on_message_send_stream(

src/a2a/server/request_handlers/jsonrpc_handler.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -183,22 +183,26 @@ async def on_cancel_task(
183183
task = await self.request_handler.on_cancel_task(
184184
request.params, context
185185
)
186-
if task:
187-
return prepare_response_object(
188-
request.id,
189-
task,
190-
(Task,),
191-
CancelTaskSuccessResponse,
192-
CancelTaskResponse,
193-
)
194-
raise ServerError(error=TaskNotFoundError()) # noqa: TRY301
195186
except ServerError as e:
196187
return CancelTaskResponse(
197188
root=JSONRPCErrorResponse(
198189
id=request.id, error=e.error if e.error else InternalError()
199190
)
200191
)
201192

193+
if task:
194+
return prepare_response_object(
195+
request.id,
196+
task,
197+
(Task,),
198+
CancelTaskSuccessResponse,
199+
CancelTaskResponse,
200+
)
201+
202+
return CancelTaskResponse(
203+
root=JSONRPCErrorResponse(id=request.id, error=TaskNotFoundError())
204+
)
205+
202206
async def on_resubscribe_to_task(
203207
self,
204208
request: TaskResubscriptionRequest,
@@ -335,22 +339,26 @@ async def on_get_task(
335339
task = await self.request_handler.on_get_task(
336340
request.params, context
337341
)
338-
if task:
339-
return prepare_response_object(
340-
request.id,
341-
task,
342-
(Task,),
343-
GetTaskSuccessResponse,
344-
GetTaskResponse,
345-
)
346-
raise ServerError(error=TaskNotFoundError()) # noqa: TRY301
347342
except ServerError as e:
348343
return GetTaskResponse(
349344
root=JSONRPCErrorResponse(
350345
id=request.id, error=e.error if e.error else InternalError()
351346
)
352347
)
353348

349+
if task:
350+
return prepare_response_object(
351+
request.id,
352+
task,
353+
(Task,),
354+
GetTaskSuccessResponse,
355+
GetTaskResponse,
356+
)
357+
358+
return GetTaskResponse(
359+
root=JSONRPCErrorResponse(id=request.id, error=TaskNotFoundError())
360+
)
361+
354362
async def list_push_notification_config(
355363
self,
356364
request: ListTaskPushNotificationConfigRequest,

0 commit comments

Comments
 (0)