
A Pythonic, async-native agent framework.
CubePi is a Pythonic, async-native agent framework designed for high performance, readability, and production-grade persistence. It provides a leaner alternative to graph-based agent runtimes by modeling agent logic as a linear while loop that developers can easily trace and debug.
| langgraph | CubePi | |
|---|---|---|
| Abstraction | Graph nodes + edges + channels | Plain async functions â run_agent_loop is a while loop |
| Streaming | Callback-based, multiple handler types | async for event in stream â one pattern everywhere |
| Checkpointing | Full snapshot per step; serializes entire message list | Append-only â O(1) DB I/O regardless of conversation length |
| Dependencies | langchain-core, langgraph-sdk, and transitive deps | 3 core deps: pydantic, anthropic, openai |
| Tool execution | Tools are graph nodes with manual wiring | Declare tools as functions; framework routes and parallelizes |
| Multi-provider | Via langchain chat model adapters | Native Provider protocol â Anthropic, OpenAI built in |
| Middleware | Graph-level middleware on node entry/exit | 7 typed hooks with declarative composition rules |
| Observability | LangSmith / Langfuse integration | Native OpenTelemetry â Tracer, Meter, GenAI semconv, OTLP / JSONL out of the box |
A single async function loop. One Provider, one AgentTool, and you're streaming.
import asyncio
from pydantic import BaseModel
from cubepi import Agent, AgentTool, Model
from cubepi.agent.types import AgentToolResult
from cubepi.providers.anthropic import AnthropicProvider
from cubepi.providers.base import TextContent
provider = AnthropicProvider(api_key="sk-...")
class GetWeatherParams(BaseModel):
city: str
async def get_weather(tool_call_id, params: GetWeatherParams, *, signal=None, on_update=None):
return AgentToolResult(
content=[TextContent(text=f"72°F and sunny in {params.city}")]
)
agent = Agent(
provider=provider,
model=Model(id="claude-sonnet-4-5-20250929", provider="anthropic"),
tools=[AgentTool(
name="get_weather",
description="Get current weather for a city",
parameters=GetWeatherParams,
execute=get_weather,
)],
system_prompt="You are a helpful weather assistant.",
)
def on_event(event, signal=None):
if event.type == "text_delta":
print(event.delta, end="", flush=True)
agent.subscribe(on_event)
asyncio.run(agent.prompt("What's the weather in Tokyo?"))
One async loop, fully typed events.
â Guides / Agentsasync for event in stream.
â Guides / StreamingPlain functions, parallel execution.
â Guides / ToolsAnthropic, OpenAI, or write your own.
â Guides / ProvidersAppend-only, O(1) per turn.
â Guides / CheckpointingPause for confirm, approve, or ask.
â Guides / Human-in-the-loopLoad remote tools at startup.
â Guides / MCPOpenTelemetry, OTLP / JSONL, GenAI semconv.
â Guides / Tracingpip install cubepiuv add cubepipoetry add cubepipip install cubepi[sqlite,postgres,mcp,tracing,tracing-otlp]