Gateway › SDK

SDK

Python

from agent_hub_webhook import Client

c = Client("https://<tunnel>", "bota", "<api_key>")
c.send({"user_id": "u1", "user_name": "an", "group_id": "g1",
        "text": "/agent dev status"})
c.on_reply(lambda u: print(u["chat"], u.get("text")))
Client(base, intg, key)Base URL (tunnel or local), integration id, API key.
sendAuto-fills event="message" and message_id (UUID4) when missing.
on_replyA blocking pull loop; acks by offset; backs off on 408 / 429 / 5xx. Pass offset= to resume after a restart.
c = Client("https://<tunnel>", "botb", "<api_key>")

def handle(body):
    if body["type"] == "message":
        return my_platform_post(body["chat"], body["text"])   # → message_id
    return None

c.serve_callback(handle, host="0.0.0.0", port=8790, path="/")

Node 18+

import { Client } from "./agent-hub-webhook.mjs";

const c = new Client({ baseUrl: "https://<tunnel>", integration: "bota", key: "<api_key>" });
await c.send({ user_id: "u1", user_name: "an", group_id: "g1", text: "/agent dev status" });

const h = c.onReply(async (u) => console.log(u.chat, u.text));
process.on("SIGINT", () => h.stop());
await h.done;
export function sign(key, timestamp, body) {
  const message = Buffer.concat([Buffer.from(timestamp + "."), Buffer.from(body)]);
  return "sha256=" + createHmac("sha256", key).update(message).digest("hex");
}
onReply → { stop, done }Returns right away; the handler can be async, the next update waits for it to finish.
doneRejects with a WebhookError on a non-retryable status (400, 401, 403, 404, 409). Always await it.
serveCallback → readyRejects if the port can’t be bound.

Semantics

  • Pull is at-least-once: the offset only advances once the handler finishes — the handler must tolerate duplicates.
  • A bad signature → 401, the handler is never called. A handler error → 500.
  • c.stop() stops both the pull loop and the receiver; a stopped Client can’t be reused.

Web chat (@agent-hub/chat)

@agent-hub/chat is an embeddable chat UI for React 19, not tied to any one transport — you supply a ChatAdapter to wire it to a real backend.

import { ChatProvider, ChatWindow } from "@agent-hub/chat";
import "@agent-hub/chat/styles.css";
ChatProvider / ChatWindowRenders messages, threads, buttons, replies, typing and toast state.
ChatAdapterSupplied by you — the package doesn’t know how to send/receive messages, only how to render.