Skip to content

Commit 3f17f3c

Browse files
committed
feat: Implement A2A Dart client and unit tests
1 parent 10b950d commit 3f17f3c

File tree

76 files changed

+13523
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+13523
-0
lines changed

packages/a2a_dart/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# https://dart.dev/guides/libraries/private-files
2+
# Created by `dart pub`
3+
.dart_tool/

packages/a2a_dart/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# a2a_dart Change Log
2+
3+
## 0.1.0
4+
5+
- Initial version of the Dart A2A library.

packages/a2a_dart/DESIGN.md

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# A2A Dart Library Design Document
2+
3+
## 1. Overview
4+
5+
This document outlines the design for a pure Dart implementation of the Agent2Agent (A2A) protocol. The `a2a_dart` library provides both client and server components for A2A communication. The client is platform-independent and can be used in web applications, while the server is designed for native platforms that support `dart:io`.
6+
7+
The primary goal is to create a library that is:
8+
9+
- **Comprehensive**: Implements the full A2A specification.
10+
- **Idiomatic**: Feels natural to Dart and Flutter developers.
11+
- **Type-Safe**: Leverages Dart's strong type system to prevent errors.
12+
- **Extensible**: Allows for future expansion and customization.
13+
14+
## 2. Goals and Non-Goals
15+
16+
### Goals
17+
18+
- Provide a type-safe, idiomatic Dart implementation of the A2A protocol.
19+
- Support the full A2A specification, including all data models and RPC methods.
20+
- Offer a clear and easy-to-use client API for interacting with A2A agents.
21+
- Provide a flexible and extensible server framework for building A2A agents in Dart.
22+
- Adhere to Dart and Flutter best practices, including null safety, effective asynchronous programming, and clean architecture.
23+
24+
### Non-Goals
25+
26+
- **Transports**: Implement transport protocols other than JSON-RPC and SSE over HTTP. gRPC and REST transports are out of scope for the initial version.
27+
- **Push Notifications**: The server-side push notification mechanism will not be implemented initially. The client will support sending the configuration, but the server will not act on it.
28+
- **Agent Framework**: Provide a full-fledged agent framework with built-in AI capabilities. This library focuses on the communication protocol.
29+
- **Extensions**: Implement any of the optional extensions to the A2A protocol in the initial version.
30+
31+
## 3. Implemented A2A Features
32+
33+
The `a2a_dart` library implements the following features from the A2A specification:
34+
35+
### Core Concepts
36+
37+
- **Client & Server**: Foundational components for initiating and responding to A2A requests.
38+
- **Agent Card**: Full implementation for agent discovery and capability advertisement.
39+
- **Task**: State management for all agent operations.
40+
- **Message**: The primary object for communication turns.
41+
- **Part**: Support for `TextPart`, `FilePart`, and `DataPart` to enable rich content exchange.
42+
- **Artifact**: Handling for agent-generated outputs.
43+
- **Context**: Grouping related tasks.
44+
45+
### Transport Protocols
46+
47+
- **JSON-RPC 2.0**: The primary transport protocol for all RPC methods over HTTP/S.
48+
- **Server-Sent Events (SSE)**: For real-time, streaming updates from the server to the client (`message/stream` and `tasks/resubscribe`).
49+
50+
### Data Models
51+
52+
- A complete, type-safe implementation of all data objects defined in the specification, including:
53+
- `Task`, `TaskStatus`, `TaskState`
54+
- `Message`, `Part` (and its variants)
55+
- `AgentCard` (and all nested objects like `AgentSkill`, `AgentProvider`, etc.)
56+
- `Artifact`
57+
- `PushNotificationConfig` (client-side only)
58+
- All JSON-RPC request, response, and error structures.
59+
60+
### RPC Methods
61+
62+
- The library provides client methods and server-side handlers for the following A2A RPC methods:
63+
- `get_agent_card` (via HTTP GET)
64+
- `create_task`
65+
- `message/stream`
66+
- `execute_task`
67+
68+
### Authentication
69+
70+
- The library will be designed to work with standard HTTP authentication mechanisms (e.g., Bearer Token, API Key) by providing hooks (middleware) for adding authentication headers to client requests.
71+
72+
## 4. Architecture
73+
74+
The `a2a_dart` library is structured with a single public entry point, `lib/a2a_dart.dart`, which exports the core, client, and server APIs. The internal structure is organized as follows:
75+
76+
- **`lib/src`**: Contains the private implementation of the library.
77+
- **`core`**: Contains the platform-independent data models and types defined in the A2A specification.
78+
- **`client`**: Provides the `A2AClient` class and transport implementations (`HttpTransport`, `SseTransport`).
79+
- **`server`**: Offers a framework for building A2A agents. It uses a conditional export (`a2a_server.dart`) to provide a native implementation (`io/a2a_server.dart`) and a web stub (`web/a2a_server.dart`).
80+
81+
```mermaid
82+
graph TD
83+
subgraph Public API
84+
A[lib/a2a_dart.dart]
85+
end
86+
87+
subgraph "Implementation (lib/src)"
88+
B[Core]
89+
C[Client]
90+
D[Server]
91+
end
92+
93+
A --> B
94+
A --> C
95+
A --> D
96+
97+
B --> B1[Data Models]
98+
99+
C --> C1[A2AClient]
100+
C --> C2[Transport]
101+
C2 --> C2a[HttpTransport]
102+
C2 --> C2b[SseTransport]
103+
104+
D --> D1[a2a_server.dart (conditional export)]
105+
D1 --> D1a[io/a2a_server.dart]
106+
D1 --> D1b[web/a2a_server.dart]
107+
D --> D2[RequestHandler]
108+
```
109+
110+
## 4. Data Models
111+
112+
All data models from the A2A specification will be implemented as immutable Dart classes. To reduce boilerplate and ensure correctness, we will use the `json_serializable` and `freezed` packages for JSON serialization and value equality.
113+
114+
- **Immutability**: All model classes will be immutable.
115+
- **JSON Serialization**: Each class will have `fromJson` and `toJson` methods.
116+
- **Null Safety**: All fields will be null-safe.
117+
118+
Example `AgentCard` model:
119+
120+
```dart
121+
import 'package:freezed_annotation/freezed_annotation.dart';
122+
123+
part 'agent_card.freezed.dart';
124+
part 'agent_card.g.dart';
125+
126+
@freezed
127+
class AgentCard with _$AgentCard {
128+
const factory AgentCard({
129+
required String protocolVersion,
130+
required String name,
131+
required String description,
132+
required String url,
133+
// ... other fields
134+
}) = _AgentCard;
135+
136+
factory AgentCard.fromJson(Map<String, dynamic> json) => _$AgentCardFromJson(json);
137+
}
138+
```
139+
140+
## 5. Client API
141+
142+
The client API will be centered around the `A2AClient` class. This class will provide methods for each of the A2A RPC calls, such as `sendMessage`, `getTask`, and `cancelTask`.
143+
144+
- **Asynchronous**: All API methods will be asynchronous, returning `Future`s.
145+
- **Transport Agnostic**: The `A2AClient` delegates the actual HTTP communication to a `Transport` interface. This allows for different transport implementations, with `HttpTransport` providing basic request-response and `SseTransport` extending it for streaming.
146+
147+
Example `A2AClient` usage:
148+
149+
```dart
150+
final log = Logger('MyClient');
151+
final client = A2AClient(
152+
url: 'https://example.com/a2a',
153+
transport: SseTransport(url: 'https://example.com/a2a', log: log),
154+
);
155+
156+
// Create a task
157+
final task = await client.createTask(Message(
158+
messageId: '1',
159+
role: Role.user,
160+
parts: [Part.text(text: 'Hello, agent!')],
161+
));
162+
163+
// Execute the task and get a stream of events
164+
final stream = client.executeTask(task.id);
165+
await for (final event in stream) {
166+
// process events
167+
}
168+
```
169+
170+
## 6. Server Framework
171+
172+
The server framework will provide the building blocks for creating A2A-compliant agents in Dart.
173+
174+
- **`A2AServer`**: A top-level class that listens for incoming HTTP requests. It is conditionally exported to support both native and web platforms. On native, it uses `dart:io` to create an HTTP server. On the web, it throws an `UnsupportedError` if instantiated.
175+
- **`RequestHandler`**: An interface for handling specific A2A methods. Developers will implement this interface to define their agent's behavior. The `handle` method returns a `HandlerResult` which can be a `SingleResult` for a single response or a `StreamResult` for a streaming response.
176+
- **`TaskManager`**: A class responsible for managing the lifecycle of tasks.
177+
178+
## 7. Error Handling
179+
180+
Errors will be handled using a combination of exceptions and a `Result` type. Network and transport-level errors will throw exceptions, while A2A-specific errors will be returned as part of a `Result` object, allowing for more granular error handling.
181+
182+
## 8. Dependencies
183+
184+
- `http`: For making HTTP requests.
185+
- `freezed`: For immutable data classes.
186+
- `json_serializable`: For JSON serialization.
187+
- `shelf`: For building the server.
188+
- `shelf_router`: For routing requests on the server.
189+
- `uuid`: For generating unique IDs.
190+
191+
## 9. Testing
192+
193+
The library will have a comprehensive suite of unit and integration tests.
194+
195+
- **Unit Tests**: Will cover individual classes and methods in isolation.
196+
- **Integration Tests**: Will test the client and server components together, as well as against a known-good A2A implementation.
197+
198+
## 10. Documentation
199+
200+
All public APIs will be thoroughly documented with DartDoc comments. The package will also include a comprehensive `README.md` and example usage.

