@opentelemetry/instrumentation-aws-sdk
Version:
OpenTelemetry instrumentation for `aws-sdk` and `@aws-sdk/client-*` clients for various AWS services
587 lines • 30.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BedrockRuntimeServiceExtension = void 0;
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const api_1 = require("@opentelemetry/api");
const semconv_1 = require("../semconv");
const core_1 = require("@opentelemetry/core");
class BedrockRuntimeServiceExtension {
tokenUsage;
operationDuration;
_diag = api_1.diag;
updateMetricInstruments(meter) {
// https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/#metric-gen_aiclienttokenusage
this.tokenUsage = meter.createHistogram(semconv_1.METRIC_GEN_AI_CLIENT_TOKEN_USAGE, {
unit: '{token}',
description: 'Measures number of input and output tokens used',
valueType: api_1.ValueType.INT,
advice: {
explicitBucketBoundaries: [
1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304,
16777216, 67108864,
],
},
});
// https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/#metric-gen_aiclientoperationduration
this.operationDuration = meter.createHistogram(semconv_1.METRIC_GEN_AI_CLIENT_OPERATION_DURATION, {
unit: 's',
description: 'GenAI operation duration',
advice: {
explicitBucketBoundaries: [
0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24,
20.48, 40.96, 81.92,
],
},
});
}
requestPreSpanHook(request, config, diag) {
switch (request.commandName) {
case 'Converse':
return this.requestPreSpanHookConverse(request, config, diag, false);
case 'ConverseStream':
return this.requestPreSpanHookConverse(request, config, diag, true);
case 'InvokeModel':
return this.requestPreSpanHookInvokeModel(request, config, diag, false);
case 'InvokeModelWithResponseStream':
return this.requestPreSpanHookInvokeModel(request, config, diag, true);
}
return {
isIncoming: false,
};
}
requestPreSpanHookConverse(request, config, diag, isStream) {
let spanName = semconv_1.GEN_AI_OPERATION_NAME_VALUE_CHAT;
const spanAttributes = {
[semconv_1.ATTR_GEN_AI_SYSTEM]: semconv_1.GEN_AI_SYSTEM_VALUE_AWS_BEDROCK,
[semconv_1.ATTR_GEN_AI_OPERATION_NAME]: semconv_1.GEN_AI_OPERATION_NAME_VALUE_CHAT,
};
const modelId = request.commandInput.modelId;
if (modelId) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MODEL] = modelId;
if (spanName) {
spanName += ` ${modelId}`;
}
}
const inferenceConfig = request.commandInput.inferenceConfig;
if (inferenceConfig) {
const { maxTokens, temperature, topP, stopSequences } = inferenceConfig;
if (maxTokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] = maxTokens;
}
if (temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] = temperature;
}
if (topP !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = topP;
}
if (stopSequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] = stopSequences;
}
}
return {
spanName,
isIncoming: false,
isStream,
spanAttributes,
};
}
requestPreSpanHookInvokeModel(request, config, diag, isStream) {
let spanName;
const spanAttributes = {
[semconv_1.ATTR_GEN_AI_SYSTEM]: semconv_1.GEN_AI_SYSTEM_VALUE_AWS_BEDROCK,
// add operation name for InvokeModel API
};
const modelId = request.commandInput?.modelId;
if (modelId) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MODEL] = modelId;
}
if (request.commandInput?.body) {
const requestBody = JSON.parse(request.commandInput.body);
if (modelId.includes('amazon.titan')) {
if (requestBody.textGenerationConfig?.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.textGenerationConfig.temperature;
}
if (requestBody.textGenerationConfig?.topP !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] =
requestBody.textGenerationConfig.topP;
}
if (requestBody.textGenerationConfig?.maxTokenCount !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.textGenerationConfig.maxTokenCount;
}
if (requestBody.textGenerationConfig?.stopSequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] =
requestBody.textGenerationConfig.stopSequences;
}
}
else if (modelId.includes('amazon.nova')) {
if (requestBody.inferenceConfig?.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.inferenceConfig.temperature;
}
if (requestBody.inferenceConfig?.top_p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] =
requestBody.inferenceConfig.top_p;
}
if (requestBody.inferenceConfig?.max_new_tokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.inferenceConfig.max_new_tokens;
}
if (requestBody.inferenceConfig?.stopSequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] =
requestBody.inferenceConfig.stopSequences;
}
}
else if (modelId.includes('anthropic.claude')) {
if (requestBody.max_tokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.max_tokens;
}
if (requestBody.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.temperature;
}
if (requestBody.top_p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = requestBody.top_p;
}
if (requestBody.stop_sequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] =
requestBody.stop_sequences;
}
}
else if (modelId.includes('meta.llama')) {
if (requestBody.max_gen_len !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.max_gen_len;
}
if (requestBody.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.temperature;
}
if (requestBody.top_p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = requestBody.top_p;
}
// request for meta llama models does not contain stop_sequences field
}
else if (modelId.includes('cohere.command-r')) {
if (requestBody.max_tokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.max_tokens;
}
if (requestBody.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.temperature;
}
if (requestBody.p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = requestBody.p;
}
if (requestBody.message !== undefined) {
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
spanAttributes[semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS] = Math.ceil(requestBody.message.length / 6);
}
if (requestBody.stop_sequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] =
requestBody.stop_sequences;
}
}
else if (modelId.includes('cohere.command')) {
if (requestBody.max_tokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.max_tokens;
}
if (requestBody.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.temperature;
}
if (requestBody.p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = requestBody.p;
}
if (requestBody.prompt !== undefined) {
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
spanAttributes[semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS] = Math.ceil(requestBody.prompt.length / 6);
}
if (requestBody.stop_sequences !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] =
requestBody.stop_sequences;
}
}
else if (modelId.includes('mistral')) {
if (requestBody.prompt !== undefined) {
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
spanAttributes[semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS] = Math.ceil(requestBody.prompt.length / 6);
}
if (requestBody.max_tokens !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_MAX_TOKENS] =
requestBody.max_tokens;
}
if (requestBody.temperature !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TEMPERATURE] =
requestBody.temperature;
}
if (requestBody.top_p !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_TOP_P] = requestBody.top_p;
}
if (requestBody.stop !== undefined) {
spanAttributes[semconv_1.ATTR_GEN_AI_REQUEST_STOP_SEQUENCES] = requestBody.stop;
}
}
}
return {
spanName,
isIncoming: false,
isStream,
spanAttributes,
};
}
responseHook(response, span, tracer, config, startTime) {
if (!span.isRecording()) {
return;
}
switch (response.request.commandName) {
case 'Converse':
return this.responseHookConverse(response, span, tracer, config, startTime);
case 'ConverseStream':
return this.responseHookConverseStream(response, span, tracer, config, startTime);
case 'InvokeModel':
return this.responseHookInvokeModel(response, span, tracer, config);
case 'InvokeModelWithResponseStream':
return this.responseHookInvokeModelWithResponseStream(response, span, tracer, config);
}
}
responseHookConverse(response, span, tracer, config, startTime) {
const { stopReason, usage } = response.data;
BedrockRuntimeServiceExtension.setStopReason(span, stopReason);
this.setUsage(response, span, usage, startTime);
}
responseHookConverseStream(response, span, tracer, config, startTime) {
return {
...response.data,
// Wrap and replace the response stream to allow processing events to telemetry
// before yielding to the user.
stream: this.wrapConverseStreamResponse(response, response.data.stream, span, startTime),
};
}
async *wrapConverseStreamResponse(response, stream, span, startTime) {
try {
let usage;
for await (const item of stream) {
BedrockRuntimeServiceExtension.setStopReason(span, item.messageStop?.stopReason);
usage = item.metadata?.usage;
yield item;
}
this.setUsage(response, span, usage, startTime);
}
finally {
span.end();
}
}
static setStopReason(span, stopReason) {
if (stopReason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [stopReason]);
}
}
setUsage(response, span, usage, startTime) {
const sharedMetricAttrs = {
[semconv_1.ATTR_GEN_AI_SYSTEM]: semconv_1.GEN_AI_SYSTEM_VALUE_AWS_BEDROCK,
[semconv_1.ATTR_GEN_AI_OPERATION_NAME]: semconv_1.GEN_AI_OPERATION_NAME_VALUE_CHAT,
[semconv_1.ATTR_GEN_AI_REQUEST_MODEL]: response.request.commandInput.modelId,
};
const durationSecs = (0, core_1.hrTimeToMilliseconds)((0, core_1.hrTimeDuration)(startTime, (0, core_1.hrTime)())) / 1000;
this.operationDuration.record(durationSecs, sharedMetricAttrs);
if (usage) {
const { inputTokens, outputTokens } = usage;
if (inputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
this.tokenUsage.record(inputTokens, {
...sharedMetricAttrs,
[semconv_1.ATTR_GEN_AI_TOKEN_TYPE]: semconv_1.GEN_AI_TOKEN_TYPE_VALUE_INPUT,
});
}
if (outputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
this.tokenUsage.record(outputTokens, {
...sharedMetricAttrs,
[semconv_1.ATTR_GEN_AI_TOKEN_TYPE]: semconv_1.GEN_AI_TOKEN_TYPE_VALUE_OUTPUT,
});
}
}
}
responseHookInvokeModel(response, span, tracer, config) {
const currentModelId = response.request.commandInput?.modelId;
if (response.data?.body) {
const decodedResponseBody = new TextDecoder().decode(response.data.body);
const responseBody = JSON.parse(decodedResponseBody);
if (currentModelId.includes('amazon.titan')) {
if (responseBody.inputTextTokenCount !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, responseBody.inputTextTokenCount);
}
if (responseBody.results?.[0]?.tokenCount !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, responseBody.results[0].tokenCount);
}
if (responseBody.results?.[0]?.completionReason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.results[0].completionReason,
]);
}
}
else if (currentModelId.includes('amazon.nova')) {
if (responseBody.usage !== undefined) {
if (responseBody.usage.inputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, responseBody.usage.inputTokens);
}
if (responseBody.usage.outputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, responseBody.usage.outputTokens);
}
}
if (responseBody.stopReason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.stopReason,
]);
}
}
else if (currentModelId.includes('anthropic.claude')) {
if (responseBody.usage?.input_tokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, responseBody.usage.input_tokens);
}
if (responseBody.usage?.output_tokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, responseBody.usage.output_tokens);
}
if (responseBody.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.stop_reason,
]);
}
}
else if (currentModelId.includes('meta.llama')) {
if (responseBody.prompt_token_count !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, responseBody.prompt_token_count);
}
if (responseBody.generation_token_count !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, responseBody.generation_token_count);
}
if (responseBody.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.stop_reason,
]);
}
}
else if (currentModelId.includes('cohere.command-r')) {
if (responseBody.text !== undefined) {
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, Math.ceil(responseBody.text.length / 6));
}
if (responseBody.finish_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.finish_reason,
]);
}
}
else if (currentModelId.includes('cohere.command')) {
if (responseBody.generations?.[0]?.text !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS,
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
Math.ceil(responseBody.generations[0].text.length / 6));
}
if (responseBody.generations?.[0]?.finish_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.generations[0].finish_reason,
]);
}
}
else if (currentModelId.includes('mistral')) {
if (responseBody.outputs?.[0]?.text !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS,
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
Math.ceil(responseBody.outputs[0].text.length / 6));
}
if (responseBody.outputs?.[0]?.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
responseBody.outputs[0].stop_reason,
]);
}
}
}
}
async responseHookInvokeModelWithResponseStream(response, span, tracer, config) {
const stream = response.data?.body;
const modelId = response.request.commandInput?.modelId;
if (!stream || !modelId)
return;
// Replace the original response body with our instrumented stream.
// - Defers span.end() until the entire stream is consumed
// This ensures downstream consumers still receive the full stream correctly,
// while OpenTelemetry can record span attributes from streamed data.
response.data.body = async function* () {
try {
for await (const chunk of stream) {
const parsedChunk = this.parseChunk(chunk?.chunk?.bytes);
if (!parsedChunk) {
// pass through
}
else if (modelId.includes('amazon.titan')) {
BedrockRuntimeServiceExtension.recordTitanAttributes(parsedChunk, span);
}
else if (modelId.includes('anthropic.claude')) {
BedrockRuntimeServiceExtension.recordClaudeAttributes(parsedChunk, span);
}
else if (modelId.includes('amazon.nova')) {
BedrockRuntimeServiceExtension.recordNovaAttributes(parsedChunk, span);
}
else if (modelId.includes('meta.llama')) {
BedrockRuntimeServiceExtension.recordLlamaAttributes(parsedChunk, span);
}
else if (modelId.includes('cohere.command-r')) {
BedrockRuntimeServiceExtension.recordCohereRAttributes(parsedChunk, span);
}
else if (modelId.includes('cohere.command')) {
BedrockRuntimeServiceExtension.recordCohereAttributes(parsedChunk, span);
}
else if (modelId.includes('mistral')) {
BedrockRuntimeServiceExtension.recordMistralAttributes(parsedChunk, span);
}
yield chunk;
}
}
finally {
span.end();
}
}.bind(this)();
return response.data;
}
parseChunk(bytes) {
if (!bytes || !(bytes instanceof Uint8Array))
return null;
try {
const str = Buffer.from(bytes).toString('utf-8');
return JSON.parse(str);
}
catch (err) {
this._diag.warn('Failed to parse streamed chunk', err);
return null;
}
}
static recordNovaAttributes(parsedChunk, span) {
if (parsedChunk.metadata?.usage !== undefined) {
if (parsedChunk.metadata?.usage.inputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, parsedChunk.metadata.usage.inputTokens);
}
if (parsedChunk.metadata?.usage.outputTokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, parsedChunk.metadata.usage.outputTokens);
}
}
if (parsedChunk.messageStop?.stopReason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.messageStop.stopReason,
]);
}
}
static recordClaudeAttributes(parsedChunk, span) {
if (parsedChunk.message?.usage?.input_tokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, parsedChunk.message.usage.input_tokens);
}
if (parsedChunk.message?.usage?.output_tokens !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, parsedChunk.message.usage.output_tokens);
}
if (parsedChunk.delta?.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.delta.stop_reason,
]);
}
}
static recordTitanAttributes(parsedChunk, span) {
if (parsedChunk.inputTextTokenCount !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, parsedChunk.inputTextTokenCount);
}
if (parsedChunk.totalOutputTextTokenCount !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, parsedChunk.totalOutputTextTokenCount);
}
if (parsedChunk.completionReason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.completionReason,
]);
}
}
static recordLlamaAttributes(parsedChunk, span) {
if (parsedChunk.prompt_token_count !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_INPUT_TOKENS, parsedChunk.prompt_token_count);
}
if (parsedChunk.generation_token_count !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, parsedChunk.generation_token_count);
}
if (parsedChunk.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.stop_reason,
]);
}
}
static recordMistralAttributes(parsedChunk, span) {
if (parsedChunk.outputs?.[0]?.text !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS,
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
Math.ceil(parsedChunk.outputs[0].text.length / 6));
}
if (parsedChunk.outputs?.[0]?.stop_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.outputs[0].stop_reason,
]);
}
}
static recordCohereAttributes(parsedChunk, span) {
if (parsedChunk.generations?.[0]?.text !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS,
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
Math.ceil(parsedChunk.generations[0].text.length / 6));
}
if (parsedChunk.generations?.[0]?.finish_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.generations[0].finish_reason,
]);
}
}
static recordCohereRAttributes(parsedChunk, span) {
if (parsedChunk.text !== undefined) {
// NOTE: We approximate the token count since this value is not directly available in the body
// According to Bedrock docs they use (total_chars / 6) to approximate token count for pricing.
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
span.setAttribute(semconv_1.ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, Math.ceil(parsedChunk.text.length / 6));
}
if (parsedChunk.finish_reason !== undefined) {
span.setAttribute(semconv_1.ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [
parsedChunk.finish_reason,
]);
}
}
}
exports.BedrockRuntimeServiceExtension = BedrockRuntimeServiceExtension;
//# sourceMappingURL=bedrock-runtime.js.map