langsmith
Version:
Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.
119 lines (118 loc) • 5.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractOutputTokenDetails = extractOutputTokenDetails;
exports.extractInputTokenDetails = extractInputTokenDetails;
exports.extractUsageMetadata = extractUsageMetadata;
function extractOutputTokenDetails(reasoningTokens) {
const outputTokenDetails = {};
if (typeof reasoningTokens === "number") {
outputTokenDetails.reasoning = reasoningTokens;
}
return outputTokenDetails;
}
function extractInputTokenDetails(providerMetadata, cachedTokenUsage) {
const inputTokenDetails = {};
if (providerMetadata.anthropic != null &&
typeof providerMetadata.anthropic === "object") {
const anthropic = providerMetadata.anthropic;
if (anthropic.usage != null && typeof anthropic.usage === "object") {
// Raw usage from Anthropic returned in AI SDK 5
const usage = anthropic.usage;
if (usage.cache_creation != null &&
typeof usage.cache_creation === "object") {
const cacheCreation = usage.cache_creation;
if (typeof cacheCreation.ephemeral_5m_input_tokens === "number") {
inputTokenDetails.ephemeral_5m_input_tokens =
cacheCreation.ephemeral_5m_input_tokens;
}
if (typeof cacheCreation.ephemeral_1h_input_tokens === "number") {
inputTokenDetails.ephemeral_1hr_input_tokens =
cacheCreation.ephemeral_1h_input_tokens;
}
// If cache_creation not returned (no beta header passed),
// fallback to assuming 5m cache tokens
}
else if (typeof usage.cache_creation_input_tokens === "number") {
inputTokenDetails.ephemeral_5m_input_tokens =
usage.cache_creation_input_tokens;
}
if (typeof usage.cache_read_input_tokens === "number") {
inputTokenDetails.cache_read = usage.cache_read_input_tokens;
}
}
else {
// AI SDK 4 fields
if (anthropic.cacheReadInputTokens != null &&
typeof anthropic.cacheReadInputTokens === "number") {
inputTokenDetails.cache_read = anthropic.cacheReadInputTokens;
}
if (anthropic.cacheCreationInputTokens != null &&
typeof anthropic.cacheCreationInputTokens === "number") {
inputTokenDetails.ephemeral_5m_input_tokens =
anthropic.cacheCreationInputTokens;
}
}
return inputTokenDetails;
}
else if (providerMetadata.openai != null &&
typeof providerMetadata.openai === "object") {
const openai = providerMetadata.openai;
if (openai.cachedPromptTokens != null &&
typeof openai.cachedPromptTokens === "number") {
inputTokenDetails.cache_read = openai.cachedPromptTokens;
}
else if (typeof cachedTokenUsage === "number") {
inputTokenDetails.cache_read = cachedTokenUsage;
}
}
return inputTokenDetails;
}
function extractUsageMetadata(span) {
const isError = span?.status?.code === 2;
if (isError || !span || !span.attributes) {
return {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
};
}
const usageMetadata = {
input_tokens: 0,
output_tokens: 0,
total_tokens: 0,
};
if (typeof span.attributes["ai.usage.promptTokens"] === "number" ||
typeof span.attributes["ai.usage.inputTokens"] === "number") {
usageMetadata.input_tokens =
span.attributes["ai.usage.promptTokens"] ??
span.attributes["ai.usage.inputTokens"];
}
if (typeof span.attributes["ai.usage.completionTokens"] === "number" ||
typeof span.attributes["ai.usage.outputTokens"] === "number") {
usageMetadata.output_tokens =
span.attributes["ai.usage.completionTokens"] ??
span.attributes["ai.usage.outputTokens"];
}
if (typeof span.attributes["ai.response.providerMetadata"] === "string") {
try {
const providerMetadata = JSON.parse(span.attributes["ai.response.providerMetadata"]);
usageMetadata.input_token_details = extractInputTokenDetails(providerMetadata, typeof span.attributes["ai.usage.cachedInputTokens"] === "number"
? span.attributes["ai.usage.cachedInputTokens"]
: undefined);
if (providerMetadata.anthropic != null &&
typeof providerMetadata.anthropic === "object") {
// AI SDK does not include Anthropic cache tokens in their stated input token
// numbers, so we need to add them manually
for (const key in usageMetadata.input_token_details) {
usageMetadata.input_tokens += usageMetadata.input_token_details[key];
}
}
}
catch {
// pass
}
}
usageMetadata.total_tokens =
usageMetadata.input_tokens + usageMetadata.output_tokens;
return usageMetadata;
}