Skip to content
PricingBlog
✨ Markdown

App setup

The runtime handler connects your app's entity definitions to the Electric Agents runtime server via webhooks.

createRuntimeHandler

Creates a runtime with a Node HTTP adapter:

ts
import {
  createEntityRegistry,
  createRuntimeHandler,
} from "@electric-ax/agents-runtime"

const registry = createEntityRegistry()
// ... register entity types ...

const runtime = createRuntimeHandler({
  baseUrl: "http://localhost:4437",
  serveEndpoint: "http://localhost:3000/webhook",
  registry,
})

Configuration

ts
interface RuntimeRouterConfig {
  baseUrl: string // Electric Agents server URL
  serveEndpoint?: string // Webhook callback URL
  webhookPath?: string // Path to match (default: derived from serveEndpoint)
  handlerUrl?: string // legacy alias for serveEndpoint
  registry?: EntityRegistry
  subscriptionPathForType?: (typeName: string) => string
  idleTimeout?: number // ms before closing idle wake (default: 20000)
  heartbeatInterval?: number // ms between heartbeats (default: 30000)
  createElectricTools?: (context: {
    entityUrl: string
    entityType: string
    args: Readonly<Record<string, unknown>>
    db: EntityStreamDBWithActions
    events: Array<ChangeEvent>
    upsertCronSchedule(opts: {
      id: string
      expression: string
      timezone?: string
      payload?: unknown
      debounceMs?: number
      timeoutMs?: number
    }): Promise<{ txid: string }>
    upsertFutureSendSchedule(opts: {
      id: string
      payload: unknown
      targetUrl?: string
      fireAt: string
      from?: string
      messageType?: string
    }): Promise<{ txid: string }>
    deleteSchedule(opts: { id: string }): Promise<{ txid: string }>
  }) => AgentTool[] | Promise<AgentTool[]> // factory for extra agent tools
  onWakeError?: (error: Error) => boolean | void // return true to mark handled
  registrationConcurrency?: number // max concurrent type registrations (default: 8)
}

HTTP server

Your app needs an HTTP server to receive webhook callbacks from the Electric Agents runtime server. Forward webhook POSTs to the runtime handler:

ts
import http from "node:http"

const server = http.createServer(async (req, res) => {
  if (req.url === "/webhook" && req.method === "POST") {
    await runtime.onEnter(req, res)
    return
  }
  res.writeHead(404)
  res.end()
})

server.listen(PORT, async () => {
  await runtime.registerTypes()
  console.log(`${runtime.typeNames.length} types registered`)
})

registerTypes

Registers all entity types with the Electric Agents runtime server and creates webhook subscriptions. Uses upsert semantics — re-registering an existing type updates it rather than erroring.

Must be called after your app starts listening.

ts
await runtime.registerTypes()

This makes two requests per entity type:

  1. POST /_electric/entity-types — registers the type definition and schemas.
  2. PUT /{type}/**?subscription={type}-handler — creates a webhook subscription for the type.

RuntimeHandler

ts
interface RuntimeHandler {
  onEnter(req: IncomingMessage, res: ServerResponse): Promise<void>
  handleRequest(request: Request): Promise<Response | null>
  handleWebhookRequest(request: Request): Promise<Response>
  dispatchWebhookWake(notification: WebhookNotification): void
  drainWakes(): Promise<void>
  waitForSettled(): Promise<void>
  abortWakes(): void
  debugState(): RuntimeDebugState
  readonly typeNames: string[]
  registerTypes(): Promise<void>
}

interface RuntimeDebugState {
  pendingWakeCount: number
  pendingWakeLabels: string[]
  wakeErrorCount: number
  typeNames: string[]
}
MethodDescription
onEnterNode HTTP adapter — reads the request body and delegates to handleWebhookRequest
handleRequestFetch-native router — returns null if the path does not match webhookPath
handleWebhookRequestProcesses a webhook POST directly, without path matching
dispatchWebhookWakeDispatches a pre-parsed notification (fire-and-forget)
drainWakesWaits for all in-flight wake handlers to settle; throws on errors
waitForSettledWaits for all in-flight wakes; throws on errors
abortWakesCancels all in-flight wake handlers immediately
debugStateReturns a snapshot of internal runtime state for diagnostics
registerTypesRegisters entity types and webhook subscriptions with the Electric Agents runtime server

createRuntimeRouter

Fetch-native alternative with no Node HTTP dependency:

ts
import { createRuntimeRouter } from "@electric-ax/agents-runtime"

const router = createRuntimeRouter(config)
const response = await router.handleRequest(request)

Use this when integrating with non-Node frameworks or edge runtimes.

Environment variables

VariableDefaultPurpose
ELECTRIC_AGENTS_URLhttp://localhost:4437Electric Agents runtime server URL
PORT3000Your app's HTTP port
ANTHROPIC_API_KEYClaude API key