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.
-
Install the plugin next to hivemind-core:
uv pip install hivemind-a2a-agent-plugin
-
Select it in
~/.config/hivemind-core/server.json.agent_protocol.modulenames 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 } } }
-
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
-
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.
Related projects
- JarbasHiveMind/HiveMind-core: the HiveMind master this plugin connects to.
- OpenVoiceOS/ovos-a2a-agent-plugin: the same A2A client as an ovos-persona solver.
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hivemind_a2a_agent_plugin-0.1.4a3.tar.gz | 21.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.