SDKS

Python SDK.

actae-client — the full Actae surface in async-first Python, with a sync bridge, WebSocket streaming, AgentSession, and framework adapters.

Install

$ pip install actae-client

Requires Python 3.9+ and aiohttp. Framework adapters (LangGraph, Claude, OpenAI Agents, CrewAI, LangChain) are optional extras.

Quick start

python
import asyncio
from actae_client import ActaeClient

async def main():
    async with ActaeClient(endpoint="http://localhost:8002", api_key="sk-…") as client:
        event = await client.record("my-channel", "agent.step",
            payload={"input": "hello"}, actor="agent")
        print(f"cursor={event.cursor}")

        events = await client.replay("my-channel", cursor=0)
        for e in events:
            print(f"[{e.cursor}] {e.event_type}")

asyncio.run(main())

endpoint alone is enough to derive the WebSocket URL (http://ws://…/ws). The client is an async context manager — use it as one unless you need manual lifecycle control.

Which API should I use?

Use caseStart here
Log what an agent didevents.record(channel, type, payload, actor=…)
Record an event and its state atomicallyevents.transition(…)
Replay / query what happenedevents.replay(…), events.query(…)
Watch events livews.stream(channel) or ws.subscribe(…)
High-level session (steps, forks, resume)AgentSession
Fork a channel into brancheschannels.fork(…)
Durable worker consuming a channelgroups.*
Exactly-once tool callsexecutions.claim_execution(…)
Schedule a future eventwakeups.schedule_wakeup(…)
Prove which fork fixed a failurechannels.diff_states(left, right)

Every method exists on the client (client.record(…)) and on a namespaced facade (client.events.record(…)) — same calls, pick what reads better.

Real time

python
async with ActaeClient(endpoint=..., api_key=..., echo_self=True) as client:
    async for event in client.stream("my-channel"):
        print(f"[{event.cursor}] {event.event_type}")

    client.on_message(lambda topic, event: print(topic, event.event_type))
    await client.subscribe("my-channel")  # wait=True by default
    await client.publish("my-channel", {"hello": "world"})
  • Both forms block until events arrive — a live stream never finishes.
  • on_message callbacks accumulate; other callbacks are single-slot.
  • The server does not echo publishes back to the publishing connection — use echo_self=True for single-client demos.
  • Auto-reconnect resumes all topics from their last cursors (no gaps, no duplicates).

Sync code? No problem.

The most common calls have blocking variants (record_sync, replay_sync, transition_sync, fork_sync, latest_state_sync, disconnect_sync, …) — each runs on its own per-thread background loop, so sync and async use can mix freely. WebSocket, groups, executions, wake-ups, and AgentSession are async-only.

Sessions, adapters, and errors

AgentSession instruments whole runs: step/fork/resume with deterministic operation IDs, inherited state, and strict boundary modes. Adapters: StateManager, ActaeCheckpointSaver (LangGraph), ActaeCrewStateHook/CrewAIResumer, ActaeContextSaver/ChainResumer (LangChain), ActaeClaudeSessionStore/ActaeClaudeHook, and install_actae_tracing (OpenAI Agents).

Errors are typed: AuthError (401), RateLimitError (429), ActaeConnectionError (transport — never shadows builtins.ConnectionError), SessionError/SessionCompletedError/NoRestorableCheckpointError, and APIError for the rest.