Skip to main content

RunResult

RunResult is returned by session.turn(), session.invoke_skill(), and deferred.start_turn(). Session creation returns runtime-backed Session or DeferredSession wrappers, and the latest RunResult remains available through session.last_result or events.result after consuming an EventStream.
from meerkat import RunResult
session_id
str
Session UUID.
text
str
Assistant response text.
turns
int
Number of LLM turns completed.
tool_calls
int
Number of tool calls made.
usage
Usage
Token usage breakdown.
session_ref
str | None
Optional human-readable session reference.
structured_output
Any | None
Parsed structured output, if an output_schema was provided.
schema_warnings
list[SchemaWarning] | None
Schema validation warnings emitted by the provider.
skill_diagnostics
SkillRuntimeDiagnostics | None
Runtime diagnostics from the skill subsystem, when present.

Session

client.create_session() returns a runtime-backed Session wrapper.
from meerkat import Session
id
str
Stable session UUID used by the runtime.
ref
str | None
Optional human-readable session reference.
text
str
Assistant text from the most recent turn.
usage
Usage
Token usage from the most recent turn.
turns
int
Number of LLM turns in the most recent run.
tool_calls
int
Number of tool calls in the most recent run.
structured_output
Any | None
Structured output from the most recent run, if present.
last_result
RunResult
Cached result from the most recent runtime-backed turn.
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.invoke_skill(...)
  • await session.subscribe_events()

DeferredSession

client.create_deferred_session() returns a DeferredSession when you want to allocate session identity now and run the first turn later.
from meerkat import DeferredSession
id
str
Stable session UUID reserved by the runtime.
ref
str | None
Optional human-readable session reference.
Use await deferred.start_turn(...) to execute the first turn through the same runtime-backed path as any other session.

Usage

Usage is a frozen dataclass describing token consumption for a single LLM turn. It appears on RunResult.usage and on the TurnCompleted and RunCompleted events.
from meerkat import Usage
input_tokens
int
Input tokens consumed.
output_tokens
int
Output tokens generated.
cache_creation_tokens
int | None
Tokens used to write to the prompt cache (provider-specific).
cache_read_tokens
int | None
Tokens read from the prompt cache (provider-specific).

SessionInfo

Returned by client.list_sessions().
from meerkat import SessionInfo
session_id
str
Session UUID.
session_ref
str | None
Optional human-readable reference.
created_at
str
ISO 8601 creation timestamp.
updated_at
str
ISO 8601 last-updated timestamp.
message_count
int
Number of messages in the session.
total_tokens
int
Cumulative tokens consumed.
is_active
bool
Whether a turn is currently in progress.

Capability

Returned as elements of client.capabilities.
from meerkat import Capability
id
str
Capability identifier (e.g. "shell", "comms", "skills").
description
str
Human-readable description.
status
str
Availability status string. Normalised from Rust-tagged enums to a plain string by the SDK.
available
bool
Convenience property — True when status == "Available".

Checking capabilities

Capability inspection is done directly on the client — there is no separate checker class.
# Property: list[Capability] populated during connect()
for cap in client.capabilities:
    if cap.available:
        print(f"{cap.id}: {cap.description}")

# Boolean check
if client.has_capability("shell"):
    ...

# Guarded code path — raises CapabilityUnavailableError if not available
client.require_capability("comms")

Skill types

SkillKey

from meerkat import SkillKey

key = SkillKey(source_uuid="abc123", skill_name="code-review")
source_uuid
str
UUID of the skill source.
skill_name
str
Name of the skill within the source.

SkillRef

SkillRef = Union[SkillKey, str]
Wherever a skill reference is accepted (e.g. session.invoke_skill(), turn(skill_refs=...)) you can pass either a SkillKey or a legacy string of the form "<source_uuid>/<skill_name>". Legacy strings emit a DeprecationWarning.

Multimodal prompts

All prompt parameters (create_session, turn, stream, create_session_streaming) accept str | list[dict]:
  • str — plain text prompt (backwards compatible).
  • list[dict] — a list of content blocks for multimodal input. Each block is a dict with a "type" key:
    • {"type": "text", "text": "..."} — text content.
    • {"type": "image", "media_type": "image/png", "data": "<base64>"} — base64-encoded image content.
# Text-only (unchanged)
session = await client.create_session("Describe this project")

# Multimodal with image
session = await client.create_session([
    {"type": "text", "text": "What is in this screenshot?"},
    {"type": "image", "media_type": "image/png", "data": base64_png},
])

# Multimodal turn
result = await session.turn([
    {"type": "text", "text": "Now analyze this second image:"},
    {"type": "image", "media_type": "image/jpeg", "data": base64_jpg},
])

