Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.rkat.ai/llms.txt

Use this file to discover all available pages before exploring further.

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

Imports

Everything public is re-exported from the package root:
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.
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;
}
FieldTypeDescription
sessionIdstringStable UUID for this session
sessionRefstring | undefinedOptional human-readable reference
textstringFull assistant text from the last LLM turn
turnsnumberNumber of LLM turns in this run
toolCallsnumberTotal tool calls executed in this run
usageUsageToken usage for this run
structuredOutputunknown | undefinedParsed structured output when outputSchema was provided
schemaWarningsSchemaWarning[] | undefinedWarnings emitted when structured output didn’t fully match the schema
skillDiagnosticsSkillRuntimeDiagnostics | undefinedRuntime diagnostics from the skill subsystem

Session

client.createSession() returns a runtime-backed Session wrapper.
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.
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.
interface Usage {
  readonly inputTokens: number;
  readonly outputTokens: number;
  readonly cacheCreationTokens?: number;
  readonly cacheReadTokens?: number;
}

SessionInfo

Summary returned by client.listSessions().
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.
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.
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" };
VariantFieldsDescription
texttext: stringPlain text content
imagemedia_type: string, data: stringBase64-encoded image with MIME type (e.g. "image/png")
// 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.
interface SchemaWarning {
  readonly provider: string;
  readonly path: string;
  readonly message: string;
}

Skill types

SkillKey

Structured skill identifier.
interface SkillKey {
  readonly sourceUuid: string;
  readonly skillName: string;
}

SkillRef

A skill reference is a structured SkillKey.
type SkillRef = SkillKey;

SkillRuntimeDiagnostics

Runtime diagnostics from the skill subsystem. Present on RunResult.skillDiagnostics when the server emits skill health data.
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.
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

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:
const result = await stream.collect();

collectText()

Accumulates all text_delta events and returns the joined string alongside the result:
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

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

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

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 }
type StopReason =
  | "end_turn"
  | "tool_use"
  | "max_tokens"
  | "stop_sequence"
  | "content_filter"
  | "cancelled";

Tool execution events

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

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

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

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

Retry events

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

Hook events

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

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

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

Tool config events

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

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

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

Type guard utilities

The SDK exports type guards for the most commonly used events:
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.
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

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 {}
ClassWhen thrown
MeerkatErrorBase class for all SDK errors
CapabilityUnavailableErrorclient.requireCapability() or session.invokeSkill() when the required capability is not available
SessionNotFoundErrorServer reports that the requested session does not exist
SkillNotFoundErrorServer reports that a skill reference cannot be resolved

Common error codes

CodeCause
NOT_CONNECTEDMethod called before connect()
VERSION_MISMATCHServer contract version incompatible with SDK
CAPABILITY_UNAVAILABLERequired capability not enabled in this build
CLIENT_CLOSEDMethod called after close()
STREAM_NOT_CONSUMEDstream.result accessed before iteration completed
BINARY_NOT_FOUNDrkat-rpc not found and auto-download failed

Skills

Both createSession() and session.turn() accept structured skill parameters.
// 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

import { CONTRACT_VERSION } from "@rkat/sdk";
console.log(CONTRACT_VERSION);  // "0.6.5"
  • 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