For the complete documentation index, see llms.txt. This page is also available as Markdown.

Gateways

Gateways are bidirectional adapters that present agent interactions — especially human approvals — on CLI, HTTP, or any external platform.

A gateway is a bidirectional human-interaction adapter. It translates platform events (a CLI keystroke, an HTTP webhook, a chat-platform button click) into normalized agent input, and translates agent events — including a suspended human-in-the-loop approval — back into a platform-native experience.

It is more than a message transport: a gateway also handles identity, threads, interactive actions, streaming, approvals, and resuming suspended runs.

🚀 Resolving a Gateway

cli  = aiGateway( "cli" )
http = aiGateway( "http", { secret: "shared-hmac-secret" } )
mock = aiGateway( "mock" )
BIF
Purpose

aiGateway( name, options )

Resolve a gateway — a core name, or one registered by a module

aiGatewayRegistry()

The singleton registry external gateway modules register into

Attach one to HITL middleware and approvals are presented there:

import bxModules.bxai.models.middleware.core.HumanInTheLoopMiddleware;

agent = aiAgent(
    tools       : [ deployTool ],
    middleware  : [ new HumanInTheLoopMiddleware(
        toolsRequiringApproval: [ "deploy" ],
        gateway               : aiGateway( "http", { secret: getSecret() } )
    ) ],
    checkpointer: aiMemory( "cache" )
)

📦 Core Gateways

Gateway
Capabilities
Use it for

cli

humanApproval

The reference implementation — a blocking stdin/stdout approval prompt

http

inboundMessages, outboundMessages, humanApproval

Network-reachable approvals via signed webhooks

mock

inboundMessages, outboundMessages, humanApproval

Tests and examples — scriptable, fully offline

CliGateway

Prints an approval banner and reads a decision from stdin. It resolves synchronously, so the run blocks rather than suspending. Offers approve / approve-always / approve-for-session / reject, plus quit as an always-available escape hatch, and re-prompts up to three times on unrecognised input before cancelling.

HttpGateway

The first gateway with real network exposure, so every inbound mutation is signed (HMAC-SHA256), timestamp-bounded and nonce-deduplicated; every pending interaction has a TTL; and resolving a decision is an atomic claim, so a duplicate decision POST for an already-resolved interaction is rejected rather than silently overwriting it.

It exposes three endpoints through the gateway.bxm front controller:

Method
Route
Purpose

POST

/bxai/gateways/{gatewayName}/events

Inbound platform event

GET

/bxai/interactions/{requestID}

Poll a pending interaction

POST

/bxai/interactions/{requestID}/decisions

Submit a human's decision

MockGateway

The reference implementation for tests — records what was delivered and lets you script decisions, with no I/O at all.

🧩 Capabilities

A gateway declares only what it actually supports. Every capability method on IGateway has a safe default — a failed GatewayDeliveryResult, or a thrown GatewayCapabilityNotSupported — so implementations stay small.

Capability
Meaning

inboundMessages

Can parse platform payloads into agent input

outboundMessages

Can deliver agent events to the platform

streaming

Can deliver response deltas as they arrive

threads

Understands platform-native threading

attachments

Can send/receive files

messageEditing

Can edit a message it already sent

interactiveActions

Supports native buttons/actions

humanApproval

Can present a HITL approval and collect a decision

argumentEditing

Can collect corrected tool arguments

authentication

Verifies inbound payload authenticity

Check supports() before calling a capability method rather than relying on the fallback.

⚙️ Configuration

Per-gateway settings live under settings.gateways, keyed by gateway name:

🌍 External Gateway Modules

Platform gateways — Slack, Discord, Teams, Telegram — ship as their own modules, not in bx-ai core. A module registers its gateway when it loads, and aiGateway() finds it by name:

Registry keys are name or name@module, so two modules can provide same-named gateways without colliding:

If nothing is registered under the name, aiGateway() falls back to treating it as a directly-instantiable class path, and throws GatewayNotSupported if that fails too.

🛠️ Building a Custom Gateway

Extend BaseGateway, declare your capabilities, and override only the methods you support.

presentInteraction( humanRequest, maxBodyLength ) gives you a normalized title, body, and one button per allowed decision — including labels and styles for approve_always/approve_session — so every chat-native gateway renders consistently. presentResolution( decision ) gives you a short summary ("Approved by alice", "Rejected: not now") for the follow-up message.

For a gateway whose pending state must outlive the process, override setCheckpointer(); HumanInTheLoopMiddleware.onAttach() passes the owning agent's checkpointer automatically.

🎯 Events

Event
Fired when

onGatewayCreate

aiGateway() resolves or creates a gateway

onGatewaySessionCreate

aiGatewaySession() constructs a session

onGatewayRegistryRegister

A gateway is registered into the registry

onGatewayRegistryUnregister

A gateway is removed

onGatewayConnect

A gateway's start() makes a real not-running → running transition

onGatewayDisconnect

A gateway's stop() makes a real running → not-running transition

onGatewayMessageReceived

A gateway's parseInbound() parses an inbound message

onGatewayMessageSent

A gateway's deliver() sends an outbound message

See Event System.

Last updated