@fiddler-ai/otel
v0.1.1
Published
OpenTelemetry-based tracing SDK for Fiddler AI observability
Maintainers
Readme
@fiddler-ai/otel
OpenTelemetry-based tracing SDK for Fiddler AI Observability. Instrument your AI agents, LLM calls, and tool invocations in TypeScript/JavaScript and send traces to Fiddler.
Mirrors the Python fiddler-otel SDK — same span types, same attribute names, same transport.
Installation
npm install @fiddler-ai/otelPeer dependency — install alongside it:
npm install @opentelemetry/apiRequirements: Node.js ≥ 20
Quick Start
import { randomUUID } from 'crypto'
import { FiddlerClient } from '@fiddler-ai/otel'
const client = new FiddlerClient({
url: 'https://your-instance.fiddler.ai',
apiKey: 'your-api-key',
applicationId: 'your-app-uuid', // UUID4 from Fiddler UI
})
const sessionId = randomUUID()
// Root agent span — becomes the session in the Fiddler UI
const agent = client.startAgent('travel-agent')
agent.setAgentName('travel-agent')
agent.setConversationId(sessionId)
agent.setInput('Book a flight to Paris')
// LLM call
const llm = client.startGeneration('plan-trip', { parent: agent })
llm.setModel('gpt-4o')
llm.setInput('Plan a 5-day Paris trip')
llm.setOutput('Day 1: Eiffel Tower...')
llm.setUsage({ inputTokens: 500, outputTokens: 300 })
llm.end()
// Tool call
const tool = client.startTool('search-flights', { parent: agent })
tool.setToolName('search_flights')
tool.setInput({ destination: 'Paris', date: '2026-06-01' })
tool.setOutput({ flights: ['AF123', 'BA456'] })
tool.end()
agent.setOutput('Trip planned and flights found.')
agent.end()
await client.flush()API Reference
new FiddlerClient(config)
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| url | string | ✅ | Base URL of your Fiddler instance |
| apiKey | string | ✅ | Fiddler API key |
| applicationId | string | ✅ | Application UUID from the Fiddler UI |
| serviceName | string | — | OTel service.name resource attribute (default: fiddler-otel) |
| serviceVersion | string | — | OTel service.version resource attribute (default: 0.1.0) |
| consoleTracer | boolean | — | If true, also prints spans to stdout for local debugging (default: false) |
Span Creation Methods
All methods return a typed span and accept an optional { parent } to establish hierarchy.
client.startAgent(name, { parent? }) // → FiddlerAgentSpan (type: chain)
client.startGeneration(name, { parent? }) // → FiddlerGenerationSpan (type: llm)
client.startTool(name, { parent? }) // → FiddlerToolSpan (type: tool)
client.startSpan(name, { parent?, type? }) // → FiddlerSpan (generic)FiddlerAgentSpan
span.setAgentName(name: string) // gen_ai.agent.name
span.setAgentId(id: string) // gen_ai.agent.id
span.setConversationId(id: string) // gen_ai.conversation.id
span.setInput(data: unknown) // fiddler.span.input (JSON)
span.setOutput(data: unknown) // fiddler.span.output (JSON)
span.setAttribute(key, value) // custom attribute
span.recordError(error) // records exception + sets ERROR status
span.end() // ends the span with OK statusFiddlerGenerationSpan
span.setModel(model: string) // gen_ai.request.model
span.setSystem(provider: string) // gen_ai.system
span.setSystemPrompt(text: string) // gen_ai.llm.input.system
span.setUserPrompt(text: string) // gen_ai.llm.input.user
span.setInput(input: string | unknown) // gen_ai.llm.input.user
span.setCompletion(text: string) // gen_ai.llm.output
span.setOutput(output: string | unknown) // gen_ai.llm.output
span.setContext(context: string) // gen_ai.llm.context (RAG)
span.setUsage({ inputTokens, outputTokens, totalTokens? })
span.setMessages(messages: object[]) // gen_ai.input.messages (JSON)
span.setOutputMessages(messages: object[]) // gen_ai.output.messages (JSON)
span.setToolDefinitions(definitions: object[]) // gen_ai.tool.definitions (JSON)FiddlerToolSpan
span.setToolName(name: string) // gen_ai.tool.name
span.setInput(input: unknown) // gen_ai.tool.input (JSON)
span.setOutput(output: unknown) // gen_ai.tool.output (JSON)
span.setToolDefinitions(definitions: object[]) // gen_ai.tool.definitions (JSON)Lifecycle Methods
await client.flush() // Force-flush all buffered spans to Fiddler
await client.shutdown() // Flush then shut down the providerflush() is called automatically on beforeExit (when the event loop drains naturally). For SIGINT/SIGTERM, call flush() explicitly in your signal handler:
process.once('SIGINT', async () => {
await client.flush()
process.exit(130)
})One FiddlerClient per process is the expected usage — mirroring the Python SDK.
How It Works
FiddlerClient
└── BasicTracerProvider (isolated — does not touch global OTel)
├── FiddlerSpanProcessor → propagates conversation_id / agent_name to child spans
└── BatchSpanProcessor
└── OTLPTraceExporter
└── POST {url}/v1/traces
Authorization: Bearer {apiKey}
fiddler-application-id: {applicationId}Spans are buffered in memory and sent together in a single HTTP request when flush() is called. This ensures the backend receives the complete trace and can build the correct parent-child hierarchy.
Multi-Agent Example
const sessionId = randomUUID()
// Root supervisor — becomes the session
const supervisor = client.startAgent('supervisor')
supervisor.setAgentName('supervisor')
supervisor.setConversationId(sessionId)
supervisor.setInput('Book flight + hotel')
// Sub-agent
const flightAgent = client.startAgent('flight-assistant', { parent: supervisor })
flightAgent.setAgentName('flight_assistant')
const llm = client.startGeneration('flight-llm', { parent: flightAgent })
llm.setModel('gpt-4o-mini')
llm.setInput('Find flights BOS → JFK')
llm.setOutput('Calling book_flight tool')
llm.setUsage({ inputTokens: 85, outputTokens: 28 })
llm.end()
const tool = client.startTool('book-flight', { parent: flightAgent })
tool.setToolName('book_flight')
tool.setInput({ from: 'BOS', to: 'JFK' })
tool.setOutput('Flight booked.')
tool.end()
flightAgent.setOutput('Flight booked.')
flightAgent.end()
supervisor.setOutput('All done.')
supervisor.end()
await client.flush()License
Apache-2.0
