-
Notifications
You must be signed in to change notification settings - Fork 80
feat(a2a_dart): Add an A2A library for Dart #497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
gspencergoog
wants to merge
15
commits into
flutter:main
Choose a base branch
from
gspencergoog:a2a_dart
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
3f17f3c
feat: Implement A2A Dart client and unit tests
gspencergoog b596936
feat: Implement A2A Dart server framework and unit tests
gspencergoog 9d9c0d7
feat: Re-implement push notification APIs
gspencergoog 2eab0ac
Merge branch 'a2a_dart_client' into a2a_dart
gspencergoog 2d6c0c7
Add Server on top of client support.
gspencergoog d3506e5
Remove accidental submodule
gspencergoog fd85093
Remove accidental submodule
gspencergoog c0761f4
Fix copyrights
gspencergoog b540fd5
Merge branch 'a2a_dart_client' into a2a_dart
gspencergoog 57057cf
Fix format
gspencergoog db91343
fix format
gspencergoog 2228e6b
Merge branch 'main' into a2a_dart_client
gspencergoog 0a7380e
Remove unneeded copyrights
gspencergoog 60fc91c
Merge branch 'a2a_dart_client' into a2a_dart
gspencergoog cb41d68
Update built files
gspencergoog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # https://dart.dev/guides/libraries/private-files | ||
| # Created by `dart pub` | ||
| .dart_tool/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # a2a_dart Change Log | ||
|
|
||
| ## 0.1.0 | ||
|
|
||
| - Initial version of the Dart A2A library. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| # A2A Dart Library Design Document | ||
|
|
||
| ## 1. Overview | ||
|
|
||
| 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`. | ||
|
|
||
| The primary goal is to create a library that is: | ||
|
|
||
| - **Comprehensive**: Implements the full A2A specification. | ||
| - **Idiomatic**: Feels natural to Dart and Flutter developers. | ||
| - **Type-Safe**: Leverages Dart's strong type system to prevent errors. | ||
| - **Extensible**: Allows for future expansion and customization. | ||
|
|
||
| ## 2. Goals and Non-Goals | ||
|
|
||
| ### Goals | ||
|
|
||
| - Provide a type-safe, idiomatic Dart implementation of the A2A protocol. | ||
| - Support the full A2A specification, including all data models and RPC methods. | ||
| - Offer a clear and easy-to-use client API for interacting with A2A agents. | ||
| - Provide a flexible and extensible server framework for building A2A agents in Dart. | ||
| - Adhere to Dart and Flutter best practices, including null safety, effective asynchronous programming, and clean architecture. | ||
|
|
||
| ### Non-Goals | ||
|
|
||
| - **Transports**: Implement transport protocols other than JSON-RPC and SSE over HTTP. gRPC and REST transports are out of scope for the initial version. | ||
| - **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. | ||
| - **Agent Framework**: Provide a full-fledged agent framework with built-in AI capabilities. This library focuses on the communication protocol. | ||
| - **Extensions**: Implement any of the optional extensions to the A2A protocol in the initial version. | ||
|
|
||
| ## 3. Implemented A2A Features | ||
|
|
||
| The `a2a_dart` library implements the following features from the A2A specification: | ||
|
|
||
| ### Core Concepts | ||
|
|
||
| - **Client & Server**: Foundational components for initiating and responding to A2A requests. | ||
| - **Agent Card**: Full implementation for agent discovery and capability advertisement. | ||
| - **Task**: State management for all agent operations. | ||
| - **Message**: The primary object for communication turns. | ||
| - **Part**: Support for `TextPart`, `FilePart`, and `DataPart` to enable rich content exchange. | ||
| - **Artifact**: Handling for agent-generated outputs. | ||
| - **Context**: Grouping related tasks. | ||
|
|
||
| ### Transport Protocols | ||
|
|
||
| - **JSON-RPC 2.0**: The primary transport protocol for all RPC methods over HTTP/S. | ||
| - **Server-Sent Events (SSE)**: For real-time, streaming updates from the server to the client (`message/stream` and `tasks/resubscribe`). | ||
|
|
||
| ### Data Models | ||
|
|
||
| - A complete, type-safe implementation of all data objects defined in the specification, including: | ||
| - `Task`, `TaskStatus`, `TaskState` | ||
| - `Message`, `Part` (and its variants) | ||
| - `AgentCard` (and all nested objects like `AgentSkill`, `AgentProvider`, etc.) | ||
| - `Artifact` | ||
| - `PushNotificationConfig` (client-side only) | ||
| - All JSON-RPC request, response, and error structures. | ||
|
|
||
| ### RPC Methods | ||
|
|
||
| - The library provides client methods and server-side handlers for the following A2A RPC methods: | ||
| - `get_agent_card` (via HTTP GET) | ||
| - `create_task` | ||
| - `message/stream` | ||
| - `execute_task` | ||
|
|
||
| ### Authentication | ||
|
|
||
| - 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. | ||
|
|
||
| ## 4. Architecture | ||
|
|
||
| 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: | ||
|
|
||
| - **`lib/src`**: Contains the private implementation of the library. | ||
| - **`core`**: Contains the platform-independent data models and types defined in the A2A specification. | ||
| - **`client`**: Provides the `A2AClient` class and transport implementations (`HttpTransport`, `SseTransport`). | ||
| - **`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`). | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| subgraph Public API | ||
| A[lib/a2a_dart.dart] | ||
| end | ||
|
|
||
| subgraph "Implementation (lib/src)" | ||
| B[Core] | ||
| C[Client] | ||
| D[Server] | ||
| end | ||
|
|
||
| A --> B | ||
| A --> C | ||
| A --> D | ||
|
|
||
| B --> B1[Data Models] | ||
|
|
||
| C --> C1[A2AClient] | ||
| C --> C2[Transport] | ||
| C2 --> C2a[HttpTransport] | ||
| C2 --> C2b[SseTransport] | ||
|
|
||
| D --> D1[a2a_server.dart (conditional export)] | ||
| D1 --> D1a[io/a2a_server.dart] | ||
| D1 --> D1b[web/a2a_server.dart] | ||
| D --> D2[RequestHandler] | ||
| ``` | ||
|
|
||
| ## 4. Data Models | ||
|
|
||
| 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. | ||
|
|
||
| - **Immutability**: All model classes will be immutable. | ||
| - **JSON Serialization**: Each class will have `fromJson` and `toJson` methods. | ||
| - **Null Safety**: All fields will be null-safe. | ||
|
|
||
| Example `AgentCard` model: | ||
|
|
||
| ```dart | ||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||
|
|
||
| part 'agent_card.freezed.dart'; | ||
| part 'agent_card.g.dart'; | ||
|
|
||
| @freezed | ||
| class AgentCard with _$AgentCard { | ||
| const factory AgentCard({ | ||
| required String protocolVersion, | ||
| required String name, | ||
| required String description, | ||
| required String url, | ||
| // ... other fields | ||
| }) = _AgentCard; | ||
|
|
||
| factory AgentCard.fromJson(Map<String, dynamic> json) => _$AgentCardFromJson(json); | ||
| } | ||
| ``` | ||
|
|
||
| ## 5. Client API | ||
|
|
||
| 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`. | ||
|
|
||
| - **Asynchronous**: All API methods will be asynchronous, returning `Future`s. | ||
| - **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. | ||
|
|
||
| Example `A2AClient` usage: | ||
|
|
||
| ```dart | ||
| final log = Logger('MyClient'); | ||
| final client = A2AClient( | ||
| url: 'https://example.com/a2a', | ||
| transport: SseTransport(url: 'https://example.com/a2a', log: log), | ||
| ); | ||
|
|
||
| // Create a task | ||
| final task = await client.createTask(Message( | ||
| messageId: '1', | ||
| role: Role.user, | ||
| parts: [Part.text(text: 'Hello, agent!')], | ||
| )); | ||
|
|
||
| // Execute the task and get a stream of events | ||
| final stream = client.executeTask(task.id); | ||
| await for (final event in stream) { | ||
| // process events | ||
| } | ||
| ``` | ||
|
|
||
| ## 6. Server Framework | ||
|
|
||
| The server framework will provide the building blocks for creating A2A-compliant agents in Dart. | ||
|
|
||
| - **`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. | ||
| - **`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. | ||
| - **`TaskManager`**: A class responsible for managing the lifecycle of tasks. | ||
|
|
||
| ## 7. Error Handling | ||
|
|
||
| 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. | ||
|
|
||
| ## 8. Dependencies | ||
|
|
||
| - `http`: For making HTTP requests. | ||
| - `freezed`: For immutable data classes. | ||
| - `json_serializable`: For JSON serialization. | ||
| - `shelf`: For building the server. | ||
| - `shelf_router`: For routing requests on the server. | ||
| - `uuid`: For generating unique IDs. | ||
|
|
||
| ## 9. Testing | ||
|
|
||
| The library will have a comprehensive suite of unit and integration tests. | ||
|
|
||
| - **Unit Tests**: Will cover individual classes and methods in isolation. | ||
| - **Integration Tests**: Will test the client and server components together, as well as against a known-good A2A implementation. | ||
|
|
||
| ## 10. Documentation | ||
|
|
||
| All public APIs will be thoroughly documented with DartDoc comments. The package will also include a comprehensive `README.md` and example usage. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # A2A Dart Package | ||
|
|
||
| ## Overview | ||
|
|
||
| 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. | ||
|
|
||
| Here's the overview of the layout of this pacakge: | ||
|
|
||
| ``` | ||
| ├── analysis_options.yaml | ||
| ├── lib | ||
| │ ├── a2a_dart.dart | ||
| │ └── src | ||
| │ ├── client | ||
| │ │ ├── a2a_client.dart | ||
| │ │ ├── transport.dart | ||
| │ │ ├── http_transport.dart | ||
| │ │ └── sse_transport.dart | ||
| │ ├── core | ||
| │ │ ├── agent_card.dart | ||
| │ │ ├── message.dart | ||
| │ │ ├── task.dart | ||
| │ │ └── ... (other data models) | ||
| │ └── server | ||
| │ ├── a2a_server.dart (conditional export) | ||
| │ ├── request_handler.dart | ||
| │ ├── io | ||
| │ │ └── a2a_server.dart (native implementation) | ||
| │ └── web | ||
| │ └── a2a_server.dart (web stub) | ||
| ├── pubspec.yaml | ||
| └── test | ||
| ├── client | ||
| │ └── a2a_client_test.dart | ||
| ├── integration | ||
| │ └── client_server_test.dart | ||
| └── server | ||
| └── a2a_server_test.dart | ||
| ``` | ||
|
|
||
| ## Documentation and References | ||
|
|
||
| The design document in the `DESIGN.md` file provides an overview of the package's architecture and design decisions. | ||
|
|
||
| The high level overview of the package in the `README.md` file. | ||
|
|
||
| The A2A protocol specification is defined here: [A2A Protocol](https://a2a-protocol.org/latest/specification/). | ||
|
|
||
| ## Client | ||
|
|
||
| `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. | ||
|
|
||
| ## Server | ||
|
|
||
| `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. | ||
|
|
||
| ## Data Models | ||
|
|
||
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| Copyright 2025 The Flutter Authors. | ||
|
|
||
| Redistribution and use in source and binary forms, with or without modification, | ||
| are permitted provided that the following conditions are met: | ||
|
|
||
| 1. Redistributions of source code must retain the above copyright notice, this | ||
| list of conditions and the following disclaimer. | ||
|
|
||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||
| this list of conditions and the following disclaimer in the documentation | ||
| and/or other materials provided with the distribution. | ||
|
|
||
| 3. Neither the name of the copyright holder nor the names of its contributors | ||
| may be used to endorse or promote products derived from this software without | ||
| specific prior written permission. | ||
|
|
||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # A2A Dart | ||
|
|
||
| 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. | ||
|
|
||
| ## Features | ||
|
|
||
| - **A2A Client**: A high-level client for communicating with A2A servers. | ||
| - **HTTP and SSE Transports**: Support for both standard request-response and streaming communication. | ||
| - **A2A Server**: A simple and extensible server framework. | ||
| - **Type-Safe Data Models**: Dart classes for all A2A data structures. | ||
| - **Web Compatible**: The client can be used in web applications. | ||
|
|
||
| ## Installation | ||
|
|
||
| Add the following to your `pubspec.yaml` file: | ||
|
|
||
| ```yaml | ||
| dependencies: | ||
| a2a_dart: ^0.1.0 # or the latest version | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Client | ||
|
|
||
| ```dart | ||
| import 'package:a2a_dart/a2a_dart.dart'; | ||
| import 'package:logging/logging.dart'; | ||
|
|
||
| void main() async { | ||
| final log = Logger('A2AClient'); | ||
| // For streaming, use SseTransport. | ||
| final transport = SseTransport(url: 'http://localhost:8080', log: log); | ||
| final client = A2AClient(url: 'http://localhost:8080', transport: transport); | ||
|
|
||
| // Get the agent card. | ||
| final agentCard = await client.getAgentCard(); | ||
| print('Agent: ${agentCard.name}'); | ||
|
|
||
| // Create a new task. | ||
| final message = Message( | ||
| messageId: '1', | ||
| role: Role.user, | ||
| parts: [Part.text(text: 'Hello')], | ||
| ); | ||
| final task = await client.createTask(message); | ||
| print('Created task: ${task.id}'); | ||
|
|
||
| // Execute the task and stream the results. | ||
| try { | ||
| final stream = client.executeTask(task.id); | ||
| await for (final event in stream) { | ||
| print('Received event: ${event.type}'); | ||
| } | ||
| } on A2AException catch (e) { | ||
| print('Error executing task: ${e.message}'); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Server | ||
|
|
||
| ```dart | ||
| import 'package:a2a_dart/a2a_dart.dart'; | ||
|
|
||
| void main() async { | ||
| final taskManager = TaskManager(); | ||
| final server = A2AServer([ | ||
| CreateTaskHandler(taskManager), | ||
| ]); | ||
|
|
||
| await server.start(); | ||
| print('Server started on port ${server.port}'); | ||
| } | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The design document states that A2A-specific errors will be returned as part of a
Resulttype. However, the client implementation ina2a_client.dartthrows anA2AExceptionfor JSON-RPC errors. This is a deviation from the documented design. While using exceptions is a valid error handling strategy, the implementation should be consistent with the design document. Please either update the implementation to use aResulttype or update the design document to reflect the use of exceptions for A2A-specific errors.