---
title: "TypeScript SDK reference"
description: "Types, events, error classes, and version compatibility for the @rkat/sdk TypeScript SDK."
icon: "book"
---

<Note>
Public SDK interfaces use camelCase by default. Protocol-bound multimodal content keys (`media_type`, `blob_id`, `duration_ms`) intentionally remain wire-shaped.
</Note>

## Imports

Everything public is re-exported from the package root:

```typescript
import {
  MeerkatClient,
  Session,
  LiveChannel,
  Mob,
  EventStream,
  EventSubscription,
  MeerkatError,
  CapabilityUnavailableError,
  SessionNotFoundError,
  SkillNotFoundError,
  CONTRACT_VERSION,
} from "@rkat/sdk";

import type {
  RunResult,
  Usage,
  SessionInfo,
  SessionOptions,
  LiveChannelOptions,
  LiveOpenResult,
  LiveRefreshResult,
  LiveStatusResult,
  LiveInputChunkWire,
  ContentBlock,
  Capability,
  SkillKey,
  SkillRef,
  SkillRuntimeDiagnostics,
  SchemaWarning,
  AgentEvent,
  AgentEventEnvelope,
  AttributedMobEvent,
  EventEnvelope,
  AttributedEvent,
  MobMember,
  MobStatus,
  MobSummary,
  SpawnSpec,
  MobFlowStatus,
  MobLifecycleAction,
  MobDefinition,
  TextDeltaEvent,
  TurnCompletedEvent,
  // ... all event types
} from "@rkat/sdk";
```

## Additional client wrappers

The package exports more than the core session lifecycle. The `MeerkatClient` also exposes:

- auth-profile helpers: `authProfileList`, `authProfileGet`, `authProfileCreate`, `authProfileDelete`
- auth-login helpers: `authLoginStart`, `authLoginComplete`, `authLoginDeviceStart`, `authLoginDeviceComplete`, `authLoginProvisionApiKey`, `authStatusGet`, `authLogout`
- realm helpers: `realmList`, `realmGet`
- typed ingress helper: `sendPeerResponseTerminal`
- MCP live-op helpers: `mcpAdd`, `mcpRemove`, `mcpReload`
- blob/skill helpers: `getBlob`, `listSkills`
- live-channel helpers: `liveOpen`, `liveStatus`, `liveClose`, `liveSendInput`,
  `liveSendInputImage`, `liveSendInputVideoFrame`, `liveCommitInput`,
  `liveInterrupt`, `liveTruncate`, `liveRefresh`, and
  `parseLiveObservation`

---

## Core types

### RunResult

The result returned by `session.turn()`, `session.invokeSkill()`, and `deferred.startTurn()`. Session creation returns runtime-backed `Session` or `DeferredSession` wrappers, and the latest `RunResult` remains available through `session.lastResult` or `stream.result` after an `EventStream` is fully consumed.

```typescript
interface RunResult {
  readonly sessionId: string;
  readonly sessionRef?: string;
  readonly text: string;
  readonly turns: number;
  readonly toolCalls: number;
  readonly usage: Usage;
  readonly structuredOutput?: unknown;
  readonly schemaWarnings?: readonly SchemaWarning[];
  readonly skillDiagnostics?: SkillRuntimeDiagnostics;
}
```

| Field | Type | Description |
|-------|------|-------------|
| `sessionId` | `string` | Stable UUID for this session |
| `sessionRef` | `string \| undefined` | Optional human-readable reference |
| `text` | `string` | Full assistant text from the last LLM turn |
| `turns` | `number` | Number of LLM turns in this run |
| `toolCalls` | `number` | Total tool calls executed in this run |
| `usage` | `Usage` | Token usage for this run |
| `structuredOutput` | `unknown \| undefined` | Parsed structured output when `outputSchema` was provided |
| `schemaWarnings` | `SchemaWarning[] \| undefined` | Warnings emitted when structured output didn't fully match the schema |
| `skillDiagnostics` | `SkillRuntimeDiagnostics \| undefined` | Runtime diagnostics from the skill subsystem |

### Session