packages/a2a_dart/GEMINI.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# A2A Dart Package
2+
3+
## Overview
4+
5+
This package provides a Dart implementation of the A2A (Agent-to-Agent) protocol. It includes a client for interacting with A2A servers and a server framework for building A2A agents.
6+
7+
Here's the overview of the layout of this pacakge:
8+
9+
```
10+
├── analysis_options.yaml
11+
├── lib
12+
│ ├── a2a_dart.dart
13+
│ └── src
14+
│ ├── client
15+
│ │ ├── a2a_client.dart
16+
│ │ ├── transport.dart
17+
│ │ ├── http_transport.dart
18+
│ │ └── sse_transport.dart
19+
│ ├── core
20+
│ │ ├── agent_card.dart
21+
│ │ ├── message.dart
22+
│ │ ├── task.dart
23+
│ │ └── ... (other data models)
24+
│ └── server
25+
│ ├── a2a_server.dart (conditional export)
26+
│ ├── request_handler.dart
27+
│ ├── io
28+
│ │ └── a2a_server.dart (native implementation)
29+
│ └── web
30+
│ └── a2a_server.dart (web stub)
31+
├── pubspec.yaml
32+
└── test
33+
├── client
34+
│ └── a2a_client_test.dart
35+
├── integration
36+
│ └── client_server_test.dart
37+
└── server
38+
└── a2a_server_test.dart
39+
```
40+
41+
## Documentation and References
42+
43+
The design document in the `DESIGN.md` file provides an overview of the package's architecture and design decisions.
44+
45+
The high level overview of the package in the `README.md` file.
46+
47+
The A2A protocol specification is defined here: [A2A Protocol](https://a2a-protocol.org/latest/specification/).
48+
49+
## Client
50+
51+
`A2AClient` interacts with A2A servers. It supports RPC calls like `get_agent_card`, `create_task`, and `execute_task`. Communication is handled by a `Transport` interface, with `HttpTransport` for single requests and `SseTransport` for streaming.
52+
53+
## Server
54+
55+
`A2AServer` is a framework for building A2A agents on top of the `shelf` package. It uses a pipeline of `RequestHandler` instances to process requests, where each handler corresponds to an RPC method. The `handle` method returns a `HandlerResult`, which can be a `SingleResult` for one response or a `StreamResult` for a stream of responses.
56+
57+
## Data Models
58+
59+
The package includes Dart classes for A2A data structures (`AgentCard`, `Message`, `Task`, `SecurityScheme`). These are built with `freezed` and `json_serializable` to be immutable and support JSON serialization.

packages/a2a_dart/LICENSE

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright 2025 The Flutter Authors.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
1. Redistributions of source code must retain the above copyright notice, this
7+
list of conditions and the following disclaimer.
8+
9+
2. Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
13+
3. Neither the name of the copyright holder nor the names of its contributors
14+
may be used to endorse or promote products derived from this software without
15+
specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
21+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/a2a_dart/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# A2A Dart
2+
3+
This package provides a Dart implementation of the A2A (Agent-to-Agent) protocol. It includes a client for interacting with A2A servers and a server framework for building A2A agents.
4+
5+
## Features
6+
7+
- **A2A Client**: A high-level client for communicating with A2A servers.
8+
- **HTTP and SSE Transports**: Support for both standard request-response and streaming communication.
9+
- **A2A Server**: A simple and extensible server framework.
10+
- **Type-Safe Data Models**: Dart classes for all A2A data structures.
11+
- **Web Compatible**: The client can be used in web applications.
12+
13+
## Installation
14+
15+
Add the following to your `pubspec.yaml` file:
16+
17+
```yaml
18+
dependencies:
19+
a2a_dart: ^0.1.0 # or the latest version
20+
```
21+
22+
## Usage
23+
24+
### Client
25+
26+
```dart
27+
import 'package:a2a_dart/a2a_dart.dart';
28+
import 'package:logging/logging.dart';
29+
30+
void main() async {
31+
final log = Logger('A2AClient');
32+
// For streaming, use SseTransport.
33+
final transport = SseTransport(url: 'http://localhost:8080', log: log);
34+
final client = A2AClient(url: 'http://localhost:8080', transport: transport);
35+
36+
// Get the agent card.
37+
final agentCard = await client.getAgentCard();
38+
print('Agent: ${agentCard.name}');
39+
40+
// Create a new task.
41+
final message = Message(
42+
messageId: '1',
43+
role: Role.user,
44+
parts: [Part.text(text: 'Hello')],
45+
);
46+
final task = await client.createTask(message);
47+
print('Created task: ${task.id}');
48+
49+
// Execute the task and stream the results.
50+
try {
51+
final stream = client.executeTask(task.id);
52+
await for (final event in stream) {
53+
print('Received event: ${event.type}');
54+
}
55+
} on A2AException catch (e) {
56+
print('Error executing task: ${e.message}');
57+
}
58+
}
59+
```
60+
61+
### Server
62+
63+
```dart
64+
import 'package:a2a_dart/a2a_dart.dart';
65+
66+
void main() async {
67+
final taskManager = TaskManager();
68+
final server = A2AServer([
69+
CreateTaskHandler(taskManager),
70+
]);
71+
72+
await server.start();
73+
print('Server started on port ${server.port}');
74+
}
75+
```
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright 2025 The Flutter Authors.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
include: package:dart_flutter_team_lints/analysis_options.yaml
6+

0 commit comments

Comments
 (0)