Cloud and BYOC for Orca Agent Engine are in Private Preview — request an invite
Docs
SDKs & libraries

TypeScript SDK

Install, configure, and use the @runorca/orca-sdk TypeScript client for the registry API in Orca Agent Engine.

The @runorca/orca-sdk package is the official TypeScript client for the Agent Engine registry API. It wraps every registry resource the SDK supports - agents, sessions, environments, files, skills, vaults, memory stores, and triggers - with typed methods, cursor-based pagination, server-sent-event (SSE) streaming, automatic retries, and a typed error hierarchy.

The package is published from the public orca-ae/orca-sdk-typescript repository to npmjs.org. It requires Node.js 20 or later. This page describes version 0.2.3.

Install

Install the public package from npm. No GitHub token or custom .npmrc is required.

npm install @runorca/orca-sdk@0.2.3

If you previously installed @orca-ae/orca-sdk from GitHub Packages, replace that dependency and its imports with @runorca/orca-sdk, then update your lockfile. Remove the old @orca-ae:registry mapping from your project's .npmrc if you no longer use that scope.

Construct the client

Import the default export and construct an Orca client. The constructor takes an apiKey and a baseURL:

import Orca from '@runorca/orca-sdk';

const orca = new Orca({
  apiKey: process.env.ORCA_API_KEY,
  baseURL: process.env.ORCA_BASE_URL,
});

When apiKey is omitted, the SDK reads process.env.ORCA_API_KEY, falling back to null (no Authorization header) if that variable is unset too. baseURL is required; pass it explicitly or set process.env.ORCA_BASE_URL. The constructor throws OrcaError when neither is set. Trailing slashes on baseURL are stripped automatically.

The client also refuses to run in a browser, because the API key would be exposed to page scripts. Set dangerouslyAllowBrowser: true only when the credential is not reachable by end users.

The SDK reads ORCA_BASE_URL and sends its ORCA_API_KEY setting as a Bearer token. The CLI reads ORCA_REGISTRY_URL; its ORCA_API_KEY setting is a Workspace key sent as x-api-key, while ORCA_ACCESS_TOKEN is an OIDC Bearer token. The Go SDK also sends ORCA_API_KEY as x-api-key. Use the host root for every base URL, but configure each credential according to its client.

baseURL is the host root for your Workspace registry. Do not include /v1 or /v1/registry; the SDK adds its own core and extension paths. See Get your registry endpoint for how to derive it from the Workspace's service endpoints.

Authentication options

apiKey accepts three forms:

ValueBehavior
stringUsed directly as the Authorization: Bearer token.
Async function () => Promise<string>Called per request; useful for token rotation. Must return a non-empty string.
nullDisables the Authorization header (for use behind a separately authenticated proxy).

Static token

const orca = new Orca({
  apiKey: process.env.ORCA_API_KEY,
  baseURL: process.env.ORCA_BASE_URL,
});

Rotating token

async function fetchFreshToken(): Promise<string> {
  const token = process.env.ORCA_API_KEY;
  if (!token) throw new Error('Set ORCA_API_KEY.');
  return token;
}

const orca = new Orca({
  apiKey: fetchFreshToken,
  baseURL: process.env.ORCA_BASE_URL,
});

Replace fetchFreshToken with your token-refresh call when tokens rotate.

No auth header

const orca = new Orca({
  apiKey: null,
  baseURL: process.env.ORCA_BASE_URL,
});

Workspace API key

The SDK sends apiKey as a Bearer token. To use a Workspace API key, send it as x-api-key instead. This configuration was verified against a Kubernetes registry with a provider-backed session:

Workspace API key client
import Orca from '@runorca/orca-sdk';

const orca = new Orca({
  apiKey: null,
  baseURL: process.env.ORCA_BASE_URL,
  defaultHeaders: { 'x-api-key': process.env.ORCA_API_KEY },
});

Client options

