minmo
Boilerplate-free SDK for building voice agents on AssemblyAI's Voice Agent API, with support for Hume, OpenAI Realtime, and ElevenLabs too.
Define a prompt, register Python functions as tools, deploy. minmo handles JSON-Schema generation, local tool hosting + tunneling, and talking to each provider's REST API — so you write the assistant, not the plumbing.
Install
pip install minmo
(Contributing or want an editable checkout instead? pip install -e ".[dev]" after cloning.)
(Set NGROK_AUTHTOKEN in your environment if you plan to use local=True —
see pyngrok's docs for how to get one.)
Quickstart
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
That's it — 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.
result always includes an "info" field — a plain-language paragraph
telling you whether the agent is hosted on the provider's servers or only
exists locally, and how to actually connect to it (usually via
mint_token()). Worth printing after every deploy, especially since this
differs per provider — see below.
Testing 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 (no server, no tunnel)
@agent.tool defaults to transport="http" — minmo hosts the function
behind a URL AssemblyAI calls. Pass transport="client" instead to declare
a client-side/function tool:
no server, no tunnel, no host_url needed for that tool.
@agent.tool(transport="client")
def get_account_balance(account_id: str) -> str:
"""Look up an account's balance."""
return "$42.00"
minmo only builds the correct agent config for this — declaring the tool
as client-side. Running the actual session (the WebSocket connection that
receives tool.call and sends back tool.result) is your own code's job:
a browser app, a Twilio bridge, whatever already holds that live connection.
If every registered tool is transport="client", deploy() skips the local
server and tunnel (or host_url requirement) entirely — nothing to host.
Providers
minmo supports AssemblyAI (default), Hume, OpenAI Realtime, and ElevenLabs. 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 your process's memory |
Call mint_token() right after, in the same process, to actually send it to OpenAI and 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=...);
see each provider's docstring in minmo/providers/ for required 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 (not local=True)
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
Your host must already be running the tool server — local=True is for
development; production tool hosting is up to you (minmo's local server
factory, minmo.server.create_tool_server, is reusable if you want to
deploy it yourself behind a real domain).
Development
pip install -e ".[dev]"
pytest -q
Pushes are auto-formatted with Black via GitHub Actions, and every push/PR runs the test suite across Python 3.10–3.12.
Contributing
Issues and PRs welcome. Keep changes small and covered by a test.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file minmo-0.2.0.tar.gz.
File metadata
- Download URL: minmo-0.2.0.tar.gz
- Upload date:
- Size: 31.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ab9e83f41ece05f3975be9965eb1da8057b69c7bb329a3708feac20c9423cea
|
|
| MD5 |
74feea576dfa35ae63073e7945a21ff3
|
|
| BLAKE2b-256 |
b6f28ac16fe33ae07b52c56b332cf8a5b5a1d459c17edc0e4a8c9ad32925ff9e
|
Provenance
The following attestation bundles were made for minmo-0.2.0.tar.gz:
Publisher:
publish.yml on a-elhaag/minmo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
minmo-0.2.0.tar.gz -
Subject digest:
2ab9e83f41ece05f3975be9965eb1da8057b69c7bb329a3708feac20c9423cea - Sigstore transparency entry: 2711810072
- Sigstore integration time:
-
Permalink:
a-elhaag/minmo@7cb00912cede3af763d85fe7b57018c38620e6fc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/a-elhaag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7cb00912cede3af763d85fe7b57018c38620e6fc -
Trigger Event:
release
-
Statement type:
File details
Details for the file minmo-0.2.0-py3-none-any.whl.
File metadata
- Download URL: minmo-0.2.0-py3-none-any.whl
- Upload date:
- Size: 21.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a16d8a7c2ac368c84c794e95c09e6522bac6bae9466361253238974f1050380f
|
|
| MD5 |
d6126d0e5eca939202477a9cad66b9be
|
|
| BLAKE2b-256 |
26d22edc9094c6e4b44c367914fbda3de225c98972658c3166e9bcfa57c2dd29
|
Provenance
The following attestation bundles were made for minmo-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on a-elhaag/minmo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
minmo-0.2.0-py3-none-any.whl -
Subject digest:
a16d8a7c2ac368c84c794e95c09e6522bac6bae9466361253238974f1050380f - Sigstore transparency entry: 2711810635
- Sigstore integration time:
-
Permalink:
a-elhaag/minmo@7cb00912cede3af763d85fe7b57018c38620e6fc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/a-elhaag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7cb00912cede3af763d85fe7b57018c38620e6fc -
Trigger Event:
release
-
Statement type: