@telemetry-dev/bedrock 0.1.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/LICENSE +21 -0
- package/README.md +157 -0
- package/dist/agents.d.mts +11 -0
- package/dist/agents.mjs +52 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +52 -0
- package/dist/internal-_ZoDhB3-.d.mts +6 -0
- package/dist/internal-handlers-BloMjBP8.mjs +1201 -0
- package/package.json +75 -0
- package/src/agent-handlers.ts +315 -0
- package/src/agents.ts +69 -0
- package/src/converse.ts +390 -0
- package/src/index.ts +69 -0
- package/src/internal-handlers.ts +230 -0
- package/src/internal.ts +301 -0
- package/src/invoke-model.ts +332 -0
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@telemetry-dev/bedrock",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AWS Bedrock instrumentation for telemetry.dev: Converse, InvokeModel, and Bedrock Agents spans for AWS SDK v3 clients.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"aws",
|
|
7
|
+
"bedrock",
|
|
8
|
+
"genai",
|
|
9
|
+
"llm",
|
|
10
|
+
"observability",
|
|
11
|
+
"opentelemetry",
|
|
12
|
+
"telemetry",
|
|
13
|
+
"tracing"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://telemetry.dev",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/telemetry-dev/telemetry.dev.git",
|
|
20
|
+
"directory": "packages/bedrock"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"default": "./dist/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./agents": {
|
|
34
|
+
"types": "./dist/agents.d.mts",
|
|
35
|
+
"import": "./dist/agents.mjs",
|
|
36
|
+
"default": "./dist/agents.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@aws-sdk/client-bedrock-agent-runtime": "^3.1000.0",
|
|
45
|
+
"@aws-sdk/client-bedrock-runtime": "^3.1000.0",
|
|
46
|
+
"@opentelemetry/api": "^1.9.1",
|
|
47
|
+
"@opentelemetry/sdk-logs": "^0.218.0",
|
|
48
|
+
"@opentelemetry/sdk-trace-base": "^2.7.1",
|
|
49
|
+
"@smithy/eventstream-codec": "^4.2.5",
|
|
50
|
+
"@smithy/protocol-http": "^5.3.10",
|
|
51
|
+
"@smithy/types": "^4.12.0",
|
|
52
|
+
"@types/node": "^25.5.0",
|
|
53
|
+
"@typescript/native-preview": "7.0.0-dev.20260328.1",
|
|
54
|
+
"typescript": "^6.0.2",
|
|
55
|
+
"vite-plus": "0.1.20",
|
|
56
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test@0.1.20",
|
|
57
|
+
"@telemetry-dev/sdk": "^0.1.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@aws-sdk/client-bedrock-agent-runtime": ">=3.600.0 <4",
|
|
61
|
+
"@aws-sdk/client-bedrock-runtime": ">=3.600.0 <4",
|
|
62
|
+
"@telemetry-dev/sdk": "^0.1.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@aws-sdk/client-bedrock-agent-runtime": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "pnpm exec vp pack",
|
|
71
|
+
"dev": "pnpm exec vp pack --watch",
|
|
72
|
+
"test": "vp test",
|
|
73
|
+
"check": "vp check"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import type { SpanFields } from "@telemetry-dev/sdk";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
arrayValue,
|
|
5
|
+
awsMetadataFields,
|
|
6
|
+
basenameArn,
|
|
7
|
+
bytesToString,
|
|
8
|
+
isRecord,
|
|
9
|
+
mergeFields,
|
|
10
|
+
modeledStreamError,
|
|
11
|
+
numberValue,
|
|
12
|
+
omitUndefined,
|
|
13
|
+
PROVIDER,
|
|
14
|
+
stringValue,
|
|
15
|
+
type BedrockInstrumentationOptions,
|
|
16
|
+
type StreamState,
|
|
17
|
+
} from "./internal.ts";
|
|
18
|
+
|
|
19
|
+
export function agentInputMessages(inputText: unknown): unknown {
|
|
20
|
+
const text = stringValue(inputText);
|
|
21
|
+
return text ? [{ role: "user", parts: [{ type: "text", content: text }] }] : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function agentRequestFields(input: Record<string, unknown>): SpanFields {
|
|
25
|
+
return omitUndefined({
|
|
26
|
+
provider: PROVIDER,
|
|
27
|
+
input: agentInputMessages(input.inputText),
|
|
28
|
+
agentId: stringValue(input.agentId),
|
|
29
|
+
metadata: omitUndefined({
|
|
30
|
+
bedrock_agent_alias_id: stringValue(input.agentAliasId),
|
|
31
|
+
bedrock_session_id: stringValue(input.sessionId),
|
|
32
|
+
bedrock_memory_id: stringValue(input.memoryId),
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function inlineAgentRequestFields(input: Record<string, unknown>): SpanFields {
|
|
38
|
+
return omitUndefined({
|
|
39
|
+
input: agentInputMessages(input.inputText),
|
|
40
|
+
model: stringValue(input.foundationModel),
|
|
41
|
+
provider: PROVIDER,
|
|
42
|
+
agentName: stringValue(input.agentName),
|
|
43
|
+
metadata: omitUndefined({ bedrock_session_id: stringValue(input.sessionId) }),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class AgentStreamState implements StreamState {
|
|
48
|
+
private text = "";
|
|
49
|
+
private usage: NonNullable<SpanFields["usage"]> = {};
|
|
50
|
+
private traceEventCount = 0;
|
|
51
|
+
private failureReason: string | undefined;
|
|
52
|
+
private guardrailAction: string | undefined;
|
|
53
|
+
private returnControl: unknown;
|
|
54
|
+
private readonly traces: unknown[] = [];
|
|
55
|
+
private error: Error | undefined;
|
|
56
|
+
private errorFields: SpanFields | undefined;
|
|
57
|
+
private citationCount = 0;
|
|
58
|
+
private readonly outputFiles: unknown[] = [];
|
|
59
|
+
|
|
60
|
+
constructor(private readonly options: BedrockInstrumentationOptions) {}
|
|
61
|
+
|
|
62
|
+
feed(event: unknown): void {
|
|
63
|
+
if (!isRecord(event)) return;
|
|
64
|
+
const streamError = modeledStreamError(event);
|
|
65
|
+
if (streamError) {
|
|
66
|
+
this.error = streamError.error;
|
|
67
|
+
this.errorFields = streamError.fields;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const chunk = isRecord(event.chunk) ? event.chunk : undefined;
|
|
71
|
+
const bytes = chunk?.bytes;
|
|
72
|
+
if (bytes !== undefined) this.text += bytesToString(bytes) ?? "";
|
|
73
|
+
const attribution = isRecord(chunk?.attribution) ? chunk.attribution : undefined;
|
|
74
|
+
const citations = arrayValue<unknown>(attribution?.citations);
|
|
75
|
+
if (citations) this.citationCount += citations.length;
|
|
76
|
+
|
|
77
|
+
const files = isRecord(event.files) ? arrayValue<unknown>(event.files.files) : undefined;
|
|
78
|
+
if (files) this.outputFiles.push(...files.map(sanitizeOutputFile));
|
|
79
|
+
|
|
80
|
+
const returnControl = isRecord(event.returnControl) ? event.returnControl : undefined;
|
|
81
|
+
if (returnControl) this.returnControl = returnControl;
|
|
82
|
+
|
|
83
|
+
const traceEvent = isRecord(event.trace) ? event.trace : undefined;
|
|
84
|
+
if (traceEvent) {
|
|
85
|
+
this.traceEventCount += 1;
|
|
86
|
+
if (this.options.captureAgentTrace) this.traces.push(traceEvent);
|
|
87
|
+
collectTrace(traceEvent, (usage) => this.addUsage(usage));
|
|
88
|
+
const failure = findKey(traceEvent, "failureTrace");
|
|
89
|
+
if (isRecord(failure))
|
|
90
|
+
this.failureReason = stringValue(failure.failureReason) ?? this.failureReason;
|
|
91
|
+
const guardrail = findKey(traceEvent, "guardrailTrace");
|
|
92
|
+
if (isRecord(guardrail))
|
|
93
|
+
this.guardrailAction = stringValue(guardrail.action) ?? this.guardrailAction;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
finish(): SpanFields {
|
|
98
|
+
const metadata = omitUndefined({
|
|
99
|
+
trace_event_count: this.traceEventCount || undefined,
|
|
100
|
+
failure_reason: this.failureReason,
|
|
101
|
+
guardrail_action: this.guardrailAction,
|
|
102
|
+
return_control: this.returnControl ? true : undefined,
|
|
103
|
+
citation_count: this.citationCount || undefined,
|
|
104
|
+
output_files: this.outputFiles.length > 0 ? this.outputFiles : undefined,
|
|
105
|
+
agent_trace:
|
|
106
|
+
this.options.captureAgentTrace && this.traces.length > 0 ? this.traces : undefined,
|
|
107
|
+
});
|
|
108
|
+
return mergeFields(
|
|
109
|
+
omitUndefined({
|
|
110
|
+
output: this.returnControl
|
|
111
|
+
? { returnControl: this.returnControl }
|
|
112
|
+
: this.text
|
|
113
|
+
? [{ role: "assistant", parts: [{ type: "text", content: this.text }] }]
|
|
114
|
+
: undefined,
|
|
115
|
+
usage: Object.keys(this.usage).length > 0 ? this.usage : undefined,
|
|
116
|
+
metadata,
|
|
117
|
+
error: this.error,
|
|
118
|
+
}),
|
|
119
|
+
this.errorFields,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
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);
|
|
127
|
+
if (inputTokens !== undefined)
|
|
128
|
+
this.usage.inputTokens = (this.usage.inputTokens ?? 0) + inputTokens;
|
|
129
|
+
if (outputTokens !== undefined)
|
|
130
|
+
this.usage.outputTokens = (this.usage.outputTokens ?? 0) + outputTokens;
|
|
131
|
+
if (totalTokens !== undefined)
|
|
132
|
+
this.usage.totalTokens = (this.usage.totalTokens ?? 0) + totalTokens;
|
|
133
|
+
else if (inputTokens !== undefined || outputTokens !== undefined) {
|
|
134
|
+
this.usage.totalTokens = (this.usage.inputTokens ?? 0) + (this.usage.outputTokens ?? 0);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function sanitizeOutputFile(value: unknown): unknown {
|
|
140
|
+
if (!isRecord(value)) return value;
|
|
141
|
+
return omitUndefined({
|
|
142
|
+
name: stringValue(value.name),
|
|
143
|
+
type: stringValue(value.type),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function retrieveRequestFields(input: Record<string, unknown>): SpanFields {
|
|
148
|
+
return omitUndefined({
|
|
149
|
+
provider: PROVIDER,
|
|
150
|
+
input: isRecord(input.retrievalQuery) ? input.retrievalQuery : undefined,
|
|
151
|
+
metadata: { knowledge_base_id: stringValue(input.knowledgeBaseId) },
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function retrieveResponseFields(output: unknown): SpanFields {
|
|
156
|
+
const result = isRecord(output) ? output : {};
|
|
157
|
+
const retrievalResults = arrayValue<unknown>(result.retrievalResults);
|
|
158
|
+
return mergeFields(awsMetadataFields(result.$metadata), {
|
|
159
|
+
output: retrievalResults,
|
|
160
|
+
metadata: omitUndefined({
|
|
161
|
+
citation_count: retrievalResults?.length,
|
|
162
|
+
guardrail_action: stringValue(result.guardrailAction),
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function ragModel(input: Record<string, unknown>): string | undefined {
|
|
168
|
+
const config = isRecord(input.retrieveAndGenerateConfiguration)
|
|
169
|
+
? input.retrieveAndGenerateConfiguration
|
|
170
|
+
: undefined;
|
|
171
|
+
const kb = isRecord(config?.knowledgeBaseConfiguration)
|
|
172
|
+
? config?.knowledgeBaseConfiguration
|
|
173
|
+
: undefined;
|
|
174
|
+
const external = isRecord(config?.externalSourcesConfiguration)
|
|
175
|
+
? config?.externalSourcesConfiguration
|
|
176
|
+
: undefined;
|
|
177
|
+
return stringValue(kb?.modelArn) ?? stringValue(external?.modelArn);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function ragRequestFields(input: Record<string, unknown>): SpanFields {
|
|
181
|
+
const text = isRecord(input.input) ? stringValue(input.input.text) : undefined;
|
|
182
|
+
return omitUndefined({
|
|
183
|
+
provider: PROVIDER,
|
|
184
|
+
model: ragModel(input),
|
|
185
|
+
input: text ? [{ role: "user", parts: [{ type: "text", content: text }] }] : undefined,
|
|
186
|
+
metadata: omitUndefined({ bedrock_session_id: stringValue(input.sessionId) }),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function ragResponseFields(output: unknown): SpanFields {
|
|
191
|
+
const result = isRecord(output) ? output : {};
|
|
192
|
+
const text = isRecord(result.output) ? stringValue(result.output.text) : undefined;
|
|
193
|
+
return mergeFields(awsMetadataFields(result.$metadata), {
|
|
194
|
+
output: text ? [{ role: "assistant", parts: [{ type: "text", content: text }] }] : undefined,
|
|
195
|
+
metadata: omitUndefined({
|
|
196
|
+
citation_count: arrayValue<unknown>(result.citations)?.length,
|
|
197
|
+
guardrail_action: stringValue(result.guardrailAction),
|
|
198
|
+
bedrock_session_id: stringValue(result.sessionId),
|
|
199
|
+
}),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export class RagStreamState implements StreamState {
|
|
204
|
+
private text = "";
|
|
205
|
+
private citationCount = 0;
|
|
206
|
+
private guardrailAction: string | undefined;
|
|
207
|
+
private error: Error | undefined;
|
|
208
|
+
private errorFields: SpanFields | undefined;
|
|
209
|
+
|
|
210
|
+
feed(event: unknown): void {
|
|
211
|
+
if (!isRecord(event)) return;
|
|
212
|
+
const streamError = modeledStreamError(event);
|
|
213
|
+
if (streamError) {
|
|
214
|
+
this.error = streamError.error;
|
|
215
|
+
this.errorFields = streamError.fields;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const output = isRecord(event.output) ? event.output : undefined;
|
|
219
|
+
this.text += stringValue(output?.text) ?? "";
|
|
220
|
+
if (event.citation) this.citationCount += 1;
|
|
221
|
+
const guardrail = isRecord(event.guardrail) ? event.guardrail : undefined;
|
|
222
|
+
this.guardrailAction = stringValue(guardrail?.action) ?? this.guardrailAction;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
finish(): SpanFields {
|
|
226
|
+
return mergeFields(
|
|
227
|
+
omitUndefined({
|
|
228
|
+
output: this.text
|
|
229
|
+
? [{ role: "assistant", parts: [{ type: "text", content: this.text }] }]
|
|
230
|
+
: undefined,
|
|
231
|
+
metadata: omitUndefined({
|
|
232
|
+
citation_count: this.citationCount || undefined,
|
|
233
|
+
guardrail_action: this.guardrailAction,
|
|
234
|
+
}),
|
|
235
|
+
error: this.error,
|
|
236
|
+
}),
|
|
237
|
+
this.errorFields,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function flowRequestFields(input: Record<string, unknown>): SpanFields {
|
|
243
|
+
return omitUndefined({
|
|
244
|
+
provider: PROVIDER,
|
|
245
|
+
input: input.inputs,
|
|
246
|
+
agentId: stringValue(input.flowIdentifier),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export class FlowStreamState implements StreamState {
|
|
251
|
+
private outputs: unknown[] = [];
|
|
252
|
+
private completionReason: string | undefined;
|
|
253
|
+
private error: Error | undefined;
|
|
254
|
+
private errorFields: SpanFields | undefined;
|
|
255
|
+
|
|
256
|
+
feed(event: unknown): void {
|
|
257
|
+
if (!isRecord(event)) return;
|
|
258
|
+
const streamError = modeledStreamError(event);
|
|
259
|
+
if (streamError) {
|
|
260
|
+
this.error = streamError.error;
|
|
261
|
+
this.errorFields = streamError.fields;
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const output = isRecord(event.flowOutputEvent) ? event.flowOutputEvent : undefined;
|
|
265
|
+
if (output) this.outputs.push(output.content);
|
|
266
|
+
const inputRequest = isRecord(event.flowMultiTurnInputRequestEvent)
|
|
267
|
+
? event.flowMultiTurnInputRequestEvent
|
|
268
|
+
: undefined;
|
|
269
|
+
if (inputRequest) this.outputs.push(inputRequest.content);
|
|
270
|
+
const completion = isRecord(event.flowCompletionEvent) ? event.flowCompletionEvent : undefined;
|
|
271
|
+
this.completionReason = stringValue(completion?.completionReason) ?? this.completionReason;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
finish(): SpanFields {
|
|
275
|
+
return mergeFields(
|
|
276
|
+
omitUndefined({
|
|
277
|
+
output: this.outputs.length > 0 ? this.outputs : undefined,
|
|
278
|
+
finishReason: this.completionReason,
|
|
279
|
+
error: this.error,
|
|
280
|
+
}),
|
|
281
|
+
this.errorFields,
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function flowName(input: Record<string, unknown>): string {
|
|
287
|
+
return `invoke_flow ${stringValue(input.flowIdentifier) ?? "unknown"}`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function ragName(input: Record<string, unknown>): string {
|
|
291
|
+
return `retrieve_and_generate ${basenameArn(ragModel(input)) ?? "knowledge-base"}`;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function collectTrace(value: unknown, onUsage: (usage: unknown) => void): void {
|
|
295
|
+
if (!isRecord(value)) return;
|
|
296
|
+
const output = isRecord(value.modelInvocationOutput) ? value.modelInvocationOutput : undefined;
|
|
297
|
+
if (output) {
|
|
298
|
+
const metadata = isRecord(output.metadata) ? output.metadata : undefined;
|
|
299
|
+
onUsage(metadata?.usage);
|
|
300
|
+
}
|
|
301
|
+
for (const child of Object.values(value)) {
|
|
302
|
+
if (isRecord(child)) collectTrace(child, onUsage);
|
|
303
|
+
else if (Array.isArray(child)) child.forEach((item) => collectTrace(item, onUsage));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
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)) {
|
|
311
|
+
const found = findKey(child, key);
|
|
312
|
+
if (found !== undefined) return found;
|
|
313
|
+
}
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
package/src/agents.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BedrockAgentRuntimeClient } from "@aws-sdk/client-bedrock-agent-runtime";
|
|
2
|
+
|
|
3
|
+
import { AGENT_HANDLERS } from "./internal-handlers.ts";
|
|
4
|
+
import {
|
|
5
|
+
createInstrumentedSend,
|
|
6
|
+
type BedrockInstrumentationOptions,
|
|
7
|
+
type SendFn,
|
|
8
|
+
} from "./internal.ts";
|
|
9
|
+
|
|
10
|
+
export type { BedrockInstrumentationOptions } from "./internal.ts";
|
|
11
|
+
|
|
12
|
+
export interface WrappableBedrockAgentClient {
|
|
13
|
+
send: (...args: never[]) => unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const WRAPPED = new WeakSet<object>();
|
|
17
|
+
let ORIGINAL: { proto: object; hadOwn: boolean; value: unknown; wrapper: SendFn } | undefined;
|
|
18
|
+
|
|
19
|
+
export function wrapBedrockAgents<T extends WrappableBedrockAgentClient>(
|
|
20
|
+
client: T,
|
|
21
|
+
options: BedrockInstrumentationOptions = {},
|
|
22
|
+
): T {
|
|
23
|
+
if (WRAPPED.has(client as object)) return client;
|
|
24
|
+
const original = client.send as SendFn;
|
|
25
|
+
Object.defineProperty(client, "send", {
|
|
26
|
+
value: createInstrumentedSend(original, options, AGENT_HANDLERS),
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
});
|
|
30
|
+
WRAPPED.add(client as object);
|
|
31
|
+
return client;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function instrumentBedrockAgents(options: BedrockInstrumentationOptions = {}): void {
|
|
35
|
+
if (ORIGINAL) return;
|
|
36
|
+
const proto = BedrockAgentRuntimeClient.prototype as unknown as { send: SendFn };
|
|
37
|
+
const hadOwn = Object.prototype.hasOwnProperty.call(proto, "send");
|
|
38
|
+
const original = proto.send;
|
|
39
|
+
const instrumentedSend = createInstrumentedSend(original, options, AGENT_HANDLERS);
|
|
40
|
+
const wrapper = function telemetryDevBedrockAgentSend(
|
|
41
|
+
this: WrappableBedrockAgentClient,
|
|
42
|
+
...args: unknown[]
|
|
43
|
+
) {
|
|
44
|
+
if (WRAPPED.has(this as object)) return original.apply(this, args);
|
|
45
|
+
return instrumentedSend.apply(this, args);
|
|
46
|
+
};
|
|
47
|
+
ORIGINAL = { proto, hadOwn, value: original, wrapper };
|
|
48
|
+
Object.defineProperty(proto, "send", {
|
|
49
|
+
configurable: true,
|
|
50
|
+
writable: true,
|
|
51
|
+
value: wrapper,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function uninstrumentBedrockAgents(): void {
|
|
56
|
+
const original = ORIGINAL;
|
|
57
|
+
if (!original) return;
|
|
58
|
+
if (Object.getOwnPropertyDescriptor(original.proto, "send")?.value !== original.wrapper) return;
|
|
59
|
+
ORIGINAL = undefined;
|
|
60
|
+
if (original.hadOwn) {
|
|
61
|
+
Object.defineProperty(original.proto, "send", {
|
|
62
|
+
configurable: true,
|
|
63
|
+
writable: true,
|
|
64
|
+
value: original.value,
|
|
65
|
+
});
|
|
66
|
+
} else {
|
|
67
|
+
Reflect.deleteProperty(original.proto, "send");
|
|
68
|
+
}
|
|
69
|
+
}
|