`client.createSession()` returns a runtime-backed `Session` wrapper.

```typescript
class Session {
  readonly id: string;
  readonly ref?: string;
  readonly text: string;
  readonly usage: Usage;
  readonly turns: number;
  readonly toolCalls: number;
  readonly structuredOutput?: unknown;
  readonly lastResult: RunResult;
}
```

The `Session` methods are thin conveniences over canonical runtime calls:

- `await session.turn(...)`
- `session.stream(...)`
- `await session.history(...)`
- `await session.archive()`
- `await session.interrupt()`
- `await session.invokeSkill(...)`
- `await session.subscribeEvents()`

### DeferredSession

`client.createDeferredSession()` reserves session identity now and runs the first turn later through `await deferred.startTurn(...)`.

### LiveChannel

`LiveChannel` is the session-bound helper for the `live/*` RPC surface.
`RealtimeChannel` was removed with the live-adapter surface; use
`LiveChannel.session(client, sessionId, options?)` instead.

```typescript
const channel = LiveChannel.session(client, session.id, {
  turningMode: "explicit_commit",
});

const opened: LiveOpenResult = await channel.open();
await channel.sendInputText("hello");
await channel.commitInput("text");
const status: LiveStatusResult = await channel.status();
const refresh: LiveRefreshResult = await channel.refresh();
await channel.close();
```

The helper stores the `channel_id` returned by `live/open`. It does not own the
WebSocket transport; connect to `opened.transport.url` with the returned token
using the transport appropriate for your app.

### Usage

Token usage for a single run. All fields are camelCase — there is no `total_tokens` field.

```typescript
interface Usage {
  readonly inputTokens: number;
  readonly outputTokens: number;
  readonly cacheCreationTokens?: number;
  readonly cacheReadTokens?: number;
}
```

### SessionInfo

Summary returned by `client.listSessions()`.

```typescript
interface SessionInfo {
  readonly sessionId: string;
  readonly sessionRef?: string;
  readonly createdAt: number;
  readonly updatedAt: number;
  readonly messageCount: number;
  readonly totalTokens?: number;
  readonly isActive: boolean;
  readonly model?: string;
  readonly provider?: string;
  readonly lastAssistantText?: string;
  readonly labels: Readonly<Record<string, string>>;
}
```

### Capability

A single runtime capability entry, as returned by `client.capabilities`.

```typescript
interface Capability {
  readonly id: string;
  readonly description: string;
  readonly status: string;  // "Available", "DisabledByPolicy", "NotCompiled", etc.
}
```

Status values may be emitted as externally-tagged Rust enum objects (e.g. `{ DisabledByPolicy: { ... } }`). The SDK normalizes these to the key string automatically.

### ContentBlock

Content blocks are used in multimodal prompts and tool results. Both `createSession()` and `session.turn()` accept `string | ContentBlock[]` as the prompt parameter.

```typescript
type ContentBlock =
  | { type: "text"; text: string }
  | { type: "image"; media_type: string; data: string; source?: "inline" }
  | { type: "image"; media_type: string; source: "blob"; blob_id: string }
  | { type: "video"; media_type: string; duration_ms: number; data: string; source?: "inline" };
```

| Variant | Fields | Description |
|---------|--------|-------------|
| `text` | `text: string` | Plain text content |
| `image` | `media_type: string`, `data: string` | Base64-encoded image with MIME type (e.g. `"image/png"`) |

```typescript
// Multimodal prompt example
const session = await client.createSession([
  { type: "text", text: "Describe this image" },
  { type: "image", media_type: "image/png", data: base64Data },
]);
```

### SchemaWarning

Emitted when a structured output response did not fully conform to the requested schema.

```typescript
interface SchemaWarning {
  readonly provider: string;
  readonly path: string;
  readonly message: string;
}
```

---

## Skill types

### SkillKey

Structured skill identifier.

```typescript
interface SkillKey {
  readonly sourceUuid: string;
  readonly skillName: string;
}
```

### SkillRef

A skill reference is a structured `SkillKey`.

```typescript
type SkillRef = SkillKey;
```

### SkillRuntimeDiagnostics

