Python SDK
Installation
pip install maev-sdkmaev.run()
The only function you need to call.
maev.run(agent, *args, gateway=True, **kwargs)Wraps your agent with full observability and Autopilot in a single call. MAEV_API_KEY is read from the environment automatically.
Basic usage
import maev
maev.run(my_agent, gateway=True)Passing arguments to your agent
import maev
maev.run(my_agent, user_input, session_id=session_id, gateway=True)Any positional and keyword arguments after agent are forwarded to the agent function as-is.
Parameters
agent (required)
The agent to run. Can be:
- A callable (function, lambda, class with
__call__) - An object with a
.run(),.kickoff(),.invoke(),.execute(), or.chat()method (CrewAI, LangGraph, AutoGen, etc.)
# Function
maev.run(my_function, gateway=True)
# CrewAI crew
maev.run(crew, gateway=True)
# LangGraph compiled graph
maev.run(graph, gateway=True)api_key str (optional)
Your Maev API key. If not provided, read from MAEV_API_KEY environment variable. Must start with vl_.
maev.run(agent, api_key="vl_0b2a5f...", gateway=True)Prefer the environment variable over hardcoding the key.
agent_name str (optional)
A human-readable name for this agent. Shown in the dashboard. Auto-detected from the function or class name if not provided.
maev.run(agent, agent_name="Invoice Processing Agent", gateway=True)Use descriptive names. If you run the same agent in multiple environments:
maev.run(agent, agent_name="Support Agent (prod)", gateway=True)cost_budget float (optional, default 1.0)
Maximum USD cost allowed for this run. If the accumulated cost exceeds this limit, Maev stops the run and raises CircuitBrokenError.
maev.run(agent, gateway=True, cost_budget=0.50) # stop if this run costs more than $0.50max_calls int (optional, default 50)
Maximum number of LLM calls allowed in this run. Protects against infinite loops.
maev.run(agent, gateway=True, max_calls=20)max_duration_s float (optional, default 300.0)
Maximum wall-clock time in seconds for this run. The run is stopped if it exceeds this limit.
maev.run(agent, gateway=True, max_duration_s=60.0) # stop after 60 secondsfallback_models list[str] (optional)
Ordered list of fallback model names to try if the primary model fails repeatedly.
maev.run(
agent,
gateway=True,
fallback_models=["gpt-4o-mini", "gpt-3.5-turbo"]
)endpoint str (optional, default "https://home.maev.dev")
Override the ingest URL. Only needed if you are self-hosting Maev.
maev.run(agent, gateway=True, endpoint="https://maev.your-company.com")gateway bool | str (optional, default False)
Routes LLM traffic through the Maev Gateway for advanced self-reflection and prompt optimization. Also accepts a custom URL string for self-hosted gateways.
maev.run(agent, gateway=True) # Maev cloud gateway
maev.run(agent, gateway="https://my-gateway.example.com") # custom / self-hostedWhat maev.run() activates
When you call maev.run(agent), Maev:
- Reads your API key from the argument or
MAEV_API_KEYenv var - Detects the agent name from the argument,
MAEV_AGENT_NAMEenv var, or the function/class name - Loads strategies from the Maev server in a background thread (patterns learned from previous runs)
- Patches your LLM clients in-process: OpenAI (+ Azure), Anthropic, LangChain, LiteLLM. Telemetry for Gemini and Cohere is also captured automatically.
- Runs your agent with all protections active
- Flushes telemetry and closes the session when the agent finishes or raises
Autopilot protections active during the run
| Protection | What it does |
|---|---|
| Auto-retry | Retries failed or empty LLM responses up to 3× with exponential backoff |
| Cost circuit breaker | Stops the run if cost_budget is exceeded |
| Call count limit | Stops the run if max_calls is exceeded |
| Duration limit | Stops the run if max_duration_s is exceeded |
| Loop detection | Detects repeated identical prompt patterns and breaks the loop |
| Fallback models | Switches to fallback models if the primary model fails repeatedly |
| Strategy application | Applies learned strategies from previous runs automatically |
Async agents
maev.run() detects async agents automatically and awaits them correctly:
import asyncio
import maev
async def my_async_agent():
# async LLM calls here
...
asyncio.run(maev.run(my_async_agent, gateway=True))Error handling
maev.run() raises ValueError if the API key is missing or invalid:
try:
maev.run(agent, gateway=True)
except ValueError as e:
print(e)
# MAEV_API_KEY not set. Set the environment variable or pass api_key= to maev.run().All telemetry errors (network failures, ingest errors) are silently swallowed. Maev will never crash your agent.
If Autopilot circuit breakers trip, maev.run() raises maev.CircuitBrokenError with a reason:
try:
maev.run(agent, gateway=True, cost_budget=0.10)
except maev.CircuitBrokenError as e:
print(e)
# Run stopped: cost limit exceeded ($0.10)If the agent gets stuck in a prompt loop, maev.run() raises maev.interceptors.loop_detector.LoopDetectedError:
try:
maev.run(agent, gateway=True)
except Exception as e:
if "LoopDetectedError" in type(e).__name__:
print("Agent stuck in a prompt loop — run was stopped automatically")The loop detector uses a rolling window of 20 prompt hashes. If the same hash appears 3 or more times, the run is stopped.
Behavior notes
maev.run()is safe to call multiple times in the same process (different agent runs)- Telemetry is sent asynchronously and never blocks agent execution. Under 5ms overhead per LLM call.
- The SDK prints a terminal notice if a newer
maev-sdkversion is available on PyPI - If the process is killed mid-run, the session is automatically timed out after 1 hour
Requirements
- Python 3.9 or higher
- Works in any environment: scripts, web servers, notebooks, containers, serverless