Skip to main content

nodus-a2a-wire

A2A 1.0.0 (Linux Foundation) wire-protocol adapter for the Nodus scripting language.

nodus-a2a-wire exposes std:tool-registered tools from a Nodus runtime as an A2A message-only agent over HTTP+JSON/REST — agent cards, transport, and handler dispatch.

pip install nodus-a2a-wire

Not to be confused with nodus-a2a

Two different packages, and the names are close:

What it is
nodus-a2a-wire (this one) the wire protocol — A2AHttpServer, agent cards, HTTP+JSON transport
nodus-a2a coordination primitives — AgentRegistry, AgentCoordinator, DeadLetterService, StuckRunWatchdog

They share no code and neither depends on the other. Both can be installed together: this package's Python module is nodus_a2a_wire, the other's is nodus_a2a.

Until 0.1.0 was published this project declared the distribution name nodus-a2a and the module name nodus_a2a, which is why it could not be published at all — and why installing it alongside the coordinator would have silently replaced that package's API. See nodus-lang#477.

Requirements

No runtime dependencies, including nodus-lang. A host constructs A2AHttpServer in Python and wires it to their own NodusRuntime.tool_registry, so the runtime arrives by injection rather than by import.

pip install nodus-a2a-wire[flask]   # optional alternative transport backend

Production authentication warning

Without a token_validator, the server runs in dev mode and accepts all requests. Production deployments must configure a validator:

config = ServerConfig(
    ...
    token_validator=lambda token: token == os.environ["MY_SECRET_TOKEN"],
)

Do not expose a nodus-a2a-wire server to the internet without configuring token_validator.


v0.1 scope

This is a message-only implementation (D5 decision). The server never creates A2A Tasks. All task-management operations return HTTP 501. Deferred to v0.2+:

  • Task lifecycle and state machine
  • SSE streaming (SendStreamingMessage)
  • Push notification webhooks
  • JSON-RPC and gRPC bindings
  • OAuth 2.0 / OIDC / mTLS auth

See docs/design/05-deferred-features.md for the full inventory.



Quick start

from nodus.runtime.embedding import NodusRuntime
from nodus_a2a_wire import A2AHttpServer, ServerConfig

# 1. Create a NodusRuntime and register tools via tool_registry
runtime = NodusRuntime()
runtime.tool_registry.register({
    "name": "myapp.greet",           # must use dotted namespace: "prefix.name"
    "description": "Greet someone by name",
    "handler": lambda args: f"Hello, {args.get('name', 'world')}!",
})

# 2. Configure the server
config = ServerConfig(
    base_url="https://myagent.example.com",
    agent_name="My Greeter Agent",
    agent_description="Greets people by name via A2A",
)

# 3. Build the tool list and start the server
tools = runtime.tool_registry.list_tools()
tool_names = [t["name"] for t in tools if not t.get("deprecated")]

server = A2AHttpServer(
    config=config,
    invoke=runtime.tool_registry.invoke,
    tool_names=tool_names,
    tools=tools,
)
server.serve()  # blocks; use serve_in_thread() for background use

Calling the agent

Send a tool-call envelope in a DataPart:

POST /message:send HTTP/1.1
Content-Type: application/a2a+json
A2A-Version: 1.0

{
  "message": {
    "messageId": "msg-001",
    "role": "ROLE_USER",
    "parts": [{"data": {"tool": "myapp.greet", "args": {"name": "Alice"}}}]
  }
}

Response:

{
  "message": {
    "messageId": "...",
    "role": "ROLE_AGENT",
    "contextId": "...",
    "parts": [{"text": "Hello, Alice!", "mediaType": "text/plain"}]
  }
}

Single-tool shortcut

If the agent has exactly one tool registered, any Message (even a plain TextPart) dispatches to that tool with empty args:

{"message": {"messageId": "m1", "role": "ROLE_USER", "parts": [{"text": "hello"}]}}

Agent Card discovery

