Lets @voightxyz/openai participate in OTel-mandated stacks (Langfuse, Phoenix, Datadog, Sentry, or Voight's own @voightxyz/vercel-ai exporter) without losing the direct ingestion to api.voight.xyz.
New option
import OpenAI from 'openai'
import { wrapOpenAI } from '@voightxyz/openai'
const openai = wrapOpenAI(new OpenAI(), {
agent: 'production-chat-api',
otel: true, // ← new
})When otel: true, every captured call is also emitted as an OpenTelemetry span with gen_ai.* semantic-convention attributes (plus the parallel Vercel-style ai.* attributes for cross-compatibility). Whichever TracerProvider is registered in the host process picks them up.
Emitted spans carry voight.source: 'wrapper' so @voightxyz/vercel-ai ≥ 0.1.1 recognises and skips them — users who wire both products into one process don't get duplicate events.
What didn't change
- Default
otel: falseis byte-identical to 0.1.6. Existing users see no behaviour change. @opentelemetry/apiis an optional peer dep. Projects that never setotel: trueare unaffected — no extra install, no extra runtime cost.- When
otel: trueis set but@opentelemetry/apiisn't installed, the wrapper logs a one-line warning and falls back to direct ingestion only.
Companion releases
@voightxyz/anthropic@0.1.8— same opt-in for Anthropic@voightxyz/vercel-ai@0.1.1— the dedup filter that closes the duplicate-event loop
Validation
Tests: 116 → 133 green (17 new). B.8.4: removing the voight.source stamp triggers 3 failures.
End-to-end smoke from the npm registry (after beta cycle): real OpenAI calls with otel: true against both a ConsoleSpanExporter (verifies OTel shape) and VoightExporter (verifies dedup loop is closed).
Install
npm install @voightxyz/openai @opentelemetry/api