UNPKG

@sentry/core

Version:
143 lines (131 loc) 4.13 kB
import { OPENAI_OPERATIONS, GEN_AI_RESPONSE_ID_ATTRIBUTE, OPENAI_RESPONSE_ID_ATTRIBUTE, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, OPENAI_RESPONSE_MODEL_ATTRIBUTE, OPENAI_RESPONSE_TIMESTAMP_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, OPENAI_USAGE_PROMPT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, OPENAI_USAGE_COMPLETION_TOKENS_ATTRIBUTE, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE } from '../gen-ai-attributes.js'; import { INSTRUMENTED_METHODS } from './constants.js'; /** * Maps OpenAI method paths to Sentry operation names */ function getOperationName(methodPath) { if (methodPath.includes('chat.completions')) { return OPENAI_OPERATIONS.CHAT; } if (methodPath.includes('responses')) { return OPENAI_OPERATIONS.RESPONSES; } return methodPath.split('.').pop() || 'unknown'; } /** * Get the span operation for OpenAI methods * Following Sentry's convention: "gen_ai.{operation_name}" */ function getSpanOperation(methodPath) { return `gen_ai.${getOperationName(methodPath)}`; } /** * Check if a method path should be instrumented */ function shouldInstrument(methodPath) { return INSTRUMENTED_METHODS.includes(methodPath ); } /** * Build method path from current traversal */ function buildMethodPath(currentPath, prop) { return currentPath ? `${currentPath}.${prop}` : prop; } /** * Check if response is a Chat Completion object */ function isChatCompletionResponse(response) { return ( response !== null && typeof response === 'object' && 'object' in response && (response ).object === 'chat.completion' ); } /** * Check if response is a Responses API object */ function isResponsesApiResponse(response) { return ( response !== null && typeof response === 'object' && 'object' in response && (response ).object === 'response' ); } /** * Check if streaming event is from the Responses API */ function isResponsesApiStreamEvent(event) { return ( event !== null && typeof event === 'object' && 'type' in event && typeof (event ).type === 'string' && ((event ).type ).startsWith('response.') ); } /** * Check if streaming event is a chat completion chunk */ function isChatCompletionChunk(event) { return ( event !== null && typeof event === 'object' && 'object' in event && (event ).object === 'chat.completion.chunk' ); } /** * Set token usage attributes * @param span - The span to add attributes to * @param promptTokens - The number of prompt tokens * @param completionTokens - The number of completion tokens * @param totalTokens - The number of total tokens */ function setTokenUsageAttributes( span, promptTokens, completionTokens, totalTokens, ) { if (promptTokens !== undefined) { span.setAttributes({ [OPENAI_USAGE_PROMPT_TOKENS_ATTRIBUTE]: promptTokens, [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: promptTokens, }); } if (completionTokens !== undefined) { span.setAttributes({ [OPENAI_USAGE_COMPLETION_TOKENS_ATTRIBUTE]: completionTokens, [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: completionTokens, }); } if (totalTokens !== undefined) { span.setAttributes({ [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: totalTokens, }); } } /** * Set common response attributes * @param span - The span to add attributes to * @param id - The response id * @param model - The response model * @param timestamp - The response timestamp */ function setCommonResponseAttributes(span, id, model, timestamp) { span.setAttributes({ [OPENAI_RESPONSE_ID_ATTRIBUTE]: id, [GEN_AI_RESPONSE_ID_ATTRIBUTE]: id, }); span.setAttributes({ [OPENAI_RESPONSE_MODEL_ATTRIBUTE]: model, [GEN_AI_RESPONSE_MODEL_ATTRIBUTE]: model, }); span.setAttributes({ [OPENAI_RESPONSE_TIMESTAMP_ATTRIBUTE]: new Date(timestamp * 1000).toISOString(), }); } export { buildMethodPath, getOperationName, getSpanOperation, isChatCompletionChunk, isChatCompletionResponse, isResponsesApiResponse, isResponsesApiStreamEvent, setCommonResponseAttributes, setTokenUsageAttributes, shouldInstrument }; //# sourceMappingURL=utils.js.map