@tracelanedev/sdk

Instrumentation for TypeScript AI agents, built on the OpenTelemetry Node SDK.
Spans are emitted via OTLP to your Tracelane ingest endpoint.
Install
npm install @tracelanedev/sdk
pnpm add @tracelanedev/sdk
Fastest path — route through the gateway (no SDK)
For Tracelane Cloud, the shortest path to your first trace needs no SDK at
all: point your existing client's base URL at the gateway and use your
tlane_… key. The gateway routes the call and captures the trace.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://gateway.tracelane.dev/v1",
apiKey: process.env.TRACELANE_API_KEY!,
});
await client.chat.completions.create({
model: "claude-sonnet-4-6",
messages: [{ role: "user", content: "Hello" }],
});
Use this SDK when you want to export OTLP spans to an endpoint you run — a
self-hosted Tracelane ingest, or your own OTLP collector (Jaeger, Tempo, …).
SDK quick start (OTLP export)
Two steps: init() once at startup, then wrap each client with its
instrument* function. There is no zero-config magic in v1 — wrapping is
explicit, so what's traced is exactly what you opted in.
import { init, instrumentAnthropic } from "@tracelanedev/sdk";
import Anthropic from "@anthropic-ai/sdk";
init({
endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? "http://localhost:4318",
apiKey: process.env.TRACELANE_API_KEY!,
serviceName: "my-agent",
});
const client = new Anthropic();
instrumentAnthropic(client);
await client.messages.create({
model: "claude-sonnet-4-6",
messages: [{ role: "user", content: "Hello" }],
max_tokens: 128,
});
init() options
endpoint | yes | OTLP HTTP endpoint you can reach, e.g. http://localhost:4318 or a self-hosted ingest. Spans POST to ${endpoint}/v1/traces. |
apiKey | yes | Your tlane_… key. Sent as the x-tracelane-api-key header. |
serviceName | no | Resource service.name (default unknown-service). |
sampleRate | no | 0.0–1.0 (default 1.0 — full trace; the tail sampler decides). |
Call shutdown() on exit to flush pending spans (an automatic flush is also
registered on beforeExit).
Streaming (v1 limitation)
Streamed calls (stream: true) pass through untouched and still produce a
span with model + latency, marked tracelane.streaming = true. Token usage
and finish reason are not captured for streamed responses yet — that
lands in v1.1. A once-per-process runtime warning says exactly this.
Instrumented libraries
Each library has its own instrument*(client) function — import it from the
package root or the matching subpath. Call it once, after constructing the
client (or, for module-level libraries, after import).
@anthropic-ai/sdk | instrumentAnthropic(client) | messages.create, streaming, tool use |
openai | instrumentOpenAI(client) | chat.completions, embeddings, Responses |
@openai/agents | instrumentOpenAIAgents(...) | agent steps, tool calls, handoffs |
langchain | instrumentLangGraph(graph) | chains, agents, tool calls |
@modelcontextprotocol/sdk | instrumentMCP(...) | tool_call, tool_result |
| Vercel AI SDK | instrumentVercelAI(...) | generateText, streamText, generateObject |
Full list (one export per library): instrumentAnthropic, instrumentOpenAI,
instrumentOpenAIAsync, instrumentLiteLLM, instrumentOpenRouter,
instrumentLangGraph, instrumentOpenAIAgents, instrumentVercelAI,
instrumentMCP, instrumentClaudeCode, instrumentCursor,
instrumentPinecone, instrumentQdrant, instrumentComposio,
instrumentBrowserbase, instrumentE2B, instrumentMem0, instrumentLetta,
instrumentFirecrawl.
Zero-config autoInstrument() is not in v1 — calling it throws with a
pointer to this explicit API. Auto-detection lands in v1.1.
Next.js App Router
Initialise in instrumentation.ts (runs once per server process):
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
const { init } = await import("@tracelanedev/sdk");
init({
endpoint: "http://localhost:4318",
apiKey: process.env.TRACELANE_API_KEY!,
serviceName: "my-nextjs-app",
});
}
}
Manual spans
The SDK sets up a standard OpenTelemetry tracer provider, so custom spans use
@opentelemetry/api directly — no Tracelane-specific wrapper:
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("my-agent");
const hits = await tracer.startActiveSpan("retrieval", async (span) => {
span.setAttribute("retrieval.top_k", 10);
const results = await vectorStore.search(query, { topK: 10 });
span.end();
return results;
});
Design invariants
- Telemetry goes to your configured
endpoint only — the SDK never calls home.
- Instrumentation is additive —
instrument* patches a client in place and does
not modify the OpenAI/Anthropic module exports.
- Redaction — set
TRACELANE_TRACE_CONTENT=false to redact prompt and
completion text from captured traces (honored on the gateway path).
- Zero runtime dependencies beyond the OpenTelemetry SDK.
Documentation
Full docs at docs.tracelane.dev/sdk-typescript.
Stack
TypeScript 5.5+ strict, Biome (lint + format), Vitest.
License
Apache 2.0 — see LICENSE.