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. |
send | Auto-fills event="message" and message_id (UUID4) when missing. |
on_reply | A 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. |
done | Rejects with a WebhookError on a non-retryable status (400, 401, 403, 404, 409). Always await it. |
serveCallback → ready | Rejects 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 / ChatWindow | Renders messages, threads, buttons, replies, typing and toast state. |
ChatAdapter | Supplied by you — the package doesn’t know how to send/receive messages, only how to render. |