SDK Guides
Getting Started
Install the SDK and run your first agent invocation.
#Quickstart
By the end of this guide you'll have a running maivn agent: it takes a plain-English question, decides on its own to call a tool you wrote, and hands you back both a readable answer and a typed, structured result your code can rely on. No servers to wire up by hand and no prompt-engineering rabbit holes — just a few lines of Python.
#What You'll Build
You'll create an agent, give it a get_weather tool, ask it a question in natural language, and read the response. Then you'll layer on two things production apps want: a guaranteed typed result (so you can report.temperature instead of parsing text) and live progress events (so a UI can show what the agent is doing while it works).
The agent does the deciding. You describe what each tool does; the agent figures out when to call it and how to combine the results into an answer.
#Prerequisites
- Python 3.10+
- A maivn API key
#Installation
pip install maivnOr with uv:
uv add maivnTo install the public Studio companion and enable maivn studio from a normal shell:
pip install maivn maivn-studiomaivn studioUsing uv? Auv add/uv pip installputs themaivncommand inside the
project's.venv, which uv does not auto-activate. Launch Studio withuv run maivn studio, or activate the environment first
(.venv\Scripts\activateon Windows,source .venv/bin/activateelsewhere)
and then runmaivn studiodirectly.
uv add maivn maivn-studiouv run maivn studio#Step 1: Set Up Your API Key
Set your API key as an environment variable:
export MAIVN_API_KEY=your-api-keyThe Agent constructor does not read environment variables automatically; read
the key explicitly or pass a preconfigured Client.
#Step 2: Create Your First Agent
import os from maivn import Agentfrom maivn.messages import HumanMessage # Create an agentagent = Agent( name='my_first_agent', description='A helpful assistant', system_prompt='You are a helpful assistant that provides clear, concise answers.', api_key=os.environ['MAIVN_API_KEY'],)#Step 3: Add a Tool
Tools are functions that the agent can call. Use the @agent.toolify() decorator:
@agent.toolify(description='Get current weather for a city')def get_weather(city: str) -> dict: # In a real app, call a weather API return {'city': city, 'temp': 72, 'condition': 'sunny'}The agent now has access to this tool and can call it when appropriate.
Tip: You can also use a docstring instead of the description argument:
@agent.toolify()def get_weather(city: str) -> dict: """Get current weather for a city.""" return {'city': city, 'temp': 72, 'condition': 'sunny'}You can register tools without decorators when that better fits your module layout:
def get_weather(city: str) -> dict: """Get current weather for a city.""" return {'city': city, 'temp': 72, 'condition': 'sunny'} agent = Agent( name='weather_agent', api_key='your-api-key', tools=[get_weather],) # Or add it after construction.agent.add_tool(get_weather)Note: Your tool code executes locally in your environment - it is never transferred to or executed on mAIvn's servers. Only the tool schema (name, description, parameters) is sent to the hosted orchestrator.
#Step 4: Invoke the Agent
# Send a message to the agentresponse = agent.invoke([ HumanMessage(content='What is the weather in Austin?')]) print(response.response)response.response holds the final assistant text — the natural-language answer the agent produced after deciding whether to call your tool.
#Complete Example
Here's the full working example:
from maivn import Agentfrom maivn.messages import HumanMessage # Create agentagent = Agent( name='weather_agent', description='An agent that can check the weather', system_prompt='You are a helpful assistant that provides weather information.', api_key='your-api-key',) # Add a tool@agent.toolify(description='Get current weather for a city')def get_weather(city: str) -> dict: # In a real app, call a weather API return {'city': city, 'temp': 72, 'condition': 'sunny'} # Invoke the agentresponse = agent.invoke([ HumanMessage(content='What is the weather in Austin?')]) print(response.response)#Step 5: Add Structured Output
When your code needs to act on the answer — not just print it — you want a guaranteed shape, not prose to parse. Mark a Pydantic model as a final tool and the agent will fill it in:
from pydantic import BaseModel, Field @agent.toolify(final_tool=True)class WeatherReport(BaseModel): """Structured weather report.""" city: str = Field(..., description='City name') temperature: int = Field(..., description='Temperature in Fahrenheit') summary: str = Field(..., description='Human-readable weather summary') # Force the structured outputresponse = agent.invoke( [HumanMessage(content='Weather report for Austin')], force_final_tool=True,) # response.result is a WeatherReport instanceprint(response.result)print(response.result.temperature)final_tool=True designates the Pydantic model as the structured-output tool, and force_final_tool=True tells the agent to finish by populating it. The typed value lands on response.result, while response.response still carries any accompanying text.
For a deeper look — including the faster agent.structured_output(MyModel).invoke(...) builder for one-shot extraction — see the Structured Output Guide.
#Step 6: Stream Live Progress
For a responsive UI, you'll want to show what the agent is doing while it works, instead of waiting for the whole turn to finish. The events builder wraps invoke() and reports progress as it happens:
response = agent.events().invoke( [HumanMessage(content='What is the weather in Austin?')],)Pass an on_event callback to react to each event as it arrives, or filter with include/exclude:
def handle(event: dict) -> None: print(event) response = agent.events(on_event=handle).invoke( [HumanMessage(content='What is the weather in Austin?')],)If you'd rather pull events yourself, iterate agent.stream(...), which yields events one at a time as the agent executes:
for event in agent.stream([HumanMessage(content='What is the weather in Austin?')]): print(event)Between tool calls and the final answer, the agent emits fixed-label phase indicators — things like evaluating the request, planning actions, and synthesizing the response — so a frontend can render a live status indicator without guessing. Status messages are a separate, opt-in channel you can turn on with agent.stream(..., status_messages=True).
To send these events to a browser frontend, see the Frontend Events guide, which covers the one-line backend mount and client examples in JavaScript, TypeScript, Swift, Kotlin, Go, Python, Rust, .NET, and more.
#Built-in Capabilities
The mAIvn runtime has several built-in capabilities that don't require custom tools:
- Datetime awareness - Agents automatically know the current date and time
- Web search - Search for current information (runs within the mAIvn runtime)
- Code execution - Run Python in a sandbox (runs within the mAIvn runtime)
See System Tools Guide for details.
#Next Steps
You now have an agent that calls a tool, returns a typed result, and streams progress. From here, the Examples tour is the fastest way to see the rest of the SDK in working code. A few core concepts to build on next:
- Core Concepts - How agents, tools, and responses fit together
- Tools Guide - Tool types, schemas, and registration patterns
- Structured Output Guide - Guaranteed typed responses
- Multi-Agent Guide - Coordinate multiple specialized agents with Swarms
#Troubleshooting
#"Agent requires either a Client instance or an api_key"
Make sure you provide either api_key or client to the Agent constructor.
If you store the key in MAIVN_API_KEY, read it explicitly withos.environ['MAIVN_API_KEY'] or construct a client with ClientBuilder.from_environment().
#Tools not being called
Check that your tool has a clear description. The LLM uses the description to decide when to call the tool.
#Connection errors
Verify your network can reach the hosted mAIvn orchestrator and that your API key is valid. Check your network configuration and any outbound proxy or firewall rules.
See Troubleshooting for more help.