AI Overview
Built-in AI capabilities in Nebutra β chat completions, embeddings, and semantic search powered by OpenAI and OpenRouter.
What's included
Nebutra ships AI features out of the box via @nebutra/agents, a thin wrapper around the Vercel AI SDK that adds tenant context, rate limiting, and usage metering automatically.
The following capabilities are available to every tenant:
| Feature | Description | Feature Flag |
|---|---|---|
| Chat completions | Streaming and non-streaming LLM responses | ai.chat |
| Embeddings | Vector representations for semantic search and RAG | ai.embeddings |
| Image analysis | Vision-capable model support (GPT-5) | ai.chat |
| Model selection | Per-tenant model overrides (Enterprise) | ai.model_selection |
Architecture
Requests flow through the API gateway, which applies auth, rate limiting, and metering before proxying to the underlying model provider:
Client App
β
βΌ
POST /api/v1/ai/chat (API Gateway β Hono)
β
ββ Auth check (API key)
ββ Feature flag check (ai.chat)
ββ Rate limit (per tenant, @nebutra/rate-limit)
β
βΌ
@nebutra/agents (Vercel AI SDK v6 wrapper)
β
ββ OpenAI (default)
ββ OpenRouter (multi-model: Claude, Llama, Mistralβ¦)
β
βΌ
Response / SSE stream
β
βΌ
@nebutra/metering (tokens consumed β billing)
β
βΌ
pgvector (embeddings only) (PostgreSQL vector storage)Supported models
| Model | Context | Best for |
|---|---|---|
gpt-5.5 | ~400 k+ | Flagship reasoning, vision, coding |
gpt-5.4-mini | ~400 k+ | Fast, cost-effective tasks |
text-embedding-3-small | β | Embeddings (1536 dims) |
text-embedding-3-large | β | High-accuracy embeddings (3072 dims) |
Ids follow models.dev. Prefer semantic tiers (flagship / fast) via @nebutra/ai-providers when possible so defaults stay current without hand-editing strings.
| Model | Provider | Notes |
|---|---|---|
anthropic/claude-sonnet-4.6 | Anthropic | Default flagship reasoning |
anthropic/claude-haiku-4.5 | Anthropic | Fast / cost-efficient |
openai/gpt-5.5 | OpenAI | OpenAI flagship via OpenRouter |
google/gemini-3.1-pro-preview | Long-context flagship | |
google/gemini-3.5-flash | Fast multimodal |
Pass the full model slug to streamText / generateText. Live catalog: models.dev / OpenRouter models.
Feature flags
AI features are disabled by default and must be enabled per tenant. The flags are checked in the API gateway before any model call is made β no tokens are consumed if a flag is off.
// Programmatically enable AI for a tenant
import { setFeatureFlag } from "@nebutra/preset";
await setFeatureFlag("org_123", "ai.chat", true);
await setFeatureFlag("org_123", "ai.embeddings", true);You can also toggle flags from the dashboard under Organization β Features.
Environment variables
Add these to your .env (or Vercel environment variables):
# Required: at least one provider key
OPENAI_API_KEY=""
# Optional: enables multi-model routing via OpenRouter
OPENROUTER_API_KEY=""
# Default model used when none is specified per-request
AI_DEFAULT_MODEL="gpt-5.4-mini"
# Optional: override for embedding model
AI_EMBEDDING_MODEL="text-embedding-3-small"Never expose OPENAI_API_KEY or OPENROUTER_API_KEY to the client. All model calls must go through the API gateway.
Usage and quotas
Token consumption is automatically metered via @nebutra/metering and counts against the tenant's API quota. You can inspect current usage from code or the dashboard:
import { getMetering, COMMON_METERS } from "@nebutra/metering";
const metering = await getMetering();
const quota = await metering.getQuota("org_123", "ai_tokens");
// β { limit: 5000000, used: 1243000, remaining: 3757000, percentage: 0.249 }Quota limits by plan:
| Plan | AI tokens / month |
|---|---|
| FREE | 100,000 |
| PRO | 5,000,000 |
| ENTERPRISE | Custom |
Quick usage example
import { streamText, generateText, embed } from "@nebutra/agents";
// Streaming chat (SSE)
const result = await streamText({
model: "gpt-5.5",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: userMessage },
],
tenantId,
});
// Non-streaming
const { text } = await generateText({
model: "gpt-5.4-mini",
prompt: "Summarize: " + content,
tenantId,
});
// Embeddings
const { embedding } = await embed({
model: "text-embedding-3-small",
value: "text to embed",
tenantId,
});Related
How is this guide?
Last updated on