openlit
Version:
OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications, facilitating the integration of observability into your GenAI-driven projects
181 lines • 9.42 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
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 = __importStar(require("../../helpers"));
const semantic_convention_1 = __importDefault(require("../../semantic-convention"));
const base_wrapper_1 = __importDefault(require("../base-wrapper"));
function spanCreationAttrs(operationName, requestModel) {
return {
[semantic_convention_1.default.GEN_AI_OPERATION]: operationName,
[semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: ReplicateWrapper.aiSystem,
[semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
[semantic_convention_1.default.SERVER_ADDRESS]: ReplicateWrapper.serverAddress,
[semantic_convention_1.default.SERVER_PORT]: ReplicateWrapper.serverPort,
};
}
class ReplicateWrapper extends base_wrapper_1.default {
static _patchRun(tracer) {
const genAIEndpoint = 'replicate.run';
return (originalMethod) => {
return async function (...args) {
if ((0, helpers_1.isFrameworkLlmActive)())
return originalMethod.apply(this, args);
const identifier = typeof args[0] === 'string' ? args[0] : '';
const requestModel = identifier.split(':')[0] || identifier;
const spanName = `${semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TEXT_COMPLETION} ${requestModel}`;
const effectiveCtx = (0, helpers_1.getFrameworkParentContext)() ?? api_1.context.active();
const span = tracer.startSpan(spanName, {
kind: api_1.SpanKind.CLIENT,
attributes: spanCreationAttrs(semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TEXT_COMPLETION, requestModel),
}, effectiveCtx);
return api_1.context
.with(api_1.trace.setSpan(effectiveCtx, span), async () => {
return originalMethod.apply(this, args);
})
.then((response) => ReplicateWrapper._run({ args, genAIEndpoint, response, span }))
.catch((e) => {
helpers_1.default.handleException(span, e);
base_wrapper_1.default.recordMetrics(span, {
genAIEndpoint,
model: requestModel,
aiSystem: ReplicateWrapper.aiSystem,
serverAddress: ReplicateWrapper.serverAddress,
serverPort: ReplicateWrapper.serverPort,
errorType: e?.constructor?.name || '_OTHER',
});
span.end();
throw e;
});
};
};
}
static async _run({ args, genAIEndpoint, response, span, }) {
let metricParams;
try {
const captureContent = config_1.default.captureMessageContent;
const identifier = typeof args[0] === 'string' ? args[0] : '';
const options = args[1] || {};
const input = options.input || {};
const prompt = input.prompt || '';
const requestModel = identifier.split(':')[0] || identifier;
span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
let outputText = '';
let outputType = semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_TEXT;
if (typeof response === 'string') {
outputText = response;
}
else if (Array.isArray(response)) {
outputText = response.join('');
}
else if (response && typeof response === 'object') {
outputType = semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_JSON;
outputText = JSON.stringify(response);
}
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_TYPE, outputType);
const promptTokens = helpers_1.default.generalTokens(prompt) ?? 0;
const completionTokens = helpers_1.default.generalTokens(outputText) ?? 0;
const pricingInfo = config_1.default.pricingInfo || {};
const cost = helpers_1.default.getChatModelCost(requestModel, pricingInfo, promptTokens, completionTokens);
ReplicateWrapper.setBaseSpanAttributes(span, {
genAIEndpoint,
model: requestModel,
cost,
aiSystem: ReplicateWrapper.aiSystem,
serverAddress: ReplicateWrapper.serverAddress,
serverPort: ReplicateWrapper.serverPort,
});
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, requestModel);
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, promptTokens);
span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, completionTokens);
span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, ['stop']);
let inputMessagesJson;
let outputMessagesJson;
if (captureContent) {
const messages = prompt ? [{ role: 'user', content: prompt }] : [];
inputMessagesJson = helpers_1.default.buildInputMessages(messages);
span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, inputMessagesJson);
outputMessagesJson = helpers_1.default.buildOutputMessages(outputText, 'stop');
span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, outputMessagesJson);
}
if (!config_1.default.disableEvents) {
const eventAttrs = {
[semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_TEXT_COMPLETION,
[semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
[semantic_convention_1.default.GEN_AI_RESPONSE_MODEL]: requestModel,
[semantic_convention_1.default.SERVER_ADDRESS]: ReplicateWrapper.serverAddress,
[semantic_convention_1.default.SERVER_PORT]: ReplicateWrapper.serverPort,
[semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON]: ['stop'],
[semantic_convention_1.default.GEN_AI_OUTPUT_TYPE]: outputType,
[semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS]: promptTokens,
[semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS]: completionTokens,
};
if (captureContent) {
if (inputMessagesJson)
eventAttrs[semantic_convention_1.default.GEN_AI_INPUT_MESSAGES] = inputMessagesJson;
if (outputMessagesJson)
eventAttrs[semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES] = outputMessagesJson;
}
helpers_1.default.emitInferenceEvent(span, eventAttrs);
}
metricParams = {
genAIEndpoint,
model: requestModel,
cost,
aiSystem: ReplicateWrapper.aiSystem,
};
return response;
}
catch (e) {
helpers_1.default.handleException(span, e);
throw e;
}
finally {
span.end();
if (metricParams) {
base_wrapper_1.default.recordMetrics(span, metricParams);
}
}
}
}
ReplicateWrapper.aiSystem = semantic_convention_1.default.GEN_AI_SYSTEM_REPLICATE;
ReplicateWrapper.serverAddress = 'api.replicate.com';
ReplicateWrapper.serverPort = 443;
exports.default = ReplicateWrapper;
//# sourceMappingURL=wrapper.js.map