a2a-web-client 0.5.0

Generic web client library for building A2A agent frontends
Documentation

a2a-client

A reusable Rust library for building web-based frontends for A2A (Agent-to-Agent) Protocol agents.

Overview

a2a-client provides reusable components, utilities, and client wrappers for creating web applications that interact with A2A protocol agents. It's designed to be integrated into your own web applications, not used as a standalone application.

Features

  • 🔌 Unified Client API - Single interface for HTTP transport
  • 📡 SSE Streaming - Server-Sent Events with automatic fallback to polling
  • 🎨 View Models - Ready-to-use view models for tasks and messages
  • 🧩 Modular Components - Use only what you need via feature flags
  • 🦀 Type-safe - Leverages Rust's type system for protocol correctness

Installation

Add to your Cargo.toml:

[dependencies]
a2a-client = { path = "../a2a-client" }

# For Axum integration with SSE streaming components
a2a-client = { path = "../a2a-client", features = ["axum-components"] }

Quick Start

Basic HTTP Client

use a2a_client::WebA2AClient;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create a client connected to your A2A agent
    let client = WebA2AClient::new_http("http://localhost:8080".to_string());

    // Send a message and get a task
    let message = a2a_rs::domain::Message::builder()
        .text("Hello, agent!")
        .build();

    let task = client.http.send_message(&message, None).await?;
    println!("Task ID: {}", task.id);

    Ok(())
}

SSE Streaming with Axum

use a2a_client::{WebA2AClient, components::create_sse_stream};
use axum::{Router, routing::get, extract::{State, Path}};
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = Arc::new(
        WebA2AClient::new_http(
            "http://localhost:8080".to_string()
        )
    );

    let app = Router::new()
        .route("/stream/:task_id", get(stream_handler))
        .with_state(client);

    // Start server...
    Ok(())
}

async fn stream_handler(
    State(client): State<Arc<WebA2AClient>>,
    Path(task_id): Path<String>,
) -> axum::response::sse::Sse<impl futures::Stream<Item = Result<axum::response::sse::Event, std::convert::Infallible>>> {
    create_sse_stream(client, task_id)
}

Architecture

flowchart TD
    subgraph WebApp[Web Application / Frontend]
        UI[UI / Frontend Component]
        AppState[AppState]
        TaskView[TaskView / MessageView]
    end

    subgraph Client[a2a-client Crate]
        WebClient[WebA2AClient]
        HTTPClient[HttpClient]
        SSE[create_sse_stream]
    end

    subgraph Server[A2A Agent Server]
        AgentCard[/agent-card Endpoint]
        Tasks[/tasks Endpoint]
    end

    UI --> AppState
    AppState --> WebClient
    WebClient --> HTTPClient

    HTTPClient -->|Discover Transport / Fetch Card| AgentCard
    HTTPClient -->|Send messages / Poll fallback| Tasks

    SSE -->|Fetch Updates| HTTPClient
    SSE -->|Emit Task Events| UI
    TaskView -->|Map Domain Model| AppState
a2a-client/
├── src/
│   ├── lib.rs              # Core client API
│   ├── components/         # Reusable UI components
│   │   ├── streaming.rs    # SSE streaming helpers
│   │   └── task_viewer.rs  # View models for tasks/messages
│   └── utils/              # Utilities
│       └── formatters.rs   # Display formatting
└── examples/               # Usage examples (coming soon)

Core Components

WebA2AClient

The main client struct that wraps both HTTP and WebSocket clients:

pub struct WebA2AClient {
    pub http: HttpClient,
}

Methods:

  • new_http(base_url) - HTTP-only client
  • auto_connect(base_url) - Auto-detect available transports

View Models

TaskView

Display model for task lists:

pub struct TaskView {
    pub task_id: String,
    pub state: String,
    pub message_count: usize,
    pub last_message_preview: Option<String>,
}

MessageView

Display model for individual messages:

pub struct MessageView {
    pub id: String,
    pub role: String,
    pub content: String,
}

Streaming Components

create_sse_stream

Creates a Server-Sent Events stream for task updates:

pub fn create_sse_stream(
    client: Arc<WebA2AClient>,
    task_id: String,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>>

Features:

  • Graceful fallback to HTTP polling
  • Emits task-update, task-status, and artifact events
  • Keep-alive heartbeat

Formatters

// Format task state for display
pub fn format_task_state(state: &TaskState) -> String;

// Extract text from message parts
pub fn format_message_content(parts: &[Part]) -> String;

// Truncate text for previews
pub fn truncate_preview(text: &str, max_len: usize) -> String;

Features

axum-components (default)

Enables Axum-specific components like SSE streaming support.

[dependencies]
a2a-client = { path = "../a2a-client", default-features = false }  # Minimal
a2a-client = { path = "../a2a-client" }  # With Axum components

Integration with A2A Agents

This library works seamlessly with agents built using:

  • a2a-rs - Core protocol implementation
  • a2a-agents - Declarative agent framework
  • a2a-agent-reimbursement - Example agent implementation

Development

Building

cargo build --all-features

Testing

# Unit tests
cargo test

# Integration tests (requires running agent)
cargo test --features integration-tests

Examples

See the examples/ directory for complete working examples:

  • basic_client.rs - Simple HTTP client usage (coming soon)
  • sse_streaming.rs - SSE streaming with Axum (coming soon)

Roadmap

See the workspace TODO.md for open and deferred work.

Contributing

This library is part of the a2a-rs workspace. Contributions are welcome!

License

MIT

See Also