OptionTypeDefaultDescription
apiKeystring | (() => Promise<string>) | nullprocess.env.ORCA_API_KEYBearer token, async token provider, or null.
baseURLstringprocess.env.ORCA_BASE_URLRegistry base URL. Required.
timeoutnumber600000Per-request timeout in milliseconds (10 minutes).
maxRetriesnumber2Retry cap for transient failures.
defaultHeadersobject-Headers merged into every request.
defaultQueryobject-Query parameters merged into every URL.
fetchOptionsRequestInit-RequestInit merged into every fetch.
loggerLoggerconsoleObject with debug, info, warn, error methods.
logLevel'off' | 'debug' | 'info' | 'warn' | 'error'process.env.ORCA_LOG or 'warn'Logging verbosity.
dangerouslyAllowBrowserbooleanfalseBypass the guard that blocks browser execution. Only set this if your token is not exposed to end users.

Resources

Each registry resource is a property on the client. Methods that create or fetch a single object return an APIPromise you can await. Core list methods return a page cursor you can iterate; Cloud extension list methods return their contract response directly (see Pagination).

In method signatures below, square brackets mark optional arguments. options supplies per-request controls such as headers, retries, timeouts, and an abort signal.

The client exposes these namespaces:

NamespaceCovers
orca.agentsAgent definitions, plus .versions.
orca.sessionsSessions, plus .events, .resources, .files, and .threads (with .threads.events).
orca.environmentsEnvironment templates.
orca.filesWorkspace-level file uploads and downloads.
orca.skillsSkill bundles, plus .versions.
orca.vaultsVaults, plus .credentials.
orca.memoryStoresMemory stores, plus .memories and .memoryVersions.
orca.triggersAgent triggers, plus .sessions.
orca.discoveryExtension API group discovery through GET /apis.
orca.cloud.apiResourcesResources advertised by StreamNative Cloud extension API group.
orca.cloud.agents.providersStreamNative Cloud model providers.
orca.cloud.connectionsPulsar, Kafka, and generic connections.
orca.cloud.functionsFunctions over Pulsar or Kafka.
orca.cloud.packagesFunction, source, and sink packages.
orca.cloud.catalogSource, sink, and Kafka connector catalogs.
orca.cloud.connectorsPulsar IO sources and sinks, plus Kafka Connect.
orca.cloud.healthStreamNative Cloud service health probes.
orca.session(sessionId)A session handle that pre-fills the session ID.

The orca.cloud.* namespaces require the deployment to advertise cloud.sn.io through GET /apis. Against a self-hosted engine, they throw ExtensionNotAvailableError before sending the resource request.

Core resource updates use POST. Trigger updates are partial POST requests. Cloud extension methods follow their published contracts: connections and function/source/sink configuration updates use PUT, while Kafka Connect exposes separate config and offset methods.

Agents

An agent is a registry resource that defines a model, system prompt, tools, MCP servers, and skills. Agents are versioned: update takes the current version for optimistic concurrency, and historical versions stay retrievable.

MethodSignature
Createorca.agents.create(params[, options])
Retrieveorca.agents.retrieve(agentId[, { version }[, options]])
Updateorca.agents.update(agentId, params[, options]) - POST /v1/agents/{agentId}
Listorca.agents.list([{ include_archived, 'created_at[gte]', 'created_at[lte]', limit, page }[, options]])
Archiveorca.agents.archive(agentId[, options]) - POST /v1/agents/{agentId}/archive

list accepts include_archived and the 'created_at[gte]' / 'created_at[lte]' timestamp filters alongside limit and page. There is no provider filter - the only provider on this surface is a field on the model object.

const agent = await orca.agents.create({
  model: 'claude-sonnet-4-6',
  name: 'Support triage',
  system: 'You triage incoming support tickets.',
});
console.log(agent.id, agent.version);

// Optimistic-concurrency update: pass the version you last saw
const updated = await orca.agents.update(agent.id, {
  version: agent.version,
  description: 'Triages and routes support tickets.',
});

Agent versions

orca.agents.versions.list(agentId[, { include_archived, 'created_at[gte]', 'created_at[lte]', limit, page }[, options]]) returns historical snapshots, each an Agent.

for await (const version of orca.agents.versions.list(agent.id)) {
  console.log(version.version, version.updated_at);
}

Agent providers

Providers are the LLM backends registered in the Workspace. A provider name is what you pass as the provider filter on list calls.

