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 connectionWhat you get back
TawaEventStream is a plain EventEmitter (node:events) with two events:
"tawa:event"— aDecisionEvent,AuditEvent, orMetaEvent(thestagefield discriminates between them)."error"— aFetchError, 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.