@telemetry-dev/bedrock 0.1.6 → 0.1.8

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/README.md CHANGED
@@ -13,6 +13,7 @@ This package instruments AWS SDK for JavaScript v3 clients for:
13
13
  - `@aws-sdk/client-bedrock-agent-runtime`
14
14
  - `InvokeAgent`
15
15
  - `InvokeInlineAgent`
16
+ - `Rerank`
16
17
  - `Retrieve`
17
18
  - `RetrieveAndGenerate`
18
19
  - `RetrieveAndGenerateStream`
@@ -113,6 +114,7 @@ All instrumented AWS responses/errors include `gen_ai.response.id` from the AWS
113
114
  | `InvokeModelWithResponseStream` | `generation` or `embedding` | `chat {modelId}` / `embeddings {modelId}` | provider-native chunk text where known, optional final `amazon-bedrock-invocationMetrics` usage |
114
115
  | `ApplyGuardrail` | `span` | `apply_guardrail {guardrailIdentifier}` | guardrail input/output, action, action reason, request id |
115
116
  | `InvokeAgent` / `InvokeInlineAgent` | `agent` | `invoke_agent {agentId}` / `invoke_agent {agentName}` | user input, streamed answer, session/memory ids, alias id, trace usage aggregation, trace event count, return-control output |
117
+ | `Rerank` | `span` (`rerank` operation) | `rerank {modelArn basename}` | queries, inline sources, model request fields, ranked results and scores, result counts, pagination metadata, request id |
116
118
  | `Retrieve` | `span` | `retrieve {knowledgeBaseId}` | query, retrieval results, guardrail action, result count metadata |
117
119
  | `RetrieveAndGenerate` / stream | `generation` | `retrieve_and_generate {modelArn basename}` | input text, generated text, citations count, session id, guardrail action |
118
120
  | `InvokeFlow` | `agent` | `invoke_flow {flowIdentifier}` | inputs, flow output events, completion reason |
@@ -149,7 +151,6 @@ The following calls pass through unless a supported operation above is used:
149
151
  - `InvokeModelWithBidirectionalStream`
150
152
  - `StartAsyncInvoke`, `GetAsyncInvoke`, `ListAsyncInvokes`
151
153
  - Agent Runtime session CRUD
152
- - `Rerank`
153
154
  - `GenerateQuery`
154
155
  - `OptimizePrompt`
155
156
  - `AgenticRetrieveStream`
package/dist/agents.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as createInstrumentedSend, t as AGENT_HANDLERS } from "./internal-handlers-B47qvHGh.mjs";
1
+ import { r as createInstrumentedSend, t as AGENT_HANDLERS } from "./internal-handlers-Byxp14OZ.mjs";
2
2
  import { BedrockAgentRuntimeClient } from "@aws-sdk/client-bedrock-agent-runtime";
3
3
  //#region src/agents.ts
4
4
  const WRAPPED = /* @__PURE__ */ new WeakSet();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as RUNTIME_HANDLERS, r as createInstrumentedSend } from "./internal-handlers-B47qvHGh.mjs";
1
+ import { n as RUNTIME_HANDLERS, r as createInstrumentedSend } from "./internal-handlers-Byxp14OZ.mjs";
2
2
  import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime";
3
3
  //#region src/index.ts
4
4
  const WRAPPED = /* @__PURE__ */ new WeakSet();
@@ -1,4 +1,4 @@
1
- import { startSpan } from "@telemetry-dev/sdk";
1
+ import { boundedCapture, captureEnabled, startSpan } from "@telemetry-dev/sdk";
2
2
  //#region src/internal.ts
3
3
  const PROVIDER = "amazon-bedrock";
4
4
  const STREAM_FINALIZER = typeof FinalizationRegistry === "function" ? new FinalizationRegistry((finish) => finish()) : void 0;
@@ -89,9 +89,23 @@ function safe(fn) {
89
89
  return;
90
90
  }
91
91
  }
92
+ function withCacheInclusiveInput(fields) {
93
+ const usage = fields?.usage;
94
+ if (usage?.inputTokens === void 0) return fields;
95
+ const inputTokens = usage.inputTokens + (usage.cacheReadInputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0);
96
+ const totalTokens = usage.totalTokens !== void 0 && usage.outputTokens !== void 0 ? inputTokens + usage.outputTokens : usage.totalTokens;
97
+ return {
98
+ ...fields,
99
+ usage: {
100
+ ...usage,
101
+ inputTokens,
102
+ totalTokens
103
+ }
104
+ };
105
+ }
92
106
  function endSpan(span, fields) {
93
107
  try {
94
- span.end(fields);
108
+ span.end(withCacheInclusiveInput(fields));
95
109
  } catch {}
96
110
  }
97
111
  function updateSpan(span, fields) {
@@ -431,6 +445,53 @@ function retrieveResponseFields(output) {
431
445
  })
432
446
  });
433
447
  }