MethodSignature
Listorca.cloud.agents.providers.list([options])
Retrieveorca.cloud.agents.providers.retrieve(providerName[, options])

providers.list resolves to a plain AgentProvider[], not a page cursor.

const providers = await orca.cloud.agents.providers.list();
for (const p of providers) {
  console.log(p.name, p.type, p.api_key_configured);
}

An AgentProvider can include name, type, api_url, api_version, beta_version, api_key_env (the environment variable that holds the key), and api_key_configured (whether the server already has one).

Cloud API resources and health

These Cloud extension methods are not paginated.

MethodSignatureReturn value
API resourcesorca.cloud.apiResources.list([options])CloudAPIResourceList for cloud.sn.io/v1
Healthorca.cloud.health.check([options])boolean
Readinessorca.cloud.health.ready([options])boolean
Livenessorca.cloud.health.live([options])boolean

Environments

An environment defines runtime configuration for a session.

MethodSignature
Createorca.environments.create(params[, options])
Retrieveorca.environments.retrieve(environmentId[, options])
Updateorca.environments.update(environmentId, params[, options]) - POST /v1/environments/{environmentId}
Listorca.environments.list([{ include_archived, limit, page }[, options]])
Deleteorca.environments.delete(environmentId[, options])
Archiveorca.environments.archive(environmentId[, options])

Environment.config is a discriminated union of the spec's cloud and self_hosted response shapes. A cloud config carries typed packages and networking blocks.

const environment = await orca.environments.create({ name: 'production' });

Sessions

A session is a single run of an agent against an environment. Sessions are top-level: create requires environment_id and either agent or the compatibility agent_id field. list filters by agent_id.

MethodSignature
Createorca.sessions.create(params[, options])
Retrieveorca.sessions.retrieve(sessionId[, options])
Updateorca.sessions.update(sessionId, params[, options]) - POST /v1/sessions/{sessionId}
Listorca.sessions.list([{ agent_id, include_archived, limit, page }[, options]])
Deleteorca.sessions.delete(sessionId[, options])
Archiveorca.sessions.archive(sessionId[, options])
const session = await orca.sessions.create({
  agent: agent.id,
  environment_id: environment.id,
});
console.log(session.id, session.status);

For working with a single session repeatedly, prefer the session handle, which pre-fills the session ID.

Session events

Events are the conversation transcript. Send user input with send, read persisted history with list, and follow the live run with stream (see Streaming).

MethodSignature
Listorca.sessions.events.list(sessionId[, { limit, page, 'created_at[gt]', 'created_at[gte]', 'created_at[lt]', 'created_at[lte]', order, types, subpath }[, options]])
Sendorca.sessions.events.send(sessionId, params[, options])
Streamorca.sessions.events.stream(sessionId[, options]) or orca.sessions.events.stream(sessionId[, { from_cursor, subpath, event_deltas }[, options]])
await orca.sessions.events.send(session.id, {
  events: [
    { type: 'user.message', content: [{ type: 'text', text: 'Summarize today\'s tickets.' }] },
  ],
});

Each event has an id and a type (such as user.message, agent.message, tool.result, or session.status_idle); event-specific fields like content vary by type.

Session resources

Resources are objects mounted into a session - for example a memory store directory the agent can read and write.

MethodSignature
Listorca.sessions.resources.list(sessionId[, { limit, page }[, options]])
Addorca.sessions.resources.add(sessionId, params[, options])
Retrieveorca.sessions.resources.retrieve(sessionId, resourceId[, options])
Updateorca.sessions.resources.update(sessionId, resourceId, params[, options]) - POST
Deleteorca.sessions.resources.delete(sessionId, resourceId[, options])

Session files

Files attached to a running session - output the agent wrote, or input mounted into it. These are scoped to one session and are distinct from the Workspace-level files resource.

MethodSignature
Listorca.sessions.files.list(sessionId[, { limit, after_id, before_id }[, options]])
Retrieveorca.sessions.files.retrieve(sessionId, fileId[, options])
Downloadorca.sessions.files.download(sessionId, fileId[, options]) - resolves to Response
Deleteorca.sessions.files.delete(sessionId, fileId[, options])

