@smarthivelabs-devs/ai-nexus
v1.0.0
Published
Official Node.js SDK for the SmartHive AI Nexus API
Readme
@smarthivelabs-devs/ai-nexus
Official Node.js / TypeScript SDK for the SmartHive AI Nexus — a unified AI gateway that routes requests to OpenAI, Anthropic, Gemini, ElevenLabs, FAL, Stability, and Runway through a single API.
What this package is: The foundation SDK. Zero runtime dependencies, works in Node.js 18+, edge runtimes, and any bundler. Every other SmartHive SDK (react-ai-nexus, next-ai-nexus, ai-nexus-expo) builds on top of this one.
Features
- Zero runtime dependencies — uses the platform
fetchAPI (Node 18+, Deno, Bun, edge runtimes) - Dual ESM + CJS —
importandrequireboth work, correct types for both - 40+ fully typed interfaces — every request param and response field has a TypeScript type
- Automatic retries — exponential backoff on 408, 429, 500, 502, 503, 504 (capped at 8 s)
- Per-request timeouts —
AbortController-based, configurable per client or per request - Streaming — type-safe
AsyncIterable<ChatStreamChunk>via function overloads; no extra setup - Structured error hierarchy — catch
AiNexusAuthError,AiNexusRateLimitError, etc. individually
Installation
npm install @smarthivelabs-devs/ai-nexus
# or
yarn add @smarthivelabs-devs/ai-nexus
# or
pnpm add @smarthivelabs-devs/ai-nexusNode.js ≥ 18 is required (uses native fetch).
Environment Setup
Create a .env file (or set these in your hosting platform):
# Required — your API key from the SmartHive AI Nexus dashboard
AI_NEXUS_API_KEY=nexus_live_xxxxxxxxxxxxxxxxxxxx
# Optional — only needed if self-hosting or pointing at a staging environment
# Default: https://api.smarthivelabs.dev
AI_NEXUS_BASE_URL=https://api.smarthivelabs.devThe SDK does not read env vars automatically. You must pass apiKey explicitly:
const nexus = new AiNexus({ apiKey: process.env.AI_NEXUS_API_KEY! });Quick Start
import { AiNexus } from '@smarthivelabs-devs/ai-nexus';
const nexus = new AiNexus({
apiKey: process.env.AI_NEXUS_API_KEY!,
});
// Blocking chat
const response = await nexus.chat.create({
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(response.choices[0]?.message.content);Client Configuration
const nexus = new AiNexus({
apiKey: 'nexus_live_xxx', // Required. API key from the dashboard.
baseUrl: 'https://...', // Optional. Default: https://api.smarthivelabs.dev
maxRetries: 2, // Optional. Default: 2. Set to 0 to disable retries.
timeout: 30_000, // Optional. Default: 30 000 ms (30 s).
defaultHeaders: { // Optional. Extra headers sent on every request.
'X-Project-ID': 'proj_123',
},
});Per-request overrides
withOptions() returns a new client with overridden settings — the original is unchanged:
// This request uses a 5 s timeout; the original client is unaffected
const response = await nexus
.withOptions({ timeout: 5_000 })
.chat.create({ model: 'gpt-4o', messages: [...] });
// Different API key for a different project
const projectClient = nexus.withOptions({ apiKey: 'nexus_live_project_b' });Resources
nexus.chat — Chat Completions
Send messages to any supported LLM (OpenAI GPT-4o, Claude, Gemini, etc.). The model name is routed through your configured model profiles.
// Blocking response
const res = await nexus.chat.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Explain async/await in one paragraph.' },
],
temperature: 0.7, // 0–2, controls randomness
max_tokens: 512, // cap the response length
top_p: 0.95, // nucleus sampling
stop: ['\n\n'], // stop sequence
n: 1, // number of completions
user: 'user_abc123', // end-user ID for abuse tracking
response_format: { type: 'json_object' }, // force JSON output
});
console.log(res.choices[0]?.message.content);
console.log(`Tokens used: ${res.usage.total_tokens}`);Streaming — stream: true narrows the return type to Promise<AsyncIterable<ChatStreamChunk>> at compile time:
const stream = await nexus.chat.create({
model: 'claude-sonnet-4-6',
messages: [{ role: 'user', content: 'Write me a poem.' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? '');
}Vision (multimodal) — pass image URLs alongside text:
await nexus.chat.create({
model: 'gpt-4o',
messages: [{
role: 'user',
content: [
{ type: 'image_url', image_url: { url: 'https://example.com/diagram.png', detail: 'high' } },
{ type: 'text', text: 'What does this diagram show?' },
],
}],
});Tool / function calling:
const res = await nexus.chat.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'What is the weather in London?' }],
tools: [{
type: 'function',
function: {
name: 'get_weather',
description: 'Get current weather for a city',
parameters: {
type: 'object',
properties: {
city: { type: 'string' },
unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },
},
required: ['city'],
},
},
}],
tool_choice: 'auto',
});
if (res.choices[0]?.finish_reason === 'tool_calls') {
const call = res.choices[0].message.tool_calls?.[0];
const args = JSON.parse(call?.function.arguments ?? '{}');
// { city: 'London' }
}Multi-turn conversation:
const messages: ChatMessage[] = [];
messages.push({ role: 'user', content: 'My name is Alex.' });
const r1 = await nexus.chat.create({ model: 'gpt-4o', messages });
messages.push(r1.choices[0]!.message);
messages.push({ role: 'user', content: 'What is my name?' });
const r2 = await nexus.chat.create({ model: 'gpt-4o', messages });
console.log(r2.choices[0]?.message.content); // "Your name is Alex."nexus.embeddings — Vector Embeddings
Generate embeddings for semantic search, clustering, and similarity matching.
const res = await nexus.embeddings.create({
model: 'text-embedding-3-large',
input: ['Hello world', 'Bonjour le monde'],
dimensions: 1024, // optional — reduce dimensions for storage
encoding_format: 'float', // 'float' (default) or 'base64'
});
// res.data[0].embedding → number[] of length 1024
const similarity = cosineSimilarity(res.data[0]!.embedding, res.data[1]!.embedding);Single string input also works:
const res = await nexus.embeddings.create({
model: 'text-embedding-3-small',
input: 'Query text for search',
});nexus.audio — Speech-to-Text and Text-to-Speech
Transcribe audio → text (Whisper):
const transcript = await nexus.audio.transcribe({
audioUrl: 'https://storage.example.com/recording.mp3', // public or pre-signed URL
model: 'whisper-large-v3', // optional, uses your default model profile
language: 'en', // optional BCP-47 code, improves accuracy
prompt: 'SmartHive, API', // optional vocabulary hint
response_format: 'json', // 'json' | 'text' | 'srt' | 'vtt'
temperature: 0, // 0 = deterministic
});
console.log(transcript.text);
console.log(transcript.segments); // timestamped word-level segmentsSynthesize text → speech (TTS):
const audio = await nexus.audio.speak({
text: 'Welcome to SmartHive AI Nexus.',
model: 'tts-1-hd', // optional — 'tts-1' (fast) or 'tts-1-hd' (quality)
voiceProfile: 'nova', // optional — voice name from your provider
speed: 1.0, // optional — 0.25–4.0
response_format: 'mp3', // optional — 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm'
});
// audio.data → ArrayBuffer
// audio.contentType → 'audio/mpeg'
// Node.js — save to file
import { writeFileSync } from 'fs';
writeFileSync('speech.mp3', Buffer.from(audio.data));
// Browser — create a download
const blob = new Blob([audio.data], { type: audio.contentType });
const url = URL.createObjectURL(blob);nexus.images — Image Generation
Image generation is async (the provider processes it as a job). Poll until complete.
// Start the job
const job = await nexus.images.generate({
prompt: 'A futuristic city skyline at sunset, photorealistic',
model: 'dall-e-3', // optional — uses default image model
size: '1024x1024', // '256x256' | '512x512' | '1024x1024' | '1024x1792' | '1792x1024'
quality: 'hd', // 'standard' | 'hd'
style: 'vivid', // 'vivid' | 'natural'
n: 1, // number of images
response_format: 'url', // 'url' | 'b64_json'
});
// Poll until done (or use useImages hook in React)
let result = await nexus.images.getJob(job.jobId);
while (result.status === 'queued' || result.status === 'processing') {
await new Promise(r => setTimeout(r, 2_000));
result = await nexus.images.getJob(job.jobId);
}
if (result.status === 'completed') {
console.log(result.data?.[0]?.url);
} else {
console.error('Generation failed:', result.error);
}nexus.videos — Video Generation
Same async job pattern as images, but may take 1–5 minutes to complete.
// Start generation
const job = await nexus.videos.generate({
prompt: 'A timelapse of clouds over mountains',
model: 'runway-gen3', // optional
duration: 5, // seconds (provider-dependent max)
aspectRatio: '16:9', // '16:9' | '9:16' | '1:1' | '4:3'
quality: 'hd', // 'standard' | 'hd'
style: 'cinematic', // optional style hint
});
// Poll
let result = await nexus.videos.getJob(job.jobId);
while (result.status === 'queued' || result.status === 'processing') {
await new Promise(r => setTimeout(r, 10_000));
result = await nexus.videos.getJob(job.jobId);
}
console.log(result.url); // video URL
console.log(result.thumbnailUrl); // thumbnail
console.log(result.duration); // actual duration in seconds
// List all video jobs
const all = await nexus.videos.listJobs();
console.log(`${all.total} total jobs`);nexus.agents — AI Agents
Run an agent by its ID. The agent uses its configured system prompt, model, and knowledge base.
// Single-turn
const res = await nexus.agents.run({
agentId: 'agent_abc123',
input: 'Summarise our Q1 sales report.',
context: { userId: 'user_456', tier: 'premium' }, // optional metadata
});
console.log(res.output);
console.log(res.sessionId); // save this for multi-turn
console.log(res.finishReason); // 'stop' | 'tool_calls' | 'length'
console.log(res.usage?.total_tokens);Multi-turn with session continuity:
// Turn 1
const turn1 = await nexus.agents.run({
agentId: 'agent_abc123',
input: 'I need help with my order #ORD-9988.',
});
// Turn 2 — pass sessionId to maintain conversation history
const turn2 = await nexus.agents.run({
agentId: 'agent_abc123',
input: 'What is its current status?',
sessionId: turn1.sessionId, // links turns together
});
// Retrieve full session history
const session = await nexus.agents.getSession(turn1.sessionId);
console.log(session.messages); // full conversation
console.log(session.status); // 'active' | 'ended'nexus.realtime — Realtime Voice Sessions
Create a LiveKit WebRTC session for real-time voice conversations with an agent.
import { Room } from 'livekit-client';
// 1. Create the session
const session = await nexus.realtime.sessions.create({
agentId: 'agent_abc123',
mode: 'voice', // 'voice' | 'text' | 'duplex'
features: ['transcription', 'tts', 'vad', 'recording'],
metadata: { userId: 'user_789' }, // optional
});
// session.livekitUrl → wss://your-livekit-server.livekit.cloud
// session.livekitToken → JWT for this participant
// session.sessionId → use for all subsequent calls
// 2. Connect to LiveKit with the returned credentials
const room = new Room();
await room.connect(session.livekitUrl, session.livekitToken);
// 3. Poll for transcript updates
const detail = await nexus.realtime.sessions.get(session.sessionId);
for (const entry of detail.transcript ?? []) {
console.log(`${entry.role}: ${entry.text}`);
}
// 4. Recording
const rec = await nexus.realtime.sessions.startRecording(session.sessionId);
console.log(rec.recordingId);
const stopped = await nexus.realtime.sessions.stopRecording(session.sessionId, {
format: 'mp4', // 'mp4' | 'webm' | 'mp3'
});
console.log(stopped.url); // download URL
console.log(stopped.duration); // seconds
console.log(stopped.size); // bytes
// 5. End the session
await nexus.realtime.sessions.end(session.sessionId);nexus.documents — Knowledge Base Documents
Ingest documents into a knowledge base for RAG (retrieval-augmented generation).
// Ingest a document by URL
const doc = await nexus.documents.ingest({
storageUrl: 'https://storage.example.com/policy.pdf', // public or pre-signed
knowledgeBaseId: 'kb_xyz789', // which knowledge base to add it to
metadata: { department: 'legal', version: '2026-Q1' },
chunkSize: 512, // optional — tokens per chunk
chunkOverlap: 64, // optional — overlap between chunks
});
// doc.status → 'queued' | 'processing' | 'completed' | 'failed'
// doc.documentId → use to check status
// Check processing status
let detail = await nexus.documents.get(doc.documentId);
while (detail.status === 'queued' || detail.status === 'processing') {
await new Promise(r => setTimeout(r, 3_000));
detail = await nexus.documents.get(doc.documentId);
}
console.log(`Chunks created: ${detail.chunkCount}`);
// List documents in a knowledge base
const list = await nexus.documents.list({
knowledgeBaseId: 'kb_xyz789',
page: 1,
pageSize: 20,
});
console.log(`${list.total} documents`);
// Delete a document
await nexus.documents.delete(doc.documentId);nexus.retrieval — Semantic Search
Query a knowledge base by semantic similarity. Used internally by RAG-enabled agents and useChat.
const results = await nexus.retrieval.query({
query: 'What is the refund window for digital products?',
knowledgeBaseId: 'kb_xyz789',
topK: 5, // number of results to return
minScore: 0.7, // optional — minimum similarity score (0–1)
filter: { department: 'legal' }, // optional metadata filter
});
for (const r of results.results) {
console.log(`[${r.score.toFixed(3)}] ${r.content}`);
console.log(` documentId: ${r.documentId}, chunkId: ${r.chunkId}`);
}nexus.moderation — Content Moderation
Check text or images for policy violations before processing.
// Text moderation
const result = await nexus.moderation.moderate({
input: 'User submitted message here',
model: 'omni-moderation-latest', // optional
});
if (result.flagged) {
// result.categories contains per-category scores
const flaggedCategories = Object.entries(result.categories)
.filter(([, v]) => v?.flagged)
.map(([k]) => k);
console.log('Blocked — flagged for:', flaggedCategories.join(', '));
}
// Image moderation
const imgResult = await nexus.moderation.moderate({
imageUrl: 'https://example.com/user-upload.jpg',
});Available categories: hate, hate/threatening, harassment, harassment/threatening, self-harm, self-harm/intent, self-harm/instructions, sexual, sexual/minors, violence, violence/graphic.
nexus.models — Model Profiles
List available models and their capabilities.
// List all active model profiles
const models = await nexus.models.list();
for (const model of models) {
console.log(`${model.slug} (${model.provider}) — ${model.capabilities.join(', ')}`);
console.log(` context: ${model.contextWindow}, cost: $${model.inputCostPer1k}/1k in`);
}
// Get a specific model
const model = await nexus.models.get('claude-sonnet-4-6');
console.log(model.maxOutputTokens);
console.log(model.isAvailable);nexus.usage — Usage & Cost Tracking
Query usage events for billing, analytics, or project cost tracking.
const report = await nexus.usage.list({
startDate: '2026-01-01', // ISO 8601 date
endDate: '2026-01-31',
projectId: 'proj_abc', // optional — filter by project
modelSlug: 'gpt-4o', // optional — filter by model
page: 1,
pageSize: 100,
});
console.log(`Total requests: ${report.summary.totalRequests}`);
console.log(`Total tokens: ${report.summary.totalTokens}`);
console.log(`Total cost: $${report.summary.totalCostUsd.toFixed(4)}`);
for (const event of report.data) {
console.log(`${event.createdAt} | ${event.modelSlug} | ${event.capability} | ${event.totalTokens} tokens | $${event.costUsd}`);
}nexus.health — Health Check
No authentication required. Use this to verify connectivity before making API calls.
const health = await nexus.health.check();
// { status: 'ok' | 'degraded' | 'down', version: '1.2.3', uptime: 99.97, timestamp: '...' }
if (health.status !== 'ok') {
console.warn('AI Nexus is degraded:', health.services);
}Error Handling
Every error thrown by the SDK extends AiNexusError. Import the specific classes to catch only what you care about:
import {
AiNexusError,
AiNexusAPIError,
AiNexusAuthError,
AiNexusRateLimitError,
AiNexusConnectionError,
AiNexusTimeoutError,
} from '@smarthivelabs-devs/ai-nexus';
try {
const res = await nexus.chat.create({ model: 'gpt-4o', messages });
} catch (err) {
if (err instanceof AiNexusAuthError) {
// HTTP 401 or 403 — invalid or expired API key
console.error('Invalid API key. Check AI_NEXUS_API_KEY.');
} else if (err instanceof AiNexusRateLimitError) {
// HTTP 429 — too many requests
console.error(`Rate limited. Retry after ${err.retryAfter ?? 'unknown'} seconds.`);
} else if (err instanceof AiNexusTimeoutError) {
// Request exceeded the configured timeout
console.error('Request timed out. Increase timeout or retry.');
} else if (err instanceof AiNexusConnectionError) {
// Network failure — no response received
console.error('Cannot reach AI Nexus. Check your network.');
} else if (err instanceof AiNexusAPIError) {
// Any other non-2xx HTTP response
console.error(`API error ${err.status}: ${err.message}`);
console.error('Code:', err.code);
console.error('Request ID:', err.requestId);
} else if (err instanceof AiNexusError) {
// All other SDK errors
console.error('SDK error:', err.message);
}
}Error Hierarchy
AiNexusError — base class for all SDK errors
├─ AiNexusAPIError — non-2xx response (has .status, .code, .requestId)
│ ├─ AiNexusAuthError — HTTP 401 or 403
│ └─ AiNexusRateLimitError — HTTP 429 (has .retryAfter in seconds)
└─ AiNexusConnectionError — no response received (network failure)
└─ AiNexusTimeoutError — request exceeded configured timeoutAutomatic Retries
The SDK retries on 408, 429, 500, 502, 503, 504 with exponential backoff:
| Attempt | Delay | |---------|-------| | 1st retry | 500 ms | | 2nd retry | 1 000 ms | | (capped at 8 000 ms) |
Configure with maxRetries: 0 to disable, or maxRetries: 5 for more resilience.
TypeScript
The SDK ships with .d.ts declaration files and source maps. All types are exported:
import type {
// Client
AiNexusClientOptions,
// Chat
ChatMessage, ChatTool, ToolCall, ContentPart,
ChatCreateParams, ChatCreateParamsStream,
ChatResponse, ChatStreamChunk, ChatUsage,
// Embeddings
EmbeddingsCreateParams, EmbeddingsResponse, EmbeddingObject,
// Audio
AudioTranscribeParams, AudioTranscribeResponse,
AudioSpeakParams, AudioSpeakResponse,
// Images
ImagesGenerateParams, ImagesGenerateResponse, ImageJob, ImageObject,
// Videos
VideosGenerateParams, VideoJob, VideoJobsListResponse,
// Agents
AgentsRunParams, AgentsRunParamsStream, AgentsRunResponse, AgentSession,
// Realtime
RealtimeCreateSessionParams, RealtimeSessionResponse, RealtimeSessionDetail,
RealtimeMode, RealtimeFeature,
RecordingStartResponse, RecordingStopParams, RecordingStopResponse,
// Documents
DocumentsIngestParams, DocumentIngestResponse, DocumentDetail, DocumentsListParams,
// Retrieval
RetrievalQueryParams, RetrievalQueryResponse, RetrievalResult,
// Moderation
ModerationParams, ModerationResponse, ModerationCategory,
// Models
ModelProfile, ModelCapability,
// Usage
UsageListParams, UsageListResponse, UsageEvent,
// Health
HealthResponse,
} from '@smarthivelabs-devs/ai-nexus';CommonJS
const { AiNexus, AiNexusAuthError } = require('@smarthivelabs-devs/ai-nexus');
const nexus = new AiNexus({ apiKey: process.env.AI_NEXUS_API_KEY });License
MIT — © SmartHive Labs
