@telemetry-dev/bedrock 0.1.9 → 0.1.12
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 +30 -5
- package/dist/agents.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{internal-handlers-Byxp14OZ.mjs → internal-handlers-CLP2wXDh.mjs} +304 -52
- package/package.json +5 -5
- package/src/agent-handlers.ts +214 -36
- package/src/converse.ts +6 -3
- package/src/internal-handlers.ts +2 -1
- package/src/internal.ts +109 -5
- package/src/invoke-model.ts +83 -13
package/src/invoke-model.ts
CHANGED
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
omitUndefined,
|
|
11
11
|
parseJson,
|
|
12
12
|
PROVIDER,
|
|
13
|
+
STREAM_CAPTURE_MAX_ITEMS,
|
|
13
14
|
stringValue,
|
|
15
|
+
StreamRetention,
|
|
14
16
|
type JsonRecord,
|
|
15
17
|
type JsonValue,
|
|
16
18
|
type StreamState,
|
|
@@ -164,12 +166,7 @@ function nativeResponseFields(
|
|
|
164
166
|
{
|
|
165
167
|
output: body,
|
|
166
168
|
finishReason: stringValue(body.stop_reason),
|
|
167
|
-
usage
|
|
168
|
-
inputTokens: numberValue(usage.input_tokens),
|
|
169
|
-
outputTokens: numberValue(usage.output_tokens),
|
|
170
|
-
cacheReadInputTokens: numberValue(usage.cache_read_input_tokens),
|
|
171
|
-
cacheCreationInputTokens: numberValue(usage.cache_creation_input_tokens),
|
|
172
|
-
}),
|
|
169
|
+
...claudeUsageFields(usage),
|
|
173
170
|
},
|
|
174
171
|
metadata,
|
|
175
172
|
);
|
|
@@ -215,6 +212,39 @@ function nativeResponseFields(
|
|
|
215
212
|
return withHeaderUsage({ output: body }, metadata);
|
|
216
213
|
}
|
|
217
214
|
|
|
215
|
+
const CLAUDE_USAGE_KEYS = {
|
|
216
|
+
inputTokens: "input_tokens",
|
|
217
|
+
outputTokens: "output_tokens",
|
|
218
|
+
cacheReadInputTokens: "cache_read_input_tokens",
|
|
219
|
+
cacheCreationInputTokens: "cache_creation_input_tokens",
|
|
220
|
+
} as const;
|
|
221
|
+
|
|
222
|
+
function claudeUsageFields(record: JsonRecord): SpanFields {
|
|
223
|
+
const usage: NonNullable<SpanFields["usage"]> = {};
|
|
224
|
+
for (const [key, source] of Object.entries(CLAUDE_USAGE_KEYS)) {
|
|
225
|
+
const value = numberValue(record[source]);
|
|
226
|
+
if (value !== undefined) usage[key as keyof typeof CLAUDE_USAGE_KEYS] = value;
|
|
227
|
+
}
|
|
228
|
+
const iterations = record.iterations;
|
|
229
|
+
if (!Array.isArray(iterations)) return { usage };
|
|
230
|
+
|
|
231
|
+
// Executor iterations are already in top-level usage; only compaction is additive.
|
|
232
|
+
const first = Math.max(0, iterations.length - STREAM_CAPTURE_MAX_ITEMS);
|
|
233
|
+
for (let index = first; index < iterations.length; index += 1) {
|
|
234
|
+
const entry = iterations[index];
|
|
235
|
+
if (!isRecord(entry) || entry.type !== "compaction") continue;
|
|
236
|
+
for (const [key, source] of Object.entries(CLAUDE_USAGE_KEYS)) {
|
|
237
|
+
const value = numberValue(entry[source]);
|
|
238
|
+
const target = key as keyof typeof CLAUDE_USAGE_KEYS;
|
|
239
|
+
if (value !== undefined) usage[target] = (usage[target] ?? 0) + value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
usage,
|
|
244
|
+
...(first > 0 ? { attributes: { "telemetry.dev.capture.truncated": true } } : {}),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
218
248
|
function withHeaderUsage<T>(fields: SpanFields, metadata: T): SpanFields {
|
|
219
249
|
if (fields.usage && Object.keys(fields.usage).length > 0) return fields;
|
|
220
250
|
|
|
@@ -251,9 +281,13 @@ function headerNumber<T>(value: T): number | undefined {
|
|
|
251
281
|
}
|
|
252
282
|
|
|
253
283
|
export class InvokeModelStreamState implements StreamState {
|
|
284
|
+
readonly retention = new StreamRetention();
|
|
254
285
|
private readonly chunks: unknown[] = [];
|
|
255
286
|
private text = "";
|
|
256
287
|
private usage: SpanFields["usage"];
|
|
288
|
+
private finalUsage: NonNullable<SpanFields["usage"]> = {};
|
|
289
|
+
private startUsage: NonNullable<SpanFields["usage"]> = {};
|
|
290
|
+
private compaction: SpanFields = {};
|
|
257
291
|
private finishReason: string | undefined;
|
|
258
292
|
private error: Error | undefined;
|
|
259
293
|
private errorFields: SpanFields | undefined;
|
|
@@ -277,8 +311,10 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
277
311
|
return (typeof raw === "string" || raw instanceof Uint8Array) && raw.length > 0;
|
|
278
312
|
}
|
|
279
313
|
|
|
280
|
-
this.
|
|
281
|
-
|
|
314
|
+
if (this.retention.accept(parsed)) {
|
|
315
|
+
this.chunks.push(parsed);
|
|
316
|
+
this.text += textFromProviderChunk(parsed);
|
|
317
|
+
}
|
|
282
318
|
|
|
283
319
|
if (isRecord(parsed)) {
|
|
284
320
|
const delta = isRecord(parsed.delta) ? parsed.delta : undefined;
|
|
@@ -286,6 +322,28 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
286
322
|
const messageUsage = isRecord(message?.usage) ? message?.usage : undefined;
|
|
287
323
|
const usage = isRecord(parsed.usage) ? parsed.usage : undefined;
|
|
288
324
|
|
|
325
|
+
for (const [key, source] of Object.entries(CLAUDE_USAGE_KEYS)) {
|
|
326
|
+
const value = numberValue(usage?.[source]);
|
|
327
|
+
if (value !== undefined) this.finalUsage[key as keyof typeof CLAUDE_USAGE_KEYS] = value;
|
|
328
|
+
}
|
|
329
|
+
// message_start counts exclude compaction like message_delta counts; metrics may not.
|
|
330
|
+
this.startUsage = omitUndefined({
|
|
331
|
+
...this.startUsage,
|
|
332
|
+
inputTokens: numberValue(messageUsage?.input_tokens) ?? this.startUsage.inputTokens,
|
|
333
|
+
outputTokens: numberValue(messageUsage?.output_tokens) ?? this.startUsage.outputTokens,
|
|
334
|
+
cacheReadInputTokens:
|
|
335
|
+
numberValue(messageUsage?.cache_read_input_tokens) ??
|
|
336
|
+
this.startUsage.cacheReadInputTokens,
|
|
337
|
+
cacheCreationInputTokens:
|
|
338
|
+
numberValue(messageUsage?.cache_creation_input_tokens) ??
|
|
339
|
+
this.startUsage.cacheCreationInputTokens,
|
|
340
|
+
});
|
|
341
|
+
// An interrupted stream keeps message_start's iterations until a cumulative delta replaces them.
|
|
342
|
+
const iterations = Array.isArray(usage?.iterations)
|
|
343
|
+
? usage.iterations
|
|
344
|
+
: messageUsage?.iterations;
|
|
345
|
+
if (Array.isArray(iterations)) this.compaction = claudeUsageFields({ iterations });
|
|
346
|
+
|
|
289
347
|
const metrics = isRecord(parsed["amazon-bedrock-invocationMetrics"])
|
|
290
348
|
? parsed["amazon-bedrock-invocationMetrics"]
|
|
291
349
|
: undefined;
|
|
@@ -310,7 +368,7 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
310
368
|
this.usage = omitUndefined({
|
|
311
369
|
...this.usage,
|
|
312
370
|
inputTokens:
|
|
313
|
-
numberValue(
|
|
371
|
+
numberValue(usage?.input_tokens) ??
|
|
314
372
|
numberValue(metrics?.inputTokenCount) ??
|
|
315
373
|
numberValue(parsed.inputTextTokenCount) ??
|
|
316
374
|
this.usage?.inputTokens,
|
|
@@ -320,10 +378,9 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
320
378
|
numberValue(parsed.totalOutputTextTokenCount) ??
|
|
321
379
|
this.usage?.outputTokens,
|
|
322
380
|
cacheReadInputTokens:
|
|
323
|
-
numberValue(
|
|
381
|
+
numberValue(usage?.cache_read_input_tokens) ?? this.usage?.cacheReadInputTokens,
|
|
324
382
|
cacheCreationInputTokens:
|
|
325
|
-
numberValue(
|
|
326
|
-
this.usage?.cacheCreationInputTokens,
|
|
383
|
+
numberValue(usage?.cache_creation_input_tokens) ?? this.usage?.cacheCreationInputTokens,
|
|
327
384
|
});
|
|
328
385
|
}
|
|
329
386
|
|
|
@@ -331,6 +388,18 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
331
388
|
}
|
|
332
389
|
|
|
333
390
|
finish(): SpanFields {
|
|
391
|
+
const usage = { ...this.startUsage, ...this.usage, ...this.finalUsage };
|
|
392
|
+
for (const key of Object.keys(CLAUDE_USAGE_KEYS) as (keyof typeof CLAUDE_USAGE_KEYS)[]) {
|
|
393
|
+
const value = this.compaction.usage?.[key];
|
|
394
|
+
const baseKey = key === "outputTokens" ? "outputTokens" : "inputTokens";
|
|
395
|
+
// Invocation metrics have no documented compaction exclusion; never add to that base.
|
|
396
|
+
if (
|
|
397
|
+
value !== undefined &&
|
|
398
|
+
(this.finalUsage[baseKey] !== undefined || this.usage?.[baseKey] === undefined)
|
|
399
|
+
) {
|
|
400
|
+
usage[key] = (usage[key] ?? 0) + value;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
334
403
|
return mergeFields(
|
|
335
404
|
omitUndefined({
|
|
336
405
|
output: this.text
|
|
@@ -343,7 +412,8 @@ export class InvokeModelStreamState implements StreamState {
|
|
|
343
412
|
]
|
|
344
413
|
: this.chunks,
|
|
345
414
|
finishReason: this.finishReason,
|
|
346
|
-
usage
|
|
415
|
+
usage,
|
|
416
|
+
attributes: this.compaction.attributes,
|
|
347
417
|
error: this.error,
|
|
348
418
|
}),
|
|
349
419
|
this.errorFields,
|