The Agent Card is served at /.well-known/agent-card.json (A2A 1.0 URI). No authentication required.


Authentication

config = ServerConfig(
    ...
    token_validator=lambda token: token == "my-secret-token",
)

Without a token_validator, the server runs in dev mode and accepts all requests. Production deployments must configure a validator.


Part type dispatch

Tool return values are mapped to A2A Part variants automatically:

Python type A2A Part mediaType
str TextPart text/plain
bytes RawPart (base64) application/octet-stream
dict / list / int / float / bool / None DataPart application/json

The url Part variant is not used in automatic dispatch (reserved for v0.2+).


Error handling

Tool exceptions are returned as an error DataPart in an HTTP 200 response:

{
  "message": {
    "role": "ROLE_AGENT",
    "parts": [{"data": {"error": "tool exploded", "type": "RuntimeError"},
               "mediaType": "application/json"}]
  }
}

Protocol errors (malformed JSON, invalid A2A-Version, missing auth) return HTTP 4xx with a structured error body.


Design notes

v0.1 is message-only (D5)

The server never creates or persists A2A Tasks. All task-management operations (GetTask, ListTasks, CancelTask, streaming, push notifications) return HTTP 501 UnsupportedOperationError. The Agent Card declares:

"capabilities": {"streaming": false, "pushNotifications": false, "extendedAgentCard": false}

v0.2 Task lifecycle: D6 inversion warning

A2A INPUT_REQUIRED / AUTH_REQUIRED are park-and-resume states — the opposite of nodus-mcp's no-thread-parks rule. When implementing Task lifecycle in v0.2, do not import the nodus-mcp no-park assertion. See docs/design/05-deferred-features.md §2 for the full inversion note.


CLI

python -m nodus_a2a_wire --version
python -m nodus_a2a_wire serve --name "My Agent" --description "..." --port 8080

The serve command starts a server with no tools — useful for smoke-testing network connectivity and verifying the Agent Card format.


Wire format

  • Spec: A2A 1.0.0 / lf.a2a.v1 (proto package)
  • Transport: HTTP+JSON/REST only (protocolBinding: "HTTP+JSON")
  • Content-Type: application/a2a+json
  • Discovery: /.well-known/agent-card.json
  • Version negotiation: A2A-Version request header; mismatch → HTTP 400
  • Codec: proto snake_case ↔ wire camelCase (ProtoJSON)
  • Signing: unsigned (v0.1); JWS signing planned for v0.2

Deferred features (v0.2+)

Task lifecycle and state machine, streaming (SendStreamingMessage), push notification webhooks, Agent Card signing (JWS/RFC 7515), extended authenticated card, JSON-RPC binding, gRPC binding, OAuth2/OIDC/mTLS, tenant routing, 0.3 wire-dialect compatibility.

See docs/design/05-deferred-features.md for the full inventory.

Metadata

Release files for nodus-a2a-wire 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nodus-a2a-wire 0.1.0
File Size Uploaded
nodus_a2a_wire-0.1.0.tar.gz 56.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nodus-a2a-wire 0.1.0
File Interpreter ABI Platform
nodus_a2a_wire-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 75.9 kB

Release files / nodus_a2a_wire-0.1.0.tar.gz

Download URL nodus_a2a_wire-0.1.0.tar.gz
Size 56.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7376ff033b42f66ad9189f1b7105c3c834f955e2e9db0f1dc9002744ea8f5701
BLAKE2b-256 checksum
How to use checksums
1672a07104b9eb0acb0232c4bd8ae8f9d700f71d00dc48624ead0a3f36e2db0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / nodus_a2a_wire-0.1.0-py3-none-any.whl

Download URL nodus_a2a_wire-0.1.0-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b7d711d745b66c890ef539065264b1bba8e315d2c8ca2e0902ed9f33ccee1960
BLAKE2b-256 checksum
How to use checksums
ccc251387281cce10fb6ed3092924be3718c7e6a8a281fc32640bd2821f9be87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page