download resolves to a Response, so read the bytes with the method that suits your target - arrayBuffer(), text(), or body for a stream.

for await (const file of orca.sessions.files.list(session.id)) {
  const response = await orca.sessions.files.download(session.id, file.id);
  console.log(file.id, (await response.arrayBuffer()).byteLength);
}

SessionFile has typed id, filename, mime_type, size_bytes, and created_at fields.

Session threads

A session has one primary thread plus zero or more child threads spawned by the coordinator as the session runs. The SDK exposes read and archive operations and per-thread event streaming; it does not create threads.

MethodSignature
Listorca.sessions.threads.list(sessionId[, { limit, page }[, options]])
Retrieveorca.sessions.threads.retrieve(sessionId, threadId[, options])
Archiveorca.sessions.threads.archive(sessionId, threadId[, options])
List eventsorca.sessions.threads.events.list(sessionId, threadId[, { limit, page }[, options]])
Stream eventsorca.sessions.threads.events.stream(sessionId, threadId[, options]) or orca.sessions.threads.events.stream(sessionId, threadId[, { from_cursor, event_deltas }[, options]])
for await (const thread of orca.sessions.threads.list(session.id)) {
  console.log(thread.id, thread.status, thread.parent_thread_id);
}

Files

Files are ad-hoc assets uploaded with multipart/form-data. Pass a File (or any Uploadable) as the file field.

Set the MIME type when you construct a File or call toFile. The upload request takes only file.

MethodSignature
Uploadorca.files.upload({ file }[, options])
Retrieveorca.files.retrieve(fileId[, options])
Downloadorca.files.download(fileId[, options]) - resolves to Response
Listorca.files.list([{ limit, after_id, before_id }[, options]])
Deleteorca.files.delete(fileId[, options])
import { toFile } from '@runorca/orca-sdk';

const file = new File(['hello\n'], 'hello.txt', { type: 'text/plain' });
const meta = await orca.files.upload({ file });
console.log(meta);

const generatedFile = await toFile(new TextEncoder().encode('hello\n'), 'generated.txt', {
  type: 'text/plain',
});
await orca.files.upload({ file: generatedFile });

// `retrieve` returns metadata; `download` returns the bytes.
const response = await orca.files.download(meta.id);
console.log(await response.text());

Skills

A skill is a filesystem-shaped bundle of expertise an agent loads on demand. Skills are uploaded as multipart bundles and are version-additive - upload a new version rather than mutating one in place.

MethodSignature
Createorca.skills.create(params[, options]) - multipart bundle
Retrieveorca.skills.retrieve(skillId[, options])
Listorca.skills.list([{ limit, page }[, options]])
Deleteorca.skills.delete(skillId[, options])
Create versionorca.skills.versions.create(skillId, params[, options]) - multipart bundle
Retrieve versionorca.skills.versions.retrieve(skillId, versionId[, options])
List versionsorca.skills.versions.list(skillId[, { limit, page }[, options]])
Delete versionorca.skills.versions.delete(skillId, versionId[, options])

Vaults

A vault is a named container for credentials that agents use to authenticate to external services.

MethodSignature
Createorca.vaults.create(params[, options])
Retrieveorca.vaults.retrieve(vaultId[, options])
Updateorca.vaults.update(vaultId, params[, options]) - POST /v1/vaults/{vaultId}
Listorca.vaults.list([{ include_archived, limit, page }[, options]])
Deleteorca.vaults.delete(vaultId[, options])
Archiveorca.vaults.archive(vaultId[, options])

Vault credentials

MethodSignature
Listorca.vaults.credentials.list(vaultId[, { include_archived, limit, page }[, options]])
Createorca.vaults.credentials.create(vaultId, params[, options])
Retrieveorca.vaults.credentials.retrieve(vaultId, credentialId[, options])
Updateorca.vaults.credentials.update(vaultId, credentialId, params[, options]) - POST
Deleteorca.vaults.credentials.delete(vaultId, credentialId[, options])
Archiveorca.vaults.credentials.archive(vaultId, credentialId[, options])
Validateorca.vaults.credentials.validate(vaultId, credentialId[, options]) - validates MCP OAuth configuration

