@telemetry-dev/bedrock 0.1.3 → 0.1.5

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/src/converse.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  } from "./internal.ts";
18
18
 
19
19
  export type MessagePart = object;
20
+
20
21
  export interface NormalizedMessage {
21
22
  role: string | undefined;
22
23
  parts: MessagePart[];
@@ -26,6 +27,7 @@ export interface NormalizedMessage {
26
27
  export function converseRequestFields(input: JsonRecord): SpanFields {
27
28
  const inference = isRecord(input.inferenceConfig) ? input.inferenceConfig : {};
28
29
  const guardrail = isRecord(input.guardrailConfig) ? input.guardrailConfig : undefined;
30
+
29
31
  return omitUndefined({
30
32
  provider: PROVIDER,
31
33
  model: stringValue(input.modelId),
@@ -53,6 +55,7 @@ export function converseResponseFields<T>(output: T): SpanFields {
53
55
  const guardrail = isRecord(trace?.guardrail) ? trace?.guardrail : undefined;
54
56
  const stopReason = stringValue(result.stopReason);
55
57
  const message = isRecord(result.output) ? result.output.message : undefined;
58
+
56
59
  return mergeFields(awsMetadataFields(result.$metadata), {
57
60
  output: normalizeOutputMessage(message, stopReason),
58
61
  usage,
@@ -68,6 +71,7 @@ export function converseResponseFields<T>(output: T): SpanFields {
68
71
 
69
72
  export function usageFromConverse<T>(value: T): SpanFields["usage"] | undefined {
70
73
  if (!isRecord(value)) return undefined;
74
+
71
75
  return omitUndefined({
72
76
  inputTokens: numberValue(value.inputTokens),
73
77
  outputTokens: numberValue(value.outputTokens),
@@ -79,7 +83,9 @@ export function usageFromConverse<T>(value: T): SpanFields["usage"] | undefined
79
83
 
80
84
  export function normalizeMessages<T>(value: T): NormalizedMessage[] | undefined {
81
85
  const messages = arrayValue<JsonRecord>(value);
86
+
82
87
  if (!messages) return undefined;
88
+
83
89
  return messages.map((message) => ({
84
90
  role: stringValue(message.role),
85
91
  parts: normalizeContentList(message.content),
@@ -91,29 +97,36 @@ export function normalizeOutputMessage<T>(
91
97
  finishReason?: string,
92
98
  ): NormalizedMessage[] | undefined {
93
99
  if (!isRecord(value)) return undefined;
100
+
94
101
  const message = omitUndefined({
95
102
  role: stringValue(value.role),
96
103
  parts: normalizeContentList(value.content),
97
104
  finish_reason: finishReason,
98
105
  });
106
+
99
107
  return [message];
100
108
  }
101
109
 
102
110
  export function normalizeSystem<T>(value: T): MessagePart[] | undefined {
103
111
  const blocks = arrayValue<JsonRecord>(value);
112
+
104
113
  if (!blocks) return undefined;
105
114
  const parts = blocks.flatMap((block) => normalizeContentBlock(block));
115
+
106
116
  return parts.length > 0 ? parts : undefined;
107
117
  }
108
118
 
109
119
  function normalizeContentList<T>(value: T): MessagePart[] {
110
120
  const blocks = arrayValue<JsonRecord>(value);
121
+
111
122
  if (!blocks) return [];
123
+
112
124
  return blocks.flatMap((block) => normalizeContentBlock(block));
113
125
  }
114
126
 
115
127
  function normalizeContentBlock(block: JsonRecord): MessagePart[] {
116
128
  const text = stringValue(block.text);
129
+
117
130
  if (text !== undefined)
118
131
  return [
119
132
  omitUndefined({
@@ -124,6 +137,7 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
124
137
  ];
125
138
 
126
139
  const toolUse = isRecord(block.toolUse) ? block.toolUse : undefined;
140
+
127
141
  if (toolUse) {
128
142
  return [
129
143
  omitUndefined({
@@ -136,6 +150,7 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
136
150
  }
137
151
 
138
152
  const toolResult = isRecord(block.toolResult) ? block.toolResult : undefined;
153
+
139
154
  if (toolResult) {
140
155
  return [
141
156
  omitUndefined({
@@ -147,8 +162,10 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
147
162
  }
148
163
 
149
164
  const reasoning = isRecord(block.reasoningContent) ? block.reasoningContent : undefined;
165
+
150
166
  if (reasoning) {
151
167
  const reasoningText = isRecord(reasoning.reasoningText) ? reasoning.reasoningText : undefined;
168
+
152
169
  return [
153
170
  {
154
171
  type: "reasoning",
@@ -160,9 +177,11 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
160
177
 
161
178
  for (const modality of ["image", "document", "video", "audio"] as const) {
162
179
  const media = isRecord(block[modality]) ? block[modality] : undefined;
180
+
163
181
  if (!media) continue;
164
182
  const format = stringValue(media.format);
165
183
  const source = isRecord(media.source) ? media.source : undefined;
184
+
166
185
  if (source?.bytes !== undefined) {
167
186
  return [
168
187
  omitUndefined({
@@ -172,25 +191,32 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
172
191
  }),
173
192
  ];
174
193
  }
194
+
175
195
  const s3 = isRecord(source?.s3Location) ? source?.s3Location : undefined;
176
196
  const uri = stringValue(source?.uri) ?? stringValue(s3?.uri) ?? s3Uri(s3);
197
+
177
198
  if (uri) return [omitUndefined({ type: "uri", uri, modality, mime_type: format })];
178
199
  }
179
200
 
180
201
  const citationsContent = isRecord(block.citationsContent) ? block.citationsContent : undefined;
202
+
181
203
  if (citationsContent) {
182
204
  const contentBlocks = arrayValue<JsonRecord>(citationsContent.content) ?? [];
183
205
  const citations = arrayValue<JsonValue>(citationsContent.citations);
206
+
184
207
  return contentBlocks.flatMap((contentBlock) => {
185
208
  if (!citations) return normalizeContentBlock(contentBlock);
209
+
186
210
  return normalizeContentBlock({ ...contentBlock, citations });
187
211
  });
188
212
  }
189
213
 
190
214
  const guardContent = isRecord(block.guardContent) ? block.guardContent : undefined;
215
+
191
216
  if (guardContent) {
192
217
  const guardText = isRecord(guardContent.text) ? guardContent.text : undefined;
193
218
  const content = stringValue(guardText?.text) ?? stringValue(guardContent.text);
219
+
194
220
  if (content) return [{ type: "text", content }];
195
221
  }
196
222
 
@@ -203,15 +229,19 @@ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
203
229
 
204
230
  function simplifyToolResult<T>(content: T): JsonValue {
205
231
  const blocks = arrayValue<JsonRecord>(content);
232
+
206
233
  if (!blocks) return isJsonValue(content) ? content : undefined;
207
234
  const text = stringValue(blocks[0]?.text);
235
+
208
236
  if (blocks.length === 1 && text !== undefined) return text;
237
+
209
238
  return blocks.flatMap((block) => normalizeContentBlock(block)) as JsonValue[];
210
239
  }
211
240
 
212
241
  function s3Uri(value: JsonRecord | undefined): string | undefined {
213
242
  const bucket = stringValue(value?.bucket);
214
243
  const key = stringValue(value?.key);
244
+
215
245
  return bucket && key ? `s3://${bucket}/${key}` : undefined;
216
246
  }
217
247
 
@@ -238,15 +268,20 @@ export class ConverseStreamState implements StreamState {
238
268
  feed<T>(event: T): void {
239
269
  if (!isRecord(event)) return;
240
270
  const streamError = modeledStreamError(event);
271
+
241
272
  if (streamError) {
242
273
  this.error = streamError.error;
243
274
  this.errorFields = streamError.fields;
275
+
244
276
  return;
245
277
  }
278
+
246
279
  const messageStart = isRecord(event.messageStart) ? event.messageStart : undefined;
280
+
247
281
  if (messageStart) this.role = stringValue(messageStart.role) ?? this.role;
248
282
 
249
283
  const blockStart = isRecord(event.contentBlockStart) ? event.contentBlockStart : undefined;
284
+
250
285
  if (blockStart) {
251
286
  const index = numberValue(blockStart.contentBlockIndex) ?? this.blocks.size;
252
287
  const start = isRecord(blockStart.start) ? blockStart.start : undefined;
@@ -280,34 +315,44 @@ export class ConverseStreamState implements StreamState {
280
315
  }
281
316
 
282
317
  const deltaEvent = isRecord(event.contentBlockDelta) ? event.contentBlockDelta : undefined;
318
+
283
319
  if (deltaEvent) {
284
320
  const index = numberValue(deltaEvent.contentBlockIndex) ?? 0;
285
321
  const delta = isRecord(deltaEvent.delta) ? deltaEvent.delta : {};
286
322
  const block = this.blocks.get(index) ?? { kind: "text", text: "" };
287
323
  const text = stringValue(delta.text);
324
+
288
325
  if (text !== undefined) {
289
326
  block.kind = "text";
290
327
  block.text = `${block.text ?? ""}${text}`;
291
328
  }
329
+
292
330
  const toolUse = isRecord(delta.toolUse) ? delta.toolUse : undefined;
293
331
  const input = stringValue(toolUse?.input);
332
+
294
333
  if (toolUse && input !== undefined) {
295
334
  block.kind = "tool";
296
335
  block.input = `${block.input ?? ""}${input}`;
297
336
  }
337
+
298
338
  const reasoning = isRecord(delta.reasoningContent) ? delta.reasoningContent : undefined;
339
+
299
340
  if (reasoning) {
300
341
  block.kind = "reasoning";
301
342
  block.text = `${block.text ?? ""}${stringValue(reasoning.text) ?? (reasoning.redactedContent ? "[redacted]" : "")}`;
302
343
  }
344
+
303
345
  const image = isRecord(delta.image) ? delta.image : undefined;
346
+
304
347
  if (image) {
305
348
  const content = isRecord(block.content) ? block.content : {};
306
349
  const current: JsonRecord = isRecord(content.image) ? content.image : {};
307
350
  block.kind = "content";
308
351
  block.content = { image: { ...current, ...image } };
309
352
  }
353
+
310
354
  const toolResult = arrayValue<JsonRecord>(delta.toolResult);
355
+
311
356
  if (toolResult) {
312
357
  const content = isRecord(block.content) ? block.content : {};
313
358
  const current: JsonRecord = isRecord(content.toolResult) ? content.toolResult : {};
@@ -320,16 +365,20 @@ export class ConverseStreamState implements StreamState {
320
365
  },
321
366
  };
322
367
  }
368
+
323
369
  if (isRecord(delta.citation)) {
324
370
  block.citations = [...(block.citations ?? []), delta.citation];
325
371
  }
372
+
326
373
  this.blocks.set(index, block);
327
374
  }
328
375
 
329
376
  const stop = isRecord(event.messageStop) ? event.messageStop : undefined;
377
+
330
378
  if (stop) this.stopReason = stringValue(stop.stopReason) ?? this.stopReason;
331
379
 
332
380
  const metadata = isRecord(event.metadata) ? event.metadata : undefined;
381
+
333
382
  if (metadata) {
334
383
  this.usage = usageFromConverse(metadata.usage) ?? this.usage;
335
384
  const metrics = isRecord(metadata.metrics) ? metadata.metrics : undefined;
@@ -352,6 +401,7 @@ export class ConverseStreamState implements StreamState {
352
401
  const parts = [...this.blocks.entries()]
353
402
  .sort(([left], [right]) => left - right)
354
403
  .map(([, block]) => blockToPart(block));
404
+
355
405
  return mergeFields(
356
406
  omitUndefined({
357
407
  output:
@@ -395,9 +445,12 @@ function blockToPart(block: StreamBlock) {
395
445
  arguments: parseJson(block.input) ?? block.input ?? "",
396
446
  });
397
447
  }
448
+
398
449
  if (block.kind === "reasoning") return { type: "reasoning", content: block.text ?? "" };
450
+
399
451
  if (block.kind === "content" && block.content)
400
452
  return normalizeContentBlock(block.content)[0] ?? {};
453
+
401
454
  return omitUndefined({
402
455
  type: "text",
403
456
  content: block.text ?? "",
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ export function wrapBedrock<T extends WrappableBedrockClient>(
28
28
  writable: true,
29
29
  });
30
30
  WRAPPED.add(client as object);
31
+
31
32
  return client;
32
33
  }
33
34
 
@@ -37,13 +38,16 @@ export function instrumentBedrock(options: BedrockInstrumentationOptions = {}):
37
38
  const hadOwn = Object.prototype.hasOwnProperty.call(proto, "send");
38
39
  const original = proto.send;
39
40
  const instrumentedSend = createInstrumentedSend(original, options, RUNTIME_HANDLERS);
41
+
40
42
  const wrapper = function telemetryDevBedrockSend(
41
43
  this: WrappableBedrockClient,
42
44
  ...args: unknown[]
43
45
  ) {
44
46
  if (WRAPPED.has(this as object)) return original.apply(this, args);
47
+
45
48
  return instrumentedSend.apply(this, args);
46
49
  };
50
+
47
51
  ORIGINAL = { proto, hadOwn, value: original, wrapper };
48
52
  Object.defineProperty(proto, "send", {
49
53
  configurable: true,
@@ -54,9 +58,12 @@ export function instrumentBedrock(options: BedrockInstrumentationOptions = {}):
54
58
 
55
59
  export function uninstrumentBedrock(): void {
56
60
  const original = ORIGINAL;
61
+
57
62
  if (!original) return;
63
+
58
64
  if (Object.getOwnPropertyDescriptor(original.proto, "send")?.value !== original.wrapper) return;
59
65
  ORIGINAL = undefined;
66
+
60
67
  if (original.hadOwn) {
61
68
  Object.defineProperty(original.proto, "send", {
62
69
  configurable: true,
@@ -39,6 +39,7 @@ export const RUNTIME_HANDLERS = {
39
39
  requestFields: converseRequestFields,
40
40
  onResult(result, span) {
41
41
  endSpan(span, converseResponseFields(result));
42
+
42
43
  return result;
43
44
  },
44
45
  },
@@ -48,10 +49,13 @@ export const RUNTIME_HANDLERS = {
48
49
  requestFields: converseRequestFields,
49
50
  onResult(result, span, t0) {
50
51
  const response = result as { stream?: unknown; $metadata?: unknown };
52
+
51
53
  if (!response.stream) {
52
54
  endSpan(span, awsMetadataFields(response.$metadata));
55
+
53
56
  return result;
54
57
  }
58
+
55
59
  return {
56
60
  ...response,
57
61
  stream: wrapAsyncIterable(
@@ -70,6 +74,7 @@ export const RUNTIME_HANDLERS = {
70
74
  requestFields: invokeModelRequestFields,
71
75
  onResult(result, span, _t0, input) {
72
76
  endSpan(span, invokeModelResponseFields(input, result));
77
+
73
78
  return result;
74
79
  },
75
80
  },
@@ -79,10 +84,13 @@ export const RUNTIME_HANDLERS = {
79
84
  requestFields: invokeModelRequestFields,
80
85
  onResult(result, span, t0) {
81
86
  const response = result as { body?: unknown; $metadata?: unknown };
87
+
82
88
  if (!response.body) {
83
89
  endSpan(span, awsMetadataFields(response.$metadata));
90
+
84
91
  return result;
85
92
  }
93
+
86
94
  return {
87
95
  ...response,
88
96
  body: wrapAsyncIterable(
@@ -119,6 +127,7 @@ export const RUNTIME_HANDLERS = {
119
127
  }),
120
128
  }),
121
129
  );
130
+
122
131
  return result;
123
132
  },
124
133
  },
@@ -143,6 +152,7 @@ export const AGENT_HANDLERS = {
143
152
  requestFields: retrieveRequestFields,
144
153
  onResult(result, span) {
145
154
  endSpan(span, retrieveResponseFields(result));
155
+
146
156
  return result;
147
157
  },
148
158
  },
@@ -152,6 +162,7 @@ export const AGENT_HANDLERS = {
152
162
  requestFields: ragRequestFields,
153
163
  onResult(result, span) {
154
164
  endSpan(span, ragResponseFields(result));
165
+
155
166
  return result;
156
167
  },
157
168
  },
@@ -161,16 +172,20 @@ export const AGENT_HANDLERS = {
161
172
  requestFields: ragRequestFields,
162
173
  onResult(result, span, t0) {
163
174
  const response = result as { stream?: unknown; $metadata?: unknown; sessionId?: string };
175
+
164
176
  const base = mergeFields(awsMetadataFields(response.$metadata), {
165
177
  metadata: omitUndefined({ bedrock_session_id: stringValue(response.sessionId) }),
166
178
  });
179
+
167
180
  if (!response.stream) {
168
181
  endSpan(span, base);
182
+
169
183
  return result;
170
184
  }
185
+
171
186
  return {
172
187
  ...response,
173
- stream: wrapAsyncIterable(response.stream, new RagStreamState(), span, t0, base),
188
+ stream: wrapAsyncIterable(response.stream, new RagStreamState(), span, t0, base, false),
174
189
  };
175
190
  },
176
191
  },
@@ -180,10 +195,13 @@ export const AGENT_HANDLERS = {
180
195
  requestFields: flowRequestFields,
181
196
  onResult(result, span, t0) {
182
197
  const response = result as { responseStream?: unknown; $metadata?: unknown };
198
+
183
199
  if (!response.responseStream) {
184
200
  endSpan(span, awsMetadataFields(response.$metadata));
201
+
185
202
  return result;
186
203
  }
204
+
187
205
  return {
188
206
  ...response,
189
207
  responseStream: wrapAsyncIterable(
@@ -192,6 +210,7 @@ export const AGENT_HANDLERS = {
192
210
  span,
193
211
  t0,
194
212
  awsMetadataFields(response.$metadata),
213
+ false,
195
214
  ),
196
215
  };
197
216
  },
@@ -212,19 +231,23 @@ function streamAgentResult(key: "completion") {
212
231
  sessionId?: string;
213
232
  memoryId?: string;
214
233
  };
234
+
215
235
  const base = mergeFields(awsMetadataFields(response.$metadata), {
216
236
  metadata: omitUndefined({
217
237
  bedrock_session_id: stringValue(response.sessionId),
218
238
  bedrock_memory_id: stringValue(response.memoryId),
219
239
  }),
220
240
  });
241
+
221
242
  if (!response[key]) {
222
243
  endSpan(span, base);
244
+
223
245
  return result;
224
246
  }
247
+
225
248
  return {
226
249
  ...response,
227
- [key]: wrapAsyncIterable(response[key], new AgentStreamState(options), span, t0, base),
250
+ [key]: wrapAsyncIterable(response[key], new AgentStreamState(options), span, t0, base, false),
228
251
  };
229
252
  };
230
253
  }