@traceloop/instrumentation-bedrock 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +12 -1
- package/dist/index.js +322 -98
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +324 -101
- package/dist/src/instrumentation.d.ts +4 -0
- package/dist/src/types.d.ts +7 -0
- package/package.json +8 -6
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
import { __awaiter, __asyncValues } from 'tslib';
|
|
2
2
|
import { trace, context, SpanStatusCode, SpanKind } from '@opentelemetry/api';
|
|
3
3
|
import { InstrumentationBase, InstrumentationNodeModuleDefinition, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { FinishReasons, SpanAttributes, CONTEXT_KEY_ALLOW_TRACE_CONTENT } from '@traceloop/ai-semantic-conventions';
|
|
5
|
+
import { GEN_AI_PROVIDER_NAME_VALUE_AWS_BEDROCK, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_PROVIDER_NAME, ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_GEN_AI_RESPONSE_FINISH_REASONS, ATTR_GEN_AI_OUTPUT_MESSAGES, ATTR_GEN_AI_REQUEST_MAX_TOKENS, ATTR_GEN_AI_REQUEST_TEMPERATURE, ATTR_GEN_AI_REQUEST_TOP_P, ATTR_GEN_AI_INPUT_MESSAGES, ATTR_GEN_AI_REQUEST_TOP_K, ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY, ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, GEN_AI_OPERATION_NAME_VALUE_CHAT, ATTR_GEN_AI_SYSTEM_INSTRUCTIONS } from '@opentelemetry/semantic-conventions/incubating';
|
|
6
|
+
import { formatOutputMessage, mapBedrockContentBlock, formatInputMessagesFromPrompt, formatInputMessages, formatSystemInstructions } from '@traceloop/instrumentation-utils';
|
|
6
7
|
|
|
7
|
-
var
|
|
8
|
+
var BedrockVendor;
|
|
9
|
+
(function (BedrockVendor) {
|
|
10
|
+
BedrockVendor["AI21"] = "ai21";
|
|
11
|
+
BedrockVendor["AMAZON"] = "amazon";
|
|
12
|
+
BedrockVendor["ANTHROPIC"] = "anthropic";
|
|
13
|
+
BedrockVendor["COHERE"] = "cohere";
|
|
14
|
+
BedrockVendor["META"] = "meta";
|
|
15
|
+
})(BedrockVendor || (BedrockVendor = {}));
|
|
8
16
|
|
|
17
|
+
var version = "0.24.0";
|
|
18
|
+
|
|
19
|
+
const bedrockFinishReasonMap = {
|
|
20
|
+
// AI21
|
|
21
|
+
endoftext: FinishReasons.STOP,
|
|
22
|
+
// Amazon Titan / Nova
|
|
23
|
+
FINISH: FinishReasons.STOP,
|
|
24
|
+
LENGTH: FinishReasons.LENGTH,
|
|
25
|
+
CONTENT_FILTERED: FinishReasons.CONTENT_FILTER,
|
|
26
|
+
// Anthropic
|
|
27
|
+
end_turn: FinishReasons.STOP,
|
|
28
|
+
max_tokens: FinishReasons.LENGTH,
|
|
29
|
+
stop_sequence: FinishReasons.STOP,
|
|
30
|
+
tool_use: FinishReasons.TOOL_CALL,
|
|
31
|
+
// Cohere
|
|
32
|
+
COMPLETE: FinishReasons.STOP,
|
|
33
|
+
MAX_TOKENS: FinishReasons.LENGTH,
|
|
34
|
+
ERROR: FinishReasons.ERROR,
|
|
35
|
+
ERROR_TOXIC: FinishReasons.CONTENT_FILTER,
|
|
36
|
+
// Meta
|
|
37
|
+
stop: FinishReasons.STOP,
|
|
38
|
+
length: FinishReasons.LENGTH,
|
|
39
|
+
};
|
|
9
40
|
class BedrockInstrumentation extends InstrumentationBase {
|
|
10
41
|
constructor(config = {}) {
|
|
11
42
|
super("@traceloop/instrumentation-bedrock", version, config);
|
|
@@ -36,9 +67,11 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
36
67
|
// eslint-disable-next-line
|
|
37
68
|
return (original) => {
|
|
38
69
|
return function method(...args) {
|
|
70
|
+
var _a, _b, _c;
|
|
39
71
|
const span = plugin._startSpan({
|
|
40
72
|
params: args[0],
|
|
41
73
|
});
|
|
74
|
+
const modelId = (_c = (_b = (_a = args[0]) === null || _a === void 0 ? void 0 : _a.input) === null || _b === void 0 ? void 0 : _b.modelId) !== null && _c !== void 0 ? _c : "";
|
|
42
75
|
const execContext = trace.setSpan(context.active(), span);
|
|
43
76
|
const execPromise = safeExecuteInTheMiddle(() => {
|
|
44
77
|
return context.with(execContext, () => {
|
|
@@ -49,17 +82,18 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
49
82
|
plugin._diag.error(`Error in bedrock instrumentation`, e);
|
|
50
83
|
}
|
|
51
84
|
});
|
|
52
|
-
const wrappedPromise = plugin._wrapPromise(span, execPromise);
|
|
85
|
+
const wrappedPromise = plugin._wrapPromise(span, execPromise, modelId);
|
|
53
86
|
return context.bind(execContext, wrappedPromise);
|
|
54
87
|
};
|
|
55
88
|
};
|
|
56
89
|
}
|
|
57
|
-
_wrapPromise(span, promise) {
|
|
90
|
+
_wrapPromise(span, promise, modelId) {
|
|
58
91
|
return promise
|
|
59
92
|
.then((result) => __awaiter(this, void 0, void 0, function* () {
|
|
60
93
|
yield this._endSpan({
|
|
61
94
|
span,
|
|
62
95
|
result: result,
|
|
96
|
+
modelId,
|
|
63
97
|
});
|
|
64
98
|
return new Promise((resolve) => resolve(result));
|
|
65
99
|
}))
|
|
@@ -78,17 +112,21 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
78
112
|
_startSpan({ params, }) {
|
|
79
113
|
var _a, _b;
|
|
80
114
|
let attributes = {};
|
|
115
|
+
let spanName = "bedrock.completion";
|
|
81
116
|
try {
|
|
82
117
|
const input = params.input;
|
|
83
118
|
const { modelVendor, model } = this._extractVendorAndModel(input.modelId || "");
|
|
84
119
|
attributes = {
|
|
85
|
-
[
|
|
120
|
+
[ATTR_GEN_AI_PROVIDER_NAME]: GEN_AI_PROVIDER_NAME_VALUE_AWS_BEDROCK,
|
|
86
121
|
[ATTR_GEN_AI_REQUEST_MODEL]: model,
|
|
87
|
-
[ATTR_GEN_AI_RESPONSE_MODEL]: input.modelId,
|
|
88
|
-
[SpanAttributes.LLM_REQUEST_TYPE]: LLMRequestTypeValues.COMPLETION,
|
|
89
122
|
};
|
|
90
123
|
if (typeof input.body === "string") {
|
|
91
124
|
const requestBody = JSON.parse(input.body);
|
|
125
|
+
const operationType = this._getOperationType(modelVendor, requestBody);
|
|
126
|
+
spanName = `${operationType} ${model}`;
|
|
127
|
+
// Set operation name before _setRequestAttributes so it is always
|
|
128
|
+
// present even if _setRequestAttributes throws for an unexpected body.
|
|
129
|
+
attributes = Object.assign(Object.assign({}, attributes), { [ATTR_GEN_AI_OPERATION_NAME]: operationType });
|
|
92
130
|
attributes = Object.assign(Object.assign({}, attributes), this._setRequestAttributes(modelVendor, requestBody));
|
|
93
131
|
}
|
|
94
132
|
}
|
|
@@ -96,50 +134,57 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
96
134
|
this._diag.debug(e);
|
|
97
135
|
(_b = (_a = this._config).exceptionLogger) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
|
98
136
|
}
|
|
99
|
-
return this.tracer.startSpan(
|
|
137
|
+
return this.tracer.startSpan(spanName, {
|
|
100
138
|
kind: SpanKind.CLIENT,
|
|
101
139
|
attributes,
|
|
102
140
|
});
|
|
103
141
|
}
|
|
104
142
|
_endSpan(_a) {
|
|
105
|
-
return __awaiter(this, arguments, void 0, function* ({ span, result, }) {
|
|
143
|
+
return __awaiter(this, arguments, void 0, function* ({ span, result, modelId, }) {
|
|
106
144
|
var _b, e_1, _c, _d;
|
|
107
|
-
var _e, _f, _g;
|
|
145
|
+
var _e, _f, _g, _h;
|
|
108
146
|
try {
|
|
109
147
|
if ("body" in result) {
|
|
110
148
|
const attributes = "attributes" in span
|
|
111
149
|
? span["attributes"]
|
|
112
150
|
: {};
|
|
113
|
-
if (
|
|
114
|
-
const modelId = attributes[ATTR_GEN_AI_RESPONSE_MODEL];
|
|
151
|
+
if (ATTR_GEN_AI_PROVIDER_NAME in attributes) {
|
|
115
152
|
const { modelVendor, model } = this._extractVendorAndModel(modelId);
|
|
116
153
|
span.setAttribute(ATTR_GEN_AI_RESPONSE_MODEL, model);
|
|
117
154
|
if (!(result.body instanceof Object.getPrototypeOf(Uint8Array))) {
|
|
118
155
|
const rawRes = result.body;
|
|
119
156
|
let streamedContent = "";
|
|
120
157
|
try {
|
|
121
|
-
for (var
|
|
158
|
+
for (var _j = true, rawRes_1 = __asyncValues(rawRes), rawRes_1_1; rawRes_1_1 = yield rawRes_1.next(), _b = rawRes_1_1.done, !_b; _j = true) {
|
|
122
159
|
_d = rawRes_1_1.value;
|
|
123
|
-
|
|
160
|
+
_j = false;
|
|
124
161
|
const value = _d;
|
|
125
162
|
// Convert it to a JSON String
|
|
126
163
|
const jsonString = new TextDecoder().decode((_e = value.chunk) === null || _e === void 0 ? void 0 : _e.bytes);
|
|
127
164
|
// Parse the JSON string
|
|
128
165
|
const parsedResponse = JSON.parse(jsonString);
|
|
129
166
|
if ("amazon-bedrock-invocationMetrics" in parsedResponse) {
|
|
130
|
-
span.setAttribute(
|
|
131
|
-
span.setAttribute(
|
|
132
|
-
|
|
133
|
-
parsedResponse["amazon-bedrock-invocationMetrics"]["outputTokenCount"]
|
|
167
|
+
span.setAttribute(ATTR_GEN_AI_USAGE_INPUT_TOKENS, parsedResponse["amazon-bedrock-invocationMetrics"]["inputTokenCount"]);
|
|
168
|
+
span.setAttribute(ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, parsedResponse["amazon-bedrock-invocationMetrics"]["outputTokenCount"]);
|
|
169
|
+
const totalTokens = parsedResponse["amazon-bedrock-invocationMetrics"]["inputTokenCount"] +
|
|
170
|
+
parsedResponse["amazon-bedrock-invocationMetrics"]["outputTokenCount"];
|
|
171
|
+
span.setAttribute(SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
|
|
134
172
|
}
|
|
135
|
-
|
|
173
|
+
this._handleNovaStreamingMetadata(span, parsedResponse);
|
|
174
|
+
const responseAttributes = this._setResponseAttributes(modelVendor, parsedResponse, true);
|
|
136
175
|
// ! NOTE: This make sure the content always have all streamed chunks
|
|
137
176
|
if (this._shouldSendPrompts()) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
177
|
+
const chunkContent = this._getStreamChunkContent(modelVendor, parsedResponse);
|
|
178
|
+
if (chunkContent !== undefined) {
|
|
179
|
+
streamedContent += chunkContent;
|
|
180
|
+
}
|
|
181
|
+
// When finish reason is available (final chunk), set OTel 1.40 output message
|
|
182
|
+
if (responseAttributes[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]) {
|
|
183
|
+
const finishReasons = responseAttributes[ATTR_GEN_AI_RESPONSE_FINISH_REASONS];
|
|
184
|
+
responseAttributes[ATTR_GEN_AI_OUTPUT_MESSAGES] =
|
|
185
|
+
formatOutputMessage(streamedContent, (_f = finishReasons[0]) !== null && _f !== void 0 ? _f : null, {}, // already mapped by _setResponseAttributes
|
|
186
|
+
attributes[ATTR_GEN_AI_OPERATION_NAME], mapBedrockContentBlock);
|
|
187
|
+
}
|
|
143
188
|
}
|
|
144
189
|
span.setAttributes(responseAttributes);
|
|
145
190
|
}
|
|
@@ -147,7 +192,7 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
147
192
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
148
193
|
finally {
|
|
149
194
|
try {
|
|
150
|
-
if (!
|
|
195
|
+
if (!_j && !_b && (_c = rawRes_1.return)) yield _c.call(rawRes_1);
|
|
151
196
|
}
|
|
152
197
|
finally { if (e_1) throw e_1.error; }
|
|
153
198
|
}
|
|
@@ -165,34 +210,51 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
165
210
|
}
|
|
166
211
|
catch (e) {
|
|
167
212
|
this._diag.debug(e);
|
|
168
|
-
(
|
|
213
|
+
(_h = (_g = this._config).exceptionLogger) === null || _h === void 0 ? void 0 : _h.call(_g, e);
|
|
169
214
|
}
|
|
170
215
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
171
216
|
span.end();
|
|
172
217
|
});
|
|
173
218
|
}
|
|
174
219
|
_setRequestAttributes(vendor, requestBody) {
|
|
220
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
175
221
|
switch (vendor) {
|
|
176
|
-
case
|
|
177
|
-
|
|
222
|
+
case BedrockVendor.AI21: {
|
|
223
|
+
// Jamba format: messages array + max_tokens + top_p
|
|
224
|
+
if (requestBody["messages"]) {
|
|
225
|
+
return Object.assign({ [ATTR_GEN_AI_REQUEST_TOP_P]: requestBody["top_p"], [ATTR_GEN_AI_REQUEST_TEMPERATURE]: requestBody["temperature"], [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: requestBody["max_tokens"] }, (this._shouldSendPrompts()
|
|
226
|
+
? {
|
|
227
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessages(requestBody["messages"], mapBedrockContentBlock),
|
|
228
|
+
}
|
|
229
|
+
: {}));
|
|
230
|
+
}
|
|
231
|
+
// Legacy Jurassic format: prompt + topP + maxTokens
|
|
232
|
+
return Object.assign({ [ATTR_GEN_AI_REQUEST_TOP_P]: requestBody["topP"], [ATTR_GEN_AI_REQUEST_TEMPERATURE]: requestBody["temperature"], [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: requestBody["maxTokens"], [ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY]: (_a = requestBody["presencePenalty"]) === null || _a === void 0 ? void 0 : _a["scale"], [ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY]: (_b = requestBody["frequencyPenalty"]) === null || _b === void 0 ? void 0 : _b["scale"] }, (this._shouldSendPrompts()
|
|
178
233
|
? {
|
|
179
|
-
[
|
|
180
|
-
[`${ATTR_GEN_AI_PROMPT}.0.content`]: requestBody["prompt"],
|
|
234
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessagesFromPrompt(requestBody["prompt"]),
|
|
181
235
|
}
|
|
182
236
|
: {}));
|
|
183
237
|
}
|
|
184
|
-
case
|
|
185
|
-
|
|
238
|
+
case BedrockVendor.AMAZON: {
|
|
239
|
+
// Amazon Nova format: messages array + inferenceConfig
|
|
240
|
+
if (requestBody["messages"]) {
|
|
241
|
+
return Object.assign({ [ATTR_GEN_AI_REQUEST_TOP_P]: (_c = requestBody["inferenceConfig"]) === null || _c === void 0 ? void 0 : _c["topP"], [ATTR_GEN_AI_REQUEST_TEMPERATURE]: (_d = requestBody["inferenceConfig"]) === null || _d === void 0 ? void 0 : _d["temperature"], [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: (_e = requestBody["inferenceConfig"]) === null || _e === void 0 ? void 0 : _e["maxTokens"] }, (this._shouldSendPrompts()
|
|
242
|
+
? {
|
|
243
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessages(requestBody["messages"], mapBedrockContentBlock),
|
|
244
|
+
}
|
|
245
|
+
: {}));
|
|
246
|
+
}
|
|
247
|
+
// Amazon Titan format: inputText + textGenerationConfig
|
|
248
|
+
return Object.assign({ [ATTR_GEN_AI_REQUEST_TOP_P]: (_f = requestBody["textGenerationConfig"]) === null || _f === void 0 ? void 0 : _f["topP"], [ATTR_GEN_AI_REQUEST_TEMPERATURE]: (_g = requestBody["textGenerationConfig"]) === null || _g === void 0 ? void 0 : _g["temperature"], [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: (_h = requestBody["textGenerationConfig"]) === null || _h === void 0 ? void 0 : _h["maxTokenCount"] }, (this._shouldSendPrompts()
|
|
186
249
|
? {
|
|
187
|
-
[
|
|
188
|
-
[`${ATTR_GEN_AI_PROMPT}.0.content`]: requestBody["inputText"],
|
|
250
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessagesFromPrompt(requestBody["inputText"]),
|
|
189
251
|
}
|
|
190
252
|
: {}));
|
|
191
253
|
}
|
|
192
|
-
case
|
|
254
|
+
case BedrockVendor.ANTHROPIC: {
|
|
193
255
|
const baseAttributes = {
|
|
194
256
|
[ATTR_GEN_AI_REQUEST_TOP_P]: requestBody["top_p"],
|
|
195
|
-
[
|
|
257
|
+
[ATTR_GEN_AI_REQUEST_TOP_K]: requestBody["top_k"],
|
|
196
258
|
[ATTR_GEN_AI_REQUEST_TEMPERATURE]: requestBody["temperature"],
|
|
197
259
|
[ATTR_GEN_AI_REQUEST_MAX_TOKENS]: requestBody["max_tokens_to_sample"] || requestBody["max_tokens"],
|
|
198
260
|
};
|
|
@@ -201,39 +263,35 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
201
263
|
}
|
|
202
264
|
// Handle new messages API format (used by langchain)
|
|
203
265
|
if (requestBody["messages"]) {
|
|
204
|
-
const promptAttributes = {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
promptAttributes[
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
: JSON.stringify(message.content);
|
|
212
|
-
});
|
|
266
|
+
const promptAttributes = {
|
|
267
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessages(requestBody["messages"], mapBedrockContentBlock),
|
|
268
|
+
};
|
|
269
|
+
if (requestBody["system"] !== undefined) {
|
|
270
|
+
promptAttributes[ATTR_GEN_AI_SYSTEM_INSTRUCTIONS] =
|
|
271
|
+
formatSystemInstructions(requestBody["system"]);
|
|
272
|
+
}
|
|
213
273
|
return Object.assign(Object.assign({}, baseAttributes), promptAttributes);
|
|
214
274
|
}
|
|
215
275
|
// Handle legacy prompt format
|
|
216
276
|
if (requestBody["prompt"]) {
|
|
217
|
-
return Object.assign(Object.assign({}, baseAttributes), { [
|
|
218
|
-
// The format is removing when we are setting span attribute
|
|
277
|
+
return Object.assign(Object.assign({}, baseAttributes), { [ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessagesFromPrompt(requestBody["prompt"]
|
|
219
278
|
.replace("\n\nHuman:", "")
|
|
220
|
-
.replace("\n\nAssistant:", "") });
|
|
279
|
+
.replace("\n\nAssistant:", "")) });
|
|
221
280
|
}
|
|
222
281
|
return baseAttributes;
|
|
223
282
|
}
|
|
224
|
-
case
|
|
225
|
-
return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
283
|
+
case BedrockVendor.COHERE: {
|
|
284
|
+
return {
|
|
285
|
+
[ATTR_GEN_AI_REQUEST_TOP_P]: requestBody["p"],
|
|
286
|
+
[ATTR_GEN_AI_REQUEST_TOP_K]: requestBody["k"],
|
|
287
|
+
[ATTR_GEN_AI_REQUEST_TEMPERATURE]: requestBody["temperature"],
|
|
288
|
+
[ATTR_GEN_AI_REQUEST_MAX_TOKENS]: requestBody["max_tokens"],
|
|
289
|
+
};
|
|
231
290
|
}
|
|
232
|
-
case
|
|
291
|
+
case BedrockVendor.META: {
|
|
233
292
|
return Object.assign({ [ATTR_GEN_AI_REQUEST_TOP_P]: requestBody["top_p"], [ATTR_GEN_AI_REQUEST_TEMPERATURE]: requestBody["temperature"], [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: requestBody["max_gen_len"] }, (this._shouldSendPrompts()
|
|
234
293
|
? {
|
|
235
|
-
[
|
|
236
|
-
[`${ATTR_GEN_AI_PROMPT}.0.content`]: requestBody["prompt"],
|
|
294
|
+
[ATTR_GEN_AI_INPUT_MESSAGES]: formatInputMessagesFromPrompt(requestBody["prompt"]),
|
|
237
295
|
}
|
|
238
296
|
: {}));
|
|
239
297
|
}
|
|
@@ -242,71 +300,182 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
242
300
|
}
|
|
243
301
|
}
|
|
244
302
|
_setResponseAttributes(vendor, response, isStream = false) {
|
|
245
|
-
var _a, _b, _c, _d;
|
|
303
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
|
|
246
304
|
switch (vendor) {
|
|
247
|
-
case
|
|
248
|
-
|
|
305
|
+
case BedrockVendor.AI21: {
|
|
306
|
+
// Jamba format: choices[0].message + choices[0].finish_reason
|
|
307
|
+
if (response["choices"]) {
|
|
308
|
+
const usage = response["usage"];
|
|
309
|
+
const finishReason = (_a = response["choices"][0]) === null || _a === void 0 ? void 0 : _a["finish_reason"];
|
|
310
|
+
const content = isStream
|
|
311
|
+
? (_c = (_b = response["choices"][0]) === null || _b === void 0 ? void 0 : _b["delta"]) === null || _c === void 0 ? void 0 : _c["content"]
|
|
312
|
+
: (_e = (_d = response["choices"][0]) === null || _d === void 0 ? void 0 : _d["message"]) === null || _e === void 0 ? void 0 : _e["content"];
|
|
313
|
+
return Object.assign(Object.assign(Object.assign({}, (finishReason != null
|
|
314
|
+
? {
|
|
315
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
316
|
+
(_f = bedrockFinishReasonMap[finishReason]) !== null && _f !== void 0 ? _f : finishReason,
|
|
317
|
+
],
|
|
318
|
+
}
|
|
319
|
+
: {})), (usage
|
|
320
|
+
? {
|
|
321
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: usage["prompt_tokens"],
|
|
322
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: usage["completion_tokens"],
|
|
323
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: usage["total_tokens"],
|
|
324
|
+
}
|
|
325
|
+
: {})), (this._shouldSendPrompts()
|
|
326
|
+
? {
|
|
327
|
+
[ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(content !== null && content !== void 0 ? content : "", finishReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, mapBedrockContentBlock),
|
|
328
|
+
}
|
|
329
|
+
: {}));
|
|
330
|
+
}
|
|
331
|
+
// Legacy Jurassic format: completions[0].data.text
|
|
332
|
+
const jurassicFinishReason = response["completions"][0]["finishReason"]["reason"];
|
|
333
|
+
const jurassicContent = response["completions"][0]["data"]["text"];
|
|
334
|
+
return Object.assign({ [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
335
|
+
(_g = bedrockFinishReasonMap[jurassicFinishReason]) !== null && _g !== void 0 ? _g : jurassicFinishReason,
|
|
336
|
+
] }, (this._shouldSendPrompts()
|
|
249
337
|
? {
|
|
250
|
-
[
|
|
338
|
+
[ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(jurassicContent, jurassicFinishReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, mapBedrockContentBlock),
|
|
251
339
|
}
|
|
252
340
|
: {}));
|
|
253
341
|
}
|
|
254
|
-
case
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
342
|
+
case BedrockVendor.AMAZON: {
|
|
343
|
+
if (isStream) {
|
|
344
|
+
// Amazon Nova format: contentBlockDelta has text, messageStop has stopReason
|
|
345
|
+
const novaFinishReason = (_h = response["messageStop"]) === null || _h === void 0 ? void 0 : _h["stopReason"];
|
|
346
|
+
// Amazon Titan format: outputText, completionReason
|
|
347
|
+
const titanFinishReason = response["completionReason"];
|
|
348
|
+
const finishReason = novaFinishReason !== null && novaFinishReason !== void 0 ? novaFinishReason : titanFinishReason;
|
|
349
|
+
return Object.assign(Object.assign({}, (finishReason != null
|
|
350
|
+
? {
|
|
351
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
352
|
+
(_j = bedrockFinishReasonMap[finishReason]) !== null && _j !== void 0 ? _j : finishReason,
|
|
353
|
+
],
|
|
354
|
+
}
|
|
355
|
+
: {})), (response["inputTextTokenCount"] != null
|
|
356
|
+
? {
|
|
357
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: response["inputTextTokenCount"],
|
|
358
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: response["totalOutputTextTokenCount"],
|
|
359
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: response["inputTextTokenCount"] +
|
|
360
|
+
response["totalOutputTextTokenCount"],
|
|
361
|
+
}
|
|
362
|
+
: {}));
|
|
363
|
+
}
|
|
364
|
+
// Amazon Titan token fields
|
|
365
|
+
const titanInputTokens = response["inputTextTokenCount"];
|
|
366
|
+
const titanOutputTokens = (_l = (_k = response["results"]) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l["tokenCount"];
|
|
367
|
+
// Amazon Nova token fields
|
|
368
|
+
const novaUsage = response["usage"];
|
|
369
|
+
const amazonFinishReason = (_p = (_o = (_m = response["results"]) === null || _m === void 0 ? void 0 : _m[0]) === null || _o === void 0 ? void 0 : _o["completionReason"]) !== null && _p !== void 0 ? _p : response["stopReason"];
|
|
370
|
+
const novaRawContent = (_r = (_q = response["output"]) === null || _q === void 0 ? void 0 : _q["message"]) === null || _r === void 0 ? void 0 : _r["content"];
|
|
371
|
+
const titanContent = (_t = (_s = response["results"]) === null || _s === void 0 ? void 0 : _s[0]) === null || _t === void 0 ? void 0 : _t["outputText"];
|
|
372
|
+
const outputContent = (_u = novaRawContent !== null && novaRawContent !== void 0 ? novaRawContent : titanContent) !== null && _u !== void 0 ? _u : "";
|
|
373
|
+
const operationType = novaRawContent
|
|
374
|
+
? GEN_AI_OPERATION_NAME_VALUE_CHAT
|
|
375
|
+
: GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION;
|
|
376
|
+
return Object.assign(Object.assign(Object.assign({}, (amazonFinishReason != null
|
|
264
377
|
? {
|
|
265
|
-
[
|
|
266
|
-
|
|
267
|
-
|
|
378
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
379
|
+
(_v = bedrockFinishReasonMap[amazonFinishReason]) !== null && _v !== void 0 ? _v : amazonFinishReason,
|
|
380
|
+
],
|
|
381
|
+
}
|
|
382
|
+
: {})), (titanInputTokens != null
|
|
383
|
+
? {
|
|
384
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: titanInputTokens,
|
|
385
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: titanOutputTokens,
|
|
386
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: titanInputTokens + titanOutputTokens,
|
|
387
|
+
}
|
|
388
|
+
: novaUsage != null
|
|
389
|
+
? {
|
|
390
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: novaUsage["inputTokens"],
|
|
391
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: novaUsage["outputTokens"],
|
|
392
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: novaUsage["totalTokens"],
|
|
393
|
+
}
|
|
394
|
+
: {})), (this._shouldSendPrompts()
|
|
395
|
+
? {
|
|
396
|
+
[ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(outputContent, amazonFinishReason, bedrockFinishReasonMap, operationType, mapBedrockContentBlock),
|
|
268
397
|
}
|
|
269
398
|
: {}));
|
|
270
399
|
}
|
|
271
|
-
case
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
400
|
+
case BedrockVendor.ANTHROPIC: {
|
|
401
|
+
if (isStream) {
|
|
402
|
+
// New messages API streaming: content_block_delta has delta.text,
|
|
403
|
+
// message_delta has delta.stop_reason
|
|
404
|
+
const stopReason = (_x = (_w = response["delta"]) === null || _w === void 0 ? void 0 : _w["stop_reason"]) !== null && _x !== void 0 ? _x : response["stop_reason"];
|
|
405
|
+
const finishReason = stopReason !== null && stopReason !== void 0 ? stopReason : undefined;
|
|
406
|
+
return Object.assign({}, (finishReason != null
|
|
407
|
+
? {
|
|
408
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
409
|
+
(_y = bedrockFinishReasonMap[finishReason]) !== null && _y !== void 0 ? _y : finishReason,
|
|
410
|
+
],
|
|
411
|
+
}
|
|
412
|
+
: {}));
|
|
413
|
+
}
|
|
414
|
+
const stopReason = response["stop_reason"];
|
|
415
|
+
const usage = response["usage"];
|
|
416
|
+
const baseAttributes = Object.assign(Object.assign({}, (stopReason != null
|
|
417
|
+
? {
|
|
418
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
419
|
+
(_z = bedrockFinishReasonMap[stopReason]) !== null && _z !== void 0 ? _z : stopReason,
|
|
420
|
+
],
|
|
421
|
+
}
|
|
422
|
+
: {})), (usage
|
|
423
|
+
? {
|
|
424
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: usage["input_tokens"],
|
|
425
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: usage["output_tokens"],
|
|
426
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: (usage["input_tokens"] || 0) + (usage["output_tokens"] || 0),
|
|
427
|
+
}
|
|
428
|
+
: {}));
|
|
276
429
|
if (!this._shouldSendPrompts()) {
|
|
277
430
|
return baseAttributes;
|
|
278
431
|
}
|
|
279
432
|
// Handle new messages API format response
|
|
280
433
|
if (response["content"]) {
|
|
281
434
|
const content = Array.isArray(response["content"])
|
|
282
|
-
? response["content"]
|
|
435
|
+
? response["content"]
|
|
283
436
|
: response["content"];
|
|
284
|
-
return Object.assign(Object.assign({}, baseAttributes), { [
|
|
437
|
+
return Object.assign(Object.assign({}, baseAttributes), { [ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(content, stopReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_CHAT, mapBedrockContentBlock) });
|
|
285
438
|
}
|
|
286
439
|
// Handle legacy completion format
|
|
287
440
|
if (response["completion"]) {
|
|
288
|
-
return Object.assign(Object.assign({}, baseAttributes), { [
|
|
441
|
+
return Object.assign(Object.assign({}, baseAttributes), { [ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(response["completion"], stopReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, mapBedrockContentBlock) });
|
|
289
442
|
}
|
|
290
443
|
return baseAttributes;
|
|
291
444
|
}
|
|
292
|
-
case
|
|
293
|
-
const
|
|
445
|
+
case BedrockVendor.COHERE: {
|
|
446
|
+
const cohereFinishReason = (_2 = (_1 = (_0 = response["generations"]) === null || _0 === void 0 ? void 0 : _0[0]) === null || _1 === void 0 ? void 0 : _1["finish_reason"]) !== null && _2 !== void 0 ? _2 : response["finish_reason"];
|
|
447
|
+
const cohereText = (_5 = (_4 = (_3 = response["generations"]) === null || _3 === void 0 ? void 0 : _3[0]) === null || _4 === void 0 ? void 0 : _4["text"]) !== null && _5 !== void 0 ? _5 : response["text"];
|
|
448
|
+
return Object.assign(Object.assign(Object.assign({}, (cohereFinishReason != null
|
|
294
449
|
? {
|
|
295
|
-
[
|
|
450
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
451
|
+
(_6 = bedrockFinishReasonMap[cohereFinishReason]) !== null && _6 !== void 0 ? _6 : cohereFinishReason,
|
|
452
|
+
],
|
|
453
|
+
}
|
|
454
|
+
: {})), (((_7 = response["meta"]) === null || _7 === void 0 ? void 0 : _7["billed_units"])
|
|
455
|
+
? {
|
|
456
|
+
[ATTR_GEN_AI_USAGE_INPUT_TOKENS]: response["meta"]["billed_units"]["input_tokens"],
|
|
457
|
+
[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: response["meta"]["billed_units"]["output_tokens"],
|
|
458
|
+
[SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: (response["meta"]["billed_units"]["input_tokens"] || 0) +
|
|
459
|
+
(response["meta"]["billed_units"]["output_tokens"] || 0),
|
|
460
|
+
}
|
|
461
|
+
: {})), (this._shouldSendPrompts() && cohereText != null
|
|
462
|
+
? {
|
|
463
|
+
[ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(cohereText, cohereFinishReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, mapBedrockContentBlock),
|
|
296
464
|
}
|
|
297
465
|
: {}));
|
|
298
|
-
// Add token usage if available
|
|
299
|
-
if (response["meta"] && response["meta"]["billed_units"]) {
|
|
300
|
-
const billedUnits = response["meta"]["billed_units"];
|
|
301
|
-
return Object.assign(Object.assign({}, baseAttributes), { [ATTR_GEN_AI_USAGE_PROMPT_TOKENS]: billedUnits["input_tokens"], [ATTR_GEN_AI_USAGE_COMPLETION_TOKENS]: billedUnits["output_tokens"], [SpanAttributes.LLM_USAGE_TOTAL_TOKENS]: (billedUnits["input_tokens"] || 0) +
|
|
302
|
-
(billedUnits["output_tokens"] || 0) });
|
|
303
|
-
}
|
|
304
|
-
return baseAttributes;
|
|
305
466
|
}
|
|
306
|
-
case
|
|
307
|
-
|
|
467
|
+
case BedrockVendor.META: {
|
|
468
|
+
const metaFinishReason = response["stop_reason"];
|
|
469
|
+
const metaContent = response["generation"];
|
|
470
|
+
return Object.assign(Object.assign(Object.assign({}, (metaFinishReason != null
|
|
471
|
+
? {
|
|
472
|
+
[ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [
|
|
473
|
+
(_8 = bedrockFinishReasonMap[metaFinishReason]) !== null && _8 !== void 0 ? _8 : metaFinishReason,
|
|
474
|
+
],
|
|
475
|
+
}
|
|
476
|
+
: {})), { [ATTR_GEN_AI_USAGE_INPUT_TOKENS]: response["prompt_token_count"], [ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: response["generation_token_count"], [SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS]: response["prompt_token_count"] + response["generation_token_count"] }), (this._shouldSendPrompts()
|
|
308
477
|
? {
|
|
309
|
-
[
|
|
478
|
+
[ATTR_GEN_AI_OUTPUT_MESSAGES]: formatOutputMessage(metaContent !== null && metaContent !== void 0 ? metaContent : "", metaFinishReason, bedrockFinishReasonMap, GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION, mapBedrockContentBlock),
|
|
310
479
|
}
|
|
311
480
|
: {}));
|
|
312
481
|
}
|
|
@@ -314,6 +483,15 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
314
483
|
return {};
|
|
315
484
|
}
|
|
316
485
|
}
|
|
486
|
+
_handleNovaStreamingMetadata(span, parsedResponse) {
|
|
487
|
+
var _a;
|
|
488
|
+
if ("metadata" in parsedResponse && ((_a = parsedResponse["metadata"]) === null || _a === void 0 ? void 0 : _a["usage"])) {
|
|
489
|
+
const usage = parsedResponse["metadata"]["usage"];
|
|
490
|
+
span.setAttribute(ATTR_GEN_AI_USAGE_INPUT_TOKENS, usage["inputTokens"]);
|
|
491
|
+
span.setAttribute(ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, usage["outputTokens"]);
|
|
492
|
+
span.setAttribute(SpanAttributes.GEN_AI_USAGE_TOTAL_TOKENS, usage["totalTokens"]);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
317
495
|
_shouldSendPrompts() {
|
|
318
496
|
const contextShouldSendPrompts = context
|
|
319
497
|
.active()
|
|
@@ -325,17 +503,62 @@ class BedrockInstrumentation extends InstrumentationBase {
|
|
|
325
503
|
? this._config.traceContent
|
|
326
504
|
: true;
|
|
327
505
|
}
|
|
506
|
+
_getOperationType(vendor, requestBody) {
|
|
507
|
+
switch (vendor) {
|
|
508
|
+
case BedrockVendor.AI21:
|
|
509
|
+
case BedrockVendor.AMAZON:
|
|
510
|
+
case BedrockVendor.ANTHROPIC:
|
|
511
|
+
return requestBody["messages"]
|
|
512
|
+
? GEN_AI_OPERATION_NAME_VALUE_CHAT
|
|
513
|
+
: GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION;
|
|
514
|
+
case BedrockVendor.COHERE:
|
|
515
|
+
case BedrockVendor.META:
|
|
516
|
+
return GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION;
|
|
517
|
+
default:
|
|
518
|
+
return GEN_AI_OPERATION_NAME_VALUE_TEXT_COMPLETION;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
_getStreamChunkContent(vendor, response) {
|
|
522
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
523
|
+
switch (vendor) {
|
|
524
|
+
case BedrockVendor.AMAZON:
|
|
525
|
+
return ((_c = (_b = (_a = response["contentBlockDelta"]) === null || _a === void 0 ? void 0 : _a["delta"]) === null || _b === void 0 ? void 0 : _b["text"]) !== null && _c !== void 0 ? _c : response["outputText"]);
|
|
526
|
+
case BedrockVendor.ANTHROPIC:
|
|
527
|
+
return (_e = (_d = response["delta"]) === null || _d === void 0 ? void 0 : _d["text"]) !== null && _e !== void 0 ? _e : response["completion"];
|
|
528
|
+
case BedrockVendor.AI21:
|
|
529
|
+
return (_h = (_g = (_f = response["choices"]) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g["delta"]) === null || _h === void 0 ? void 0 : _h["content"];
|
|
530
|
+
case BedrockVendor.META:
|
|
531
|
+
return response["generation"];
|
|
532
|
+
default:
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
328
536
|
_extractVendorAndModel(modelId) {
|
|
329
537
|
if (!modelId) {
|
|
330
538
|
return { modelVendor: "", model: "" };
|
|
331
539
|
}
|
|
332
|
-
|
|
540
|
+
// Handle cross-region inference profile IDs like "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
|
|
541
|
+
// Mirrors Python's _cross_region_check logic.
|
|
542
|
+
const prefixes = ["us", "us-gov", "eu", "apac"];
|
|
543
|
+
const hasCrossRegionPrefix = prefixes.some((prefix) => modelId.startsWith(prefix + "."));
|
|
544
|
+
if (hasCrossRegionPrefix) {
|
|
545
|
+
const parts = modelId.split(".");
|
|
546
|
+
if (parts.length > 2) {
|
|
547
|
+
parts.shift(); // remove region prefix ("us", "eu", etc.)
|
|
548
|
+
}
|
|
549
|
+
return { modelVendor: parts[0] || "", model: parts[1] || "" };
|
|
550
|
+
}
|
|
551
|
+
// Standard format: "vendor.model-name"
|
|
552
|
+
const dotIndex = modelId.indexOf(".");
|
|
553
|
+
if (dotIndex === -1) {
|
|
554
|
+
return { modelVendor: modelId, model: "" };
|
|
555
|
+
}
|
|
333
556
|
return {
|
|
334
|
-
modelVendor:
|
|
335
|
-
model:
|
|
557
|
+
modelVendor: modelId.slice(0, dotIndex),
|
|
558
|
+
model: modelId.slice(dotIndex + 1),
|
|
336
559
|
};
|
|
337
560
|
}
|
|
338
561
|
}
|
|
339
562
|
|
|
340
|
-
export { BedrockInstrumentation };
|
|
563
|
+
export { BedrockInstrumentation, BedrockVendor, bedrockFinishReasonMap };
|
|
341
564
|
//# sourceMappingURL=index.mjs.map
|