AERDocumentation

Guide

Recording from your own code

When the drop-in collector cannot see what your agent does, or you want precise control over what is recorded, emit events yourself with the SDK. Same wire protocol, same signed record, same bodies-off contract.

Install

npm install @adastracomputing/aer-sdk-ts

Record a run

import { createAerClient } from '@adastracomputing/aer-sdk-ts';

// Session ids and the ingest token come from POST /v1/sessions
// (tenant API key), or from your orchestrator.
const client = createAerClient({
  baseUrl: 'https://api.aer.run',
  sessionId: sess.agent_session_id,
  ingestToken: sess.ingest_token,
});

await client.emit('tool.started', { tool: 'web_search' });
await client.emit('tool.completed', { tool: 'web_search', ok: true });
await client.emit('llm.completed', {
  model: 'claude-sonnet-4-5', input_tokens: 812, output_tokens: 102, ok: true,
});

const result = await client.complete();
// result.aer_id, result.canonical_hash, result.signing_key_id

Events buffer in memory and post in batches (500 ms flush by default; size-triggered when a batch fills). Server errors retry with exponential backoff; client errors fail fast and the batch requeues for the next flush, so a transient outage never silently drops events. complete() flushes everything and seals the signed record. abort() is the crash path: the session terminates and no record is generated.

What to emit

The full event taxonomy with required and common fields is documented at aer.run/events. The rule for every payload: metadata only. Model names, token counts, tool names, hosts and paths belong in a record; prompts, completions, tool arguments and response bodies never do. The server enforces this at ingest: unknown payload keys are stripped before storage (the response reports aggregate counts when that happens) and out-of-bounds values reject the event.

Severity hints

await client.emit('guardrail.triggered', { rule: 'egress-denied' }, { severity_hint: 'high' });

severity_hint (info, low, medium, high, critical) feeds the findings pipeline and the console feeds; it never changes what is captured.

Sessions from scratch

POST /v1/sessions      (tenant API key)
→ { agent_session_id, ingest_token }

# then emit events with the ingest token and complete when done

The ingest token is scoped to one session and expires with it; your tenant API key never needs to reach the agent process. A Python SDK with the same contract is in beta; Go and Rust follow once the wire protocol stabilises past v1, and any language can speak the raw HTTP API today (see the API reference).