Skip to content

TypeScript SDK

The official TypeScript client for Agent on Demand. Covers every endpoint with typed models, a single async Client, and an AsyncIterable SSE event stream. Works in Node 18+ and modern browsers with zero runtime dependencies.

Install

npm install @ravi-hq/aod-sdk

Quickstart

import { Client } from "@ravi-hq/aod-sdk";

const client = new Client({
  baseUrl: "http://localhost:8777",
  token: "aod_...",
  // or set AOD_API_URL / AOD_API_TOKEN in env (Node only)
});

const agent = await client.agents.create({
  name: "hello",
  model: "anthropic/claude-sonnet-4-6",
  runtime: "claude",
});

const ack = await client.sessions.create({
  agent_id: agent.id,
  prompt: "Say hello.",
  timeout: 120,
});

const stream = await client.sessions.stream(ack.id);
try {
  for await (const event of stream) {
    if (event.type === "output") {
      process.stdout.write(event.extra.data ?? "");
    } else if (event.type === "exit") {
      console.log(`\n[exit ${event.extra.code}]`);
      break;
    }
  }
} finally {
  await stream.close();
}

Configuration

baseUrl and token can be passed to the constructor or read from AOD_API_URL and AOD_API_TOKEN environment variables (Node only). baseUrl defaults to http://localhost:8777.

Option Default Notes
baseUrl AOD_API_URL or localhost:8777 Trailing slash stripped.
token AOD_API_TOKEN Required. Sent as Authorization: Bearer <token>.
fetch globalThis.fetch Inject a custom fetch for tests or proxies.
timeoutMs 30000 Per-request timeout. Streaming requests use AbortSignal.

Errors

Non-2xx responses throw a typed subclass of AodHTTPError. All share .statusCode, .detail, .method, .url:

import { ConflictError } from "@ravi-hq/aod-sdk";

try {
  await client.agents.update(agentId, { version: 1, name: "renamed" });
} catch (err) {
  if (err instanceof ConflictError) {
    // 409: stale version or archived row
    console.error(err.statusCode, err.detail);
  }
}
Status Class When
401 AuthError Missing or invalid token
404 NotFoundError Resource missing
409 ConflictError Archived row, terminal session, or stale version
422 ValidationError Server-side validation failure
429 RateLimitError Per-user concurrent session limit (.limit, .active)
5xx ServerError

Optimistic concurrency

agents and environments carry a version integer. Pass the current version on every PUT; a stale version throws ConflictError:

const agent = await client.agents.get(agentId);
await client.agents.update(agent.id, {
  version: agent.version,
  name: "renamed",
});

See Core Concepts → Optimistic concurrency for the full semantics.

Streaming

client.sessions.stream(sessionId, opts?) returns a StreamHandle — an AsyncIterable<StreamEvent> with a close() method.

const stream = await client.sessions.stream(sessionId, { since: lastSeenId });
try {
  for await (const event of stream) {
    switch (event.type) {
      case "stage":
        console.log(`[${event.extra.stage} ${event.extra.state}]`);
        break;
      case "output":
        process.stdout.write(event.extra.data ?? "");
        break;
      case "exit":
        console.log(`\n[exit ${event.extra.code}]`);
        return;
      case "error":
      case "terminated":
      case "stale":
        console.error(`\n[${event.type}]`);
        return;
    }
  }
} finally {
  await stream.close();
}

Pass since: lastSeenId to resume after a disconnect. Pass signal: abortController.signal to cancel from outside.

Event types: start, turn_start, output, stage, exit, error, terminated, stale. Everything except type and id lands in event.extra. See Streaming reference for the full event schema.

Browser use

The SDK has no Node-only dependencies — it uses built-in fetch, ReadableStream, and AbortController. Pass baseUrl and token explicitly in browser code; the AOD_API_URL / AOD_API_TOKEN env fallbacks are Node-only.

If you're calling Agent on Demand from a browser origin other than the API's own origin, the server must send appropriate CORS headers (not enabled by default on self-hosted instances).

See also