One complete example per tower.

Each strip below is a full, runnable main.py for that provider, not a fragment. Swap in your own API key and it deploys as shown. Hume has no HTTP-tool concept, so its tools register with transport="client"; AssemblyAI and ElevenLabs default to transport="http" and can host the tool for you.

AssemblyAI default provider

deploy() creates a persistent agent record on AssemblyAI's servers. local=True starts a local tool server and tunnels it publicly via ngrok, so AssemblyAI can call get_weather over HTTP.

main.py
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["info"])

token = agent.mint_token()  # short-lived client token
# open a voice session with `token` (browser SDK, phone bridge, etc.)

Connect: mint_token() returns a short-lived client token. Open a voice session with it (AssemblyAI's browser SDK or a phone bridge); that live session is what actually calls get_weather.

ElevenLabs

Closest analog to AssemblyAI: deploy() creates a persistent agent, and both tool transports work. provider_options picks the LLM and voice; both have defaults (gemini-2.5-flash, ElevenLabs' "Rachel" voice) if omitted.

main.py
from minmo import VoiceAgent
from minmo.providers.elevenlabs import ElevenLabsProvider

agent = VoiceAgent(
    prompt="You are a friendly voice assistant. Keep answers short.",
    api_key="YOUR_ELEVENLABS_API_KEY",
    provider=ElevenLabsProvider(),
    provider_options={"voice_id": "21m00Tcm4TlvDq8ikWAM"},  # optional, this is the default
)

@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["info"])

signed_url = agent.mint_token()  # a signed WebSocket URL, not a bare token

Connect: mint_token() returns a signed WebSocket URL, not a bare token. Open a conversation directly against it.

Hume client tools only

Hume has no HTTP-tool concept, so get_weather registers with transport="client". Hume issues an api_key and a secret_key separately; pass the secret through provider_options. Hume's prompts, tools, and configs are name-unique versioned resources: redeploying with the same name adds a new version instead of erroring.

main.py
from minmo import VoiceAgent
from minmo.providers.hume import HumeProvider

agent = VoiceAgent(
    prompt="You are a friendly voice assistant. Keep answers short.",
    api_key="YOUR_HUME_API_KEY",
    provider=HumeProvider(),
    provider_options={
        "secret_key": "YOUR_HUME_SECRET_KEY",
        "voice": {"name": "Ava Song", "provider": "HUME_AI"},  # optional, this is the default
    },
)

@agent.tool(transport="client")
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"It's sunny in {city}."

result = agent.deploy()  # no HTTP tools registered, nothing to host or tunnel
print(result["info"])

access_token = agent.mint_token()  # OAuth token, needs the secret_key above

Connect: mint_token() exchanges your api_key + secret_key for an OAuth access token. Start an EVI session with it; your own app code (not minmo) handles each tool.call over that session.

Full API reference →