API Reference¶
This document covers the complete public API of the arcana package — everything
exported from import arcana. Internal modules, private helpers, and contract
sub-types are intentionally omitted.
Choosing an API — three tiers¶
Arcana exposes a wide surface. Most users only need the primary tier. The others exist for explicit workflows or for backward compatibility.
| Tier | Use when | Methods |
|---|---|---|
| Primary | One-shot tasks, conversational sessions, multi-agent collaboration where you control the orchestration. | arcana.run() · Runtime.run() · Runtime.chat() · Runtime.collaborate() |
| Structured workflows | The work has a fixed shape — a pipeline of dependent steps, a state machine with branches, or many independent tasks at once. | Runtime.chain() · Runtime.graph() · Runtime.run_batch() |
| Legacy / compatibility | You're maintaining code that predates the V2 engine. Not the recommended path for new code. | engine="adaptive" (use the default "conversation") |
Detailed signatures for each method appear in their sections below.
Table of Contents¶
- Quick-Start Functions
- arcana.run()
- arcana.tool()
- Core Classes
- Runtime
- Session
- Budget
- Result Types
- RunResult (sdk)
- RunResult (runtime)
- BatchResult
- Configuration
- AgentConfig
- ChainStep
- MCPServerConfig
- Graph Engine
- StateGraph
- START / END
- CompiledGraph
- Streaming
- StreamEvent
Quick-Start Functions¶
arcana.run()¶
The simplest entry point. Creates a temporary Runtime, runs a single task, and
returns the result. Best for scripts, demos, and one-off calls.
async def run(
goal: str,
*,
tools: list[Callable] | None = None,
provider: str = "deepseek",
model: str | None = None,
api_key: str | None = None,
max_turns: int = 20,
max_cost_usd: float = 1.0,
auto_route: bool = True,
engine: str = "conversation",
stream: bool = False,
) -> RunResult
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
goal |
str |
required | What you want the agent to accomplish. |
tools |
list[Callable] \| None |
None |
List of @arcana.tool decorated functions. |
provider |
str |
"deepseek" |
LLM provider name ("deepseek", "openai", "anthropic", "gemini", "kimi", "glm", "minimax", "ollama"). |
model |
str \| None |
None |
Model ID. Auto-selected from provider default when None. |
api_key |
str \| None |
None |
API key for the provider. Falls back to <PROVIDER>_API_KEY env var. |
max_turns |
int |
20 |
Maximum number of agent turns before stopping. |
max_cost_usd |
float |
1.0 |
Maximum spend in USD for this run. |
auto_route |
bool |
True |
Enable intent routing (direct answer vs. agent loop). |
engine |
str |
"conversation" |
Execution engine: "conversation" (V2, recommended) or "adaptive" (V1). |
stream |
bool |
False |
Reserved for future use. |
Returns: RunResult with output text and execution metadata.
Example
import arcana
# Simplest usage
result = await arcana.run("What is 2+2?", api_key="sk-xxx")
print(result.output)
# With tools
@arcana.tool(when_to_use="For math calculations")
def calc(expression: str) -> str:
return str(eval(expression))
result = await arcana.run("What is 15 * 37 + 89?", tools=[calc], api_key="sk-xxx")
# With OpenAI
result = await arcana.run(
"Summarize quantum computing",
provider="openai",
api_key="sk-proj-xxx",
)
arcana.tool()¶
Decorator that registers a function as an Arcana tool. The decorated function
retains its normal behavior but gains metadata that Runtime reads at
registration time.
def tool(
*,
name: str | None = None,
description: str | None = None,
when_to_use: str | None = None,
what_to_expect: str | None = None,
failure_meaning: str | None = None,
side_effect: str = "read",
requires_confirmation: bool = False,
) -> Callable
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
name |
str \| None |
None |
Override tool name. Defaults to the function name. |
description |
str \| None |
None |
Override tool description. Defaults to the function docstring. |
when_to_use |
str \| None |
None |
Guidance for the LLM on when this tool is appropriate. |
what_to_expect |
str \| None |
None |
Describes what the tool returns so the LLM knows how to interpret results. |
failure_meaning |
str \| None |
None |
Explains what a failure means so the LLM can decide whether to retry. |
side_effect |
str |
"read" |
Side effect category: "read", "write", "network", "filesystem". |
requires_confirmation |
bool |
False |
If True, the runtime asks for user confirmation before execution. |
Returns: The original function, with _arcana_tool_spec attached.
Notes:
- Input schema is auto-inferred from the function signature (type hints map to JSON Schema types).
- Both sync and async functions are supported.
- Pass the decorated function directly in the tools= list to arcana.run() or Runtime().
Example
import arcana
@arcana.tool(
when_to_use="When you need to search the web for current information",
what_to_expect="Returns a list of search result snippets",
side_effect="network",
)
async def web_search(query: str) -> str:
results = await search_api(query)
return "\n".join(results)
@arcana.tool(
name="calculator",
when_to_use="For any mathematical computation",
requires_confirmation=False,
)
def calc(expression: str) -> str:
return str(eval(expression))
Core Classes¶
Runtime¶
The central object in Arcana. Create once at application startup; reuse across requests. Holds long-lived resources: provider connections, tool registry, trace backend, budget policy, and memory store.
class Runtime:
def __init__(
self,
*,
providers: dict[str, str] | None = None,
tools: list[Callable] | None = None,
guardrails: list[Callable] | None = None,
mcp_servers: list[MCPServerConfig] | None = None,
budget: Budget | None = None,
trace: bool = False,
memory: bool = False,
memory_budget_tokens: int = 800,
config: RuntimeConfig | None = None,
namespace: str | None = None,
) -> None
Constructor Parameters
| Name | Type | Default | Description |
|---|---|---|---|
providers |
dict[str, str] \| None |
None |
Provider name to API key mapping, e.g. {"deepseek": "sk-xxx", "openai": "sk-proj-xxx"}. Empty string reads from env var. |
tools |
list[Callable] \| None |
None |
List of @arcana.tool decorated functions to register. |
guardrails |
list[Callable] \| None |
None |
Tool-call boundary guardrails. Each receives ToolGuardrailRequest and returns GuardrailDecision; can block, warn, redact args, or require approval. |
mcp_servers |
list[MCPServerConfig] \| None |
None |
MCP server configurations for external tool servers. |
budget |
Budget \| None |
None |
Default budget policy. Defaults to Budget(max_cost_usd=10.0). |
trace |
bool |
False |
Enable JSONL trace logging. |
memory |
bool |
False |
Enable cross-run memory (fact extraction and retrieval). |
memory_budget_tokens |
int |
800 |
Token budget for memory context injection. |
config |
RuntimeConfig \| None |
None |
Advanced runtime configuration (default provider, model, max turns, system prompt). |
namespace |
str \| None |
None |
Tenant isolation namespace. When set, memory and trace are partitioned. |
Import note:
Do not useRuntimeConfigis not exported fromarcana. Import it directly:arcana.RuntimeConfig-- it does not exist.
Runtime.run()¶
Run a task to completion.
async def run(
self,
goal: str,
*,
engine: str = "conversation",
max_turns: int | None = None,
budget: Budget | None = None,
tools: list[Callable] | None = None,
) -> RunResult
| Name | Type | Default | Description |
|---|---|---|---|
goal |
str |
required | What to accomplish. |
engine |
str |
"conversation" |
"conversation" (V2) or "adaptive" (V1). |
max_turns |
int \| None |
None |
Override default max turns for this run. |
budget |
Budget \| None |
None |
Override default budget for this run. |
tools |
list[Callable] \| None |
None |
Additional tools for this run only (merged with runtime tools). |
Returns: RunResult
Runtime.stream()¶
Stream agent execution events in real time.
async def stream(
self,
goal: str,
*,
engine: str = "conversation",
max_turns: int | None = None,
) -> AsyncGenerator[StreamEvent, None]
| Name | Type | Default | Description |
|---|---|---|---|
goal |
str |
required | What to accomplish. |
engine |
str |
"conversation" |
Only "conversation" is supported for streaming. |
max_turns |
int \| None |
None |
Override default max turns. |
Yields: StreamEvent objects.
Example
Runtime.session()¶
Create a session for manual control over execution. Used as an async context manager.
@asynccontextmanager
async def session(
self,
*,
engine: str = "conversation",
max_turns: int | None = None,
budget: Budget | None = None,
tools: list[Callable] | None = None,
) -> AsyncGenerator[Session, None]
Returns: Session (via async with).
Example
async with runtime.session() as s:
result = await s.run("Do something")
print(s.state)
print(s.budget.to_snapshot())
Runtime.collaborate()¶
Open an AgentPool for multi-agent collaboration. Returns an async context
manager. Inside the pool, each agent is an independent ChatSession; user
code controls who speaks, what they read, and when the collaboration ends.
The runtime provides shared infrastructure (channel, shared context, shared
budget) but never imposes a planner/executor topology.
async with runtime.collaborate() as pool:
architect = pool.spawn("architect", prompt="...")
reviewer = pool.spawn("reviewer", prompt="...")
plan = await architect.send("design X")
feedback = await reviewer.send(f"review: {plan.text}")
See docs/guide/multi-agent.md for the full
collaboration guide, including shared context, message-bus patterns, and
per-agent cognitive-primitive opt-in.
This is the multi-agent API for v1.0.0+. The older Runtime.team() was
removed in v1.0.0; see the
migration recipe.
Runtime.chain()¶
Run a sequential pipeline of steps with automatic context passing. Each step's output flows as context to the next. Parallel branches (nested lists) run concurrently.
async def chain(
self,
steps: list[ChainStep | list[ChainStep]],
*,
budget: Budget | None = None,
) -> ChainResult
| Name | Type | Default | Description |
|---|---|---|---|
steps |
list[ChainStep \| list[ChainStep]] |
required | Steps to execute. Nested lists run in parallel. |
budget |
Budget \| None |
None |
Budget for the entire chain. |
Returns: ChainResult with per-step outputs accessible via result.steps["name"].
Example
result = await runtime.chain([
arcana.ChainStep(name="research", goal="Find key facts about quantum computing"),
[ # parallel branch
arcana.ChainStep(name="summary", goal="Write a concise summary"),
arcana.ChainStep(name="critique", goal="Identify gaps and biases",
budget=arcana.Budget(max_cost_usd=0.50)),
],
arcana.ChainStep(name="final", goal="Integrate summary and critique into a report"),
])
print(result.steps["final"])
Runtime.run_batch()¶
Run multiple independent tasks concurrently. Individual failures do not crash
the batch -- the corresponding RunResult will have success=False.
| Name | Type | Default | Description |
|---|---|---|---|
tasks |
list[dict[str, Any]] |
required | List of task dicts. Each must have a "goal" key. Optional keys match run() parameters (tools, system, provider, model, response_format, etc.). |
concurrency |
int |
5 |
Maximum number of concurrent runs. |
Returns: BatchResult
Example
from pydantic import BaseModel
class Summary(BaseModel):
title: str
key_points: list[str]
results = await runtime.run_batch([
{"goal": "Summarize article 1", "response_format": Summary},
{"goal": "Summarize article 2", "response_format": Summary},
{"goal": "Summarize article 3", "response_format": Summary},
], concurrency=10)
print(f"{results.succeeded}/{len(results.results)} succeeded")
print(f"Total cost: ${results.total_cost_usd:.4f}")
Runtime.graph()¶
Create a StateGraph connected to this runtime's resources.
| Name | Type | Default | Description |
|---|---|---|---|
state_schema |
type \| None |
None |
Pydantic model class for graph state. |
Returns: StateGraph ready for node/edge configuration.
Example
graph = runtime.graph(state_schema=MyState)
graph.add_node("search", search_fn)
graph.add_edge(START, "search")
app = graph.compile()
result = await app.ainvoke(initial_state)
Runtime.make_llm_node()¶
Create an LLMNode pre-wired with this runtime's gateway and model config.
Runtime.make_tool_node()¶
Create a ToolNode pre-wired with this runtime's tool gateway.
Raises ValueError if no tools are registered.
Runtime.connect_mcp()¶
Connect to configured MCP servers and register their tools.
Returns: List of registered MCP tool names.
Runtime.close()¶
Clean up runtime resources (MCP connections, etc.).
Runtime Properties¶
| Property | Type | Description |
|---|---|---|
providers |
list[str] |
List of registered provider names. |
tools |
list[str] |
List of registered tool names. |
namespace |
str \| None |
The namespace for tenant isolation, or None. |
memory |
Any |
Access the memory store (if enabled). |
Session¶
Per-run execution context. Created by Runtime.session(). Holds run-scoped
resources: run ID, per-run budget tracker, and execution state.
class Session:
def __init__(
self,
runtime: Runtime,
engine: str = "conversation",
max_turns: int = 20,
budget: Budget | None = None,
extra_tools: list[Callable] | None = None,
memory_context: str = "",
) -> None
You typically do not construct Session directly. Use Runtime.session() instead.
Session.run()¶
Run a task within this session.
Session Attributes¶
| Attribute | Type | Description |
|---|---|---|
run_id |
str |
Unique identifier for this run (UUID). |
state |
AgentState \| None |
The execution state after run() completes. |
budget |
BudgetTracker |
Per-run budget tracker. Call budget.to_snapshot() for current usage. |
Budget¶
Budget configuration. Passed to Runtime() or Runtime.run() to cap spending.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
max_cost_usd |
float |
10.0 |
Maximum spend in USD before the runtime stops. |
max_tokens |
int |
500_000 |
Maximum total tokens (input + output) before the runtime stops. |
Example
import arcana
# Conservative budget for a demo
budget = arcana.Budget(max_cost_usd=0.50, max_tokens=100_000)
runtime = arcana.Runtime(
providers={"deepseek": "sk-xxx"},
budget=budget,
)
Result Types¶
Two
RunResultclasses -- read this first.Arcana has two separate
RunResultclasses with identical fields but different origins. This is intentional: the SDK and runtime layers are decoupled.
Class Import path Returned by arcana.RunResultimport arcana; arcana.RunResultarcana.run()(SDK convenience function)arcana.RuntimeResultimport arcana; arcana.RuntimeResultRuntime.run(),Session.run()Both have the same fields (
output,parsed,success,steps,tokens_used,cost_usd,run_id), but they are different classes --isinstancechecks will not match across them.Rule of thumb: If you are type-checking results from
RuntimeorSession, usearcana.RuntimeResult. If you are type-checking results fromarcana.run(), usearcana.RunResult.
RunResult (sdk)¶
Returned by arcana.run(). A simplified result with execution metadata.
Import path: arcana.RunResult (this is the SDK version).
class RunResult(BaseModel):
output: Any = None
parsed: Any = None
success: bool = False
steps: int = 0
tokens_used: int = 0
cost_usd: float = 0.0
run_id: str = ""
Fields
| Field | Type | Default | Description |
|---|---|---|---|
output |
Any |
None |
The agent's final output (usually a string, or the parsed model when response_format succeeds). |
parsed |
BaseModel \| None |
None |
Validated Pydantic instance when response_format is set and parsing succeeds. Always BaseModel \| None -- never a raw dict. |
success |
bool |
False |
Whether the task completed successfully. |
steps |
int |
0 |
Number of execution steps taken. |
tokens_used |
int |
0 |
Total tokens consumed (input + output). |
cost_usd |
float |
0.0 |
Estimated cost in USD. |
run_id |
str |
"" |
Unique run identifier for trace correlation. |
RunResult (runtime)¶
Returned by Runtime.run() and Session.run(). Identical fields to the SDK
version. Defined in arcana.runtime_core.
Import path: arcana.RuntimeResult (aliased from arcana.runtime_core.RunResult).
class RunResult(BaseModel):
output: Any = None
parsed: Any = None
success: bool = False
steps: int = 0
tokens_used: int = 0
cost_usd: float = 0.0
run_id: str = ""
Fields are identical to RunResult (sdk).
BatchResult¶
Returned by Runtime.run_batch(). Aggregates results from all tasks in the batch.
class BatchResult(BaseModel):
results: list[RunResult] = []
total_tokens: int = 0
total_cost_usd: float = 0.0
succeeded: int = 0
failed: int = 0
Fields
| Field | Type | Default | Description |
|---|---|---|---|
results |
list[RunResult] |
[] |
All results, preserving input order. Failed tasks have success=False. |
total_tokens |
int |
0 |
Total tokens consumed across all tasks. |
total_cost_usd |
float |
0.0 |
Estimated total cost in USD. |
succeeded |
int |
0 |
Number of tasks that completed successfully. |
failed |
int |
0 |
Number of tasks that failed. |
Configuration¶
AgentConfig¶
A serializable configuration struct for a single agent (name, system prompt,
optional model/provider overrides). Useful for storing agent definitions in
configs or passing them between processes; expand into
pool.add(name=cfg.name, system=cfg.prompt, model=cfg.model, provider=cfg.provider)
when collaborating via Runtime.collaborate().
class AgentConfig(BaseModel):
name: str
prompt: str
model: str | None = None
provider: str | None = None
Fields
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Unique name for this agent (appears in conversation log). |
prompt |
str |
required | System prompt defining this agent's role and personality. |
model |
str \| None |
None |
Override the runtime's default model for this agent. |
provider |
str \| None |
None |
Override the runtime's default provider for this agent. |
ChainStep¶
Configuration for a single step in a Runtime.chain() pipeline.
class ChainStep(BaseModel):
name: str
goal: str
system: str | None = None
response_format: type[BaseModel] | None = None
tools: list[Callable] | None = None
provider: str | None = None
model: str | None = None
on_parse_error: Callable[[str, Exception], BaseModel | None] | None = None
budget: Budget | None = None
Fields
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Unique name for this step (used as key in ChainResult.steps). |
goal |
str |
required | Prompt for this step. Previous step output is injected as context automatically. |
system |
str \| None |
None |
System prompt override for this step. |
response_format |
type[BaseModel] \| None |
None |
Pydantic model for structured output. |
tools |
list[Callable] \| None |
None |
Additional tools for this step only. |
provider |
str \| None |
None |
Override provider for this step. |
model |
str \| None |
None |
Override model for this step. |
on_parse_error |
Callable \| None |
None |
Callback for structured output parse failures. |
budget |
Budget \| None |
None |
Per-step budget cap. Capped by chain-level remaining budget. Steps without budget share the chain pool. |
MCPServerConfig¶
Configuration for connecting to an MCP (Model Context Protocol) server. Pass a
list of these to Runtime(mcp_servers=[...]).
class MCPServerConfig(BaseModel):
name: str
transport: MCPTransportType = MCPTransportType.STDIO
# stdio transport
command: str | None = None
args: list[str] = []
env: dict[str, str] = {}
# HTTP transport
url: str | None = None
headers: dict[str, str] = {}
# Common
timeout_ms: int = 30000
reconnect_attempts: int = 3
reconnect_delay_ms: int = 1000
capability_prefix: str | None = None
Fields
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Human-readable name for this MCP server. |
transport |
MCPTransportType |
STDIO |
Transport type: "stdio", "sse", or "streamable_http". |
command |
str \| None |
None |
Command to launch the server (stdio transport). |
args |
list[str] |
[] |
Command-line arguments (stdio transport). |
env |
dict[str, str] |
{} |
Environment variables for the server process (stdio transport). |
url |
str \| None |
None |
Server URL (SSE / HTTP transport). |
headers |
dict[str, str] |
{} |
HTTP headers (SSE / HTTP transport). |
timeout_ms |
int |
30000 |
Connection timeout in milliseconds. |
reconnect_attempts |
int |
3 |
Number of reconnection attempts on failure. |
reconnect_delay_ms |
int |
1000 |
Delay between reconnection attempts in milliseconds. |
capability_prefix |
str \| None |
None |
Prefix for tool names to avoid collisions across servers. |
Example
import arcana
runtime = arcana.Runtime(
providers={"deepseek": "sk-xxx"},
mcp_servers=[
arcana.MCPServerConfig(
name="filesystem",
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
),
arcana.MCPServerConfig(
name="remote-tools",
transport="sse",
url="http://localhost:8080/sse",
),
],
)
# MCP tools are auto-connected on first run, or connect manually:
tool_names = await runtime.connect_mcp()
print(f"Registered MCP tools: {tool_names}")
Graph Engine¶
The graph engine is for advanced orchestration with explicit control flow. For
most tasks, Runtime.run() (which uses the conversation engine internally) is
the right entry point.
StateGraph¶
Declarative graph builder. Add nodes (functions) and edges (control flow), then compile into an executable graph.
| Name | Type | Default | Description |
|---|---|---|---|
state_schema |
type[BaseModel] \| None |
None |
Pydantic model class defining the graph state shape. |
StateGraph.add_node()¶
def add_node(
self,
name: str,
fn: Callable[..., Any],
*,
node_type: NodeType = NodeType.FUNCTION,
metadata: dict[str, Any] | None = None,
) -> StateGraph
Add a node to the graph. The function fn receives the current state and
returns an updated state (or partial state dict).
Returns: self (for chaining).
StateGraph.add_edge()¶
Add a direct edge between two nodes. Use START and END constants for
entry/exit points.
Returns: self (for chaining).
StateGraph.add_conditional_edges()¶
def add_conditional_edges(
self,
source: str,
path_fn: Callable[..., str],
path_map: dict[str, str] | None = None,
) -> StateGraph
Add conditional routing from a source node. The path_fn receives the current
state and returns a string key. If path_map is provided, the key is mapped to
a target node name; otherwise the key is used directly as the target.
Returns: self (for chaining).
StateGraph.compile()¶
def compile(
self,
*,
checkpointer: Any | None = None,
interrupt_before: list[str] | None = None,
interrupt_after: list[str] | None = None,
name: str = "default",
) -> CompiledGraph
Compile the graph into an executable CompiledGraph. Validates that an entry
point exists, all edge references are valid, and at least one path reaches END.
| Name | Type | Default | Description |
|---|---|---|---|
checkpointer |
Any \| None |
None |
Checkpoint backend for interrupt/resume. |
interrupt_before |
list[str] \| None |
None |
Node names to interrupt before executing. |
interrupt_after |
list[str] \| None |
None |
Node names to interrupt after executing. |
name |
str |
"default" |
Name for this compiled graph. |
Returns: CompiledGraph -- call await app.ainvoke(state) to execute.
StateGraph.set_entry_point() / StateGraph.set_finish_point()¶
def set_entry_point(self, name: str) -> StateGraph
def set_finish_point(self, name: str) -> StateGraph
Alternative to add_edge(START, name) and add_edge(name, END).
Example
import arcana
from arcana import START, END
graph = arcana.StateGraph(state_schema=MyState)
graph.add_node("search", search_fn)
graph.add_node("summarize", summarize_fn)
graph.add_node("decide", decide_fn)
graph.add_edge(START, "search")
graph.add_conditional_edges("search", route_fn, {
"needs_more": "search",
"ready": "summarize",
})
graph.add_edge("summarize", END)
app = graph.compile()
result = await app.ainvoke({"query": "quantum computing trends"})
START / END¶
Sentinel constants for graph entry and exit points.
from arcana import START, END
# Values (for reference, do not hardcode these):
# START = "__start__"
# END = "__end__"
Use these with StateGraph.add_edge():
CompiledGraph¶
The return type of StateGraph.compile(). You never instantiate this directly --
always obtain it via graph.compile().
CompiledGraph.ainvoke()¶
Execute the graph to completion and return the final state.
async def ainvoke(
self,
input: dict[str, Any],
config: dict[str, Any] | None = None,
) -> dict[str, Any]
| Name | Type | Default | Description |
|---|---|---|---|
input |
dict[str, Any] |
required | Initial state for the graph (must match the state schema). |
config |
dict[str, Any] \| None |
None |
Optional runtime configuration passed through to node functions. |
Returns: dict[str, Any] -- the final graph state after all nodes have executed.
Example
app = graph.compile()
result = await app.ainvoke({"query": "quantum computing trends"})
print(result["summary"])
CompiledGraph.astream()¶
Execute the graph with streaming output, yielding state or updates after each node.
async def astream(
self,
input: dict[str, Any],
*,
config: dict[str, Any] | None = None,
mode: str = "values",
) -> AsyncGenerator[dict[str, Any], None]
| Name | Type | Default | Description |
|---|---|---|---|
input |
dict[str, Any] |
required | Initial state for the graph. |
config |
dict[str, Any] \| None |
None |
Optional runtime configuration. |
mode |
str |
"values" |
Streaming mode: "values" (full state after each node), "updates" ({"node": name, "output": {...}} after each node), or "messages" (new messages added at each step). |
Yields: dict[str, Any] -- state snapshots or update dicts depending on mode.
Example
app = graph.compile()
async for state in app.astream({"query": "search me"}, mode="updates"):
print(f"Node: {state['node']}, Output: {state['output']}")
CompiledGraph.aresume()¶
Resume execution from a checkpoint after a human-in-the-loop interrupt.
| Name | Type | Default | Description |
|---|---|---|---|
checkpoint_id |
str |
required | The checkpoint ID from a GraphInterrupt exception. |
command |
Command \| None |
None |
Optional command to influence resumed execution. |
Returns: dict[str, Any] -- the final graph state after resumed execution completes.
Raises: RuntimeError if the graph was compiled without a checkpointer.
ValueError if the checkpoint ID is not found.
The Command class (from arcana.graph.interrupt) has three optional fields:
| Field | Type | Default | Description |
|---|---|---|---|
resume |
Any |
None |
Value passed to the interrupted node on resume. |
update |
dict[str, Any] \| None |
None |
State updates to apply before resuming. |
goto |
str \| None |
None |
Jump to a specific node instead of resuming at the interrupt point. |
Example
from arcana.graph.interrupt import Command, GraphInterrupt
app = graph.compile(
checkpointer=my_checkpointer,
interrupt_before=["human_review"],
)
try:
result = await app.ainvoke({"query": "draft a proposal"})
except GraphInterrupt as e:
# Human reviews and approves
result = await app.aresume(
e.checkpoint_id,
command=Command(resume="approved", update={"feedback": "Looks good"}),
)
CompiledGraph Properties¶
| Property | Type | Description |
|---|---|---|
config |
GraphConfig |
The graph configuration (name, interrupt settings). |
nodes |
dict[str, GraphNodeSpec] |
Copy of the registered node specifications. |
Streaming¶
StreamEvent¶
Event emitted during streaming execution via Runtime.stream().
class StreamEvent(BaseModel):
event_type: StreamEventType
timestamp: datetime
run_id: str
step_id: str | None = None
# Content
content: str | None = None
thinking: str | None = None
node_name: str | None = None
# Structured data
step_result_data: dict[str, Any] | None = None
tool_result_data: dict[str, Any] | None = None
state_delta: dict[str, Any] | None = None
# Metrics
tokens_used: int | None = None
cost_usd: float | None = None
budget_remaining_pct: float | None = None
# Error
error: str | None = None
error_type: str | None = None
# Metadata
metadata: dict[str, Any] = {}
Key Fields
| Field | Type | Description |
|---|---|---|
event_type |
StreamEventType |
The event kind (see table below). |
timestamp |
datetime |
When the event was created (UTC). |
run_id |
str |
Run identifier for correlation. |
content |
str \| None |
LLM text content (for LLM_CHUNK / LLM_COMPLETE). |
thinking |
str \| None |
LLM thinking/reasoning text (for LLM_THINKING). |
tokens_used |
int \| None |
Cumulative token usage at this point. |
cost_usd |
float \| None |
Cumulative cost at this point. |
error |
str \| None |
Error message (for ERROR events). |
StreamEventType Values
Import note:
Do not useStreamEventTypeis not exported fromarcana. If you need to reference it directly, import it from the contracts module:arcana.StreamEventType-- it does not exist.As a simpler alternative, compare against
.valuestrings instead of importing the enum:
| Value | Description |
|---|---|
RUN_START |
Execution has started. |
RUN_COMPLETE |
Execution has finished. |
STEP_START |
A new agent step/turn is starting. |
STEP_COMPLETE |
An agent step/turn has finished. |
LLM_CHUNK |
A chunk of streaming LLM output. |
LLM_COMPLETE |
The full LLM response for this turn is ready. |
LLM_THINKING |
LLM reasoning/thinking text (chain-of-thought). |
TOOL_CALL_START |
A tool call is about to execute. |
TOOL_RESULT |
A tool call has returned. |
STATE_UPDATE |
Agent state has changed. |
CHECKPOINT |
A checkpoint was saved. |
ERROR |
An error occurred. |
NODE_START |
A graph node has started executing. |
NODE_COMPLETE |
A graph node has finished executing. |
Example
import arcana
runtime = arcana.Runtime(providers={"deepseek": "sk-xxx"})
async for event in runtime.stream("Explain quantum entanglement"):
if event.event_type.value == "llm_chunk":
print(event.content, end="", flush=True)
elif event.event_type.value == "tool_call_start":
print(f"\n[Calling tool: {event.metadata.get('tool_name')}]")
elif event.event_type.value == "error":
print(f"\nError: {event.error}")