Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
1 line
8.3 KiB
Plaintext
1 line
8.3 KiB
Plaintext
{"version":3,"file":"utils.js","sources":["../../../../src/tracing/ai/utils.ts"],"sourcesContent":["/**\n * Shared utils for AI integrations (OpenAI, Anthropic, Verce.AI, etc.)\n */\nimport type { Span } from '../../types-hoist/span';\nimport {\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from './gen-ai-attributes';\nimport { truncateGenAiMessages, truncateGenAiStringInput } from './messageTruncation';\n/**\n * Maps AI method paths to OpenTelemetry semantic convention operation names\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/#llm-request-spans\n */\nexport function getFinalOperationName(methodPath: string): string {\n if (methodPath.includes('messages')) {\n return 'chat';\n }\n if (methodPath.includes('completions')) {\n return 'text_completion';\n }\n // Google GenAI: models.generateContent* -> generate_content (actually generates AI responses)\n if (methodPath.includes('generateContent')) {\n return 'generate_content';\n }\n // Anthropic: models.get/retrieve -> models (metadata retrieval only)\n if (methodPath.includes('models')) {\n return 'models';\n }\n if (methodPath.includes('chat')) {\n return 'chat';\n }\n return methodPath.split('.').pop() || 'unknown';\n}\n\n/**\n * Get the span operation for AI methods\n * Following Sentry's convention: \"gen_ai.{operation_name}\"\n */\nexport function getSpanOperation(methodPath: string): string {\n return `gen_ai.${getFinalOperationName(methodPath)}`;\n}\n\n/**\n * Build method path from current traversal\n */\nexport function buildMethodPath(currentPath: string, prop: string): string {\n return currentPath ? `${currentPath}.${prop}` : prop;\n}\n\n/**\n * Set token usage attributes\n * @param span - The span to add attributes to\n * @param promptTokens - The number of prompt tokens\n * @param completionTokens - The number of completion tokens\n * @param cachedInputTokens - The number of cached input tokens\n * @param cachedOutputTokens - The number of cached output tokens\n */\nexport function setTokenUsageAttributes(\n span: Span,\n promptTokens?: number,\n completionTokens?: number,\n cachedInputTokens?: number,\n cachedOutputTokens?: number,\n): void {\n if (promptTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: promptTokens,\n });\n }\n if (completionTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: completionTokens,\n });\n }\n if (\n promptTokens !== undefined ||\n completionTokens !== undefined ||\n cachedInputTokens !== undefined ||\n cachedOutputTokens !== undefined\n ) {\n /**\n * Total input tokens in a request is the summation of `input_tokens`,\n * `cache_creation_input_tokens`, and `cache_read_input_tokens`.\n */\n const totalTokens =\n (promptTokens ?? 0) + (completionTokens ?? 0) + (cachedInputTokens ?? 0) + (cachedOutputTokens ?? 0);\n\n span.setAttributes({\n [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: totalTokens,\n });\n }\n}\n\n/**\n * Get the truncated JSON string for a string or array of strings.\n *\n * @param value - The string or array of strings to truncate\n * @returns The truncated JSON string\n */\nexport function getTruncatedJsonString<T>(value: T | T[]): string {\n if (typeof value === 'string') {\n // Some values are already JSON strings, so we don't need to duplicate the JSON parsing\n return truncateGenAiStringInput(value);\n }\n if (Array.isArray(value)) {\n // truncateGenAiMessages returns an array of strings, so we need to stringify it\n const truncatedMessages = truncateGenAiMessages(value);\n return JSON.stringify(truncatedMessages);\n }\n // value is an object, so we need to stringify it\n return JSON.stringify(value);\n}\n\n/**\n * Extract system instructions from messages array.\n * Finds the first system message and formats it according to OpenTelemetry semantic conventions.\n *\n * @param messages - Array of messages to extract system instructions from\n * @returns systemInstructions (JSON string) and filteredMessages (without system message)\n */\nexport function extractSystemInstructions(messages: unknown[] | unknown): {\n systemInstructions: string | undefined;\n filteredMessages: unknown[] | unknown;\n} {\n if (!Array.isArray(messages)) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessageIndex = messages.findIndex(\n msg => msg && typeof msg === 'object' && 'role' in msg && (msg as { role: string }).role === 'system',\n );\n\n if (systemMessageIndex === -1) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessage = messages[systemMessageIndex] as { role: string; content?: string | unknown };\n const systemContent =\n typeof systemMessage.content === 'string'\n ? systemMessage.content\n : systemMessage.content !== undefined\n ? JSON.stringify(systemMessage.content)\n : undefined;\n\n if (!systemContent) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemInstructions = JSON.stringify([{ type: 'text', content: systemContent }]);\n const filteredMessages = [...messages.slice(0, systemMessageIndex), ...messages.slice(systemMessageIndex + 1)];\n\n return { systemInstructions, filteredMessages };\n}\n"],"names":[],"mappings":"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"} |