448
+ function rerankConfiguration(input) {
449
+ const configuration = isRecord(input.rerankingConfiguration) ? input.rerankingConfiguration : void 0;
450
+ const bedrock = isRecord(configuration?.bedrockRerankingConfiguration) ? configuration.bedrockRerankingConfiguration : void 0;
451
+ return {
452
+ bedrock,
453
+ model: isRecord(bedrock?.modelConfiguration) ? bedrock.modelConfiguration : void 0
454
+ };
455
+ }
456
+ function rerankModel(input) {
457
+ return stringValue(rerankConfiguration(input).model?.modelArn);
458
+ }
459
+ function rerankName(input) {
460
+ return `rerank ${rerankModel(input)?.split("/").at(-1) ?? "unknown"}`;
461
+ }
462
+ function rerankRequestFields(input) {
463
+ const { bedrock, model } = rerankConfiguration(input);
464
+ const capture = captureEnabled("input") ? boundedCapture(omitUndefined({
465
+ queries: input.queries,
466
+ sources: input.sources,
467
+ additionalModelRequestFields: model?.additionalModelRequestFields,
468
+ nextToken: input.nextToken
469
+ })) : void 0;
470
+ return omitUndefined({
471
+ provider: PROVIDER,
472
+ model: stringValue(model?.modelArn),
473
+ input: capture?.value,
474
+ attributes: {
475
+ "gen_ai.operation.name": "rerank",
476
+ ...capture?.truncated ? { "telemetry.dev.capture.truncated": true } : void 0
477
+ },
478
+ metadata: omitUndefined({ requested_result_count: numberValue(bedrock?.numberOfResults) })
479
+ });
480
+ }
481
+ function rerankResponseFields(output) {
482
+ const raw = output;
483
+ const result = isRecord(raw) ? raw : {};
484
+ const results = arrayValue(result.results);
485
+ const capture = captureEnabled("output") ? boundedCapture(results) : void 0;
486
+ return mergeFields(awsMetadataFields(result.$metadata), {
487
+ output: capture?.value,
488
+ attributes: capture?.truncated ? { "telemetry.dev.capture.truncated": true } : void 0,
489
+ metadata: omitUndefined({
490
+ result_count: results?.length,
491
+ has_next_token: stringValue(result.nextToken) ? true : void 0
492
+ })
493
+ });
494
+ }
434
495
  function ragModel(input) {
435
496
  const config = isRecord(input.retrieveAndGenerateConfiguration) ? input.retrieveAndGenerateConfiguration : void 0;
436
497
  const kb = isRecord(config?.knowledgeBaseConfiguration) ? config?.knowledgeBaseConfiguration : void 0;
@@ -1212,6 +1273,15 @@ const AGENT_HANDLERS = {
1212
1273
  requestFields: inlineAgentRequestFields,
1213
1274
  onResult: streamAgentResult("completion")
1214
1275
  },
1276
+ RerankCommand: {
1277
+ spanName: rerankName,
1278
+ spanType: () => "span",
1279
+ requestFields: rerankRequestFields,
1280
+ onResult(result, span) {
1281
+ endSpan(span, rerankResponseFields(result));
1282
+ return result;
1283
+ }
1284
+ },
1215
1285
  RetrieveCommand: {
1216
1286
  spanName: (input) => `retrieve ${stringValue(input.knowledgeBaseId) ?? "unknown"}`,
1217
1287
  spanType: () => "span",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telemetry-dev/bedrock",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "AWS Bedrock instrumentation for telemetry.dev: Converse, InvokeModel, and Bedrock Agents spans for AWS SDK v3 clients.",
5
5
  "keywords": [
6
6
  "aws",
@@ -49,7 +49,7 @@
49
49
  "@smithy/eventstream-codec": "^4.2.5",
50
50
  "@smithy/protocol-http": "^5.3.10",
51
51
  "@smithy/types": "^4.12.0",
52
- "@telemetry-dev/sdk": "^0.1.5",
52
+ "@telemetry-dev/sdk": "^0.1.6",
53
53
  "@types/node": "^25.5.0",
54
54
  "@typescript/native-preview": "7.0.0-dev.20260328.1",
55
55
  "typescript": "^6.0.2",
@@ -59,7 +59,7 @@
59
59
  "peerDependencies": {
60
60
  "@aws-sdk/client-bedrock-agent-runtime": ">=3.600.0 <4",
61
61
  "@aws-sdk/client-bedrock-runtime": ">=3.600.0 <4",
62
- "@telemetry-dev/sdk": "^0.1.5"
62
+ "@telemetry-dev/sdk": "^0.1.6"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "@aws-sdk/client-bedrock-agent-runtime": {
@@ -1,4 +1,4 @@
1
- import type { SpanFields } from "@telemetry-dev/sdk";
1
+ import { boundedCapture, captureEnabled, type SpanFields } from "@telemetry-dev/sdk";
2
2
 
3
3
  import {
4
4
  arrayValue,
@@ -191,6 +191,75 @@ export function retrieveResponseFields<T>(output: T): SpanFields {
191
191
  });
192
192
  }
193
193
 
194
+ function rerankConfiguration(input: JsonRecord) {
195
+ const configuration = isRecord(input.rerankingConfiguration)
196
+ ? input.rerankingConfiguration
197
+ : undefined;
198
+
199
+ const bedrock = isRecord(configuration?.bedrockRerankingConfiguration)
200
+ ? configuration.bedrockRerankingConfiguration
201
+ : undefined;
202
+
203
+ return {
204
+ bedrock,
205
+ model: isRecord(bedrock?.modelConfiguration) ? bedrock.modelConfiguration : undefined,
206
+ };
207
+ }
208
+
209
+ export function rerankModel(input: JsonRecord): string | undefined {
210
+ return stringValue(rerankConfiguration(input).model?.modelArn);
211
+ }
212
+
213
+ export function rerankName(input: JsonRecord): string {
214
+ const model = rerankModel(input);
215
+
216
+ return `rerank ${model?.split("/").at(-1) ?? "unknown"}`;
217
+ }
218
+
219
+ export function rerankRequestFields(input: JsonRecord): SpanFields {
220
+ const { bedrock, model } = rerankConfiguration(input);
221
+
222
+ const capture = captureEnabled("input")
223
+ ? boundedCapture(
224
+ omitUndefined({
225
+ queries: input.queries,
226
+ sources: input.sources,
227
+ additionalModelRequestFields: model?.additionalModelRequestFields,
228
+ nextToken: input.nextToken,
229
+ }),
230
+ )
231
+ : undefined;
232
+
233
+ return omitUndefined({
234
+ provider: PROVIDER,
235
+ model: stringValue(model?.modelArn),
236
+ input: capture?.value,
237
+ attributes: {
238
+ "gen_ai.operation.name": "rerank",
239
+ ...(capture?.truncated ? { "telemetry.dev.capture.truncated": true } : undefined),
240
+ },
241
+ metadata: omitUndefined({
242
+ requested_result_count: numberValue(bedrock?.numberOfResults),
243
+ }),
244
+ });
245
+ }
246
+
247
+ export function rerankResponseFields<T>(output: T): SpanFields {
248
+ const raw: unknown = output;
249
+ const result = isRecord(raw) ? raw : {};
250
+ const results = arrayValue<unknown>(result.results);
251
+ const capture = captureEnabled("output") ? boundedCapture(results) : undefined;
252
+
253
+ return mergeFields(awsMetadataFields(result.$metadata), {
254
+ output: capture?.value,
255
+ attributes: capture?.truncated ? { "telemetry.dev.capture.truncated": true } : undefined,
256
+ metadata: omitUndefined({
257
+ result_count: results?.length,
258
+ has_next_token: stringValue(result.nextToken) ? true : undefined,
259
+ }),
260
+ });
261
+ }
262
+
194
263
  export function ragModel(input: JsonRecord): string | undefined {
195
264
  const config = isRecord(input.retrieveAndGenerateConfiguration)
196
265
  ? input.retrieveAndGenerateConfiguration
@@ -10,6 +10,9 @@ import {
10
10
  ragName,
11
11
  ragRequestFields,
12
12
  ragResponseFields,
13
+ rerankName,
14
+ rerankRequestFields,
15
+ rerankResponseFields,
13
16
  retrieveRequestFields,
14
17
  retrieveResponseFields,
15
18
  } from "./agent-handlers.ts";
@@ -146,6 +149,16 @@ export const AGENT_HANDLERS = {
146
149
  requestFields: inlineAgentRequestFields,
147
150
  onResult: streamAgentResult("completion"),
148
151
  },
152
+ RerankCommand: {
153
+ spanName: rerankName,
154
+ spanType: () => "span",
155
+ requestFields: rerankRequestFields,
156
+ onResult(result, span) {
157
+ endSpan(span, rerankResponseFields(result));
158
+
159
+ return result;
160
+ },
161
+ },
149
162
  RetrieveCommand: {
150
163
  spanName: (input) => `retrieve ${stringValue(input.knowledgeBaseId) ?? "unknown"}`,
151
164
  spanType: () => "span",
package/src/internal.ts CHANGED
@@ -145,9 +145,24 @@ export function safe<T>(fn: () => T): T | undefined {
145
145
  }
146
146
  }
147
147
 
148
+ // Bedrock reports input tokens without cache reads and writes; span input tokens include them.
149
+ function withCacheInclusiveInput(fields: SpanFields | undefined): SpanFields | undefined {
150
+ const usage = fields?.usage;
151
+
152
+ if (usage?.inputTokens === undefined) return fields;
153
+ const inputTokens =
154
+ usage.inputTokens + (usage.cacheReadInputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0);
155
+ const totalTokens =
156
+ usage.totalTokens !== undefined && usage.outputTokens !== undefined
157
+ ? inputTokens + usage.outputTokens
158
+ : usage.totalTokens;
159
+
160
+ return { ...fields, usage: { ...usage, inputTokens, totalTokens } };
161
+ }
162
+
148
163
  export function endSpan(span: SpanHandle, fields?: SpanFields): void {
149
164
  try {
150
- span.end(fields);
165
+ span.end(withCacheInclusiveInput(fields));
151
166
  } catch {
152
167
  // Instrumentation must never throw into caller code.
153
168
  }