UNPKG

openlit

Version:

OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications, facilitating the integration of observability into your GenAI-driven projects

186 lines 8.49 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const api_1 = require("@opentelemetry/api"); const config_1 = __importDefault(require("../../config")); const helpers_1 = __importDefault(require("../../helpers")); const semantic_convention_1 = __importDefault(require("../../semantic-convention")); const base_wrapper_1 = __importDefault(require("../base-wrapper")); class AnthropicWrapper extends base_wrapper_1.default { static _patchMessageCreate(tracer) { const genAIEndpoint = 'anthropic.resources.messages'; return (originalMethod) => { return async function (...args) { const span = tracer.startSpan(genAIEndpoint, { kind: api_1.SpanKind.CLIENT }); const { stream = false } = args[0]; return api_1.context .with(api_1.trace.setSpan(api_1.context.active(), span), async () => { return originalMethod.apply(this, args); }) .then((response) => { if (!!stream) { return helpers_1.default.createStreamProxy(response, AnthropicWrapper._messageCreateGenerator({ args, genAIEndpoint, response, span, })); } return AnthropicWrapper._messageCreate({ args, genAIEndpoint, response, span }); }) .catch((e) => { helpers_1.default.handleException(span, e); span.end(); throw e; }); }; }; } static async _messageCreate({ args, genAIEndpoint, response, span, }) { try { await AnthropicWrapper._messageCreateCommonSetter({ args, genAIEndpoint, result: response, span, }); return response; } catch (e) { helpers_1.default.handleException(span, e); } finally { span.end(); } } static async *_messageCreateGenerator({ args, genAIEndpoint, response, span, }) { try { const result = { id: '0', model: '', stop_reason: '', content: [ { text: '', role: '', }, ], usage: { input_tokens: 0, output_tokens: 0, total_tokens: 0, }, }; for await (const chunk of response) { switch (chunk.type) { case 'content_block_delta': result.content[0].text += chunk.delta?.text ?? ''; break; case 'message_stop': break; case 'content_block_stop': break; case 'message_start': if (chunk.message) { result.id = chunk.message.id; result.model = chunk.message.model; result.content[0].role = chunk.message.role; result.usage.input_tokens += Number(chunk.message.usage?.input_tokens) ?? 0; result.usage.output_tokens += Number(chunk.message.usage?.output_tokens) ?? 0; result.stop_reason = chunk.message?.stop_reason ?? ''; } break; case 'content_block_start': result.content[0].text = chunk.content_block?.text ?? ''; break; case 'message_delta': result.stop_reason = chunk.delta?.stop_reason ?? ''; result.usage.output_tokens += Number(chunk.usage?.output_tokens) ?? 0; break; } yield chunk; } result.usage.total_tokens = result.usage.output_tokens + result.usage.input_tokens; await AnthropicWrapper._messageCreateCommonSetter({ args, genAIEndpoint, result, span, }); return response; } catch (e) { helpers_1.default.handleException(span, e); } finally { span.end(); } } static async _messageCreateCommonSetter({ args, genAIEndpoint, result, span, }) { const traceContent = config_1.default.traceContent; const { messages, max_tokens = null, seed = null, temperature = 1, top_p, top_k, user, stream = false, stop_reason, } = args[0]; // Format 'messages' into a single string const messagePrompt = messages || ''; const formattedMessages = []; for (const message of messagePrompt) { const role = message.role; const content = message.content; if (Array.isArray(content)) { const contentStr = content .map((item) => { if ('type' in item) { return `${item.type}: ${item.text ? item.text : item.image_url}`; } else { return `text: ${item.text}`; } }) .join(', '); formattedMessages.push(`${role}: ${contentStr}`); } else { formattedMessages.push(`${role}: ${content}`); } } const prompt = formattedMessages.join('\n'); span.setAttribute(semantic_convention_1.default.GEN_AI_TYPE, semantic_convention_1.default.GEN_AI_TYPE_CHAT); span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, result.id); const model = result.model || 'claude-3-sonnet-20240229'; const pricingInfo = await config_1.default.updatePricingJson(config_1.default.pricing_json); // Calculate cost of the operation const cost = helpers_1.default.getChatModelCost(model, pricingInfo, result.usage.input_tokens, result.usage.output_tokens); AnthropicWrapper.setBaseSpanAttributes(span, { genAIEndpoint, model, user, cost, aiSystem: AnthropicWrapper.aiSystem, }); // Request Params attributes : Start span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TOP_P, top_p); span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TOP_K, top_k); span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_MAX_TOKENS, max_tokens); span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_TEMPERATURE, temperature); span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, stop_reason); span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, stream); span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_SEED, seed); if (traceContent) { span.setAttribute(semantic_convention_1.default.GEN_AI_CONTENT_PROMPT, prompt); } // Request Params attributes : End span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_PROMPT_TOKENS, result.usage.input_tokens); span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_COMPLETION_TOKENS, result.usage.output_tokens); span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, result.usage.input_tokens + result.usage.output_tokens); if (result.stop_reason) { span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, result.stop_reason); } if (traceContent) { span.setAttribute(semantic_convention_1.default.GEN_AI_CONTENT_COMPLETION, result.content?.[0]?.text || ''); } } } AnthropicWrapper.aiSystem = semantic_convention_1.default.GEN_AI_SYSTEM_ANTHROPIC; exports.default = AnthropicWrapper; //# sourceMappingURL=wrapper.js.map