Skip to main content

PyPI Python versions License Downloads

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="")

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: OpenAICompat swaps into any stack that expects openai.
  • 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.


📄 License

MIT © ChristopherDond


Português (PT-BR) · ⬆ back to top

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nover-2.0.0.tar.gz (220.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nover-2.0.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file nover-2.0.0.tar.gz.

File metadata

  • Download URL: nover-2.0.0.tar.gz
  • Upload date:
  • Size: 220.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for nover-2.0.0.tar.gz
Algorithm Hash digest
SHA256 6bd525c1bf60521683f1f64172674f22ec3e52e5156b7d3b0ebb69470a5b7fdb
MD5 6619093caaaf2f965dc7abf3942c74de
BLAKE2b-256 b298c84e136fbd64588d889a0d8278dee2e75490f5c0ab3e9d5b095b09db2267

See more details on using hashes here.

File details

Details for the file nover-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: nover-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for nover-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ea7f88247b06c4222dbb3c56c427388aa4de0c26d76468000681f6e02826f938
MD5 6e5d65b06c1fbf04d219243ad30d10b2
BLAKE2b-256 066844e23bd3f946f9230a03637b458e127fc34df024e3b9ce29033ced7b4085

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page