This static_bearer example needs MCP_SERVER_URL and MCP_ACCESS_TOKEN for the MCP server you configure.

const vault = await orca.vaults.create({ display_name: 'Production secrets' });
const mcpServerURL = process.env['MCP_SERVER_URL'];
const mcpToken = process.env['MCP_ACCESS_TOKEN'];
if (!mcpServerURL || !mcpToken) {
  throw new Error('Set MCP_SERVER_URL and MCP_ACCESS_TOKEN.');
}

const credential = await orca.vaults.credentials.create(vault.id, {
  display_name: 'Support MCP',
  auth: {
    type: 'static_bearer',
    mcp_server_url: mcpServerURL,
    token: mcpToken,
  },
});
console.log(credential.id);

Memory stores

A memory store is a named, long-lived container you attach to a session through resources[] to mount as a directory the agent reads and writes.

MethodSignature
Createorca.memoryStores.create(params[, options])
Retrieveorca.memoryStores.retrieve(memoryStoreId[, options])
Updateorca.memoryStores.update(memoryStoreId, params[, options]) - POST /v1/memory_stores/{memoryStoreId}
Listorca.memoryStores.list([{ provider, include_archived, limit, page }[, options]])
Deleteorca.memoryStores.delete(memoryStoreId[, options])
Archiveorca.memoryStores.archive(memoryStoreId[, options])

delete resolves to a DeletedMemoryStore tombstone, not void.

const store = await orca.memoryStores.create({
  name: 'project-notes',
  description: 'Long-lived notes for project X',
});

await orca.memoryStores.update(store.id, { description: 'Updated description' });

Memories

Read and write individual entries inside a store. Memory has typed id, path, content hash, size, timestamps, and optional content fields. A list can also contain a MemoryPrefix entry. The request body stays separate from view query controls.

MethodSignature
Listorca.memoryStores.memories.list(memoryStoreId[, { depth, path_prefix, view, limit, page }[, options]])
Createorca.memoryStores.memories.create(memoryStoreId, { body: { path, content }[, view] }[, options])
Retrieveorca.memoryStores.memories.retrieve(memoryStoreId, memoryId[, { view }[, options]])
Updateorca.memoryStores.memories.update(memoryStoreId, memoryId, { body[, view] }[, options]) - POST
Deleteorca.memoryStores.memories.delete(memoryStoreId, memoryId[, { expected_content_sha256 }[, options]])
const memory = await orca.memoryStores.memories.create(store.id, {
  body: {
    path: '/customers/acme/preferences.md',
    content: 'The customer prefers email over phone.',
  },
});

for await (const entry of orca.memoryStores.memories.list(store.id)) {
  console.log(entry);
}

delete resolves to a DeletedMemory tombstone. Pass expected_content_sha256 to make deletion conditional on the entry's current content, so a concurrent write is not silently discarded.

Memory versions

Every write to a memory produces a version. Use these methods to audit that history and to redact a version's content in place.

MethodSignature
Listorca.memoryStores.memoryVersions.list(memoryStoreId[, { memory_id, api_key_id, operation, 'created_at[gte]', 'created_at[lte]', view, limit, page }[, options]])
Retrieveorca.memoryStores.memoryVersions.retrieve(memoryStoreId, memoryVersionId[, options]) or orca.memoryStores.memoryVersions.retrieve(memoryStoreId, memoryVersionId[, { view }[, options]])
Redactorca.memoryStores.memoryVersions.redact(memoryStoreId, memoryVersionId[, options])
const memoryVersions = await orca.memoryStores.memoryVersions.list(store.id, {
  memory_id: memory.id,
});

for (const version of memoryVersions.data) {
  console.log(version);
}

const firstVersion = memoryVersions.data[0];
if (firstVersion) {
  await orca.memoryStores.memoryVersions.redact(store.id, firstVersion.id);
}

redact removes the stored content of a version while leaving the version record in place. It is not reversible.

Agent triggers

An agent trigger runs an agent automatically on a cron schedule or, on StreamNative Cloud, in response to Pulsar or Kafka messages. Triggers are core /v1/triggers operations exposed as orca.triggers on every deployment.

