Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

hivemind-a2a-agent-plugin

An agent-protocol plugin for hivemind-core. It answers the questions a hive sends to its master with an external agent that speaks the Agent2Agent (A2A) protocol.

What you can do

A2A is an open protocol that lets one agent call another, whatever framework each one uses inside. An A2A agent publishes an agent card at /.well-known/agent-card.json. The card names the agent, its skills, and the URL that accepts messages.

With this plugin as its agent protocol, hivemind-core answers each QUERY from a satellite or a child node. It sends the question to one A2A agent and returns the answer as speak chunks. The plugin uses the a2a-sdk client. It reads the card, picks the transport the card offers, and speaks A2A 1.0 or 0.3, whichever the agent supports.

The plugin answers QUERY and CASCADE messages, through the natural_language_query seam of the HiveMind agent protocol. A plain BUS recognizer_loop:utterance gets no answer. That is the message that hivemind-client terminal and a voice satellite send. See Troubleshooting.

User stories

My hive answers questions with an A2A agent

You run hivemind-core and have an A2A agent: a LangGraph or CrewAI service, a hosted assistant, or an OVOS box running ovos-persona-server with --a2a-base-url. You want the hive to answer with that agent.

  1. Install the plugin next to hivemind-core:

    uv pip install hivemind-a2a-agent-plugin
    
  2. Select it in ~/.config/hivemind-core/server.json. agent_protocol.module names the plugin, and the key with the plugin name holds its settings:

    {
      "agent_protocol": {
        "module": "hivemind-a2a-agent-plugin",
        "hivemind-a2a-agent-plugin": {
          "agent_url": "http://127.0.0.1:8337/a2a",
          "timeout": 30
        }
      }
    }
    
  3. Add a client, allow the message type it will ask with, and start the hub:

    hivemind-core add-client --name kitchen-sat --access-key kitchen-key \
        --password 'Correct-Horse-Battery-77' --allow recognizer_loop:utterance
    hivemind-core listen
    

On start, the log names the plugin:

hivemind_core.service:run:441 - INFO - Agent protocol: A2AAgentProtocol
hivemind_a2a_agent_plugin:__post_init__:99 - INFO - A2AAgentProtocol: configured for A2A agent at http://127.0.0.1:8337/a2a
  1. Ask a question with a QUERY. This client script uses hivemind-bus-client:

    import threading
    import uuid
    
    from hivemind_bus_client.client import HiveMessageBusClient
    from hivemind_bus_client.identity import NodeIdentity
    from hivemind_bus_client.message import HiveMessage, HiveMessageType
    from ovos_bus_client.message import Message
    
    client = HiveMessageBusClient(key="kitchen-key", password="Correct-Horse-Battery-77",
                                  host="ws://127.0.0.1", port=5678,
                                  identity=NodeIdentity(app_name="a2a-query-example",
                                                        shared_fallback=False))
    done = threading.Event()
    
    
    def on_query(message: HiveMessage):
        payload = message.payload
        while isinstance(payload, HiveMessage):
            payload = payload.payload
        if payload.msg_type == "speak":
            print(payload.data["utterance"])
        elif payload.msg_type in ("hive.query.complete", "hive.query.timeout"):
            done.set()
    
    
    client.on(HiveMessageType.QUERY, on_query)
    client.connect()
    client.wait_for_handshake()
    question = Message("recognizer_loop:utterance",
                       {"utterances": ["what is the capital of portugal"], "lang": "en-US"})
    client.emit(HiveMessage(HiveMessageType.QUERY,
                            payload=HiveMessage(HiveMessageType.BUS, payload=question),
                            metadata={"query_id": str(uuid.uuid4())}))
    done.wait(30)
    client.close()
    

On success, the agent's answer is printed. With a test agent that echoes its input and its A2A contextId, the hive answered:

echo[8a086dca-691d-499b-8def-a67bc59f3ddd]: what is the capital of portugal

NodeIdentity(app_name="a2a-query-example", shared_fallback=False) gives the script its own identity under ~/.config/hivemind/a2a-query-example/. Without it, the client uses the shared ~/.config/hivemind/_identity.json. That fails when the shared identity already pinned another hub at the same address, and it changes key files that other HiveMind clients of the same user read.

The agent asks a question back

An agent can stop a task in TASK_STATE_INPUT_REQUIRED or TASK_STATE_AUTH_REQUIRED and ask for more. The satellite hears the question. With a test agent that asks for a city, the hive answered:

which city?

The next QUERY starts a new A2A conversation, because hivemind-core passes no session id. The agent receives the answer without the question that came before it.

The remote agent is down, slow or fails

The plugin never leaves a query without an answer. When the agent cannot answer, the satellite receives an error sentence, and then the end of the query.