Diagnostic types

SchemaWarning

from meerkat import SchemaWarning
provider
str
Provider that emitted the warning.
path
str
JSON path to the offending schema location.
message
str
Warning message.

SkillRuntimeDiagnostics

from meerkat import SkillRuntimeDiagnostics, SourceHealthSnapshot, SkillQuarantineDiagnostic
Present on RunResult.skill_diagnostics when the skill subsystem emits diagnostics.
source_health
SourceHealthSnapshot
Health snapshot for skill source resolution.
quarantined
list[SkillQuarantineDiagnostic]
Skills that have been quarantined due to repeated failures.
SourceHealthSnapshot fields: state, invalid_ratio, invalid_count, total_count, failure_streak, handshake_failed. SkillQuarantineDiagnostic fields: source_uuid, skill_id, location, error_code, error_class, message, first_seen_unix_secs, last_seen_unix_secs.

EventStream

EventStream is an async context manager returned by session.stream() and client.create_session_streaming(). Iterating it yields typed Event subclass instances.
from meerkat import EventStream
session.stream() and client.create_session_streaming() are synchronous — they return an EventStream directly. The JSON-RPC request is sent when entering the async with block.

Properties

session_id
str
Session UUID. For create_session_streaming, this is set after the response arrives (once __aenter__ has flushed the request).
result
RunResult
The final result. Available only after the stream has been fully consumed. Raises MeerkatError("STREAM_NOT_CONSUMED") if accessed beforehand.

Usage patterns

# Pattern matching on typed events
async with session.stream("Explain monads") as events:
    async for event in events:
        match event:
            case TextDelta(delta=chunk):
                print(chunk, end="", flush=True)
            case ToolCallRequested(name=name, args=args):
                print(f"\nCalling tool: {name} with args: {args}")
            case TurnCompleted(usage=u):
                print(f"\nTokens: {u.input_tokens} in / {u.output_tokens} out")
            case _:
                pass
    result = events.result
# Consume silently, get RunResult
result = await session.stream("prompt").collect()

# Accumulate text, get (full_text, RunResult)
text, result = await session.stream("prompt").collect_text()

Typed events

All events are frozen dataclasses. Import them from the top-level meerkat package.
from meerkat import (
    Event,
    RunStarted, RunCompleted, RunFailed,
    TurnStarted, TurnCompleted,
    TextDelta, TextComplete,
    ToolCallRequested, ToolResultReceived,
    ToolExecutionStarted, ToolExecutionCompleted, ToolExecutionTimedOut,
    CompactionStarted, CompactionCompleted, CompactionFailed,
    BudgetWarning,
    Retrying,
    HookStarted, HookCompleted, HookFailed, HookDenied,
    HookRewriteApplied, HookPatchPublished,
    SkillsResolved, SkillResolutionFailed,
    InteractionComplete, InteractionFailed,
    StreamTruncated,
    ToolConfigChanged, ToolConfigChangedPayload,
    UnknownEvent,
)

Session lifecycle

Agent run has started.
session_id
str
Session UUID.
prompt
str
The prompt that started this run.
Agent run completed successfully.
session_id
str
Session UUID.
result
str
Final result text.
usage
Usage
Token usage for this run.
Agent run failed.
session_id
str
Session UUID.
error
str
Error description.

LLM turn events

A new LLM turn has begun.
turn_number
int
1-based turn index within the current run.
An incremental text chunk streamed from the LLM. Handle these to display output in real time.
delta
str
The text chunk.
Full assistant text for the current turn, emitted after streaming finishes.
content
str
The complete text.
The LLM wants to invoke a tool.
id
str
Tool call identifier.
name
str
Tool name.
args
Any
Parsed tool arguments.
A tool result was fed back to the LLM.
id
str
Tool call identifier.
name
str
Tool name.
is_error
bool
True if the tool returned an error result.
An LLM turn finished.
stop_reason
str
The stop reason reported by the LLM provider (e.g. "end_turn", "tool_use").
usage
Usage
Token usage for this turn.

Tool execution events

id
str
Tool call identifier.
name
str
Tool name.
id
str
Tool call identifier.
name
str
Tool name.
result
str
Tool output (truncated for large results).
is_error
bool
True if the tool execution resulted in an error.
duration_ms
int
Execution duration in milliseconds.
id
str
Tool call identifier.
name
str
Tool name.
timeout_ms
int
The configured timeout threshold in milliseconds.

Compaction events