MethodSignature
Createorca.triggers.create(params[, options])
Listorca.triggers.list([{ agent_id, limit, page }[, options]])
Retrieveorca.triggers.retrieve(triggerId[, options])
Updateorca.triggers.update(triggerId, params[, options]) - partial POST
Deleteorca.triggers.delete(triggerId[, options])
Pauseorca.triggers.pause(triggerId[, options])
Unpauseorca.triggers.unpause(triggerId[, options])
List created sessionsorca.triggers.sessions.list(triggerId[, { include_archived, limit, page }[, options]])

The create request uses agent, either as an agent ID string or { type: 'agent', id, version? }. Omitting version pins the agent's current version at create time; it does not track later agent updates.

const trigger = await orca.triggers.create({
  name: 'nightly-digest',
  agent: { type: 'agent', id: agent.id, version: agent.version },
  session_mode: 'SESSION_PER_EVENT',
  source: {
    type: 'cron',
    schedule: '0 2 * * *',
    timezone: 'Etc/UTC',
    payload: 'Summarize unresolved tickets.',
  },
  session: { environment_id: environment.id },
});

await orca.triggers.pause(trigger.id);
await orca.triggers.unpause(trigger.id);

for await (const session of orca.triggers.sessions.list(trigger.id)) {
  console.log(session.id, session.status);
}

Trigger configuration

FieldTypeDescription
namestringDisplay name for the trigger.
agentstring | { type: 'agent', id, version? }Agent to run. The registry stores the resolved version.
session_mode'SESSION_PER_EVENT' | 'SESSION_PER_TOPIC' | 'SESSION_PER_KEY' | 'SHARED'How incoming events map onto sessions.
sourceTriggerSourceCreateParamsCron, Pulsar, or Kafka source. See below.
session{ environment_id, metadata?, title_template?, vault_ids? }Template applied to each session the trigger creates.
replicasnumberNumber of trigger workers.
pausedbooleanCreate the trigger without starting it.

The open-source engine accepts cron with SESSION_PER_EVENT and one replica. StreamNative Cloud widens the same types with Pulsar and Kafka sources, all four messaging session modes, SHARED for cron, and positive replica counts.

For a messaging trigger, set ORCA_KAFKA_CONNECTION_NAME to the name of a configured Cloud connection.

const connectionName = process.env['ORCA_KAFKA_CONNECTION_NAME'];
if (!connectionName) throw new Error('Set ORCA_KAFKA_CONNECTION_NAME.');

await orca.triggers.create({
  name: 'ticket-ingest',
  agent: { type: 'agent', id: agent.id },
  session_mode: 'SESSION_PER_TOPIC',
  source: {
    type: 'kafka',
    connection: connectionName,
    topics: ['tickets'],
    subscription_name: 'triage-sub',
    schema_type: 'json',
  },
  session: { environment_id: environment.id },
});

update accepts only mutable fields and preserves omitted values. It cannot change the pinned agent or set paused; call pause or unpause for lifecycle changes.

Session handle

orca.session(sessionId) returns a SessionHandle that pre-fills the session ID on events, resources, files, and threads calls, so you don't repeat it. It mirrors the methods on orca.sessions.* for a single session, and exposes the ID it was built with as handle.sessionId. handle.events.stream([options]) and handle.events.stream([{ from_cursor, subpath, event_deltas }[, options]]) support the session stream overloads. handle.threads.events.stream(threadId[, options]) and handle.threads.events.stream(threadId[, { from_cursor, event_deltas }[, options]]) do the same for one thread.

handle.sessionId
handle.events           list  send  stream
handle.resources        list  add  retrieve  update  delete
handle.files            list  retrieve  download  delete
handle.threads          list  retrieve  archive
handle.threads.events   list  stream
const handle = orca.session(session.id);

await handle.events.send({
  events: [{ type: 'user.message', content: [{ type: 'text', text: 'Hello' }] }],
});

for await (const event of await handle.events.stream()) {
  console.log(event.type);
  if (event.type === 'session.status_idle') break;
}

// Files the session produced
for await (const file of handle.files.list()) {
  const response = await handle.files.download(file.id);
  console.log(file.id, (await response.arrayBuffer()).byteLength);
}

