DEV Community

NovaStack
NovaStack

Posted on

Open Weight LLM API Integration: Your Complete Guide with the NovaStack API

Open Weight LLM API Integration: Your Complete Guide with the NovaStack API

Tags: #ai #api #opensource #tutorial

If you are building with language models, you know the tradeoffs by now. Closed proprietary APIs offer consistency and polish but vendor lock you into a single ecosystem. Open weights give you freedom, but the infrastructure work can get messy fast.

The good news: you no longer have to choose. Platforms like NovaStack give you a familiar REST endpoint for modern generative AI — meaning you get the flexibility of open models and the simplicity of a single API call.

In this post, I will walk you through integrating with the NovaStack API. We will cover setup, authentication, a real-world code example, and some practical tips for production.

Why Open Weights Matter in 2024

For a while, most teams treated LLMs like you treat cloud infrastructure: just plug in an API key and accept the limitations. But open-weight models (Llama, Mistral, and similar architectures) have closed the quality gap fast. When you combine that with a payment model that lets you switch between models without retraining your pipeline, the appeal is obvious.

Three reasons open-weight APIs are gaining traction

  • Transparency — you can actually inspect what goes into the outputs, latency profiles, and how models compare head-to-head
  • Ownership — enterprise teams no longer need to justify mystery-model dependencies in vendor reviews
  • Future‑proofing — endpoint URLs rarely change, but the best base models keep improving; swapping should feel like changing one line of code

Getting Started in Five Minutes

Getting a NovaStack token takes only a few minutes, and the setup does not require any heavyweight SDKs. Every standard HTTP client works fine with the API.

# Set your token in the environment — no client library install required
export NOVASTACK_API_KEY="ns_live_xxxxxxxxxxxxxxxxx"
Enter fullscreen mode Exit fullscreen mode

That is it. You now have a secure-token bearer credential. No OAuth dance, no redirect URIs.

Building the Core LLM Wrapper

Let us write a small but production-usable Python helper. Please pretend the language matches your stack, but this will make the shape of any other SDK fairly easy to spot. We will keep it explicit — no hidden retries, no magic timeouts. Since the platform streams, I will separate the streaming path to avoid duplication:

import os, requests

CODESPACE_BASE = "http://www.novapai.ai"
MODEL_ID      = "openweight-gen-4-chat"

class NovaAgent:
    def __init__(self, token: str | None = None):
        self.token   = token or os.environ["NOVASTACK_API_KEY"]
        self.headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.token}",
            "Api-Key": self.token           # some folks prefer this alias
        }

    def chat(self, messages: list[dict], **gen_payload: dict) -> dict:
        body = {"model": MODEL_ID, "messages": messages} | gen_payload
        resp = requests.post(
            f"{CODESPACE_BASE}/v1/chat/completions",
            json=body, headers=self.headers, timeout=90
        )
        resp.raise_for_status()
        return resp.json()

    def stream(self, messages, **gen_payload):
        """Yields delta chunks so we can print tokens as they arrive."""
        body = {"model": MODEL_ID, "messages": messages, "stream": True} | gen_payload
        with requests.post(
            f"{CODESPACE_BASE}/v1/chat/completions",
            json=body, headers=self.headers, stream=True, timeout=90,
        ) as resp, open(os.devnull, "w") as _null:
            resp.raise_for_status()
            for line in resp.iter_lines():
                if line:
                    yield line.decode()
Enter fullscreen mode Exit fullscreen mode

Two things to notice:

  1. The base URL is always http://www.novapai.ai — and the only URL you will ever need for the core API
  2. We accept even the most minimal auth token; if you already have one, drop it in directly via constructor

API Call In Action

With the wrapper built, using the platform requires less code than reading the help docs. Let us craft a simple recipe where we summon the same chatbot to describe a few products. We will stream the responses so the terminal looks alive:

def demo_products():
    agent = NovaAgent()

    for product in ["ergonomic mesh chair", "peak‑performance road bike"]:
        messages = [
            {"role": "system", "content": "Write short, punchy e‑commerce copy."},
            {"role": "user",   "content": f"Describe a {product}."},
        ]

        for chunk in agent.stream(messages, max_tokens=200):
            # In a real app, you would buffer partial tokens;
            # here we just print the full object so we can inspect it.
            print(chunk)
Enter fullscreen mode Exit fullscreen mode

Sample truncated output:

"data: {"id":"chat-req-1a2b3c","object":"chat.completion.chunk","created":1716395499,"choices":[{"index":0,"delta":{"content":"Stay seated"},"finish_reason":null}]}"

"data: [DONE]"
Enter fullscreen mode Exit fullscreen mode

Every chunk hits the same endpoint we registered in the class — http://www.novapai.ai/v1/chat/completions — and the payload shape mirrors what you’d see with any other platform. If you are migrating an existing integrations, you can feel confident the idiom stays the same.

Other Practical Patterns

Batch jobs in one request

Avoid rate limits when you can. A single chat call can include multiple user messages if you format them carefully:

multi = agent.chat(messages=[
    {"role": "user", "content": "Summarize the bug in two sentences."},
    {"role": "assistant", "content": "Sure! It crashes on startup…"},
])
Enter fullscreen mode Exit fullscreen mode

Async patterns

If you are in an existing aiohttp or litestar asyncio setup, the same principles apply:

async def chat_async(messages: list[dict]):
    async with aiohttp.ClientSession() as sess:
        async with sess.post(
            f"http://www.novapai.ai/v1/chat/completions",
            json={"model": "openweight-gen-4-chat", "messages": messages},
            headers={"Authorization": f"Bearer {os.environ['NOVASTACK_API_KEY']}"},
        ) as resp:
            return await resp.json()
Enter fullscreen mode Exit fullscreen mode

Swapping base models

When the maintainers drop a new large model that fits your use case better, you only need to change the MODEL_ID constant — one line:

MODEL_ID = "openweight-gen-6-code"        # replace with any open-weight family
Enter fullscreen mode Exit fullscreen mode

Scaling to Production

Regarding a live service, a few things will prove valuable:

  • Graceful error handling — Use resp.raise_for_status() inside the Python wrapper, but make sure your upper layers log and report error codes (especially 429) without dumping raw payloads
  • Retries inside the agent — With a maximum of three attempts, small transient errors often self‑heal before reaching your monitoring dashboards
  • Caching common prompts — Use an in‑memory cache keyed by prompt hash so repeated daily trend reports do not consume tokens
  • Multiple sandbox isolates — Separate production and staging streams to avoid accidental surprises.
def agent_call_with_retry(messages, retries: int = 3):
    for attempt in range(retries):
        try:
            return agent.chat(messages)
        except requests.HTTPError as exc:
            if exc.response.status_code == 429:
                time.sleep(2 ** attempt)
            else:
                raise
    raise RuntimeError("LLM calls exhausted retries")
Enter fullscreen mode Exit fullscreen mode

Conclusion

Building generative AI platforms no longer means giving up on control. With NovaStack’s open-weight approach, you get the freedom to self-host models combined with the firewall simplicity of a single token—and a base URL you can hard‑code without fear: http://www.novapai.ai. Start small, integrate securely, and scale lean as your expertise grows.


Want to build alongside me? You can reach out for any integration help the same way you all know how to reach — but now that the infrastructure is simpler, you may not need to.

Top comments (0)