SmallestAI Python SDK
pip install smallestai gives you one package with two surfaces, plus a CLI:
- Atoms — build, configure, deploy, and phone-call voice AI agents (
client.atoms). - Models — low-latency text-to-speech and speech-to-text, sync/async and streaming (
client.waves;smallestai modelsin the CLI). - CLI —
smallestaifor managing agents, deploying agent-crew code, and running speech models.
pip install smallestai
Table of Contents
- Quickstart
- Text-to-speech and speech-to-text
- Agent crew: your own LLM
- Reusable tools and secrets
- CLI
- Async client
- Environments
- Exception handling
- Streaming and websockets
- Advanced
- Reference and docs
- Contributing
Quickstart: create an agent and call it
from smallestai import SmallestAI
client = SmallestAI(api_key="<your-api-key>")
# create an agent (the response .data is the new agent id)
agent_id = client.atoms.agents.create_agent(name="my-first-agent").data
# place an outbound call (from_product_id is a rented number's product id)
client.atoms.calls.start_outbound_call(
agent_id=agent_id,
phone_number="+1XXXXXXXXXX",
from_product_id="<rented-number-product-id>",
)
Text-to-speech and speech-to-text (Models)
synthesize_tts streams audio bytes. List available voices with client.waves.get_voices().
from smallestai import SmallestAI
client = SmallestAI(api_key="<your-api-key>")
with open("out.wav", "wb") as f:
for chunk in client.waves.synthesize_tts(text="Hello from Smallest.", voice_id="<voice-id>"):
f.write(chunk)
Streaming speech-to-text helper:
from smallestai.waves.helpers import stream_speech_to_text
for event in stream_speech_to_text(client, language="en"):
print(event)
Agent crew: your own LLM in the middle
An agent crew runs the LLM turn on a model you choose while Smallest handles
STT and TTS. Point the crew node's OpenAIClient at any OpenAI-compatible
endpoint (a hosted API, or a local model via Ollama):
from smallestai.atoms.crew.nodes import OutputCrewNode
from smallestai.atoms.crew.clients.openai import OpenAIClient
class Assistant(OutputCrewNode):
def __init__(self):
super().__init__(name="assistant")
self.llm = OpenAIClient(
model="claude-haiku-4-5",
api_key="<your-llm-key>",
base_url="https://api.anthropic.com/v1/", # or http://localhost:11434/v1 for Ollama
)
async def generate_response(self):
async for chunk in await self.llm.chat(self.context.messages, stream=True):
if chunk.content:
yield chunk.content
Conversation history is handled for you: every turn is appended to self.context,
and you send self.context.messages to the model each turn.
Deploy it with the CLI:
smallestai auth login
smallestai agent-crew init --agent-id <agent-id>
smallestai agent-crew deploy --entry-point server.py
smallestai agent-crew builds # pick the build -> Make Live
A flat directory (server.py + requirements.txt at the root) is the simplest
layout; a src/ layout with a pyproject.toml also works (declare all runtime
deps in the pyproject).
Reusable tools and secrets
Build a tool once in your org's registry and reference it from any agent, and store
API keys in a write-only secrets vault. Tools and Secrets wrap the /tool and
/secret endpoints; both default to the SMALLEST_API_KEY environment variable.
from smallestai.atoms.helpers import Tools, Secrets
tools = Tools() # or Tools(api_key="sk_...")
created = tools.create(
{
"name": "get_order_status",
"description": "Look up an order status by id",
"type": "api_call",
"method": "GET",
"url": "https://api.example.com/orders",
"parameters": [{"name": "order_id", "type": "text", "description": "order id", "required": True}],
}
)
tool_id = created["data"]["toolId"]
tools.list()
tools.duplicate(tool_id)
tools.delete(tool_id)
# secrets are write-only: the value is encrypted at rest and never returned
secrets = Secrets()
secrets.create(name="example_api_key", value="...")
secrets.list() # names and metadata only
Reference a saved tool from an agent with toolRefs: ["<toolId>"] on its single-prompt
config. The tool must exist in the registry first, or the reference is dropped when the
agent runs. Referencing a tool makes it available; the agent only calls it when its
prompt says to.
CLI
smallestai auth login # store your API key
smallestai agents list # list, get, call, and manage agents
smallestai calls list # inspect call logs, transcripts, recordings
smallestai calls events <call-id> # stream a live call's events (transcript, latency, tools)
smallestai calls transcript <call-id> -f # stream the transcript live
smallestai models # text-to-speech, speech-to-text, voices
smallestai agent-crew deploy ... # package and deploy crew code
smallestai agent-crew logs [build-id] # stream a build's compile + deploy logs
smallestai agent-crew chat # talk to a running crew locally
The speech command group is now
models(text-to-speech, speech-to-text, voices);wavesstill works as a hidden, back-compatible alias.
Async client
The SDK exports an async client with the same surface:
import asyncio
from smallestai import AsyncSmallestAI
async def main():
client = AsyncSmallestAI(api_key="<your-api-key>")
agents = await client.atoms.agents.list_agents()
print(agents.data)
asyncio.run(main())
Environments
from smallestai import SmallestAI
from smallestai.environment import SmallestAIEnvironment
client = SmallestAI(environment=SmallestAIEnvironment.PRODUCTION)
Exception handling
from smallestai.core.api_error import ApiError
try:
client.atoms.agents.get_agent(id="does-not-exist")
except ApiError as e:
print(e.status_code, e.body)
Streaming and websockets
The speech models support real-time, low-latency streaming over websockets. stream() returns a context manager; iterate it to process messages as they arrive.
from smallestai import SmallestAI
client = SmallestAI(api_key="<your-api-key>")
# real-time speech-to-text
with client.waves.speech_to_text.stream() as socket:
for message in socket:
print(message)
The async client mirrors this with async with / async for. Text-to-speech streams too: synthesize_tts(...) yields audio bytes as they are generated (see above).
Advanced
Access raw response data
Use .with_raw_response to get the response headers and status alongside the parsed data.
response = client.atoms.agents.with_raw_response.get_agent(id="<agent-id>")
print(response.headers) # response headers
print(response.status_code) # status code
print(response.data) # parsed object
Retries
The SDK retries retryable requests with exponential backoff (default 2). Configure it at the client or per request.
client = SmallestAI(api_key="<your-api-key>", max_retries=3)
# or per request
client.atoms.agents.get_agent(id="<agent-id>", request_options={"max_retries": 1})
Timeouts
Defaults to 60 seconds. Configure at the client or per request.
client = SmallestAI(api_key="<your-api-key>", timeout=20.0)
# or per request
client.atoms.agents.get_agent(id="<agent-id>", request_options={"timeout_in_seconds": 5})
Custom client
Override the httpx client for proxies, custom transports, and similar.
import httpx
from smallestai import SmallestAI
client = SmallestAI(
api_key="<your-api-key>",
httpx_client=httpx.Client(
proxy="http://my.test.proxy.example.com",
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
),
)
Reference and docs
- Full API reference: reference.md
- Product docs: https://smallest.ai/docs
Telemetry
The SDK sends anonymous, aggregated usage telemetry (which CLI commands run, deploy outcomes) so we can see what to improve. It never includes personal data or secrets: no API keys, agent ids, prompts, transcripts, phone numbers, file paths, or error messages. Only the event name, SDK / Python / OS version, and a random anonymous install id. It is fire-and-forget and never blocks your program.
Opt out any time:
export SMALLESTAI_TELEMETRY=0 # or DO_NOT_TRACK=1
Contributing
Most of src/ is generated from an API spec and gets overwritten on regeneration,
so hand edits there will not stick. If you spot a bug or a gap, open an issue.
Metadata
Release files for smallestai 5.12.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| smallestai-5.12.2.tar.gz | 503.3 kB | Without provenance | Details for smallestai-5.12.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| smallestai-5.12.2-py3-none-any.whl | Python 3 | none | any | Details for smallestai-5.12.2-py3-none-any.whl |
Total release size: 1.6 MB
Release files / smallestai-5.12.2.tar.gz
| Download URL | smallestai-5.12.2.tar.gz |
|---|---|
| Size | 503.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
16e03804d968daa11c7e7d94ab722c657afdb319131132476facdcbbca013368
|
|
BLAKE2b-256 checksum How to use checksums |
fe9338ef98ff205d81260eecfcf619cce60e3fb7672d6c659a5e5190b8b661da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.5.1 CPython/3.9.25 Linux/6.17.0-1022-azure
|
Release files / smallestai-5.12.2-py3-none-any.whl
| Download URL | smallestai-5.12.2-py3-none-any.whl |
|---|---|
| Size | 1.0 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ba758679f76268e2f958dde3570a564bd36bec7364457fb0a5a94f097688814c
|
|
BLAKE2b-256 checksum How to use checksums |
c16a559d1ccc16f190812e497fa01fb81711ce95ec10b1f91119e7fe5858fc34
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.5.1 CPython/3.9.25 Linux/6.17.0-1022-azure
|
Security for smallestai 5.12.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.