Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
4713797
a2a-stdio: scaffold crate with error types and STDIO transport constant
Ketankhunti Apr 13, 2026
0bf6caa
a2a-stdio: implement LSP-style Content-Length framing module
Ketankhunti Apr 15, 2026
5fef643
a2a-stdio: implement handshake types and negotiation logic
Ketankhunti Apr 15, 2026
242c0d4
a2a-stdio: implement StdioTransport client with true async streaming
Ketankhunti Apr 15, 2026
d6197ef
feat(a2a-stdio): implement StdioServer with macro-based dispatch
Ketankhunti Apr 15, 2026
1c3bd1a
test(a2a-stdio): add end-to-end integration tests
Ketankhunti Apr 15, 2026
1a28864
style(a2a-stdio): fix clippy warnings
Ketankhunti Apr 15, 2026
d2df2dd
chore: update Cargo.lock for a2a-stdio crate
Ketankhunti Apr 15, 2026
2ab6d45
fix(a2a-stdio): handle malformed JSON and stream results gracefully
Ketankhunti Apr 15, 2026
c74e09e
style(a2a-stdio): apply rustfmt formatting
Ketankhunti Apr 15, 2026
20e7cf1
fix(a2a-stdio): address quick review items
Ketankhunti Apr 18, 2026
af03f94
fix(a2a-stdio): serialize requests and bound handshake/close waits
Ketankhunti Apr 18, 2026
217cf5b
test(a2a-stdio): cover all Transport methods, factory, and error paths
Ketankhunti Apr 18, 2026
52d8754
test(a2a-stdio): cover handshake error branches and server dispatch e…
Ketankhunti Apr 18, 2026
0bd45f3
style(a2a-client): drop useless .into_iter() in rest error parsing
Ketankhunti Apr 18, 2026
877e7fc
style(a2a-stdio): apply rustfmt to client and tests
Ketankhunti Apr 18, 2026
b3ca336
test(a2a-stdio): cover server::serve and streaming reader error paths
Ketankhunti Apr 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 89 additions & 70 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"a2a-pb",
"a2a-grpc",
"a2a-slimrpc",
"a2a-stdio",
"a2acli",
"examples/helloworld",
]
Expand All @@ -25,6 +26,7 @@ a2a-server = { package = "a2a-server-lf", path = "a2a-server", version = "0.2.6"
a2a-pb = { package = "a2a-pb", path = "a2a-pb", version = "0.1.6" }
a2a-grpc = { package = "a2a-grpc", path = "a2a-grpc", version = "0.1.11" }
a2a-slimrpc = { package = "a2a-slimrpc", path = "a2a-slimrpc", version = "0.1.8" }
a2a-stdio = { package = "agntcy-a2a-stdio", path = "a2a-stdio", version = "0.1.0" }

# Serialization
serde = { version = "1", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion a2a-client/src/rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn parse_rest_error(status: reqwest::StatusCode, body: &str) -> A2AError {
}

if let Value::Object(values) = raw_detail {
details.extend(values.into_iter());
details.extend(values);
}
}

Expand Down
32 changes: 32 additions & 0 deletions a2a-stdio/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "agntcy-a2a-stdio"
version = "0.1.0"
description = "A2A v1 STDIO transport binding for client and server"
readme = "README.md"
Comment thread
Ketankhunti marked this conversation as resolved.
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[lib]
name = "a2a_stdio"

# Test-only helper subprocess used by integration tests in tests/spawned.rs.
# Not part of the public surface; kept under tests/bin/ to make that explicit.
[[bin]]
name = "stdio_test_helper"
path = "tests/bin/stdio_test_helper.rs"

[dependencies]
a2a = { workspace = true }
a2a-client = { workspace = true }
a2a-server = { workspace = true }
tokio = { workspace = true }
tokio-stream = { workspace = true }
futures = { workspace = true }
async-trait = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }
66 changes: 66 additions & 0 deletions a2a-stdio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# a2a-stdio

STDIO transport binding for A2A v1 client and server implementations.

This crate is published as `agntcy-a2a-stdio` and imported in Rust as `a2a_stdio`.

## What It Provides

- `StdioTransport` — `Transport` implementation that spawns an agent
subprocess and speaks A2A JSON-RPC over its stdin/stdout
- `StdioTransportFactory` — `TransportFactory` integration for agent cards
that advertise the `STDIO` protocol
- `StdioServer` — server-side dispatcher that wraps an
`a2a_server::RequestHandler` and serves requests over a pair of
asynchronous reader/writer streams

## Wire Format

Messages on the wire use LSP-style framing followed by a JSON-RPC 2.0 body:

```text
Content-Length: <N>\r\n
Content-Type: application/json\r\n
\r\n
<N bytes of JSON>
```

Method names use the slash-separated A2A convention
(`message/send`, `tasks/get`, `tasks/subscribe`, ...).

## Handshake

Before serving requests, the server emits a `handshake` message advertising
its supported variants and features. The client replies with a
`handshakeAck` that either accepts (selecting a variant) or rejects the
session.

A session identifier may be passed via the `A2A_SESSION_ID` environment
variable; otherwise the server generates a UUIDv7.

## Agent Card Target Format

`StdioTransportFactory` interprets `supportedInterfaces[].url` as one of:

- `stdio:///path/to/binary` — spawn the binary with no arguments
- `stdio:///path/to/binary?arg1&arg2` — spawn with the given arguments
- `/path/to/binary arg1 arg2` — plain command line, split on whitespace

Arguments in the `stdio://` form are split on `&` and the path is split on
the first `?`, so individual arguments cannot contain `&` or `?`. Use the
plain command-line form when those characters are required.

## Install

```toml
[dependencies]
a2a = { package = "a2a-lf", version = "0.2" }
a2a-stdio = { package = "agntcy-a2a-stdio", version = "0.1" }
```

## Workspace

This crate is part of the `a2a-rs` workspace.

- Repository: https://github.com/a2aproject/a2a-rs
- Workspace README: https://github.com/a2aproject/a2a-rs/blob/main/README.md
Loading
Loading