nirixa
v2.3.0
Published
AI Observability & Cost Intelligence — track token costs, latency, and hallucination risk for every LLM call
Downloads
216
Maintainers
Readme
nirixa
AI Observability & Cost Intelligence for JavaScript & TypeScript. Track token costs, latency, and hallucination risk for every LLM call — with zero friction.
npm install nirixa
# or
pnpm add nirixaQuick Start
import * as nirixa from 'nirixa'
import OpenAI from 'openai'
nirixa.init({ apiKey: 'nirixa-your-key' })
const openai = new OpenAI()
const ai = nirixa.wrap(openai, { feature: '/api/chat' })
const response = await ai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Hello!' }],
})
console.log(response.choices[0].message.content)
await nirixa.flush()Four Ways to Integrate
1. wrap() — Transparent client proxy (recommended)
Wrap a provider client once and use it exactly like the original. Model, provider, prompt, and request params are auto-extracted from every call.
import { NirixaClient } from 'nirixa'
import OpenAI from 'openai'
const nirixa = new NirixaClient({ apiKey: 'nirixa-your-key' })
const openai = new OpenAI()
const ai = nirixa.wrap(openai, { feature: '/api/chat', user: userId })
const response = await ai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Hello!' }],
})Works with any provider:
import Anthropic from '@anthropic-ai/sdk'
const claude = nirixa.wrap(new Anthropic(), { feature: '/api/analyze' })
const response = await claude.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Summarize this...' }],
})2. track() — Explicit per-call wrapping
const prompt = 'Summarize this document...'
const response = await nirixa.track({
feature: '/api/summarize',
user: 'user-123',
prompt,
prompt_version: 'v2-concise', // optional: A/B test prompt versions
fn: () => openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
}),
})3. observe() — Decorator / Observer style
HOF pattern (works everywhere):
import * as nirixa from 'nirixa'
nirixa.init({ apiKey: 'nirixa-your-key' })
const trackedChat = nirixa.observe({ feature: '/api/chat' })(
async (messages: Message[]) =>
openai.chat.completions.create({ model: 'gpt-4o', messages })
)
const response = await trackedChat(messages)TypeScript class method decorator (requires experimentalDecorators: true):
import { NirixaClient, Observe } from 'nirixa'
class ChatService {
@Observe({ feature: '/api/chat' })
async chat(messages: Message[]) {
return openai.chat.completions.create({ model: 'gpt-4o', messages })
}
}4. Auto-patch — Zero code changes
import { NirixaClient, patchOpenAI, patchAll } from 'nirixa'
const nirixa = new NirixaClient({ apiKey: 'nirixa-your-key' })
patchOpenAI(nirixa, '/api/chat') // patch a specific provider
patchAll(nirixa) // or patch everything installed
// [nirixa] Patched 4 providers: OpenAI, Anthropic, Groq, GeminiModule-level API
import * as nirixa from 'nirixa'
nirixa.init({ apiKey: 'nirixa-your-key' })
const response = await nirixa.track({ feature: '/api/chat', fn: () => openai.chat.completions.create({ ... }) })
const ai = nirixa.wrap(openai, { feature: '/api/chat' })
await nirixa.flush() // always call before process exitAgent Tracing
Group multi-step agent runs into a single observable trace — with aggregated cost, token, and latency totals, and a waterfall view in the dashboard.
import * as nirixa from 'nirixa'
import OpenAI from 'openai'
nirixa.init({ apiKey: 'nirixa-your-key' })
const openai = new OpenAI()
const ai = nirixa.wrap(openai, { feature: 'agent/step' })
await nirixa.agent('research-agent', async () => {
// Every track() call here inherits the trace_id automatically
const r1 = await ai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Classify this query: ...' }],
})
const r2 = await ai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Answer based on: ...' }],
})
// Track a non-LLM tool call inside the same trace
await nirixa.tool('db_lookup', () => db.find(query), { query })
})
await nirixa.flush()View traces at Dashboard → Agents.
Prompt Version Tracking
A/B test prompt versions and compare cost, latency, and hallucination score across versions in the dashboard.
const response = await nirixa.track({
feature: '/api/chat',
prompt_version: 'v3-concise',
fn: () => openai.chat.completions.create({ ... }),
})View version performance at Dashboard → Prompts.
Request Replay
Re-run any logged call locally with a different model to compare cost and output. No credentials are stored — replay executes on your machine using your existing env API key.
import * as nirixa from 'nirixa'
nirixa.init({ apiKey: 'nirixa-your-key' })
// First make a tracked call — request params are stored automatically
const ai = nirixa.wrap(openai, { feature: '/api/chat' })
await ai.chat.completions.create({ model: 'gpt-4o', messages: [...] })
await nirixa.flush()
// Grab the call_id from the dashboard or logs endpoint, then replay
const result = await nirixa.replay('call-id-here')
console.log(result.responseText)
console.log(`Cost delta: $${result.costDelta.toFixed(6)}`)
// Swap to a cheaper model
const cheaper = await nirixa.replay('call-id-here', { modelOverride: 'gpt-4o-mini' })
console.log(`Saved $${(-cheaper.costDelta).toFixed(6)}`)replay() returns:
| Key | Type | Description |
|-----|------|-------------|
| responseText | string \| null | The new response |
| originalCost | number | Cost of the original call |
| replayCost | number | Cost of the replay |
| costDelta | number | replayCost - originalCost (negative = savings) |
| replayCallId | string | New call_id logged for this replay |
Supported providers for replay: OpenAI, Anthropic, Groq.
LLM-as-Judge
Get a factual grounding score from a second LLM after every call. Requires captureResponse: true.
const nirixa = new NirixaClient({
apiKey: 'nirixa-your-key',
captureResponse: true,
judgeEnabled: true,
})Results appear in the log detail drawer under LLM-as-Judge. Judge model can be changed in Dashboard → Alerts → LLM-as-Judge.
Configuration
const nirixa = new NirixaClient({
apiKey: 'nirixa-your-key', // Required
host: 'https://api.nirixa.in', // Default
scoreHallucinations: true, // Heuristic hallucination scoring (LOW/MEDIUM/HIGH)
captureResponse: false, // Store prompt_text + response_text (needed for judge & replay)
judgeEnabled: false, // Fire LLM-as-Judge after every call (requires captureResponse)
asyncIngest: true, // Non-blocking — zero added latency
debug: false, // Log each tracked call to console
})Supported Providers
| Provider | Auto-detected via | Patch function |
|--------------|--------------------------------|--------------------|
| OpenAI | choices + usage | patchOpenAI |
| Anthropic | content + usage | patchAnthropic |
| Google Gemini| usageMetadata | patchGemini |
| Sarvam AI | OpenAI-compatible shape | — |
What Gets Tracked
| Metric | Description | |---------------------|--------------------------------------------------| | Token cost | Per-call USD cost by feature and model | | Latency | p50 / p95 / p99 response times | | Hallucination risk | LOW / MEDIUM / HIGH heuristic scoring | | Prompt drift | Output variance over time | | Error rate | Failed calls by feature | | Prompt version | Per-version cost, latency, halluc score | | Agent traces | Grouped runs with waterfall view | | Request params | Full provider kwargs stored for replay |
flush() — Before process exit
await nirixa.flush()
process.exit(0)Runtime Support
- Node.js 18+ (native
fetch) - Bun and Deno
- Edge runtimes (Vercel Edge, Cloudflare Workers)
- Browser (proxy the ingest endpoint)
Links
- Dashboard: nirixa.in
- Python SDK:
pip install nirixa - Docs: nirixa.in/docs
- Email: [email protected]
