open source ยท MIT licensed
Voice agents, without the boilerplate.
Define a prompt, register Python functions as tools, deploy. minmo handles JSON-Schema generation, local tool hosting + tunneling, and talking to AssemblyAI, Hume, OpenAI Realtime, or ElevenLabs โ so you write the assistant, not the plumbing.
pip install minmo
Quickstart
Three moving parts: a prompt, a tool, a deploy call.
from minmo import VoiceAgent
agent = VoiceAgent(
prompt="You are a friendly voice assistant. Keep answers short.",
api_key="YOUR_ASSEMBLYAI_API_KEY",
)
@agent.tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
result = agent.deploy(local=True)
print(result) # the created AssemblyAI agent record, including its id
deploy(local=True) starts a local tool server, tunnels it
publicly, and registers get_weather as a real tool your
live voice agent can call. The returned result always
includes an info field โ plain language on whether the
agent lives on the provider's servers and how to connect to it.
Test tool logic without burning session minutes
from minmo import VoiceAgent
from minmo.testing import simulate
agent = VoiceAgent(
prompt="You are a friendly voice assistant.",
api_key="YOUR_ASSEMBLYAI_API_KEY",
llm={"base_url": "https://api.openai.com/v1", "model": "gpt-4o-mini", "api_key": "YOUR_OPENAI_KEY"},
)
@agent.tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
result = simulate(agent, transcript=["What's the weather in Paris?"])
print(result["tool_calls"])
simulate() calls the llm you configured
directly (any OpenAI-compatible endpoint) and runs tool calls against
your local Python functions โ no AssemblyAI session, no phone call.
Client-side tools
@agent.tool defaults to transport="http" โ
minmo hosts the function behind a URL the provider calls. Pass
transport="client" to declare a client-side/function tool
instead: no server, no tunnel, no host_url needed.
@agent.tool(transport="client")
def get_account_balance(account_id: str) -> str:
"""Look up an account's balance."""
return "$42.00"
If every registered tool is client-side, deploy() skips
the local server and tunnel entirely โ nothing to host.
Providers
minmo supports four backends. They don't all host your agent the same way:
| Provider | Hosted on their servers? | How you use it |
|---|---|---|
| AssemblyAI | Yes โ deploy() creates a persistent agent record |
mint_token() for a client token, connect a voice session with it |
| Hume | Yes โ deploy() creates/versions a config resource |
mint_token() for an access token, start an EVI session with it |
| OpenAI Realtime | No โ deploy() only builds a config in memory |
Call mint_token() right after, same process, to get a session token |
| ElevenLabs | Yes โ deploy() creates a persistent agent record |
mint_token() for a signed WebSocket URL, connect a conversation with it |
Pass a different provider via VoiceAgent(provider=..., provider_options=...).
CLI
minmo init # scaffold main.py, .env.example, requirements.txt
minmo deploy # import main.py, find the VoiceAgent, deploy it
minmo logs # print the most recent session log
Deploying to a real server
agent.deploy(local=False, host_url="https://your-deployed-tool-server.example.com")
# or set MINMO_HOST_URL in the environment instead of passing host_url
local=True is for development; production tool hosting is
up to you. minmo.server.create_tool_server is reusable if
you want to deploy it yourself behind a real domain.