import { DeepPartial } from '../types'; import { resetCurrentSpan, setCurrentSpan, withNewSpanContext, } from './context'; import { CreateSpanOptions, getGlobalTraceProvider } from './provider'; import { Span, ResponseSpanData, SpanData, AgentSpanData, FunctionSpanData, HandoffSpanData, GenerationSpanData, CustomSpanData, GuardrailSpanData, TranscriptionSpanData, SpeechSpanData, SpeechGroupSpanData, MCPListToolsSpanData, } from './spans'; import { Trace } from './traces'; type CreateArgs = DeepPartial>; function _withSpanFactory< TData extends SpanData, TCreateSpanFunction extends (...args: any[]) => Span, >(createSpan: TCreateSpanFunction) { return async ( fn: (span: Span) => Promise, ...args: Parameters ) => { // Creating a new span context to make sure that the previous span is correctly reset return withNewSpanContext(async () => { const span = createSpan(...args); setCurrentSpan(span); try { span.start(); return await fn(span); } catch (error: any) { span.setError({ message: error.message, data: error.data, }); throw error; } finally { span.end(); resetCurrentSpan(); } }); }; } /** * Create a new response span. The span will not be started automatically, you should either * use `withResponseSpan()` or call `span.start()` and `span.end()` manually. * * This span captures the details of a model response, primarily the response identifier. * If you need to capture detailed generation information such as input/output messages, * model configuration, or usage data, use `createGenerationSpan()` instead. * * @param options - Optional span creation options, including span data and identifiers. * @param parent - The parent span or trace. If not provided, the current trace/span will be used * automatically. * * @returns The newly created response span. */ export function createResponseSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { options = {}; return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'response', ...options.data, }, }, parent, ); } /** * Create a new response span and automatically start and end it. * * This span captures the details of a model response, primarily the response identifier. * If you need to capture detailed generation information such as input/output messages, * model configuration, or usage data, use `generationSpan()` instead. */ export const withResponseSpan = _withSpanFactory< ResponseSpanData, typeof createResponseSpan >(createResponseSpan); /** * Create a new agent span. The span will not be started automatically, you should either * use `withAgentSpan()` or call `span.start()` and `span.end()` manually. * * @param options - Optional span creation options, including span data and identifiers. * @param parent - The parent span or trace. If not provided, the current trace/span will be used * automatically. * * @returns The newly created agent span. */ export function createAgentSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'agent', name: options?.data?.name ?? 'Agent', ...options?.data, }, }, parent, ); } /** * Create a new agent span and automatically start and end it. */ export const withAgentSpan = _withSpanFactory< AgentSpanData, typeof createAgentSpan >(createAgentSpan); /** * Create a new function span. The span will not be started automatically, you should either * use `withFunctionSpan()` or call `span.start()` and `span.end()` manually. * * @param options - Optional span creation options, including span data and identifiers. * @param parent - The parent span or trace. If not provided, the current trace/span will be used * automatically. * * @returns The newly created function span. */ export function createFunctionSpan( options: CreateArgs & { data: { name: string } }, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'function', input: options?.data?.input ?? '', output: options?.data?.output ?? '', ...options?.data, }, }, parent, ); } /** * Create a new function span and automatically start and end it. */ export const withFunctionSpan = _withSpanFactory< FunctionSpanData, typeof createFunctionSpan >(createFunctionSpan); /** * Create a new handoff span. The span will not be started automatically, you should either * use `withHandoffSpan()` or call `span.start()` and `span.end()` manually. * * @param options - Optional span creation options, including span data and identifiers. * @param parent - The parent span or trace. If not provided, the current trace/span will be used * automatically. * * @returns The newly created handoff span. */ export function createHandoffSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'handoff', ...options?.data }, }, parent, ); } /** * Create a new handoff span and automatically start and end it. */ export const withHandoffSpan = _withSpanFactory< HandoffSpanData, typeof createHandoffSpan >(createHandoffSpan); /** * Create a new generation span. The span will not be started automatically, you should either * use `withGenerationSpan()` or call `span.start()` and `span.end()` manually. * * This span captures the details of a model generation, including input/output message * sequences, model information, and usage data. If you only need to capture a model response * identifier, consider using `createResponseSpan()` instead. */ export function createGenerationSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'generation', ...options?.data, }, }, parent, ); } /** Automatically create a generation span, run fn and close the span */ export const withGenerationSpan = _withSpanFactory< GenerationSpanData, typeof createGenerationSpan >(createGenerationSpan); /** * Create a new custom span. The span will not be started automatically, you should either use * `withCustomSpan()` or call `span.start()` and `span.end()` manually. */ export function createCustomSpan( options: CreateArgs & { data: { name: string } }, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'custom', data: {}, ...options?.data, }, }, parent, ); } export const withCustomSpan = _withSpanFactory< CustomSpanData, typeof createCustomSpan >(createCustomSpan); /** * Create a new guardrail span. The span will not be started automatically, you should either use * `withGuardrailSpan()` or call `span.start()` and `span.end()` manually. */ export function createGuardrailSpan( options: CreateArgs & { data: { name: string } }, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'guardrail', triggered: false, ...options?.data, }, }, parent, ); } export const withGuardrailSpan = _withSpanFactory< GuardrailSpanData, typeof createGuardrailSpan >(createGuardrailSpan); /** * Create a new transcription span. The span will not be started automatically. */ export function createTranscriptionSpan( options: CreateArgs & { data: { input: { data: string; format: 'pcm' | string } }; }, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'transcription', ...options.data, }, }, parent, ); } export const withTranscriptionSpan = _withSpanFactory< TranscriptionSpanData, typeof createTranscriptionSpan >(createTranscriptionSpan); /** * Create a new speech span. The span will not be started automatically. */ export function createSpeechSpan( options: CreateArgs & { data: { output: { data: string; format: 'pcm' | string } }; }, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'speech', ...options.data, }, }, parent, ); } export const withSpeechSpan = _withSpanFactory< SpeechSpanData, typeof createSpeechSpan >(createSpeechSpan); /** * Create a new speech group span. The span will not be started automatically. */ export function createSpeechGroupSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'speech_group', ...options?.data, }, }, parent, ); } export const withSpeechGroupSpan = _withSpanFactory< SpeechGroupSpanData, typeof createSpeechGroupSpan >(createSpeechGroupSpan); /** * Create a new MCP list tools span. The span will not be started automatically. */ export function createMCPListToolsSpan( options?: CreateArgs, parent?: Span | Trace, ): Span { return getGlobalTraceProvider().createSpan( { ...options, data: { type: 'mcp_tools', ...options?.data, }, }, parent, ); } export const withMCPListToolsSpan = _withSpanFactory< MCPListToolsSpanData, typeof createMCPListToolsSpan >(createMCPListToolsSpan);