@biroai/agent-events-openclaw
v2026.513.0
Published
**P1.4** from `ROADMAP-NEXT.md` — third runtime adapter for the universal Biro event bus.
Downloads
214
Readme
@biroai/agent-events-openclaw
P1.4 from ROADMAP-NEXT.md — third runtime adapter for the universal Biro event bus.
Translates OpenClaw Gateway hook payloads into normalized
BiroAgentEvent objects from @biroai/agent-events.
Relationship to the Gateway adapter
@biroai/adapter-openclaw-gateway invokes the Gateway over WebSocket and
handles connection auth, session routing, and result extraction.
This package is a pure translator — no HTTP server, no WebSocket client.
It sits in the delivery path after a webhook receiver parses req.body:
OpenClaw Gateway → HTTP POST → your server receiver
│
parseOpenClawHookPayload()
│
translateOpenClawEvent()
│
BiroAgentEvent[] → event busHook payload assumptions
The canonical discriminator field is event, matching the
GatewayEventFrame wire format observed in
packages/adapters/openclaw-gateway/src/server/execute.ts:
type GatewayEventFrame = { type: "event"; event: string; payload?: unknown }As a webhook subscriber, the outer envelope is typically unwrapped before
delivery, leaving just the inner object. parseOpenClawHookPayload also
tolerates type and eventType as fallback discriminators and normalises
them to event before translation.
Session identity is resolved from sessionId → runId → generated UUID.
Event mapping
| OpenClaw hook event | BiroAgentEvent type | Notes |
|---------------------------|-----------------------------|-------|
| session.started | agent.session.started | permissionMode always "unknown"; cwd always null |
| session.ended | agent.session.ended | status mapped via END_REASON_MAP |
| heartbeat.tick | (dropped — returns []) | Ticks fire on schedule, not on agent turns; emitting session.started per tick would produce misleading duplicates |
| tool.call.requested | agent.tool.requested | |
| tool.call.completed | agent.tool.completed | |
| subagent.spawned | agent.subagent.spawned | |
| subagent.completed | agent.subagent.completed | |
| channel.message.received| (dropped — returns []) | Channels are P5; not part of the event bus yet |
| (unknown) | (dropped — returns []) | Forward-compatible with new hook types |
Compaction events do not exist at the Gateway hook surface. Compaction is
internal to the underlying model session and is not surfaced as a hook.
No agent.compacted events are emitted by this translator.
Usage
import { parseOpenClawHookPayload, translateOpenClawEvent, translateOpenClawBatch } from "@biroai/agent-events-openclaw";
// Single payload (e.g. from Express req.body)
const raw = parseOpenClawHookPayload(req.body);
if (raw) {
const events = translateOpenClawEvent(raw, {
companyId: "co-123",
agentId: "agent-456",
issueId: "issue-789",
generateEventId: () => crypto.randomUUID(),
});
// events is BiroAgentEvent[]
}
// Batch (buffered payloads)
const events = translateOpenClawBatch(payloads, ctx);Out of scope for P1.4
channel.message.received— channels live in P5.- HTTP delivery / webhook receiving — write your own Express/Fastify route that calls into this translator.
- Compaction events — not surfaced at the Gateway hook layer.
- File-based state (
SOUL.md,MEMORY.md,cookies.md) — OpenClaw's internal source of truth; not part of the hook event surface.
Wire-format TODOs
The following are inferred from the existing adapter rather than official public docs. Verify against live Gateway traces before relying on them in production:
- Exact field names for token counts on
session.ended(totalTokensvstokenCountvs nestedusage.total). - Whether
heartbeat.tickcarries amodelfield. - Whether
subagent.spawnedusesinheritsBudgetor a numericbudgetfield. - The exact set of
statusvalues onsession.endedbeyondsuccess,error,timeout,completed. - Whether
tool.call.requestednests the input undertoolInputorinput.
