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 protocolA2AHttpServer, agent cards, HTTP+JSON transport
nodus-a2a coordination primitivesAgentRegistry, 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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nodus_a2a_wire-0.1.0.tar.gz (56.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nodus_a2a_wire-0.1.0-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

Details for the file nodus_a2a_wire-0.1.0.tar.gz.

File metadata

  • Download URL: nodus_a2a_wire-0.1.0.tar.gz
  • Upload date:
  • Size: 56.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.9

File hashes

Hashes for nodus_a2a_wire-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7376ff033b42f66ad9189f1b7105c3c834f955e2e9db0f1dc9002744ea8f5701
MD5 e53d0434ddf05b6c37ab9ba63534a974
BLAKE2b-256 1672a07104b9eb0acb0232c4bd8ae8f9d700f71d00dc48624ead0a3f36e2db0d

See more details on using hashes here.

File details

Details for the file nodus_a2a_wire-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nodus_a2a_wire-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.9

File hashes

Hashes for nodus_a2a_wire-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b7d711d745b66c890ef539065264b1bba8e315d2c8ca2e0902ed9f33ccee1960
MD5 d1dc25b47836364167ca93d918499306
BLAKE2b-256 ccc251387281cce10fb6ed3092924be3718c7e6a8a281fc32640bd2821f9be87

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 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