Agents
Generated from the type stubs and docstrings. Do not edit by hand.
APIKeyAuth
Section titled “APIKeyAuth”FastAPI dependency that validates a static Bearer token.
Usage::
router = AgentRouter(worker=..., config=AgentRouterConfig(auth_config=AuthConfig(provider=APIKeyAuth("sk-proj-xxx"))))AgentClient
Section titled “AgentClient”Async HTTP client for Pyrula agents.
submit
Section titled “submit”submit(self, agent_name: str, metadata: Optional[dict[str, Any]] = None, idempotency_key: Optional[str] = None, headers: Optional[dict[str, str]] = None, **params: Any) -> TurnHandlestream
Section titled “stream”stream(self, agent_name: str, turn_id: str, last_event_id: Optional[str] = None, headers: Optional[dict[str, str]] = None, idle_timeout_seconds: Optional[float] = None) -> AsyncIterator[Event]stream_from_path
Section titled “stream_from_path”stream_from_path(self, stream_path: str, last_event_id: Optional[str] = None, headers: Optional[dict[str, str]] = None, idle_timeout_seconds: Optional[float] = None) -> AsyncIterator[Event]replay
Section titled “replay”replay(self, agent_name: str, turn_id: str, headers: Optional[dict[str, str]] = None) -> AsyncIterator[Event]stream_with_replay_fallback
Section titled “stream_with_replay_fallback”stream_with_replay_fallback(self, agent_name: str, turn_id: str, last_event_id: Optional[str] = None, headers: Optional[dict[str, str]] = None, include_overflow_event: bool = False) -> AsyncIterator[Event]Stream live events, falling back to replay when the live cursor is stale.
This is useful when reconnecting with a saved Last-Event-ID that may
have fallen behind the retained live stream window. In that case the live
stream emits stream:overflow; this helper can switch to replay()
automatically.
run(self, agent_name: str, metadata: Optional[dict[str, Any]] = None, idempotency_key: Optional[str] = None, headers: Optional[dict[str, str]] = None, **params: Any) -> list[Event]Submit a turn and collect all events until the terminal event.
cancel
Section titled “cancel”cancel(self, agent_name: str, turn_id: str, headers: Optional[dict[str, str]] = None) -> Nonestatus
Section titled “status”status(self, agent_name: str, turn_id: str, headers: Optional[dict[str, str]] = None) -> TurnStatusInfoAgentContext
Section titled “AgentContext”Agent execution context extending BaseContext with LLM/stream/tool-loop.
Inherits from pyrula.workflows BaseContext: step, sleep, signal, timers, determinism, checkpoint, emit, emit_status, interrupt.
Adds agent-only: call_agent, gather, memory, thread, llm.
Fields:
llm: Any = Nonestate: Optional[TurnState] = Nonecancelled: boolturn_id: strmemory: Anythread: Optional[ThreadHandle]
mcp_tools
Section titled “mcp_tools”mcp_tools(self, server: Optional[str] = None) -> list[Any]Discovered MCP tool callables to splat into ctx.llm.stream(tools=[…]).
Live: the worker pool’s tools for one server (or all when server is None). Replay with a dead server: stub callables named from the run’s recorded tool_use names, so tool_map matches the recorded run.
server=None means “all MCP tools”: the live pool’s tools, or on replay
the recorded MCP tool_use names, or [] when no MCP is configured (asking for
all tools is empty, not an error). A named, unconnected server raises.
emit_status
Section titled “emit_status”emit_status(self, text: str) -> TurnEventemit(self, kind: str, payload: dict[str, Any], id: Optional[str] = None) -> TurnEventsleep_until
Section titled “sleep_until”sleep_until(self, dt: datetime) -> Nonewait_for_signal
Section titled “wait_for_signal”wait_for_signal(self, name: str) -> Signalinterrupt
Section titled “interrupt”interrupt(self, event_id: str, payload: dict[str, Any]) -> InterruptResponsecall_agent
Section titled “call_agent”call_agent(self, agent_fn: Any, llm: Optional[Any] = None, id: Optional[str] = None, **kwargs: Any) -> Anygather
Section titled “gather”gather(self, *calls: tuple[Any, dict[str, Any]], id: Optional[str] = None, poll_interval: float = 0.5) -> list[Any]spawn_workflow
Section titled “spawn_workflow”spawn_workflow(self, name: str, params: Optional[dict[str, Any]] = None) -> strSubmit a @workflow run; returns run_id immediately.
wait_for_workflow
Section titled “wait_for_workflow”wait_for_workflow(self, name: str, run_id: str, poll_interval: float = 0.5) -> AnyPoll the store until a spawned workflow completes.
Returns the workflow result on success.
Raises RuntimeError if the workflow ended with an error event.
Recognises run:complete/run:error event kinds so it works
regardless of which runner executes the spawned workflow.
AgentLimits
Section titled “AgentLimits”Fields:
max_tool_calls: Optional[int] = Nonemax_llm_calls: Optional[int] = DEFAULT_MAX_LLM_CALLSmax_agent_depth: Optional[int] = Nonemax_parallel_subagents: Optional[int] = Nonemax_event_count_per_turn: Optional[int] = Nonemax_event_payload_bytes: Optional[int] = Nonemax_turn_wall_seconds: Optional[float] = None
AgentRegistrationError
Section titled “AgentRegistrationError”AgentRouter
Section titled “AgentRouter”FastAPI router that exposes pyrula.agents over HTTP with SSE streaming.
Fields:
get_stream = get_streamget_replay = get_replayget_status = get_statusdelete_cancel = delete_cancelpost_resume = post_resumepost_signal = post_signalpost_create_thread = post_create_threadget_thread = get_threaddelete_thread = delete_threadget_thread_turns = get_thread_turnsget_agents = get_agentsget_runs = get_runsconnector_state: Optional[str]Pyrula Cloud connector state, or None when cloud is not active.draining: boolTrue after lifespan shutdown begins; used by readiness probes.
ping_store
Section titled “ping_store”ping_store(self) -> NonePing the backing store. Raises StoreUnavailable if unreachable.
attach
Section titled “attach”attach(self, app: Any, prefix: str = '') -> NoneMount the router on a FastAPI app and compose lifespans.
lifespan
Section titled “lifespan”lifespan(self) -> AsyncGenerator[None, None]Embedded-mode startup (recovery) and shutdown (drain + cancel).
apply_redaction_hook
Section titled “apply_redaction_hook”apply_redaction_hook(store: Any, hook: Callable[[str, dict[str, Any]], dict[str, Any]]) -> NonePatch store.append_event in-place to fire hook for every event.
Only intercepts appends through this store instance. Raises ValueError if a hook is already installed to prevent silent hook-chaining.
AgentRouterConfig
Section titled “AgentRouterConfig”Configuration for AgentRouter.
Grouped config replaces the 15+ individual constructor parameters. Individual params still work for backward compatibility.
Fields:
sse_keepalive_interval: float = 15.0reporter: Any = Nonecloud: bool = Truemax_queue_depth: Optional[int] = Noneidempotency_ttl_s: float = 86400.0redaction_hook: Optional[Callable[[str, dict[str, Any]], dict[str, Any]]] = Noneheartbeat_config: Optional[ReaderHeartbeatConfig] = Noneauth_config: Optional[AuthConfig] = Nonedeps: Any = Nonedeps_factory: Optional[Callable[..., Any]] = None
AnthropicLLM
Section titled “AnthropicLLM”Anthropic Messages API adapter.
Fields:
provider = 'anthropic'model = modelstreaming_mode = streaming_modemax_buffer_bytes = max_buffer_bytesmax_retries = max_retriesretry_delay = retry_delaymax_tokens = max_tokens
stream
Section titled “stream”stream(self, messages: list[dict[str, Any]], tools: Optional[list[ToolDefinition]] = None, system: Optional[str] = None, tool_choice: Optional[dict[str, Any]] = None) -> AsyncGenerator[ContentBlock, None]complete
Section titled “complete”complete(self, messages: list[dict[str, Any]], system: Optional[str] = None) -> strAppOptions
Section titled “AppOptions”Fields:
prefix: str = '/agents'auth: Any = UNSETdeployment_mode: Optional[str] = Nonesse_keepalive_interval: float = 15.0cancel_on_reader_disconnect: bool = Falseinclude_health: bool = Trueinclude_ready: bool = Truehealth_path: str = '/healthz'ready_path: str = '/readyz'reporter: Optional[Reporter] = Nonemax_queue_depth: Optional[int] = Nonedeps: Any = Nonecloud: bool = Trueredaction_hook: Optional[Callable[[str, dict[str, Any]], dict[str, Any]]] = Noneidempotency_ttl_s: float = 86400.0cors_origins: Optional[list[str]] = None
ConfigurationError
Section titled “ConfigurationError”ErrorCode
Section titled “ErrorCode”Fields:
STORE_UNAVAILABLE = 'store_unavailable'STREAM_TOO_LARGE = 'stream_too_large'TURN_TIMEOUT = 'turn_timeout'VERSION_SKEW = 'version_skew'CANCELLED = 'cancelled'PAUSED = 'paused'TOOL_ERROR = 'tool_error'BUDGET_EXCEEDED = 'budget_exceeded'AGENT_ERROR = 'agent_error'BUFFER_OVERFLOW = 'buffer_overflow'LLM_ERROR = 'llm_error'LLM_RATE_LIMITED = 'llm_rate_limited'LLM_PROVIDER_UNAVAILABLE = 'llm_provider_unavailable'POISON_QUARANTINE = 'poison_quarantine'MAX_RETRIES = 'max_retries'OUTPUT_VALIDATION = 'output_validation'AUTH_MISSING = 'auth_missing'AUTH_INVALID = 'auth_invalid'AUTH_FORBIDDEN = 'auth_forbidden'NOT_FOUND = 'not_found'INVALID_REQUEST = 'invalid_request'BACKPRESSURE_REJECTED = 'backpressure_rejected'IDEMPOTENCY_CONFLICT = 'idempotency_conflict'INTERNAL = 'internal'INTERRUPT_TIMEOUT = 'interrupt_timeout'
LifecycleAdapter
Section titled “LifecycleAdapter”Run-neutral lifecycle + event-log view over a pyrula.agents turn-scoped store.
Implements both core ABCs in one object. The engine holds a single
reference; mixin methods (cache_get, cache_set, set_thread_completed,
get_sleeping_turns, wake_turn, …) pass through via __getattr__.
Idempotent: LifecycleAdapter(LifecycleAdapter(store)) returns the
existing adapter (no double-wrap).
When the underlying store is a core store (with run_* naming), the run_* methods delegate directly; turn_* aliases still work by remapping to run_*.
Fields:
raw: Store
submit_turn
Section titled “submit_turn”submit_turn(self, name: str, turn_id: str, params: dict[str, object], **kwargs: Any) -> strclaim_next_turn
Section titled “claim_next_turn”claim_next_turn(self, name: str, worker_id: str) -> Optional[str]claim_run
Section titled “claim_run”claim_run(self, name: str, run_id: str, worker_id: str) -> Nonerelease_turn
Section titled “release_turn”release_turn(self, name: str, turn_id: str, **kwargs: Any) -> Nonerequeue_turn
Section titled “requeue_turn”requeue_turn(self, name: str, turn_id: str, **kwargs: Any) -> Noneexpire_turn
Section titled “expire_turn”expire_turn(self, name: str, turn_id: str, **kwargs: Any) -> boolset_turn_owner
Section titled “set_turn_owner”set_turn_owner(self, name: str, turn_id: str, owner: str) -> Noneresume_turn
Section titled “resume_turn”resume_turn(self, name: str, turn_id: str, action: str, value: Any) -> Nonerecover_pending_turns
Section titled “recover_pending_turns”recover_pending_turns(self, name: str, now: Optional[float] = None) -> list[str]submit_run
Section titled “submit_run”submit_run(self, name: str, run_id: str, params: dict[str, object], metadata: Optional[dict[str, Any]] = None, owner: Optional[str] = None, idempotency_key: Optional[str] = None, idempotency_body_hash: Optional[str] = None, idempotency_ttl: int = 86400) -> strclaim_next_run
Section titled “claim_next_run”claim_next_run(self, name: str, worker_id: str) -> Optional[str]release_run
Section titled “release_run”release_run(self, name: str, run_id: str, worker_id: Optional[str] = None) -> Nonerequeue_run
Section titled “requeue_run”requeue_run(self, name: str, run_id: str, worker_id: Optional[str] = None) -> Nonerecover_pending_runs
Section titled “recover_pending_runs”recover_pending_runs(self, name: str, now: Optional[float] = None) -> list[str]get_pending_count
Section titled “get_pending_count”get_pending_count(self, name: str) -> intheartbeat
Section titled “heartbeat”heartbeat(self, name: str, run_id: str, worker_id: str) -> Nonerequest_cancel
Section titled “request_cancel”request_cancel(self, name: str, run_id: str) -> strget_cancel_requested_at
Section titled “get_cancel_requested_at”get_cancel_requested_at(self, name: str, run_id: str) -> Optional[str]request_pause
Section titled “request_pause”request_pause(self, name: str, run_id: str) -> strget_pause_requested_at
Section titled “get_pause_requested_at”get_pause_requested_at(self, name: str, run_id: str) -> Optional[str]clear_pause
Section titled “clear_pause”clear_pause(self, name: str, run_id: str) -> Noneresume_paused_turn
Section titled “resume_paused_turn”resume_paused_turn(self, name: str, run_id: str) -> Noneexpire_run
Section titled “expire_run”expire_run(self, name: str, run_id: str, ttl_seconds: int = 360) -> boolset_run_owner
Section titled “set_run_owner”set_run_owner(self, name: str, run_id: str, owner: str) -> Noneget_run_owner
Section titled “get_run_owner”get_run_owner(self, name: str, run_id: str) -> Optional[str]ping(self) -> Nonelist_runs
Section titled “list_runs”list_runs(self, name: str, limit: int = 50, cursor: Optional[str] = None, owner: Optional[str] = None) -> tuple[list[dict[str, Any]], Optional[str]]set_interrupted
Section titled “set_interrupted”set_interrupted(self, name: str, run_id: str, event_id: str, payload: dict[str, Any]) -> Noneresume_run
Section titled “resume_run”resume_run(self, name: str, run_id: str, action: str, value: Any) -> Noneget_interrupt_response
Section titled “get_interrupt_response”get_interrupt_response(self, name: str, run_id: str) -> Optional[dict[str, Any]]complete_run
Section titled “complete_run”complete_run(self, name: str, run_id: str) -> Noneappend_event
Section titled “append_event”append_event(self, name: str, run_id: str, event: RunEvent) -> Noneappend_event_sequenced
Section titled “append_event_sequenced”append_event_sequenced(self, name: str, run_id: str, event: RunEvent) -> intload_run
Section titled “load_run”load_run(self, name: str, run_id: str, max_events: Optional[int] = None) -> list[RunEvent]replay_run
Section titled “replay_run”replay_run(self, name: str, run_id: str, cursor: Optional[Any] = None, count: Optional[int] = None) -> tuple[list[RunEvent], Optional[Any]]get_last_event
Section titled “get_last_event”get_last_event(self, name: str, run_id: str) -> Optional[RunEvent]read_entries_from
Section titled “read_entries_from”read_entries_from(self, name: str, run_id: str, cursor: Optional[str], count: int) -> tuple[list[tuple[str, RunEvent]], Optional[str]]LiteLLM
Section titled “LiteLLM”LiteLLM adapter - routes to any supported provider.
Model names follow LiteLLM format: "provider/model".
complete
Section titled “complete”complete(self, messages: list[dict[str, Any]], system: Optional[str] = None) -> strOpenAI
Section titled “OpenAI”OpenAI Chat Completions adapter.
base_url can point to any OpenAI-compatible API (Ollama, Groq,
Together AI, OpenRouter, Azure, etc.).
Fields:
provider = 'openai'base_url = base_url
complete
Section titled “complete”complete(self, messages: list[dict[str, Any]], system: Optional[str] = None) -> strPoisonOptions
Section titled “PoisonOptions”Fields:
max_retries: int = 3retry_ttl_s: float = 3600.0
PyrulaError
Section titled “PyrulaError”Base class for Pyrula exceptions.
Fields:
code: Optional[ErrorCode] = None
PyrulaWorker
Section titled “PyrulaWorker”Simplified entry point for running a Pyrula worker process.
Fields:
connector_state: Optional[str]
run(self) -> Nonerun_async
Section titled “run_async”run_async(self) -> Nonesubmit
Section titled “submit”submit(self, agent_name: str, metadata: Optional[dict[str, Any]] = None, **params: object) -> strStoreUnavailable
Section titled “StoreUnavailable”Fields:
code = ErrorCode.STORE_UNAVAILABLE
ValkeyStore
Section titled “ValkeyStore”Fields:
SLEEPING_INDEX_KEY: str = 'sleeping:index'SCHEDULES_KEY: str = 'schedule:index'SCHEDULE_FIRE_TTL: int = 300max_thread_turns = max_thread_turns
WorkerOptions
Section titled “WorkerOptions”Fields:
max_concurrent_turns: int = 50orphan_scan_interval: float = 60.0shutdown_grace: float = 30.0cancel_timeout: float = 5.0claim_poll_interval: float = 0.1reporter: Optional[Reporter] = Nonetimer_poll_interval_s: float = 5.0timer_max_batch: int = 100schedule_poll_interval_s: float = 30.0poison: PoisonOptions = field(default_factory=PoisonOptions)
Functions
Section titled “Functions”agent(fn: Optional[Callable[..., Any]] = None, name: Optional[str] = None, timeout: float = 600.0, hide_thinking: bool = False, llm: Any = None, limits: Optional[AgentLimits] = None, output_type: Optional[Any] = None, deps_type: Optional[Any] = None, capture: str = CaptureLevel.lifecycle, mcp_servers: Optional[list[Any]] = None) -> AgentCallable | Callable[[Callable[..., Any]], AgentCallable]create_app
Section titled “create_app”create_app(agents: Optional[list[Callable[..., Any]]] = None, store: Optional[Store] = None, llm: Any, options: Optional[AppOptions] = None) -> FastAPIdata_step
Section titled “data_step”data_step(ctx: BaseContext, step_id: str, op: Any, *args: Any, **kwargs: Any) -> AnyDurable data operation with codec-driven replay.
registered_agents
Section titled “registered_agents”registered_agents() -> list[AgentCallable]