Runnable transport preset

Expose runs through Node HTTP and SSE

Use the HTTP/SSE layer when your product wants a conventional REST run resource and server-sent event stream without rebuilding replay cursor, framing, backpressure, and disconnect correctness.

Customization depth

Transport adapter

Hosting depth

Node HTTP; Express reference

Documentation status

Runnable reference

Assumptions

  • A long-lived `ConversationRunService` already owns the run lifecycle.
  • Your server uses Node `IncomingMessage` and `ServerResponse` semantics.
  • Your host will authenticate before resolving a run and will define strict public schemas.
Heddle owns
  • Strict replay cursor parsing with query-over-header precedence.
  • Canonical SSE headers and frames, response backpressure, and subscriber cleanup.
  • Ending an opened event stream when its subscription completes or fails.
Your product owns
  • Route registration, request validation, authentication, authorization, and tenant scope.
  • Public payload schemas, HTTP status and error policy, CORS, limits, rate limiting, and audit.
  • Run lookup, result projection, cancellation policy, deployment, and transport observability.

The conventional resource

The runnable example uses these run endpoints:

Text
POST /api/agent/runs
GET  /api/agent/runs/:runId/events?after=<sequence>
POST /api/agent/runs/:runId/cancel

Starting returns 202 Accepted with a stable runId. Subscription and cancellation are separate authenticated operations. Additional session read or reset endpoints belong to the product and are not part of Heddle's transport preset.

Install direct dependencies

This page uses Heddle's Node runtime, the browser-safe protocol codec, and Zod. Declare every imported package directly:

Shell
npm install @roackb2/heddle @roackb2/heddle-remote zod

Import the Node helper

TypeScript
import {
  parseConversationRunSseReplayCursor,
  streamConversationRunSse,
} from '@roackb2/heddle/hosted/http-sse'

The helper accepts Node request and response objects. Express is the maintained runnable reference, but the package does not register routes or depend on Express.

Validate the public boundary

Create host-owned schemas for start input, accepted output, public activity, public result, cancellation, and errors. Use ConversationRunProtocolCodec to validate the event envelope and remove fields that must not cross the network.

TypeScript
import { z } from 'zod'
import { ConversationRunProtocolCodec } from '@roackb2/heddle-remote'

const PublicActivitySchema = z.object({
  type: z.string().min(1),
  text: z.string().optional(),
  tool: z.string().optional(),
})

const PublicResultSchema = z.object({
  outcome: z.string().min(1),
  summary: z.string(),
})

const protocol = new ConversationRunProtocolCodec({
  activity: PublicActivitySchema,
  result: PublicResultSchema,
})

Never pass internal ConversationActivity or turn results through an unknown schema. They may contain tool input, tool output, filesystem paths, trace locations, or other data the remote caller is not authorized to receive.

Stream from a route

The framework adapter should authenticate first, validate the resource ID, authorize the retained handle, resolve the replay cursor, and then open the stream:

TypeScript
const account = await authenticate(request)
const runId = RunIdSchema.parse(request.params.runId)
const afterSequence = parseConversationRunSseReplayCursor({
  query: request.query.after,
  lastEventId: request.header('Last-Event-ID'),
})

await streamConversationRunSse({
  request,
  response,
  protocol,
  subscribe: (signal) => agent.subscribe({
    accountId: account.id,
    runId,
    afterSequence,
    signal,
  }),
})

The explicit after query wins over Last-Event-ID. Each canonical run sequence becomes the SSE id; event name, ID, and JSON envelope stay aligned. Response backpressure is honored rather than buffering an unbounded stream in user code.

When the request aborts or response closes, Heddle cleans up that subscription. The underlying run continues until it settles or receives explicit cancellation.

Start and cancel remain host routes

A start handler validates { sessionId, prompt }, derives account scope from verified identity, calls the application service, and returns the accepted run. A cancel handler authorizes the same retained run before calling cancel().

Translate validation failures, run conflicts, missing runs, and internal errors into stable public status codes and safe error bodies. Log the original server-side error; do not return raw provider or persistence details.

Production warning

The repository server is deliberately a local demonstration. It refuses NODE_ENV=production, uses a fixed bearer token, listens on loopback, and omits product CORS, rate limits, audit, and deployment policy. Copy its lifecycle boundaries, not its authentication design.

Canonical sources