Skip to content
/ nodes Public

Example remote nodes for Hurozo Agentic platform

Notifications You must be signed in to change notification settings

hurozo/nodes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

Hurozo Remote Nodes

What is a “remote node”?

A remote node lets a graph running in your backend call into out‑of‑process code (e.g., a Python script running on another machine). At runtime, the backend node:

  • Opens a temporary WebSocket channel and waits for a response.
  • Publishes a remote_node event (with your node name, inputs, and a uuid) to the user’s WebSocket stream.
  • Your remote worker, already connected to the WebSocket, receives that event, performs work, and sends back outputs
  • The backend node returns those outputs to the graph.

The "Hello World" worker in this repo demonstrates the remote half of the handshake: it registers + keeps a WebSocket connection, listens for events matching its NODE_NAME, computes outputs, and sends them back.

Running a remote node with the Hurozo Python package

Building and running remote node with the Hurozo python package is straightforward:

pip install hurozo
export HUROZO_API_TOKEN=... your API key...

Example node:

from hurozo import Node

def my_amazing_node(name):
    outputs = {
        'greeting': f'Gwuaaak {name}',
        'shout': f'GWUAAAAK {name.upper()}'
    }
    return outputs

def main():
    Node(my_amazing_node, {
        'inputs': ['name'],
        'outputs': ['greeting', 'shout']
    })

if __name__ == '__main__':
    main()

When you run this script your node will register in Hurozo and you can use it as a component to build your agents.

High-level end‑to‑end architecture

Registration (HTTP)
  • Remote workers periodically call POST /api/remote_nodes/register with {name, inputs[], outputs[]}. The backend stores (or refreshes) the registration and responds with {websocket_url, token} that the worker uses to connect. Registrations expire if not refreshed.
Execution (WebSocket)
  • When a graph executes a RemoteNode, the backend:
    • Generates a short‑lived WS token and opens a waiting connection for a unique uuid. It also sends a remote_node event to the user stream with {node, inputs, uuid}. It then waits up to 600 seconds for a reply.
    • Your remote worker (connected using the token it received during registration) receives the event and must reply on the socket with {node, outputs: {…}, uuid}.
Security
  • All API calls require Authorization: Bearer <token> (either a Firebase ID token or an API token you issued).
  • WebSocket tokens are HMAC‑signed and expire after 60 seconds.

Backend API & Message contracts

Register a remote node

Request:

POST /api/remote_nodes/register
Authorization: Bearer <HUROZO_TOKEN>
Content-Type: application/json

{
  "name": "ws_hello",
  "inputs": ["name"],
  "outputs": ["greeting", "shout"]
}
Semantics & constraints
  • name is required and may not contain “/”.
  • outputs must contain at least one output.
  • The registration expires 10 minutes after creation; refresh before it expires
Response
{
  "status": "registered",
  "websocket_url": "wss://…/Prod",
  "token": "<base64-ws-token>",
  "inputs": ["name"],
  "outputs": ["greeting", "shout"]
}
  • The backend returns a WS URL and a short‑lived WS token bound to the user (the one behind HUROZO_TOKEN).
List active remote nodes
GET /api/remote_nodes
Authorization: Bearer <HUROZO_TOKEN>

Returns your non‑expired registrations:

{
  "nodes": [
    {"name": "ws_hello", "inputs": ["name"], "outputs": ["greeting","shout"]}
  ]
}

The remote worker

A remote worker must do two things:

  • Register in a loop
  • The example uses a background thread to call POST /api/remote_nodes/register every 60s:
url = f"https://app.hurozo.com/api/remote_nodes/register"
headers = {"Authorization": f"Bearer {API_TOKEN}"}
payload = {"name": NODE_NAME, "inputs": NODE_INPUTS, "outputs": NODE_OUTPUTS}
res = requests.post(url, json=payload, headers=headers, timeout=60)
  • Hold a WebSocket and serve requests and use the websocket_url and token returned from registration:
async with websockets.connect(f"{url}?auth={token}") as ws:
    while True:
        msg = await ws.recv()
        payload = json.loads(msg)
        if payload.get("node") != NODE_NAME:
            continue  # ignore messages for other nodes
        inputs = payload.get("inputs", {})
        # ... compute outputs dict ...
        await ws.send(json.dumps({
            "node": NODE_NAME,
            "outputs": outputs,      # keys must match your outputs[] list
            "uuid": payload.get("uuid")  # echo uuid so backend correlates
        }))

Environment variables

Common errors

  • Missing or invalid name — you sent an empty name or it contained “/”. Fix your name.
  • At least one output required — your outputs array was empty. Remote nodes must have an output defined. Define an output.
  • Invalid API token / Missing Authorization header — your Bearer token is wrong or missing. Check your API Token. Ensure it's a write token.

Operational tips & best practices

  • Refresh aggressively. Re‑register at least every 60s (the example’s approach) to keep your node visible and ensure you always have a fresh WS token on hand.
  • Echo the uuid. The backend depends on it to correlate request→response.
  • Name uniqueness. Registrations are stored per user. Ppick unique names if you run multiple workers under the same account.
  • Map outputs carefully. The backend returns a tuple in the same order as your outputs list; if your worker mis‑names keys, the backend will return None or an empty string.
  • Deal with timeouts. Long jobs must respond within 600 seconds or the backend node returns empty values. Consider chunking or background job IDs if you need longer.
  • Permissions: Using a read‑only API token will block write endpoints; registration requires POST, so ensure your token has the right permission.

About

Example remote nodes for Hurozo Agentic platform

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published