VaaniEval
Node.js SDK

Overview

Installing and configuring the VaaniEval Node.js SDK — options, defaults, automatic fetch instrumentation and the upload API.

@vaanieal/observer is a zero-dependency, pure-ESM package that records voice-agent calls to a local session package and uploads them after the call.

VaaniEval is in closed beta

The repositories below are private while the product is in closed beta, so the links will 404 unless your GitHub account has been granted access. Neither SDK is published to a public package registry yet — both install from Git.

To get access, email shubham@vaanieval.com or book a call — a short conversation about your use case tells us whether VaaniEval fits, and gets you onboarded with the setup that matches your stack.

Install

npm install github:shubhamofbce/vaanieval-observer-nodejs-sdk

Requires Node.js 20 or newer. The package is ESM-only and uses only Node built-ins — node:async_hooks, node:fs/promises, node:crypto, node:perf_hooks. Nothing else enters your dependency tree.

package.json
{
  "type": "module"
}

Pin a commit or tag in production (github:shubhamofbce/vaanieval-observer-nodejs-sdk#v0.1.0). Installing from a moving branch means a redeploy can change your instrumentation without a version bump.

Constructing the observer

import { VaaniObserver } from '@vaanieal/observer';

const vaani = new VaaniObserver({
  endpoint: 'http://localhost:8000',
  apiKey: 'local-dev',
  spoolDirectory: './.vaani-spool',
  capture: { audio: true, httpBodies: false },
  instrumentations: { fetch: true, websocket: true },
  endpoints: [
    { id: 'stt', type: 'stt', url: 'wss://api.deepgram.com/v1/listen' },
    { id: 'llm', type: 'llm', url: 'https://api.openai.com/v1' },
    { id: 'tts', type: 'tts', url: 'https://api.elevenlabs.io' },
  ],
  upload: { retries: 3 },
  strict: false,
});

Prop

Type

Constructing the observer patches global fetch immediately. It performs no network I/O. Construct it once at process start.

Because fetch is a global, constructing more than one observer in a process stacks patches. Create exactly one and share it.

Lifecycle

Start a session per call

const session = vaani.startSession({ agentId: 'support-bot', metadata: { env: 'prod' } });

End the session

const finalized = await session.end({ outcome: 'completed' });
console.log(finalized.directory, finalized.sessionId);

Closes open spans, composes stereo audio, writes manifest.json last.

Upload

await vaani.uploadPackage(finalized);

Requires endpoint and apiKey — it throws if either is missing. If you skip this, the package simply stays on disk.

Flush at shutdown

process.on('SIGTERM', async () => {
  await vaani.flush();
  process.exit(0);
});

Finalizes every open session. Finalization errors reject, matching Promise.all semantics — a package that could not be written is visible, not swallowed.

Observer API

MethodPurpose
startSession(input)Open a session (sessionId, agentId, metadata)
flush()Finalize all open sessions
run(session, fn)Install ambient context
runWithEndpoint(session, endpointId, fn, turnId)Force an endpoint rule
runWithTurn(session, turnId, fn)Tag ambient work with a turn
currentContext()Read the ambient context
classifyUrl(url)Which endpoint rule a URL matches
observeWebSocket(socket, options)Observe a socket; returns { detach }
uploadPackage(finalized)Upload a written package

Automatic fetch instrumentation

A patched fetch is recorded only when there is an ambient session and the URL matches one of your endpoint rules:

await session.run(async () => {
  await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', body });
});

Everything else passes through untouched — your database, your feature flag service, your own APIs.

Streaming response bodies are never drained to capture them. Reading a stream to inspect it would hold back the first token, which is exactly the latency this SDK exists to measure. httpBodies: true captures non-streaming bodies only.

Failure behaviour

With strict: false (the default), instrumentation errors are swallowed. Recording problems surface as capture_status counters in the manifest and as the unverifiable class in the dashboard. Set strict: true in staging so those failures throw.

Spool directories are not removed after a successful upload. Add a cleanup sweep of .vaani-spool to your deployment, or audio will accumulate on your agent hosts indefinitely.

Next

On this page