Runtime diagnostics from the skill subsystem. Present on `RunResult.skillDiagnostics` when the server emits skill health data.

```typescript
interface SkillRuntimeDiagnostics {
  readonly sourceHealth: SourceHealthSnapshot;
  readonly quarantined: readonly SkillQuarantineDiagnostic[];
}

interface SourceHealthSnapshot {
  readonly state: string;
  readonly invalidRatio: number;
  readonly invalidCount: number;
  readonly totalCount: number;
  readonly failureStreak: number;
  readonly handshakeFailed: boolean;
}

interface SkillQuarantineDiagnostic {
  readonly sourceUuid: string;
  readonly skillId: string;
  readonly location: string;
  readonly errorCode: string;
  readonly errorClass: string;
  readonly message: string;
  readonly firstSeenUnixSecs: number;
  readonly lastSeenUnixSecs: number;
}
```

---

## EventStream

`EventStream` is an `AsyncIterable<AgentEvent>` returned by `createSessionStreaming()` and `session.stream()`. It yields typed events as the agent runs, then makes the final `RunResult` available on `stream.result`.

```typescript
class EventStream implements AsyncIterable<AgentEvent> {
  readonly sessionId: string;
  readonly result: RunResult;  // throws if accessed before iteration completes

  [Symbol.asyncIterator](): AsyncGenerator<AgentEvent>;

  /** Consume all events and return the final RunResult. */
  collect(): Promise<RunResult>;

  /** Consume events, accumulate text deltas, return [fullText, result]. */
  collectText(): Promise<[string, RunResult]>;
}
```

### Iterating

```typescript
for await (const event of session.stream("Summarise this")) {
  if (event.type === "text_delta") {
    process.stdout.write(event.delta);
  }
}
const result = stream.result;
```

### collect()

Discards all events and returns the final result:

```typescript
const result = await stream.collect();
```

### collectText()

Accumulates all `text_delta` events and returns the joined string alongside the result:

```typescript
const [fullText, result] = await stream.collectText();
console.log(fullText);
console.log("Output tokens:", result.usage.outputTokens);
```

---

## Typed events

All events are discriminated on the `type` field (snake_case, matching the wire protocol). All other fields are camelCase.

### AgentEvent union

```typescript
type AgentEvent =
  | RunStartedEvent
  | RunCompletedEvent
  | RunFailedEvent
  | TurnStartedEvent
  | TextDeltaEvent
  | TextCompleteEvent
  | ToolCallRequestedEvent
  | ToolResultReceivedEvent
  | TurnCompletedEvent
  | ToolExecutionStartedEvent
  | ToolExecutionCompletedEvent
  | ToolExecutionTimedOutEvent
  | CompactionStartedEvent
  | CompactionCompletedEvent
  | CompactionFailedEvent
  | BudgetWarningEvent
  | RetryingEvent
  | HookStartedEvent
  | HookCompletedEvent
  | HookFailedEvent
  | HookDeniedEvent
  | SkillsResolvedEvent
  | SkillResolutionFailedEvent
  | InteractionCompleteEvent
  | InteractionFailedEvent
  | StreamTruncatedEvent
  | ToolConfigChangedEvent
  | BackgroundJobCompletedEvent
  | UnknownEvent;
```

Unknown event types are surfaced as `UnknownEvent` for forward-compatibility.

### Session lifecycle events

```typescript
interface RunStartedEvent   { type: "run_started";   sessionId: string; prompt: string }
interface RunCompletedEvent { type: "run_completed";  sessionId: string; result: string; usage: Usage }
interface RunFailedEvent    { type: "run_failed";     sessionId: string; error: string }
```

### Turn and LLM events

```typescript
interface TurnStartedEvent        { type: "turn_started";         turnNumber: number }
interface TextDeltaEvent          { type: "text_delta";            delta: string }
interface TextCompleteEvent       { type: "text_complete";         content: string }
interface ToolCallRequestedEvent  { type: "tool_call_requested";   id: string; name: string; args: unknown }
interface ToolResultReceivedEvent { type: "tool_result_received";  id: string; name: string; content: ContentBlock[]; isError: boolean }
interface TurnCompletedEvent      { type: "turn_completed";        stopReason: StopReason; usage: Usage }
```