Context compaction has begun to free up context window space.
input_tokens
int
Token count before compaction.
estimated_history_tokens
int
Estimated history tokens subject to compaction.
message_count
int
Number of messages before compaction.
summary_tokens
int
Tokens in the compacted summary.
messages_before
int
Message count before compaction.
messages_after
int
Message count after compaction.
error
str
Failure description.

Budget and retry events

A budget threshold has been crossed.
budget_type
str
Budget category (e.g. "tokens", "turns").
used
int
Current usage.
limit
int
Configured limit.
percent
float
Usage as a percentage of the limit.
An LLM request is being retried after a transient failure.
attempt
int
Current attempt number (1-based).
max_attempts
int
Maximum configured attempts.
error
str
The error that triggered the retry.
delay_ms
int
Backoff delay before this attempt in milliseconds.

Hook events

Lifecycle events for hook invocations.
hook_id
str
Hook identifier.
point
str
Hook point (e.g. "pre_turn", "post_turn").
duration_ms
int
HookCompleted only — execution duration.
error
str
HookFailed only — failure description.
A hook denied the current operation.
hook_id
str
Hook identifier.
point
str
Hook point.
reason_code
str
Machine-readable denial reason.
message
str
Human-readable denial message.
payload
Any
Additional context from the hook.
Hook mutation events.
hook_id
str
Hook identifier.
point
str
Hook point.
patch
dict
Applied patch (HookRewriteApplied) or published envelope (HookPatchPublished).

Skill events

Skills were resolved and injected for this turn.
skills
list[str]
List of resolved skill identifiers.
injection_bytes
int
Bytes of skill content injected into the context.
A skill reference could not be resolved.
reference
str
The skill reference that failed.
error
str
Failure description.

Comms events

Comms interaction lifecycle events.
interaction_id
str
Interaction identifier.
result
str
InteractionComplete only — interaction result.
error
str
InteractionFailed only — failure description.

Forward compatibility

Emitted when the server sends an event type not recognised by this SDK version. Inspect type and data to handle it manually.
type
str
The wire discriminator string.
data
dict
The raw event payload.

Error handling

All errors inherit from MeerkatError.
from meerkat import MeerkatError, CapabilityUnavailableError, SessionNotFoundError, SkillNotFoundError
ClassDescription
MeerkatErrorBase error with code, message, details, capability_hint
CapabilityUnavailableErrorRequired capability not available
SessionNotFoundErrorSession not found
SkillNotFoundErrorSkill reference cannot be resolved

Client-side error codes

CodeDescription
BINARY_NOT_FOUNDrkat-rpc binary not found on PATH and auto-download failed
BINARY_DOWNLOAD_FAILEDAutomatic binary download failed
NOT_CONNECTEDOperation attempted before connect()
CONNECTION_CLOSEDrkat-rpc process closed unexpectedly
VERSION_MISMATCHServer contract version incompatible with SDK
CAPABILITY_UNAVAILABLECapability check failed via require_capability()
STREAM_NOT_CONSUMEDEventStream.result accessed before the stream was iterated
INVALID_ARGSMutually exclusive options provided (e.g. realm_id + isolated)

Server-side error codes

CodeJSON-RPC codeDescription
SESSION_NOT_FOUND-32001Session does not exist
SESSION_BUSY-32002Turn already in progress
PROVIDER_ERROR-32010LLM provider error
BUDGET_EXHAUSTED-32011Budget exceeded
HOOK_DENIED-32012Hook blocked operation
AGENT_ERROR-32013Internal agent error
INVALID_PARAMS-32602Invalid method parameters

Example

from meerkat import MeerkatClient, MeerkatError, CapabilityUnavailableError

async def main():
    async with MeerkatClient() as client:
        session = await client.create_session("Hello!")

        try:
            result = await session.turn("Follow up")
        except MeerkatError as e:
            print(f"Error code: {e.code}")
            print(f"Message: {e.message}")

        try:
            client.require_capability("comms")
        except CapabilityUnavailableError as e:
            print(f"Comms not available: {e.message}")

Version compatibility

The SDK negotiates version compatibility during connect():
  • 0.x: Requires exact minor version match (SDK 0.2.0 works with server 0.2.x)
  • 1.0+: Requires same major version
from meerkat import CONTRACT_VERSION
print(CONTRACT_VERSION)  # e.g. "0.5.0"

Running tests

pip install -e "sdks/python[dev]"

# Type conformance tests (no rkat binary needed)
pytest sdks/python/tests/test_types.py -v

# E2E tests (requires rkat on PATH)
pytest sdks/python/tests/test_e2e.py -v

# E2E smoke tests (requires rkat + ANTHROPIC_API_KEY)
pytest sdks/python/tests/test_e2e_smoke.py -v

See also