OpenTelemetry-Native Telemetry SDK for AI Agents
@void-hq/sdk is a lightweight, vendor-neutral SDK with explicit wrappers (agent(), tool()) to instrument AI Agent execution loops, tool calls, and prompt reasoning pipelines. It emits standard OpenTelemetry (OTLP) trace streams directly to SigNoz Cloud, Self-Hosted SigNoz, or any OTLP-compliant collector.
- π€ AI-Native Instrumentation: First-class abstractions for
agent(),tool(),span(), andevent(). - β‘ OpenTelemetry Native: Native OTLP/HTTP exporter sending spans with
openinferencespan kinds andvoid.*telemetry attributes, plusSEMCONVconstants for GenAI semantic conventions. - π― SigNoz Ready: Native support for SigNoz Cloud (ingestion key headers) and Self-Hosted SigNoz instances.
- π‘οΈ Fail-Safe Execution: Zero-impact error isolation ensures telemetry errors never break production agent loops.
- π¦ Circular & BigInt Safe: Handles circular JSON references, functions, symbols, and BigInt values without throwing.
flowchart TD
subgraph Agent Loop
Agent[voidSdk.agent]
Tool[voidSdk.tool]
end
subgraph VOID SDK
Index[voidSdk Facade]
Engine[TelemetryEngine]
Context[AsyncHooks Context]
Exporter[OTLP Trace Exporter]
end
subgraph Backends
Signoz[SigNoz / OTLP Backend]
Server[VOID Server]
end
Agent --> Index
Tool --> Index
Index --> Engine
Engine --> Context
Engine --> Exporter
Exporter -->|OTLP HTTP/JSON| Signoz
Engine -->|POST /api/traces| Server
The SDK requires zero low-level OpenTelemetry setup. Signal handlers (SIGINT/SIGTERM) flush pending spans automatically upon exit, though calling await voidSdk.shutdown() is recommended before explicit process.exit() calls or in serverless environments.
import { voidSdk } from '@void-hq/sdk';
// 1. Initialize (Zero-config by default, reads env vars)
await voidSdk.init({
serviceName: 'customer-support-agent',
serverUrl: 'http://localhost:3001',
});
// 2. Wrap Agent Execution
const response = await voidSdk.agent(
{ name: 'RefundAgent', role: 'customer-support', promptVersion: 'v2.1' },
async (agentSpan) => {
// 3. Instrument Tool Execution
const tx = await voidSdk.tool(
{ name: 'lookupTransaction', input: { txId: 'tx_992481' } },
async (toolSpan) => {
return await fetchTransaction('tx_992481');
}
);
// 4. Record Custom Telemetry Events & Attributes
voidSdk.event('memory_lookup_hit', { docsReturned: 4 });
voidSdk.setAttribute('customer.tier', 'gold');
return tx;
}
);
// 5. Graceful Teardown (Recommended prior to explicit process.exit() or serverless finish)
await voidSdk.shutdown();Tip
The SDK registers process exit handlers for SIGINT and SIGTERM. If your process is terminated by standard system signals, pending spans are flushed automatically. Call await voidSdk.shutdown() before explicit process.exit() calls or in serverless environments.
src/
βββ index.ts # Primary developer facade and public exports
βββ telemetry.ts # OpenTelemetry TracerProvider & AsyncHooks context manager
βββ config.ts # Environment variable resolution & endpoint parser
βββ semconv.ts # GenAI and OpenInference semantic convention constants
index.ts: Developer facade exposinginit(),agent(),tool(),span(),event(),setAttribute(), andshutdown().telemetry.ts: Usestracer.startActiveSpan()with Node'sAsyncHooksContextManagerto manage parent-child span nesting, status code recording, exception capturing, and signal process exit flushing.semconv.ts: Unified attribute key dictionary (gen_ai.system,openinference.span.kind,void.agent.name,void.tool.name,void.tool.result,void.prompt.version).config.ts: Resolves explicit options withVOID_*andOTEL_*environment variable fallbacks.
The SDK evaluates configuration in the following precedence order:
Explicit init(options) > VOID_* Env Vars > OTEL_* Env Vars > Defaults
| Parameter | Environment Variable | Default Value | Description |
|---|---|---|---|
serviceName |
VOID_SERVICE_NAME / OTEL_SERVICE_NAME |
void-agent-service |
Service identifier tag |
environment |
VOID_ENVIRONMENT / NODE_ENV |
development |
Environment tag (production, staging) |
serverUrl |
VOID_SERVER_URL |
http://localhost:3001 |
VOID Server URL for execution summaries |
endpoint |
VOID_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
http://localhost:4318/v1/traces |
Target OTLP HTTP receiver URL |
headers |
VOID_OTLP_HEADERS / OTEL_EXPORTER_OTLP_HEADERS |
{} |
Key=value headers (e.g. SigNoz keys) |
disabled |
VOID_DISABLED |
false |
Disables telemetry when set to true |
The SDK automatically submits execution summaries to the VOID Server after each agent run. The server evaluates risk, detects incidents, and triggers investigation workflows.
import { voidSdk } from '@void-hq/sdk';
await voidSdk.init({
serviceName: 'my-agent',
serverUrl: 'http://localhost:3001',
otlp: { endpoint: 'http://localhost:4318/v1/traces' },
});
// Everything else is automatic
await voidSdk.agent({ name: 'MyAgent' }, async () => {
await voidSdk.tool({ name: 'search' }, async () => { /* ... */ });
});
// β OTLP traces β SigNoz
// β Execution summary β VOID Server β Risk evaluation β Incident detectionThe SDK sends a POST /api/traces request with:
| Field | Description |
|---|---|
execution_id |
Unique ID for this agent run |
trace_id |
OpenTelemetry trace ID (correlates with SigNoz) |
steps |
Tool calls with name, input, output, success, latency |
total_latency_ms |
Total wall-clock time |
crashed |
Whether the agent threw an error |
context_window_exceeded |
Whether context overflow occurred |
Set serverUrl to an empty string to disable server submission:
await voidSdk.init({ serverUrl: '' });By default, Self-Hosted SigNoz receives OTLP HTTP traces at port 4318:
await voidSdk.init({
serviceName: 'my-local-agent',
otlp: {
endpoint: 'http://localhost:4318/v1/traces',
},
});SigNoz Cloud uses the standard signoz-ingestion-key header:
await voidSdk.init({
serviceName: 'production-agent',
otlp: {
endpoint: 'https://ingest.us.signoz.cloud:443/v1/traces',
headers: {
'signoz-ingestion-key': process.env.SIGNOZ_INGESTION_KEY!,
},
},
});The VOID SDK is 100% agent framework agnostic. It works seamlessly with LangChain.js, Vercel AI SDK, AutoGen.js, or custom TypeScript/JavaScript agent loops:
await voidSdk.agent({ name: 'LangChainAgent' }, async () => {
return await agentExecutor.invoke({ input: 'Process refund' });
});(For Python agents using CrewAI or PydanticAI, use OpenTelemetry Python OTLP exporters emitting standard openinference.* and void.* attributes).
Unit and integration tests use an in-memory exporter and require zero external running services:
# Typecheck TypeScript
npm run typecheck
# Build ESM & CommonJS bundles via tsup
npm run build
# Run Vitest unit & integration test suite (fully self-contained)
npm testMIT Β© VOID