```typescript
type StopReason =
  | "end_turn"
  | "tool_use"
  | "max_tokens"
  | "stop_sequence"
  | "content_filter"
  | "cancelled";
```

### Tool execution events

```typescript
interface ToolExecutionStartedEvent   { type: "tool_execution_started";    id: string; name: string }
interface ToolExecutionCompletedEvent { type: "tool_execution_completed";   id: string; name: string; result: string; content: ContentBlock[]; isError: boolean; durationMs: number }
interface ToolExecutionTimedOutEvent  { type: "tool_execution_timed_out";   id: string; name: string; timeoutMs: number }
```

### Compaction events

```typescript
interface CompactionStartedEvent   { type: "compaction_started";   inputTokens: number; estimatedHistoryTokens: number; messageCount: number }
interface CompactionCompletedEvent { type: "compaction_completed";  summaryTokens: number; messagesBefore: number; messagesAfter: number }
interface CompactionFailedEvent    { type: "compaction_failed";     error: string }
```

### Budget events

```typescript
interface BudgetWarningEvent { type: "budget_warning"; budgetType: BudgetType; used: number; limit: number; percent: number }

type BudgetType = "tokens" | "time" | "tool_calls";
```

### Retry events

```typescript
interface RetryingEvent { type: "retrying"; attempt: number; maxAttempts: number; error: string; delayMs: number }
```

### Hook events

```typescript
type HookPoint =
  | "run_started" | "run_completed" | "run_failed"
  | "pre_llm_request" | "post_llm_response"
  | "pre_tool_execution" | "post_tool_execution"
  | "turn_boundary";

interface HookStartedEvent        { type: "hook_started";         hookId: string; point: HookPoint }
interface HookCompletedEvent      { type: "hook_completed";        hookId: string; point: HookPoint; durationMs: number }
interface HookFailedEvent         { type: "hook_failed";           hookId: string; point: HookPoint; error: string }
interface HookDeniedEvent         { type: "hook_denied";           hookId: string; point: HookPoint; reasonCode: string; message: string; payload?: unknown }
```

### Skill events

```typescript
interface SkillsResolvedEvent       { type: "skills_resolved";         skills: readonly SkillKey[]; injectionBytes: number }
interface SkillResolutionFailedEvent { type: "skill_resolution_failed"; skillKey?: SkillKey; reason: SkillResolutionFailureReason; reference: string; error: string }
```

### Comms events

```typescript
interface InteractionCompleteEvent { type: "interaction_complete"; interactionId: string; result: string }
interface InteractionFailedEvent   { type: "interaction_failed";   interactionId: string; error: string }
```

### Tool config events

```typescript
interface ToolConfigChangedEvent { type: "tool_config_changed"; payload: ToolConfigChangedPayload }

interface ToolConfigChangedPayload {
  operation: "add" | "remove" | "reload";
  target: string;
  status: string;
  statusInfo?: ToolConfigChangeStatus;
  persisted: boolean;
  appliedAtTurn?: number;
}

type ToolConfigChangeStatus =
  | { kind: "boundary_applied"; baseChanged: boolean; visibleChanged: boolean; revision: number }
  | { kind: "deferred_catalog_delta"; addedHiddenCount: number; removedHiddenCount: number; pendingSourceCount: number }
  | { kind: "warning_failed_closed"; error: string }
  | { kind: "external_tool_delta"; phase: "pending" | "applied" | "draining" | "forced" | "failed"; detail?: string };
```

### Background job events

```typescript
type BackgroundJobTerminalStatus =
  | "completed"
  | "failed"
  | "aborted"
  | "cancelled"
  | "retired"
  | "terminated";

interface BackgroundJobCompletedEvent {
  type: "background_job_completed";
  jobId: string;
  displayName: string;
  terminalStatus: BackgroundJobTerminalStatus;
  legacyStatus?: string;
  detail: string;
}
```

`terminalStatus` is the semantic status. `legacyStatus` is the optional wire `status` display mirror.