Situation What the satellite receives
Agent unreachable Error validating A2A agent at http://127.0.0.1:1: could not fetch or parse its agent card (Network communication error fetching agent card from http://127.0.0.1:1/.well-known/agent-card.json: All connection attempts failed)
Agent task failed Error contacting A2A agent: A2A task ended in TASK_STATE_FAILED: backend exploded
Agent slower than timeout Error contacting A2A agent: Client Request timed out
agent_url not set A2A agent not configured — no agent_url set.

A slow agent within timeout still answers. An agent that took 12 seconds, with timeout: 30, was answered after 13.8 seconds.

Reference

Settings

Key Default Description
agent_url none Required. Base URL of the agent: the part before /.well-known/agent-card.json.
auth_header none Full Authorization header value, for example Bearer <token>.
timeout 60 Seconds to wait for each HTTP request.
streaming false Use SendStreamingMessage, so each chunk the agent sends becomes one speak.

The plugin also reads the same keys from the OVOS configuration at hivemind.a2a_agent. Keys in server.json win.

What is sent and received

HiveMind A2A
The QUERY utterance SendMessage with one text part, role ROLE_USER
The query language {"lang": ...} in the message metadata
Agent message, task artifacts, artifact updates the speak text
Task status message, when the task has no artifact text the speak text
Task state FAILED, REJECTED or CANCELED an error sentence

hivemind-core calls natural_language_query(utterance, lang) without a session id. The plugin then sends no contextId, the agent assigns a new one, and every query starts a new A2A conversation. A2A 1.0.1 section 3.4.1 says a client SHOULD NOT send a contextId it generated itself. A caller that passes session_id directly keeps the agent-assigned contextId of that session for its later queries.

Deployment

The plugin runs inside hivemind-core and opens outbound HTTP connections only. A2A has no built-in encryption. Use an https:// agent_url when the agent is on another machine, and auth_header when the agent asks for a token.

Troubleshooting

Symptom Cause and fix
A voice satellite or hivemind-client terminal gets no answer They send BUS messages. The hub logs Forwarding message 'recognizer_loop:utterance' to agent bus, and this plugin does not answer the bus. Send a QUERY, as in the user story.
Error validating A2A agent ... (HTTP 404) agent_url points at the wrong path, or the agent publishes only /.well-known/agent.json, the A2A 0.2 path. The plugin speaks A2A 0.3 and 1.0 only.
ImportError: cannot import name 'BitStream' from 'bitstring' hivemind-bus-client 1.2.11a1 and older import BitStream, which bitstring 5 removed. With those versions, install bitstring<5.
AttributeError: module 'httpx' has no attribute 'AsyncClient' A prerelease of httpx 1.0 is installed. Install httpx<1.

Development

git clone https://github.com/JarbasHiveMind/hivemind-a2a-agent-plugin
cd hivemind-a2a-agent-plugin
uv venv && uv pip install --prerelease=allow -e ".[test]"
.venv/bin/pytest tests/

The tests start a real a2a-sdk agent (tests/a2a_agent.py) in a subprocess. Run it alone to try the plugin by hand: python tests/a2a_agent.py 9999.

Credits

Funded by NGI0 Commons Fund / NLnet under grant agreement No 101135429, through the European Commission's Next Generation Internet programme.

Metadata

Release files for hivemind-a2a-agent-plugin 0.1.4a3

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

Source distribution (sdist)

Source distribution for hivemind-a2a-agent-plugin 0.1.4a3
File Size Uploaded Provenance
hivemind_a2a_agent_plugin-0.1.4a3.tar.gz 21.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for hivemind-a2a-agent-plugin 0.1.4a3
File Interpreter ABI Platform
hivemind_a2a_agent_plugin-0.1.4a3-py3-none-any.whl Python 3 none any Details

Total release size: 35.7 kB

Release files / hivemind_a2a_agent_plugin-0.1.4a3.tar.gz

Download URL hivemind_a2a_agent_plugin-0.1.4a3.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
20e4b1cd058bd3f51c80bcf58ac2eac991884c66d62ccdade5b2123da88ea1fa
BLAKE2b-256 checksum
How to use checksums
4029adc28b381ff949f0dd9001a45c9725fe552115e36112077d3253eb02d820
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / hivemind_a2a_agent_plugin-0.1.4a3-py3-none-any.whl

Download URL hivemind_a2a_agent_plugin-0.1.4a3-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
94f85cd1bc82805162092f1ea3532b127c9a5f847cbeef5bfc518b10a6e0b6ed
BLAKE2b-256 checksum
How to use checksums
fbdeb5c8cfab5b2a8506c1714e961d07f2ddc2ada180bf57009e38e68efe035a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for hivemind-a2a-agent-plugin 0.1.4a3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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