Skip to main content
All public types use camelCase field names. The SDK translates to and from the snake_case JSON-RPC wire format internally.

Imports

Everything public is re-exported from the package root:
import {
  MeerkatClient,
  Session,
  Mob,
  EventStream,
  EventSubscription,
  MeerkatError,
  CapabilityUnavailableError,
  SessionNotFoundError,
  SkillNotFoundError,
  CONTRACT_VERSION,
} from "@rkat/sdk";

import type {
  RunResult,
  Usage,
  SessionInfo,
  SessionOptions,
  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";

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(...).

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: string;
  readonly updatedAt: string;
  readonly messageCount: number;
  readonly totalTokens: number;
  readonly isActive: boolean;
}

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 };
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. Preferred over legacy string references.
interface SkillKey {
  readonly sourceUuid: string;
  readonly skillName: string;
}

SkillRef

A skill reference is either a SkillKey or a legacy string in the form "<source_uuid>/<skill_name>". Legacy strings emit a deprecation warning.
type SkillRef = SkillKey | string;

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
  | HookRewriteAppliedEvent
  | HookPatchPublishedEvent
  | SkillsResolvedEvent
  | SkillResolutionFailedEvent
  | InteractionCompleteEvent
  | InteractionFailedEvent
  | StreamTruncatedEvent
  | ToolConfigChangedEvent
  | 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; 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; 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 }
interface HookRewriteAppliedEvent { type: "hook_rewrite_applied";  hookId: string; point: HookPoint; patch: Record<string, unknown> }
interface HookPatchPublishedEvent { type: "hook_patch_published";  hookId: string; point: HookPoint; envelope: Record<string, unknown> }

Skill events

interface SkillsResolvedEvent       { type: "skills_resolved";         skills: readonly string[]; injectionBytes: number }
interface SkillResolutionFailedEvent { type: "skill_resolution_failed"; 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;
  persisted: boolean;
  appliedAtTurn?: number;
}

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 skill parameters. Use SkillKey objects (preferred) or legacy strings.
// Preload skills into the system prompt at session creation
const session = await client.createSession("Hello!", {
  preloadSkills: ["extraction/email", "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);  // e.g. "0.5.0"
  • 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