### Stream management

```typescript
interface StreamTruncatedEvent { type: "stream_truncated"; reason: string }
```

### Type guard utilities

The SDK exports type guards for the most commonly used events:

```typescript
import {
  isTextDelta,
  isTextComplete,
  isTurnCompleted,
  isToolCallRequested,
  isRunCompleted,
  isRunFailed,
} from "@rkat/sdk";

for await (const event of session.stream("prompt")) {
  if (isTextDelta(event)) {
    process.stdout.write(event.delta);  // TypeScript knows event.delta exists
  }
  if (isTurnCompleted(event)) {
    console.log(event.stopReason, event.usage.inputTokens);
  }
}
```

---

## Error handling

All errors extend `MeerkatError`. Catch it as a base class or use the specific subclasses for targeted handling.

```typescript
import { MeerkatError, CapabilityUnavailableError } from "@rkat/sdk";

try {
  await client.connect();
  const session = await client.createSession("Hello");
  await session.turn("Next");
} catch (err) {
  if (err instanceof CapabilityUnavailableError) {
    console.error("Missing capability:", err.message, err.capabilityHint);
  } else if (err instanceof MeerkatError) {
    console.error(`[${err.code}] ${err.message}`);
  }
} finally {
  await client.close();
}
```

### Error classes

```typescript
class MeerkatError extends Error {
  readonly code: string;
  readonly details?: unknown;
  readonly capabilityHint?: { capability_id: string; message: string };
}

class CapabilityUnavailableError extends MeerkatError {}
class SessionNotFoundError extends MeerkatError {}
class SkillNotFoundError extends MeerkatError {}
```

| Class | When thrown |
|-------|-------------|
| `MeerkatError` | Base class for all SDK errors |
| `CapabilityUnavailableError` | `client.requireCapability()` or `session.invokeSkill()` when the required capability is not available |
| `SessionNotFoundError` | Server reports that the requested session does not exist |
| `SkillNotFoundError` | Server reports that a skill reference cannot be resolved |

### Common error codes

| Code | Cause |
|------|-------|
| `NOT_CONNECTED` | Method called before `connect()` |
| `VERSION_MISMATCH` | Server contract version incompatible with SDK |
| `CAPABILITY_UNAVAILABLE` | Required capability not enabled in this build |
| `CLIENT_CLOSED` | Method called after `close()` |
| `STREAM_NOT_CONSUMED` | `stream.result` accessed before iteration completed |
| `BINARY_NOT_FOUND` | `rkat-rpc` not found and auto-download failed |

---

## Skills

Both `createSession()` and `session.turn()` accept structured skill parameters.

```typescript
// Preload skills into the system prompt at session creation
const session = await client.createSession("Hello!", {
  preloadSkills: [
    { sourceUuid: "dc256086-0d2f-4f61-a307-320d4148107f", skillName: "extraction-email" },
    { sourceUuid: "dc256086-0d2f-4f61-a307-320d4148107f", skillName: "formatting-markdown" },
  ],
});

// Inject a skill for a specific turn via session.turn()
const result = await session.turn("Extract emails from this text", {
  skillRefs: [{ sourceUuid: "abc123", skillName: "extraction-email" }],
});

// Convenience method on Session — wraps turn() with requireCapability check
const result2 = await session.invokeSkill(
  { sourceUuid: "abc123", skillName: "extraction-email" },
  "Extract emails from this text",
);
```

---

## Version compatibility

```typescript
import { CONTRACT_VERSION } from "@rkat/sdk";
console.log(CONTRACT_VERSION);  // "0.6.19"
```

- While the major version is `0`, minor versions must match exactly between SDK and server.
- From `1.0.0` onwards, standard semver applies: major versions must match.

Version checking happens automatically during `connect()`. A `MeerkatError` with code `VERSION_MISMATCH` is thrown if versions are incompatible.

---

## See also

- [TypeScript SDK overview](/sdks/typescript/overview) - getting started, client and session API
- [Python SDK](/sdks/python/overview) - Python SDK
- [RPC reference](/api/rpc) - JSON-RPC protocol specification
