Nover
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
✨ What you can do
| 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 |
— |
🚀 Quickstart
30 seconds to first chat
$ pip install nover
$ nover chat "Hello, world!" --stream
Chat & tools
from 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)
Async
from nover import NoverAsync
import asyncio
async def main():
async with NoverAsync() as c:
return await c.chat("Hi")
print(asyncio.run(main()).text)
Stay with the openai SDK
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="")
Connect ANY AI tool via MCP (Model Context Protocol)
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 stdio
It 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.
Images, TTS, STT, embeddings, web — all in one
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)
🖥️ CLI
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.
🔧 Configuration
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
☁️ Into the ecosystem
- OpenAI-compatible:
OpenAICompatswaps into any stack that expectsopenai. - Designed to sit behind LangChain/LiteLLM style routers and orchestrators.
🔒 Privacy & Security
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.
📦 Install & develop
pip install -e ".[dev]"
pytest # unit + live tests (live needs gateway)
pip install nover[interactive] # for the TUI
Requires Python 3.9+.
🇧🇷 Português
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 interactive
Config, quickstart e CLI são idênticos à seção em inglês acima.
🗺️ Roadmap
See docs/L5_PLAN.md — plan for nover serve (Nover as a standalone gateway).
📄 License
MIT © ChristopherDond
Metadata
Release files for nover 2.1.1
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 | |
|---|---|---|---|---|
| nover-2.1.1.tar.gz | 237.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nover-2.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 272.9 kB
Release files / nover-2.1.1.tar.gz
| Download URL | nover-2.1.1.tar.gz |
|---|---|
| Size | 237.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ae08f476f2e5b5258ef2555ce0787e39e5509ca685da2af1d01982b34fd29080
|
|
BLAKE2b-256 checksum How to use checksums |
64b3b8edfb3c5c4ba00ee2de0eb5a650db61523a8f24031feed4274482e108e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / nover-2.1.1-py3-none-any.whl
| Download URL | nover-2.1.1-py3-none-any.whl |
|---|---|
| Size | 35.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
addcb1393f496a2391ff7915de704ee7bb4be430acc07cbe94d7ea4c8b7d2d8a
|
|
BLAKE2b-256 checksum How to use checksums |
3e126d0e57ebcb75fe6c061893b5084f6e1559a0ceef5e0efe1bdacc4410dd57
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Security for nover 2.1.1
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.