Nover is a typed Python SDK + CLI for self-hosted, multi-provider AI gateways (9Router-compatible). One local endpoint routes to Gemini, NVIDIA, OpenRouter, Groq, Ollama, Tavily and Exa with automatic fallback — and Nover lets you talk to all of it from Python or the terminal: chat (streaming + tool calling), structured JSON output, images, TTS, STT, embeddings and web search/fetch.
$ pip install nover| Capability | SDK method | CLI |
|---|---|---|
| 💬 Chat (streaming) | client.chat() / chat_stream() |
nover chat "..." --stream |
| 🛠️ Tool / function calling | chat(..., tools=...), chat_with_tools() |
via code |
| 📐 Structured output (JSON) | chat(..., response_format=...) |
nover chat --json |
| 🔄 Async | NoverAsync |
— |
| 🌀 Embeddings | client.embeddings() |
nover embed |
| 🖼️ Image generation | client.image() |
nover image |
| 🔊 Text-to-speech | client.tts() |
nover tts |
| 🎙️ Speech-to-text | client.stt() |
nover stt |
| 🔎 Web search | client.web_search() |
nover web search |
| 📄 Fetch URL → markdown | client.web_fetch() |
nover web fetch |
| 🖥️ Interactive chat (TUI) | — | nover interactive |
| 🔌 OpenAI-compatible | from nover import OpenAICompat |
— |
$ pip install nover
$ nover chat "Hello, world!" --streamfrom nover import Nover
with Nover() as client:
reply = client.chat("Explain a monad in one sentence")
print(reply.text)Tool calling:
from nover import Nover, tool
weather = tool("get_weather", "Get weather for a city",
{"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]})
with Nover() as c:
reply = c.chat("What's the weather in Paris?",
tools=[weather],
tool_choice="auto")
print(reply.tool_calls) # None, or [{name, arguments}]Auto-execute tools with an agent-style loop:
handlers = {"get_weather": lambda args: {"temp": 25}}
reply = c.chat_with_tools("Weather in Paris?", tools=[weather], tool_handler=handlers)
print(reply.text)Structured output:
reply = c.chat("Return JSON: {\"name\": \"Ada\", \"age\": 36}",
response_format={"type": "json_object"})
print(reply.text) # clean JSON (code fences auto-stripped)from nover import NoverAsync
import asyncio
async def main():
async with NoverAsync() as c:
return await c.chat("Hi")
print(asyncio.run(main()).text)OpenAICompat is a drop-in: code written against openai keeps working.
from nover import OpenAICompat
client = OpenAICompat()
r = client.chat.completions.create(
model="Code",
messages=[{"role": "user", "content": "Say NOVER"}],
stream=True,
)
for chunk in r:
print(chunk["choices"][0]["delta"].get("content", ""), end="")Nover ships a local MCP server so tools like VS Code, Cursor, Claude Desktop and other MCP clients can use your entire gateway.
pip install "nover[mcp]"
nover mcp # serves the MCP server over stdioIt exposes health, models, chat, chat_tool_calls, image, tts,
stt, embeddings, web_search and web_fetch as MCP tools. Add it to a
client, e.g. in VS Code settings.json / Claude Desktop claude_desktop_config.json:
{
"mcpServers": {
"nover": {
"command": "nover",
"args": ["mcp"]
}
}
}NINEROUTER_URL and NINEROUTER_KEY env vars configure where Nover points.
img = client.image("a watercolor of mountains")
open("mountains.png", "wb").write(img.content)
audio = client.tts("Olá, mundo", voice="pt-BR-FernandaNeural")
open("speech.wav", "wb").write(audio)
text = client.stt(("rec.wav", open("rec.wav", "rb").read()))
print(text.text)
vec = client.embeddings("RAG-ready footnote")[0]
res = client.web_search("9Router open source")
for r in res.results: print(r.title, "-", r.url)
page = client.web_fetch("https://example.com")
print(page.content.text)nover # help
nover version
nover health # gateway status
nover models --kind chat # list chat models
nover chat "Hello" --stream # chat with streaming
nover interactive # interactive TUI chat
nover embed "text"
nover image "a red fox" --out fox.png
nover tts "Hello" --voice pt-BR-FernandaNeural
nover stt recording.wav
nover web search "9Router"
nover web fetch linkedin.com/p
nover config
ninerouter aliases the same nover CLI for compatibility.
Resolution order: CLI flags > env vars > defaults.
| Setting | Env var | Default |
|---|---|---|
| Base URL | NINEROUTER_URL |
http://localhost:20128 |
| API key | NINEROUTER_KEY |
(optional) |
export NINEROUTER_URL="http://localhost:20128"
export NINEROUTER_KEY="sk-..." # optional if auth disabled- OpenAI-compatible:
OpenAICompatswaps into any stack that expectsopenai. - Designed to sit behind LangChain/LiteLLM style routers and orchestrators.
nover is a thin HTTP client. It stores no provider keys, sends your prompts
nowhere except the gateway you configure, and has no telemetry.
- Provider keys live in your gateway, on your machine/VM — not in this library.
- Only tight runtime deps (
httpx,typer), CI-tested across Python 3.9–3.13. - A CI test scans the repo for committed credentials.
See SECURITY.md for details.
pip install -e ".[dev]"
pytest # unit + live tests (live needs gateway)
pip install nover[interactive] # for the TUIRequires Python 3.9+.
SDK Python + CLI para gateways de IA multi-provedor self-hosted.
Um único pacote que conversa com um gateway compatível com a API da OpenAI que roteia Gemini, NVIDIA, OpenRouter, Groq, Ollama, Tavily e Exa — com chat, tools, saída estruturada em JSON, imagens, TTS, STT, embeddings e busca web.
pip install "nover"
nover chat "Olá, mundo" --stream
nover interactiveConfig, quickstart e CLI são idênticos à seção em inglês acima.
See docs/L5_PLAN.md — plan for nover serve (Nover as a standalone gateway).
MIT © ChristopherDond