a2a-rs-v0.3.0
·
32 commits
to master
since this release
Fixed
- allow clippy::result_large_err in request processor
Other
- fmt,clippy
- Fix clippy warnings and failing tests
- migrate to Connect-Rust, refactor project structure, update protobuf specs, and clean up temporary scripts
- docs
Changed
- Demoted the
⚠️ No WebSocket subscribers found for tasklog in
InMemoryTaskStorage::broadcast_status_updatefrom WARN to DEBUG. The
no-subscriber case is the steady state formessage/send(non-streaming)
flows and was previously flooding logs on every status broadcast.
a2a-rs/src/adapter/storage/task_storage.rs:189.
Added - v1.0.0 Compliance
New API Methods
tasks/list- List tasks with comprehensive filtering and pagination- Filter by context_id, status, last_updated_after, and metadata
- Offset-based pagination with page tokens
- Configurable history length and artifact inclusion per request
- Returns ListTasksResult with tasks, total_size, page_size, and next_page_token
tasks/pushNotificationConfig/list- List all push notification configs for a tasktasks/pushNotificationConfig/delete- Delete a specific push notification configagent/getAuthenticatedExtendedCard- Get extended agent card for authenticated clients
Core Type Enhancements
- Added
TransportProtocolenum with JSONRPC, GRPC, and HTTP+JSON variants - Added
AgentInterfacetype for additional transport protocol interfaces - Added
AgentExtensiontype for protocol extension framework- URI-based extension identification
- Optional description and required flags
- Arbitrary parameters via JSON object
- Added
extensionsfield toMessageandArtifacttypes - Added
extensionsfield toAgentCapabilities
Agent Card Updates
- Added
protocol_versionfield (defaults to "0.3.0") - Added
preferred_transportfield (defaults to "JSONRPC") - Added
additional_interfacesfield for multi-transport support - Added
icon_urlfield for agent branding - Changed
signaturetosignatures(now supports multiple signatures)
Push Notification Enhancements
- Added
idfield toPushNotificationConfigfor unique identification - Added
GetTaskPushNotificationConfigParamsfor retrieving specific configs - Added
ListTaskPushNotificationConfigParamsfor listing all configs - Added
DeleteTaskPushNotificationConfigParamsfor config deletion - Updated storage implementations with full CRUD operations for push notification configs
Task Management
- Added
ListTasksParamswith comprehensive filtering options:context_id: Filter by contextstatus: Filter by task statepage_size: Control pagination (1-100, default 50)page_token: Offset-based paginationhistory_length: Control message history depthinclude_artifacts: Toggle artifact inclusionlast_updated_after: Filter by timestamp (ms since epoch)metadata: Filter by metadata fields
- Added
ListTasksResultwith pagination metadata - Added
list_tasks_v3toAsyncTaskManagertrait - Added push notification config management methods to
AsyncTaskManager:get_push_notification_configlist_push_notification_configsdelete_push_notification_config
Protocol Migration & ConnectRPC
- Completely migrated from legacy JSON-RPC and WebSocket transport to ConnectRPC (gRPC-compatible) over HTTP.
- Replaced manual JSON-RPC routing with
connectrpc-buildandprost-generated models based on the official A2Av1.0.0protocol buffers. - Deleted legacy WebSocket transport infrastructure across the workspace.
- Updated
a2a-clientto utilizeconnectrpcstubs for client-server communication. - Built and verified a resilient in-process dispatch architecture for MCP standard I/O.
Storage Layer
- Implemented all v1.0.0 methods in
InMemoryTaskStorage:- Full filtering support for task listing
- Timestamp-based filtering
- Metadata filtering
- Push notification config CRUD operations
- All new trait methods have default implementations returning
UnsupportedOperationerror - Proper sorting of tasks by timestamp (most recent first)
- Efficient pagination with configurable page sizes
Error Handling
- Added
AuthenticatedExtendedCardNotConfigurederror variant - Moved
DATABASE_ERRORcode from -32007 to -32100 to avoid conflict with spec
Changed - Breaking Changes
Agent Card
- BREAKING:
signaturefield renamed tosignaturesand changed toOption<Vec<AgentCardSignature>>- Migration: Wrap single signature in a Vec:
signature: Some(sig)→signatures: Some(vec![sig])
- Migration: Wrap single signature in a Vec:
- BREAKING: Added required
protocol_versionfield (has default: "0.3.0") - BREAKING: Added required
preferred_transportfield (has default: "JSONRPC") - New optional fields:
additional_interfaces,icon_url
Message and Artifact
- BREAKING: Added
extensionsfield (optional, defaults to None)- Migration: Add
extensions: Noneto all struct initializations
- Migration: Add
AgentCapabilities
- BREAKING: Added
extensionsfield (optional, defaults to None)- Migration: Add
extensions: Noneto all struct initializations
- Migration: Add
PushNotificationConfig
- BREAKING: Added
idfield (optional, used for multi-config support)- Migration: Add
id: Noneto existing configs
- Migration: Add
MessageSendConfiguration
- BREAKING:
accepted_output_modesis now optional (was required)- Migration: Wrap existing values in Some():
vec![...]→Some(vec![...])
- Migration: Wrap existing values in Some():
Error Codes
- BREAKING:
DATABASE_ERRORmoved from -32007 to -32100 - New error code: -32007 now used for
AUTHENTICATED_EXTENDED_CARD_NOT_CONFIGURED
Migration Guide
Updating Agent Card Initializations
// Before (v0.2.x)
let card = AgentCard {
signature: Some(my_signature),
// ... other fields
};
// After (v1.0.0)
let card = AgentCard {
protocol_version: "0.3.0".to_string(), // NEW - required
preferred_transport: "JSONRPC".to_string(), // NEW - required
additional_interfaces: None, // NEW - optional
icon_url: None, // NEW - optional
signatures: Some(vec![my_signature]), // CHANGED - now plural, wrapped in Vec
// ... other fields
};Updating Message and Artifact Initializations
// Before (v0.2.x)
let message = Message {
message_id: "msg-1".to_string(),
// ... other fields
};
// After (v1.0.0)
let message = Message {
message_id: "msg-1".to_string(),
extensions: None, // NEW - add this field
// ... other fields
};
// Same for Artifact
let artifact = Artifact {
artifact_id: "art-1".to_string(),
extensions: None, // NEW - add this field
// ... other fields
};Updating Capabilities
// Before (v0.2.x)
let caps = AgentCapabilities {
streaming: true,
push_notifications: false,
state_transition_history: true,
};
// After (v1.0.0)
let caps = AgentCapabilities {
streaming: true,
push_notifications: false,
state_transition_history: true,
extensions: None, // NEW - add this field
};Updating Push Notification Configs
// Before (v0.2.x)
let config = PushNotificationConfig {
url: "https://example.com/webhook".to_string(),
token: Some("token".to_string()),
authentication: None,
};
// After (v1.0.0)
let config = PushNotificationConfig {
id: None, // NEW - for multi-config support
url: "https://example.com/webhook".to_string(),
token: Some("token".to_string()),
authentication: None,
};Using New Task Listing API
use a2a_rs::domain::{ListTasksParams, TaskState};
// List tasks with filtering and pagination
let params = ListTasksParams {
context_id: Some("ctx-123".to_string()),
status: Some(TaskState::Working),
page_size: Some(25),
page_token: None, // Start at beginning
history_length: Some(10),
include_artifacts: Some(true),
last_updated_after: None,
metadata: None,
};
let result = task_manager.list_tasks_v3(¶ms).await?;
println!("Found {} tasks, showing {}", result.total_size, result.tasks.len());
// Get next page if available
if !result.next_page_token.is_empty() {
let next_params = ListTasksParams {
page_token: Some(result.next_page_token),
..params
};
let next_result = task_manager.list_tasks_v3(&next_params).await?;
}Managing Push Notification Configs
use a2a_rs::domain::{
GetTaskPushNotificationConfigParams,
ListTaskPushNotificationConfigParams,
DeleteTaskPushNotificationConfigParams,
};
// List all configs for a task
let list_params = ListTaskPushNotificationConfigParams {
id: "task-123".to_string(),
metadata: None,
};
let configs = task_manager.list_push_notification_configs(&list_params).await?;
// Get a specific config
let get_params = GetTaskPushNotificationConfigParams {
id: "task-123".to_string(),
push_notification_config_id: Some("config-1".to_string()),
metadata: None,
};
let config = task_manager.get_push_notification_config(&get_params).await?;
// Delete a config
let delete_params = DeleteTaskPushNotificationConfigParams {
id: "task-123".to_string(),
push_notification_config_id: "config-1".to_string(),
metadata: None,
};
task_manager.delete_push_notification_config(&delete_params).await?;Notes
- All new trait methods have default implementations that return
UnsupportedOperationerror - Existing code will continue to work after adding required fields to struct initializations
- The
InMemoryTaskStorageimplementation supports all new features - SQLx storage implementations need to be updated to support multi-config push notifications