lenxes
v0.3.1
Published
Lenxes Node SDK — one-line auto-instrumentation for LLM cost & observability (OpenAI, Azure, Anthropic, Google, Mistral, Bedrock, Vercel AI SDK, LangChain).
Readme
lenxes (Node SDK)
LLM cost & observability in one line. Capture every model call — tokens, latency, status, cost — streaming or not, and ship it out-of-band. Tenancy comes from your API key server-side; cost is computed server-side. Fail-open: it never breaks your app. Zero dependencies, ships with TypeScript types.
npm install lenxesRequires Node 18+ (global fetch).
import lenxes from "lenxes";
lenxes.init({ apiKey: process.env.LENXES_API_KEY }); // once, at startupobserve() — wrap a client once
Auto-detects OpenAI, Azure OpenAI, Anthropic, Google (@google/genai), and
Mistral clients. Streaming and non-streaming calls are both captured — your
for await loop is untouched. Use the client exactly as before; nothing per call.
import OpenAI from "openai";
const client = lenxes.observe(new OpenAI());
await client.chat.completions.create({ model: "gpt-4o", messages: [...] });
// streaming works too — captured automatically:
for await (const chunk of await client.chat.completions.create({ model: "gpt-4o", stream: true, messages: [...] })) { /* ... */ }| Provider | Wrap | Notes |
|---|---|---|
| OpenAI | observe(new OpenAI()) | streaming auto-captured |
| Azure OpenAI | observe(new AzureOpenAI(...)) | provider auto-tagged azure |
| Anthropic | observe(new Anthropic()) | dated IDs (claude-haiku-4-5-20251001) supported |
| Google | observe(new GoogleGenAI(...)) | models.generateContent + stream |
| Mistral | observe(new Mistral(...)) | chat.complete + chat.stream |
Per-call tags optional: observe(client, { featureTag: "chat", customerTag: tenantId }).
track() — gateways, Bedrock, raw transports
For a multi-provider gateway, AWS Bedrock, or raw fetch, emit one event from
your funnel. Hand us the raw response and we read model + tokens for you
(OpenAI / Anthropic / Google / Bedrock / Vercel / OpenAI-compatible shapes):
lenxes.track({ provider, response, latencyMs, status,
featureTag: agentId, customerTag: tenantId });
// AWS Bedrock (Converse):
lenxes.track({ provider: "bedrock", response: converseOutput });
// or pass counts explicitly:
lenxes.track({ provider, model, inputTokens, outputTokens, latencyMs, status });Vercel AI SDK
Wrap your model with the AI SDK's wrapLanguageModel; generateText /
streamText are then captured automatically:
import { wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
const model = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: lenxes.aiSdkMiddleware({ featureTag: "chat" }),
});LangChain / LangGraph
Pass the handler in callbacks:
const handler = lenxes.langchainHandler({ featureTag: "agent" });
await chain.invoke(input, { callbacks: [handler] });Tenancy & environment
LENXES_API_KEYidentifies your org / project / environment server-side; the request body can't override it.- The key prefix (
clx_live_/clx_test_) signals prod vs non-prod; the actual environment is a property of the key. - Optional
LENXES_INGEST_URLto point at a self-hosted ingest endpoint.
Privacy
Prompt/response content is never sent unless your org turns on sampling for that environment (server-controlled). When on, samples are redacted client-side and truncated before they leave your app.
Guarantees
Fail-open (never throws into your call path) and fire-and-forget. In a short-lived
script, await lenxes.flush() before exit to drain in-flight sends.
License
© 2026 Lenxes. All rights reserved. Proprietary and confidential — licensed for use with a valid Lenxes account, not for copying, redistribution, modification, or reverse engineering. See LICENSE.
