@telemetry-dev/bedrock 0.1.0 → 0.1.1

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.
@@ -13,15 +13,17 @@ import {
13
13
  PROVIDER,
14
14
  stringValue,
15
15
  type BedrockInstrumentationOptions,
16
+ type JsonRecord,
17
+ type JsonValue,
16
18
  type StreamState,
17
19
  } from "./internal.ts";
18
20
 
19
- export function agentInputMessages(inputText: unknown): unknown {
21
+ export function agentInputMessages<T>(inputText: T): JsonValue {
20
22
  const text = stringValue(inputText);
21
23
  return text ? [{ role: "user", parts: [{ type: "text", content: text }] }] : undefined;
22
24
  }
23
25
 
24
- export function agentRequestFields(input: Record<string, unknown>): SpanFields {
26
+ export function agentRequestFields(input: JsonRecord): SpanFields {
25
27
  return omitUndefined({
26
28
  provider: PROVIDER,
27
29
  input: agentInputMessages(input.inputText),
@@ -34,7 +36,7 @@ export function agentRequestFields(input: Record<string, unknown>): SpanFields {
34
36
  });
35
37
  }
36
38
 
37
- export function inlineAgentRequestFields(input: Record<string, unknown>): SpanFields {
39
+ export function inlineAgentRequestFields(input: JsonRecord): SpanFields {
38
40
  return omitUndefined({
39
41
  input: agentInputMessages(input.inputText),
40
42
  model: stringValue(input.foundationModel),
@@ -59,28 +61,29 @@ export class AgentStreamState implements StreamState {
59
61
 
60
62
  constructor(private readonly options: BedrockInstrumentationOptions) {}
61
63
 
62
- feed(event: unknown): void {
63
- if (!isRecord(event)) return;
64
- const streamError = modeledStreamError(event);
64
+ feed<T>(event: T): void {
65
+ const raw: unknown = event;
66
+ if (!isRecord(raw)) return;
67
+ const streamError = modeledStreamError(raw);
65
68
  if (streamError) {
66
69
  this.error = streamError.error;
67
70
  this.errorFields = streamError.fields;
68
71
  return;
69
72
  }
70
- const chunk = isRecord(event.chunk) ? event.chunk : undefined;
73
+ const chunk = isRecord(raw.chunk) ? raw.chunk : undefined;
71
74
  const bytes = chunk?.bytes;
72
75
  if (bytes !== undefined) this.text += bytesToString(bytes) ?? "";
73
76
  const attribution = isRecord(chunk?.attribution) ? chunk.attribution : undefined;
74
77
  const citations = arrayValue<unknown>(attribution?.citations);
75
78
  if (citations) this.citationCount += citations.length;
76
79
 
77
- const files = isRecord(event.files) ? arrayValue<unknown>(event.files.files) : undefined;
80
+ const files = isRecord(raw.files) ? arrayValue<JsonValue>(raw.files.files) : undefined;
78
81
  if (files) this.outputFiles.push(...files.map(sanitizeOutputFile));
79
82
 
80
- const returnControl = isRecord(event.returnControl) ? event.returnControl : undefined;
83
+ const returnControl = isRecord(raw.returnControl) ? raw.returnControl : undefined;
81
84
  if (returnControl) this.returnControl = returnControl;
82
85
 
83
- const traceEvent = isRecord(event.trace) ? event.trace : undefined;
86
+ const traceEvent = isRecord(raw.trace) ? raw.trace : undefined;
84
87
  if (traceEvent) {
85
88
  this.traceEventCount += 1;
86
89
  if (this.options.captureAgentTrace) this.traces.push(traceEvent);
@@ -119,11 +122,12 @@ export class AgentStreamState implements StreamState {
119
122
  this.errorFields,
120
123
  );
121
124
  }
122
- private addUsage(value: unknown): void {
123
- if (!isRecord(value)) return;
124
- const inputTokens = numberValue(value.inputTokens);
125
- const outputTokens = numberValue(value.outputTokens);
126
- const totalTokens = numberValue(value.totalTokens);
125
+ private addUsage<T>(value: T): void {
126
+ const raw: unknown = value;
127
+ if (!isRecord(raw)) return;
128
+ const inputTokens = numberValue(raw.inputTokens);
129
+ const outputTokens = numberValue(raw.outputTokens);
130
+ const totalTokens = numberValue(raw.totalTokens);
127
131
  if (inputTokens !== undefined)
128
132
  this.usage.inputTokens = (this.usage.inputTokens ?? 0) + inputTokens;
129
133
  if (outputTokens !== undefined)
@@ -136,15 +140,16 @@ export class AgentStreamState implements StreamState {
136
140
  }
137
141
  }
138
142
 
139
- function sanitizeOutputFile(value: unknown): unknown {
140
- if (!isRecord(value)) return value;
143
+ function sanitizeOutputFile<T>(value: T): JsonValue {
144
+ const raw: unknown = value;
145
+ if (!isRecord(raw)) return undefined;
141
146
  return omitUndefined({
142
- name: stringValue(value.name),
143
- type: stringValue(value.type),
147
+ name: stringValue(raw.name),
148
+ type: stringValue(raw.type),
144
149
  });
145
150
  }
146
151
 
147
- export function retrieveRequestFields(input: Record<string, unknown>): SpanFields {
152
+ export function retrieveRequestFields(input: JsonRecord): SpanFields {
148
153
  return omitUndefined({
149
154
  provider: PROVIDER,
150
155
  input: isRecord(input.retrievalQuery) ? input.retrievalQuery : undefined,
@@ -152,8 +157,9 @@ export function retrieveRequestFields(input: Record<string, unknown>): SpanField
152
157
  });
153
158
  }
154
159
 
155
- export function retrieveResponseFields(output: unknown): SpanFields {
156
- const result = isRecord(output) ? output : {};
160
+ export function retrieveResponseFields<T>(output: T): SpanFields {
161
+ const raw: unknown = output;
162
+ const result = isRecord(raw) ? raw : {};
157
163
  const retrievalResults = arrayValue<unknown>(result.retrievalResults);
158
164
  return mergeFields(awsMetadataFields(result.$metadata), {
159
165
  output: retrievalResults,
@@ -164,7 +170,7 @@ export function retrieveResponseFields(output: unknown): SpanFields {
164
170
  });
165
171
  }
166
172
 
167
- export function ragModel(input: Record<string, unknown>): string | undefined {
173
+ export function ragModel(input: JsonRecord): string | undefined {
168
174
  const config = isRecord(input.retrieveAndGenerateConfiguration)
169
175
  ? input.retrieveAndGenerateConfiguration
170
176
  : undefined;
@@ -177,7 +183,7 @@ export function ragModel(input: Record<string, unknown>): string | undefined {
177
183
  return stringValue(kb?.modelArn) ?? stringValue(external?.modelArn);
178
184
  }
179
185
 
180
- export function ragRequestFields(input: Record<string, unknown>): SpanFields {
186
+ export function ragRequestFields(input: JsonRecord): SpanFields {
181
187
  const text = isRecord(input.input) ? stringValue(input.input.text) : undefined;
182
188
  return omitUndefined({
183
189
  provider: PROVIDER,
@@ -187,8 +193,9 @@ export function ragRequestFields(input: Record<string, unknown>): SpanFields {
187
193
  });
188
194
  }
189
195
 
190
- export function ragResponseFields(output: unknown): SpanFields {
191
- const result = isRecord(output) ? output : {};
196
+ export function ragResponseFields<T>(output: T): SpanFields {
197
+ const raw: unknown = output;
198
+ const result = isRecord(raw) ? raw : {};
192
199
  const text = isRecord(result.output) ? stringValue(result.output.text) : undefined;
193
200
  return mergeFields(awsMetadataFields(result.$metadata), {
194
201
  output: text ? [{ role: "assistant", parts: [{ type: "text", content: text }] }] : undefined,
@@ -207,18 +214,19 @@ export class RagStreamState implements StreamState {
207
214
  private error: Error | undefined;
208
215
  private errorFields: SpanFields | undefined;
209
216
 
210
- feed(event: unknown): void {
211
- if (!isRecord(event)) return;
212
- const streamError = modeledStreamError(event);
217
+ feed<T>(event: T): void {
218
+ const raw: unknown = event;
219
+ if (!isRecord(raw)) return;
220
+ const streamError = modeledStreamError(raw);
213
221
  if (streamError) {
214
222
  this.error = streamError.error;
215
223
  this.errorFields = streamError.fields;
216
224
  return;
217
225
  }
218
- const output = isRecord(event.output) ? event.output : undefined;
226
+ const output = isRecord(raw.output) ? raw.output : undefined;
219
227
  this.text += stringValue(output?.text) ?? "";
220
- if (event.citation) this.citationCount += 1;
221
- const guardrail = isRecord(event.guardrail) ? event.guardrail : undefined;
228
+ if (raw.citation) this.citationCount += 1;
229
+ const guardrail = isRecord(raw.guardrail) ? raw.guardrail : undefined;
222
230
  this.guardrailAction = stringValue(guardrail?.action) ?? this.guardrailAction;
223
231
  }
224
232
 
@@ -239,7 +247,7 @@ export class RagStreamState implements StreamState {
239
247
  }
240
248
  }
241
249
 
242
- export function flowRequestFields(input: Record<string, unknown>): SpanFields {
250
+ export function flowRequestFields(input: JsonRecord): SpanFields {
243
251
  return omitUndefined({
244
252
  provider: PROVIDER,
245
253
  input: input.inputs,
@@ -253,21 +261,22 @@ export class FlowStreamState implements StreamState {
253
261
  private error: Error | undefined;
254
262
  private errorFields: SpanFields | undefined;
255
263
 
256
- feed(event: unknown): void {
257
- if (!isRecord(event)) return;
258
- const streamError = modeledStreamError(event);
264
+ feed<T>(event: T): void {
265
+ const raw: unknown = event;
266
+ if (!isRecord(raw)) return;
267
+ const streamError = modeledStreamError(raw);
259
268
  if (streamError) {
260
269
  this.error = streamError.error;
261
270
  this.errorFields = streamError.fields;
262
271
  return;
263
272
  }
264
- const output = isRecord(event.flowOutputEvent) ? event.flowOutputEvent : undefined;
273
+ const output = isRecord(raw.flowOutputEvent) ? raw.flowOutputEvent : undefined;
265
274
  if (output) this.outputs.push(output.content);
266
- const inputRequest = isRecord(event.flowMultiTurnInputRequestEvent)
267
- ? event.flowMultiTurnInputRequestEvent
275
+ const inputRequest = isRecord(raw.flowMultiTurnInputRequestEvent)
276
+ ? raw.flowMultiTurnInputRequestEvent
268
277
  : undefined;
269
278
  if (inputRequest) this.outputs.push(inputRequest.content);
270
- const completion = isRecord(event.flowCompletionEvent) ? event.flowCompletionEvent : undefined;
279
+ const completion = isRecord(raw.flowCompletionEvent) ? raw.flowCompletionEvent : undefined;
271
280
  this.completionReason = stringValue(completion?.completionReason) ?? this.completionReason;
272
281
  }
273
282
 
@@ -283,31 +292,33 @@ export class FlowStreamState implements StreamState {
283
292
  }
284
293
  }
285
294
 
286
- export function flowName(input: Record<string, unknown>): string {
295
+ export function flowName(input: JsonRecord): string {
287
296
  return `invoke_flow ${stringValue(input.flowIdentifier) ?? "unknown"}`;
288
297
  }
289
298
 
290
- export function ragName(input: Record<string, unknown>): string {
299
+ export function ragName(input: JsonRecord): string {
291
300
  return `retrieve_and_generate ${basenameArn(ragModel(input)) ?? "knowledge-base"}`;
292
301
  }
293
302
 
294
- function collectTrace(value: unknown, onUsage: (usage: unknown) => void): void {
295
- if (!isRecord(value)) return;
296
- const output = isRecord(value.modelInvocationOutput) ? value.modelInvocationOutput : undefined;
303
+ function collectTrace<T>(value: T, onUsage: <TUsage>(usage: TUsage) => void): void {
304
+ const raw: unknown = value;
305
+ if (!isRecord(raw)) return;
306
+ const output = isRecord(raw.modelInvocationOutput) ? raw.modelInvocationOutput : undefined;
297
307
  if (output) {
298
308
  const metadata = isRecord(output.metadata) ? output.metadata : undefined;
299
309
  onUsage(metadata?.usage);
300
310
  }
301
- for (const child of Object.values(value)) {
311
+ for (const child of Object.values(raw)) {
302
312
  if (isRecord(child)) collectTrace(child, onUsage);
303
313
  else if (Array.isArray(child)) child.forEach((item) => collectTrace(item, onUsage));
304
314
  }
305
315
  }
306
316
 
307
- function findKey(value: unknown, key: string): unknown {
308
- if (!isRecord(value)) return undefined;
309
- if (value[key] !== undefined) return value[key];
310
- for (const child of Object.values(value)) {
317
+ function findKey<T>(value: T, key: string): JsonValue {
318
+ const raw: unknown = value;
319
+ if (!isRecord(raw)) return undefined;
320
+ if (raw[key] !== undefined) return raw[key];
321
+ for (const child of Object.values(raw)) {
311
322
  const found = findKey(child, key);
312
323
  if (found !== undefined) return found;
313
324
  }
package/src/agents.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  export type { BedrockInstrumentationOptions } from "./internal.ts";
11
11
 
12
12
  export interface WrappableBedrockAgentClient {
13
- send: (...args: never[]) => unknown;
13
+ send: (...args: never[]) => any;
14
14
  }
15
15
 
16
16
  const WRAPPED = new WeakSet<object>();
@@ -33,7 +33,7 @@ export function wrapBedrockAgents<T extends WrappableBedrockAgentClient>(
33
33
 
34
34
  export function instrumentBedrockAgents(options: BedrockInstrumentationOptions = {}): void {
35
35
  if (ORIGINAL) return;
36
- const proto = BedrockAgentRuntimeClient.prototype as unknown as { send: SendFn };
36
+ const proto = BedrockAgentRuntimeClient.prototype as { send: SendFn };
37
37
  const hadOwn = Object.prototype.hasOwnProperty.call(proto, "send");
38
38
  const original = proto.send;
39
39
  const instrumentedSend = createInstrumentedSend(original, options, AGENT_HANDLERS);
package/src/converse.ts CHANGED
@@ -11,17 +11,19 @@ import {
11
11
  parseJson,
12
12
  PROVIDER,
13
13
  stringValue,
14
+ type JsonRecord,
15
+ type JsonValue,
14
16
  type StreamState,
15
17
  } from "./internal.ts";
16
18
 
17
- export type MessagePart = Record<string, unknown>;
19
+ export type MessagePart = object;
18
20
  export interface NormalizedMessage {
19
21
  role: string | undefined;
20
22
  parts: MessagePart[];
21
23
  finish_reason?: string;
22
24
  }
23
25
 
24
- export function converseRequestFields(input: Record<string, unknown>): SpanFields {
26
+ export function converseRequestFields(input: JsonRecord): SpanFields {
25
27
  const inference = isRecord(input.inferenceConfig) ? input.inferenceConfig : {};
26
28
  const guardrail = isRecord(input.guardrailConfig) ? input.guardrailConfig : undefined;
27
29
  return omitUndefined({
@@ -42,8 +44,8 @@ export function converseRequestFields(input: Record<string, unknown>): SpanField
42
44
  });
43
45
  }
44
46
 
45
- export function converseResponseFields(output: unknown): SpanFields {
46
- const result = isRecord(output) ? output : {};
47
+ export function converseResponseFields<T>(output: T): SpanFields {
48
+ const result: JsonRecord = isRecord(output) ? output : {};
47
49
  const usage = usageFromConverse(result.usage);
48
50
  const metrics = isRecord(result.metrics) ? result.metrics : undefined;
49
51
  const trace = isRecord(result.trace) ? result.trace : undefined;
@@ -64,7 +66,7 @@ export function converseResponseFields(output: unknown): SpanFields {
64
66
  });
65
67
  }
66
68
 
67
- export function usageFromConverse(value: unknown): SpanFields["usage"] | undefined {
69
+ export function usageFromConverse<T>(value: T): SpanFields["usage"] | undefined {
68
70
  if (!isRecord(value)) return undefined;
69
71
  return omitUndefined({
70
72
  inputTokens: numberValue(value.inputTokens),
@@ -75,8 +77,8 @@ export function usageFromConverse(value: unknown): SpanFields["usage"] | undefin
75
77
  });
76
78
  }
77
79
 
78
- export function normalizeMessages(value: unknown): NormalizedMessage[] | undefined {
79
- const messages = arrayValue<Record<string, unknown>>(value);
80
+ export function normalizeMessages<T>(value: T): NormalizedMessage[] | undefined {
81
+ const messages = arrayValue<JsonRecord>(value);
80
82
  if (!messages) return undefined;
81
83
  return messages.map((message) => ({
82
84
  role: stringValue(message.role),
@@ -84,34 +86,33 @@ export function normalizeMessages(value: unknown): NormalizedMessage[] | undefin
84
86
  }));
85
87
  }
86
88
 
87
- export function normalizeOutputMessage(
88
- value: unknown,
89
+ export function normalizeOutputMessage<T>(
90
+ value: T,
89
91
  finishReason?: string,
90
92
  ): NormalizedMessage[] | undefined {
91
93
  if (!isRecord(value)) return undefined;
92
- return [
93
- omitUndefined({
94
- role: stringValue(value.role),
95
- parts: normalizeContentList(value.content),
96
- finish_reason: finishReason,
97
- }) as NormalizedMessage,
98
- ];
94
+ const message = omitUndefined({
95
+ role: stringValue(value.role),
96
+ parts: normalizeContentList(value.content),
97
+ finish_reason: finishReason,
98
+ });
99
+ return [message];
99
100
  }
100
101
 
101
- export function normalizeSystem(value: unknown): MessagePart[] | undefined {
102
- const blocks = arrayValue<Record<string, unknown>>(value);
102
+ export function normalizeSystem<T>(value: T): MessagePart[] | undefined {
103
+ const blocks = arrayValue<JsonRecord>(value);
103
104
  if (!blocks) return undefined;
104
105
  const parts = blocks.flatMap((block) => normalizeContentBlock(block));
105
106
  return parts.length > 0 ? parts : undefined;
106
107
  }
107
108
 
108
- function normalizeContentList(value: unknown): MessagePart[] {
109
- const blocks = arrayValue<Record<string, unknown>>(value);
109
+ function normalizeContentList<T>(value: T): MessagePart[] {
110
+ const blocks = arrayValue<JsonRecord>(value);
110
111
  if (!blocks) return [];
111
112
  return blocks.flatMap((block) => normalizeContentBlock(block));
112
113
  }
113
114
 
114
- function normalizeContentBlock(block: Record<string, unknown>): MessagePart[] {
115
+ function normalizeContentBlock(block: JsonRecord): MessagePart[] {
115
116
  const text = stringValue(block.text);
116
117
  if (text !== undefined)
117
118
  return [
@@ -178,11 +179,12 @@ function normalizeContentBlock(block: Record<string, unknown>): MessagePart[] {
178
179
 
179
180
  const citationsContent = isRecord(block.citationsContent) ? block.citationsContent : undefined;
180
181
  if (citationsContent) {
181
- const contentBlocks = arrayValue<Record<string, unknown>>(citationsContent.content) ?? [];
182
- const citations = arrayValue<unknown>(citationsContent.citations);
183
- return contentBlocks.flatMap((contentBlock) =>
184
- normalizeContentBlock(citations ? { ...contentBlock, citations } : contentBlock),
185
- );
182
+ const contentBlocks = arrayValue<JsonRecord>(citationsContent.content) ?? [];
183
+ const citations = arrayValue<JsonValue>(citationsContent.citations);
184
+ return contentBlocks.flatMap((contentBlock) => {
185
+ if (!citations) return normalizeContentBlock(contentBlock);
186
+ return normalizeContentBlock({ ...contentBlock, citations });
187
+ });
186
188
  }
187
189
 
188
190
  const guardContent = isRecord(block.guardContent) ? block.guardContent : undefined;
@@ -199,14 +201,15 @@ function normalizeContentBlock(block: Record<string, unknown>): MessagePart[] {
199
201
  }
200
202
  }
201
203
 
202
- function simplifyToolResult(content: unknown): unknown {
203
- const blocks = arrayValue<Record<string, unknown>>(content);
204
- if (!blocks) return content;
205
- if (blocks.length === 1 && typeof blocks[0]?.text === "string") return blocks[0].text;
206
- return blocks.flatMap((block) => normalizeContentBlock(block));
204
+ function simplifyToolResult<T>(content: T): JsonValue {
205
+ const blocks = arrayValue<JsonRecord>(content);
206
+ if (!blocks) return isJsonValue(content) ? content : undefined;
207
+ const text = stringValue(blocks[0]?.text);
208
+ if (blocks.length === 1 && text !== undefined) return text;
209
+ return blocks.flatMap((block) => normalizeContentBlock(block)) as JsonValue[];
207
210
  }
208
211
 
209
- function s3Uri(value: Record<string, unknown> | undefined): string | undefined {
212
+ function s3Uri(value: JsonRecord | undefined): string | undefined {
210
213
  const bucket = stringValue(value?.bucket);
211
214
  const key = stringValue(value?.key);
212
215
  return bucket && key ? `s3://${bucket}/${key}` : undefined;
@@ -218,7 +221,7 @@ interface StreamBlock {
218
221
  toolUseId?: string;
219
222
  name?: string;
220
223
  input?: string;
221
- content?: Record<string, unknown>;
224
+ content?: JsonRecord;
222
225
  citations?: unknown[];
223
226
  }
224
227
 
@@ -227,12 +230,12 @@ export class ConverseStreamState implements StreamState {
227
230
  private readonly blocks = new Map<number, StreamBlock>();
228
231
  private stopReason: string | undefined;
229
232
  private usage: SpanFields["usage"];
230
- private metadata: Record<string, unknown> = {};
233
+ private metadata: JsonRecord = {};
231
234
  private responseModel: string | undefined;
232
235
  private error: Error | undefined;
233
236
  private errorFields: SpanFields | undefined;
234
237
 
235
- feed(event: unknown): void {
238
+ feed<T>(event: T): void {
236
239
  if (!isRecord(event)) return;
237
240
  const streamError = modeledStreamError(event);
238
241
  if (streamError) {
@@ -281,14 +284,16 @@ export class ConverseStreamState implements StreamState {
281
284
  const index = numberValue(deltaEvent.contentBlockIndex) ?? 0;
282
285
  const delta = isRecord(deltaEvent.delta) ? deltaEvent.delta : {};
283
286
  const block = this.blocks.get(index) ?? { kind: "text", text: "" };
284
- if (typeof delta.text === "string") {
287
+ const text = stringValue(delta.text);
288
+ if (text !== undefined) {
285
289
  block.kind = "text";
286
- block.text = `${block.text ?? ""}${delta.text}`;
290
+ block.text = `${block.text ?? ""}${text}`;
287
291
  }
288
292
  const toolUse = isRecord(delta.toolUse) ? delta.toolUse : undefined;
289
- if (toolUse && typeof toolUse.input === "string") {
293
+ const input = stringValue(toolUse?.input);
294
+ if (toolUse && input !== undefined) {
290
295
  block.kind = "tool";
291
- block.input = `${block.input ?? ""}${toolUse.input}`;
296
+ block.input = `${block.input ?? ""}${input}`;
292
297
  }
293
298
  const reasoning = isRecord(delta.reasoningContent) ? delta.reasoningContent : undefined;
294
299
  if (reasoning) {
@@ -298,15 +303,15 @@ export class ConverseStreamState implements StreamState {
298
303
  const image = isRecord(delta.image) ? delta.image : undefined;
299
304
  if (image) {
300
305
  const content = isRecord(block.content) ? block.content : {};
301
- const current = isRecord(content.image) ? content.image : {};
306
+ const current: JsonRecord = isRecord(content.image) ? content.image : {};
302
307
  block.kind = "content";
303
308
  block.content = { image: { ...current, ...image } };
304
309
  }
305
- const toolResult = arrayValue<Record<string, unknown>>(delta.toolResult);
310
+ const toolResult = arrayValue<JsonRecord>(delta.toolResult);
306
311
  if (toolResult) {
307
312
  const content = isRecord(block.content) ? block.content : {};
308
- const current = isRecord(content.toolResult) ? content.toolResult : {};
309
- const currentContent = arrayValue<unknown>(current.content) ?? [];
313
+ const current: JsonRecord = isRecord(content.toolResult) ? content.toolResult : {};
314
+ const currentContent = arrayValue<JsonValue>(current.content) ?? [];
310
315
  block.kind = "content";
311
316
  block.content = {
312
317
  toolResult: {
@@ -370,7 +375,18 @@ export class ConverseStreamState implements StreamState {
370
375
  }
371
376
  }
372
377
 
373
- function blockToPart(block: StreamBlock): MessagePart {
378
+ function isJsonValue<T>(value: T): value is T & JsonValue {
379
+ return (
380
+ value == null ||
381
+ String(value) === value ||
382
+ Number(value) === value ||
383
+ Boolean(value) === value ||
384
+ Array.isArray(value) ||
385
+ isRecord(value)
386
+ );
387
+ }
388
+
389
+ function blockToPart(block: StreamBlock) {
374
390
  if (block.kind === "tool") {
375
391
  return omitUndefined({
376
392
  type: "tool_call",
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  export type { BedrockInstrumentationOptions } from "./internal.ts";
11
11
 
12
12
  export interface WrappableBedrockClient {
13
- send: (...args: never[]) => unknown;
13
+ send: (...args: never[]) => any;
14
14
  }
15
15
 
16
16
  const WRAPPED = new WeakSet<object>();
@@ -33,7 +33,7 @@ export function wrapBedrock<T extends WrappableBedrockClient>(
33
33
 
34
34
  export function instrumentBedrock(options: BedrockInstrumentationOptions = {}): void {
35
35
  if (ORIGINAL) return;
36
- const proto = BedrockRuntimeClient.prototype as unknown as { send: SendFn };
36
+ const proto = BedrockRuntimeClient.prototype as { send: SendFn };
37
37
  const hadOwn = Object.prototype.hasOwnProperty.call(proto, "send");
38
38
  const original = proto.send;
39
39
  const instrumentedSend = createInstrumentedSend(original, options, RUNTIME_HANDLERS);
@@ -1,4 +1,4 @@
1
- import type { OpHandler } from "./internal.ts";
1
+ import type { JsonRecord, JsonValue, OpHandler } from "./internal.ts";
2
2
  import {
3
3
  AgentStreamState,
4
4
  FlowStreamState,
@@ -32,7 +32,7 @@ import {
32
32
  type BedrockInstrumentationOptions,
33
33
  } from "./internal.ts";
34
34
 
35
- export const RUNTIME_HANDLERS: Record<string, OpHandler> = {
35
+ export const RUNTIME_HANDLERS = {
36
36
  ConverseCommand: {
37
37
  spanName: (input) => `chat ${stringValue(input.modelId) ?? "unknown"}`,
38
38
  spanType: () => "generation",
@@ -108,7 +108,7 @@ export const RUNTIME_HANDLERS: Record<string, OpHandler> = {
108
108
  }),
109
109
  }),
110
110
  onResult(result, span) {
111
- const response = result as Record<string, unknown>;
111
+ const response = result as JsonRecord;
112
112
  endSpan(
113
113
  span,
114
114
  mergeFields(awsMetadataFields(response.$metadata), {
@@ -122,9 +122,9 @@ export const RUNTIME_HANDLERS: Record<string, OpHandler> = {
122
122
  return result;
123
123
  },
124
124
  },
125
- };
125
+ } satisfies Record<string, OpHandler>;
126
126
 
127
- export const AGENT_HANDLERS: Record<string, OpHandler> = {
127
+ export const AGENT_HANDLERS = {
128
128
  InvokeAgentCommand: {
129
129
  spanName: (input) => `invoke_agent ${stringValue(input.agentId) ?? "unknown"}`,
130
130
  spanType: () => "agent",
@@ -196,19 +196,19 @@ export const AGENT_HANDLERS: Record<string, OpHandler> = {
196
196
  };
197
197
  },
198
198
  },
199
- };
199
+ } satisfies Record<string, OpHandler>;
200
200
 
201
201
  function streamAgentResult(key: "completion") {
202
202
  return (
203
- result: unknown,
203
+ result: JsonValue,
204
204
  span: Parameters<OpHandler["onResult"]>[1],
205
205
  t0: number,
206
- _input: Record<string, unknown>,
206
+ _input: JsonRecord,
207
207
  options: BedrockInstrumentationOptions,
208
- ): unknown => {
209
- const response = result as {
210
- completion?: unknown;
211
- $metadata?: unknown;
208
+ ) => {
209
+ const response = result as JsonRecord & {
210
+ completion?: JsonValue;
211
+ $metadata?: JsonValue;
212
212
  sessionId?: string;
213
213
  memoryId?: string;
214
214
  };