Tawa docs
Guides

Live event stream

Subscribe to a real-time stream of every scan in an agent turn.

Every scan call accepts an optional sessionId that groups it with every other scan in the same agent turn — its tool calls, RAG lookups, and the model's own response — so a subscriber sees the whole thing as one connected, real-time timeline instead of separate one-shot calls.

import { randomUUID } from "node:crypto";
import { TawaGuard } from "@tawaguard/sdk";

const tawa = await TawaGuard.create(apiKey);
const sessionId = randomUUID();

const stream = tawa.subscribe(sessionId);
stream.on("tawa:event", (event) => console.log(event));
// {stage:"prompt", action:"allow", risk:14, latency:8, ...}
// {stage:"tool", phase:"call", tool:"refundCustomer", action:"review", needsReview:true, enforcedAction:"block", ...}
// {stage:"response", action:"allow", risk:2, ...}
// {stage:"audit", id:"<job_id>"}  <- fires once the decision is durably persisted

await tawa.scanContext(promptText, { sessionId });
await tawa.scanToolCall(toolName, args, { sessionId });
await tawa.scanResponse(llmReply, { sessionId });

stream.close(); // stop reconnecting and tear down the connection

What you get back

TawaEventStream is a plain EventEmitter (node:events) with two events:

  • "tawa:event" — a DecisionEvent, AuditEvent, or MetaEvent (the stage field discriminates between them).
  • "error" — a FetchError, non-fatal. The stream reconnects on its own with jittered backoff; this is informational, not something you need to react to by tearing the stream down.

action on a decision event is the engine's own label, so review appears here. needsReview is true when the engine's action was review, and enforcedAction ("allow" or "block") is what the gateway enforced after applying your app's setting for that content type. On the wire these are needs_review and enforced_action. Both are optional on older gateways. See The review flag.

It never carries the scanned text itself — only the compact decision summary (stage, action, risk, latency, PII category names, policy directives, and the job id to correlate with the eventual audit record).

Call close() when you're done with a session to stop reconnecting and tear down the underlying connection.

On this page