Metadata-Version: 2.5
Name: minmo
Version: 0.2.0
Summary: Boilerplate-free SDK for building voice agents on AssemblyAI's Voice Agent API
Project-URL: Homepage, https://github.com/a-elhaag/minmo
Author: Anas Elhaag
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: fastapi>=0.110
Requires-Dist: jsonschema>=4.0
Requires-Dist: openai>=1.30
Requires-Dist: pyngrok>=7.0
Requires-Dist: requests>=2.31
Requires-Dist: uvicorn>=0.29
Provides-Extra: dev
Requires-Dist: black>=24.0; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: responses>=0.25; extra == 'dev'
Description-Content-Type: text/markdown

# minmo

[![CI](https://github.com/a-elhaag/minmo/actions/workflows/ci.yml/badge.svg)](https://github.com/a-elhaag/minmo/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/minmo.svg)](https://pypi.org/project/minmo/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml)

**Boilerplate-free SDK for building voice agents** on [AssemblyAI's Voice Agent API](https://assemblyai.com/docs/voice-agents/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.

📖 **[Full documentation](https://a-elhaag.github.io/minmo/)**

## Install

```bash
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](https://pyngrok.readthedocs.io/) for how to get one.)

## Quickstart

```python
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

```python
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](https://assemblyai.com/docs/voice-agents/voice-agent-api/tools/client-side-tools):
no server, no tunnel, no `host_url` needed for that tool.

```python
@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

```bash
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`)

```python
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

```bash
pip install -e ".[dev]"
pytest -q
```

Pushes are auto-formatted with [Black](https://black.readthedocs.io/) 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

[MIT](LICENSE) © [Anas Elhaag](https://github.com/a-elhaag)
