{"version":3,"file":"utils.js","sources":["../../../../src/tracing/openai/utils.ts"],"sourcesContent":["import type { Span } from '../../types-hoist/span';\nimport type { SpanAttributeValue } from '../../types-hoist/span';\nimport {\n  GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n  GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE,\n  GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE,\n  GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n  GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n  GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE,\n  GEN_AI_REQUEST_STREAM_ATTRIBUTE,\n  GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n  GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n  GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n  GEN_AI_RESPONSE_ID_ATTRIBUTE,\n  GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n  GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n  GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n  GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n  GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n  GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { ChatCompletionChunk, ResponseStreamingEvent } from './types';\n\n/**\n * Check if streaming event is from the Responses API\n */\nexport function isResponsesApiStreamEvent(event: unknown): event is ResponseStreamingEvent {\n  return (\n    event !== null &&\n    typeof event === 'object' &&\n    'type' in event &&\n    typeof (event as Record<string, unknown>).type === 'string' &&\n    ((event as Record<string, unknown>).type as string).startsWith('response.')\n  );\n}\n\n/**\n * Check if streaming event is a chat completion chunk\n */\nexport function isChatCompletionChunk(event: unknown): event is ChatCompletionChunk {\n  return (\n    event !== null &&\n    typeof event === 'object' &&\n    'object' in event &&\n    (event as Record<string, unknown>).object === 'chat.completion.chunk'\n  );\n}\n\n/**\n * Add response attributes to a span using duck-typing.\n * Works for Chat Completions, Responses API, Embeddings, and Conversations API responses.\n */\nexport function addResponseAttributes(span: Span, result: unknown, recordOutputs?: boolean): void {\n  if (!result || typeof result !== 'object') return;\n\n  const response = result as Record<string, unknown>;\n  const attrs: Record<string, SpanAttributeValue> = {};\n\n  // Response ID\n  if (typeof response.id === 'string') {\n    attrs[GEN_AI_RESPONSE_ID_ATTRIBUTE] = response.id;\n  }\n\n  // Response model\n  if (typeof response.model === 'string') {\n    attrs[GEN_AI_RESPONSE_MODEL_ATTRIBUTE] = response.model;\n  }\n\n  // Conversation ID (conversation objects use id as conversation link)\n  if (response.object === 'conversation' && typeof response.id === 'string') {\n    attrs[GEN_AI_CONVERSATION_ID_ATTRIBUTE] = response.id;\n  }\n\n  // Token usage — supports both naming conventions (chat: prompt_tokens/completion_tokens, responses: input_tokens/output_tokens)\n  if (response.usage && typeof response.usage === 'object') {\n    const usage = response.usage as Record<string, unknown>;\n\n    const inputTokens = usage.prompt_tokens ?? usage.input_tokens;\n    if (typeof inputTokens === 'number') {\n      attrs[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE] = inputTokens;\n    }\n\n    const outputTokens = usage.completion_tokens ?? usage.output_tokens;\n    if (typeof outputTokens === 'number') {\n      attrs[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] = outputTokens;\n    }\n\n    if (typeof usage.total_tokens === 'number') {\n      attrs[GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE] = usage.total_tokens;\n    }\n  }\n\n  // Finish reasons from choices (chat completions)\n  if (Array.isArray(response.choices)) {\n    const choices = response.choices as Array<Record<string, unknown>>;\n    const finishReasons = choices\n      .map(choice => choice.finish_reason)\n      .filter((reason): reason is string => typeof reason === 'string');\n    if (finishReasons.length > 0) {\n      attrs[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE] = JSON.stringify(finishReasons);\n    }\n\n    if (recordOutputs) {\n      // Response text from choices\n      const responseTexts = choices.map(choice => {\n        const message = choice.message as Record<string, unknown> | undefined;\n        return (message?.content as string) || '';\n      });\n      attrs[GEN_AI_RESPONSE_TEXT_ATTRIBUTE] = JSON.stringify(responseTexts);\n\n      // Tool calls from choices\n      const toolCalls = choices\n        .map(choice => {\n          const message = choice.message as Record<string, unknown> | undefined;\n          return message?.tool_calls;\n        })\n        .filter(calls => Array.isArray(calls) && calls.length > 0)\n        .flat();\n\n      if (toolCalls.length > 0) {\n        attrs[GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE] = JSON.stringify(toolCalls);\n      }\n    }\n  }\n\n  // Finish reason from status (responses API)\n  if (typeof response.status === 'string') {\n    // Only set if not already set from choices\n    if (!attrs[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]) {\n      attrs[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE] = JSON.stringify([response.status]);\n    }\n  }\n\n  if (recordOutputs) {\n    // Response text from output_text (responses API)\n    if (typeof response.output_text === 'string' && !attrs[GEN_AI_RESPONSE_TEXT_ATTRIBUTE]) {\n      attrs[GEN_AI_RESPONSE_TEXT_ATTRIBUTE] = response.output_text;\n    }\n\n    // Tool calls from output array (responses API)\n    if (Array.isArray(response.output) && response.output.length > 0 && !attrs[GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]) {\n      const functionCalls = (response.output as Array<Record<string, unknown>>).filter(\n        item => item?.type === 'function_call',\n      );\n      if (functionCalls.length > 0) {\n        attrs[GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE] = JSON.stringify(functionCalls);\n      }\n    }\n  }\n\n  span.setAttributes(attrs);\n}\n\n/**\n * Extract conversation ID from request parameters\n * Supports both Conversations API and previous_response_id chaining\n * @see https://platform.openai.com/docs/guides/conversation-state\n */\nfunction extractConversationId(params: Record<string, unknown>): string | undefined {\n  // Conversations API: conversation parameter (e.g., \"conv_...\")\n  if ('conversation' in params && typeof params.conversation === 'string') {\n    return params.conversation;\n  }\n  // Responses chaining: previous_response_id links to parent response\n  if ('previous_response_id' in params && typeof params.previous_response_id === 'string') {\n    return params.previous_response_id;\n  }\n  return undefined;\n}\n\n/**\n * Extract request parameters including model settings and conversation context\n */\nexport function extractRequestParameters(params: Record<string, unknown>): Record<string, unknown> {\n  const attributes: Record<string, unknown> = {\n    [GEN_AI_REQUEST_MODEL_ATTRIBUTE]: params.model ?? 'unknown',\n  };\n\n  if ('temperature' in params) attributes[GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE] = params.temperature;\n  if ('top_p' in params) attributes[GEN_AI_REQUEST_TOP_P_ATTRIBUTE] = params.top_p;\n  if ('frequency_penalty' in params) attributes[GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE] = params.frequency_penalty;\n  if ('presence_penalty' in params) attributes[GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE] = params.presence_penalty;\n  if ('stream' in params) attributes[GEN_AI_REQUEST_STREAM_ATTRIBUTE] = params.stream;\n  if ('encoding_format' in params) attributes[GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE] = params.encoding_format;\n  if ('dimensions' in params) attributes[GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE] = params.dimensions;\n\n  // Capture conversation ID for linking messages across API calls\n  const conversationId = extractConversationId(params);\n  if (conversationId) {\n    attributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE] = conversationId;\n  }\n\n  return attributes;\n}\n"],"names":[],"mappings":"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"}