// Per-thread events through the handle
for await (const thread of handle.threads.list()) {
  for await (const event of await handle.threads.events.stream(thread.id)) {
    console.log(thread.id, event.type);
    break;
  }
}

Streaming

Session and thread events stream over server-sent events (SSE). stream() resolves to a Stream<SessionEvent> that is async-iterable. Iterate with for await and break when the session reaches a terminal state.

const session = await orca.sessions.create({
  agent: agent.id,
  environment_id: environment.id,
});

await orca.sessions.events.send(session.id, {
  events: [{ type: 'user.message', content: [{ type: 'text', text: 'Hello' }] }],
});

const stream = await orca.sessions.events.stream(session.id);
for await (const event of stream) {
  if (event.type === 'agent.message') console.log(event);
  if (event.type === 'session.status_idle') break;
}

A stream can be consumed only once. To process the same stream in two places, split it with .tee(). To stop early and release the connection, call stream.controller.abort() or break out of the loop. The SDK sets Accept: text/event-stream on streaming requests automatically.

Pagination

Core list methods other than files use opaque page tokens. await the call, read .data, and pass next_page as page until it is null.

let page = await orca.agents.list({ limit: 100 });
const all = [...page.data];

while (page.next_page) {
  page = await orca.agents.list({ limit: 100, page: page.next_page });
  all.push(...page.data);
}

File lists use ID cursors instead: orca.files.list and orca.sessions.files.list accept after_id or before_id and return has_more, first_id, and last_id. Automatic iteration preserves direction. For manual iteration, follow last_id with after_id or first_id with before_id.

let filePage = await orca.files.list({ limit: 100 });
const files = [...filePage.data];

while (filePage.hasNextPage()) {
  filePage = await filePage.getNextPage();
  files.push(...filePage.data);
}

Cloud extension list methods are not cursor-based. They resolve directly to plain arrays, objects, or unknown contract responses. Do not read .data or use for await with them.

const providers = await orca.cloud.agents.providers.list();
const apiResources = await orca.cloud.apiResources.list();
console.log(providers.length, apiResources.resources.length);

Error handling

Every error the SDK throws extends OrcaError. HTTP errors extend APIError and carry .status, .headers, and .error. Catch specific subclasses to branch on the failure:

import { OrcaError, APIError, NotFoundError, RateLimitError } from '@runorca/orca-sdk';

try {
  await orca.agents.retrieve(agent.id);
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error('Agent not found:', err.status); // 404
  } else if (err instanceof RateLimitError) {
    console.error('Rate limited; inspect retry headers:', err.headers);
  } else if (err instanceof APIError) {
    console.error(err.status, err.message);
  } else if (err instanceof OrcaError) {
    console.error('SDK error:', err.message);
  } else {
    throw err;
  }
}

The error hierarchy:

ClassHTTP status
BadRequestError400
AuthenticationError401
PermissionDeniedError403
NotFoundError404
ConflictError409
UnprocessableEntityError422
RateLimitError429
InternalServerError5xx
APIConnectionErrornetwork failure
APIConnectionTimeoutErrorrequest timed out
APIUserAbortErrorrequest aborted by the caller

Retries and timeouts

The client retries transient failures - network errors and 408, 409, 429, and 5xx responses - with exponential backoff and jitter. Tune the defaults on the client, or override per request.

const orca = new Orca({
  apiKey: process.env.ORCA_API_KEY,
  baseURL: process.env.ORCA_BASE_URL,
  maxRetries: 3,    // default: 2
  timeout: 30_000,  // milliseconds; default: 600000 (10 minutes)
});

// Per-request override
await orca.agents.list({}, { maxRetries: 0, timeout: 5_000 });

Logging

Pass a logger (any object with debug, info, warn, and error methods) and set logLevel to control verbosity. The default is console at 'warn'. Set it to 'off' to suppress SDK logs. The level can also come from process.env.ORCA_LOG.

const orca = new Orca({
  apiKey: process.env.ORCA_API_KEY,
  baseURL: process.env.ORCA_BASE_URL,
  logger: console,
  logLevel: 'info', // 'off' | 'debug' | 'info' | 'warn' | 'error'
});

What's next

On this page