Skip to content

Commit 4f599a3

Browse files
committed
suppress the exception from unspported InvokeModel streaming APIs
1 parent 47b7770 commit 4f599a3

File tree

2 files changed

+28
-61
lines changed
  • aws-distro-opentelemetry-node-autoinstrumentation/test/patches/aws/services
  • sample-applications/simple-express-server

2 files changed

+28
-61
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/test/patches/aws/services/bedrock.test.ts

Lines changed: 26 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -738,53 +738,15 @@ describe('BedrockRuntime', () => {
738738
});
739739

740740
describe('Response Body Type Handling', () => {
741-
it('handles string response body correctly', async () => {
741+
it('handles normal Anthropic Claude response correctly', async () => {
742742
const modelId: string = 'anthropic.claude-3-5-sonnet-20240620-v1:0';
743743
const mockRequestBody: string = JSON.stringify({
744744
anthropic_version: 'bedrock-2023-05-31',
745745
max_tokens: 1000,
746746
messages: [{ role: 'user', content: [{ type: 'text', text: 'test' }] }],
747747
});
748748

749-
// Mock response body as already converted string
750-
const mockResponseBodyString = JSON.stringify({
751-
stop_reason: 'end_turn',
752-
usage: { input_tokens: 15, output_tokens: 13 },
753-
});
754-
755-
nock(`https://bedrock-runtime.${region}.amazonaws.com`)
756-
.post(`/model/${encodeURIComponent(modelId)}/invoke`)
757-
.reply(200, mockResponseBodyString);
758-
759-
await bedrock
760-
.invokeModel({
761-
modelId: modelId,
762-
body: mockRequestBody,
763-
})
764-
.catch((err: any) => {});
765-
766-
const testSpans: ReadableSpan[] = getTestSpans();
767-
const invokeModelSpans: ReadableSpan[] = testSpans.filter((s: ReadableSpan) => {
768-
return s.name === 'BedrockRuntime.InvokeModel';
769-
});
770-
expect(invokeModelSpans.length).toBe(1);
771-
const invokeModelSpan = invokeModelSpans[0];
772-
773-
// Verify attributes are set correctly despite body being a string
774-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_INPUT_TOKENS]).toBe(15);
775-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_OUTPUT_TOKENS]).toBe(13);
776-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_RESPONSE_FINISH_REASONS]).toEqual(['end_turn']);
777-
});
778-
779-
it('handles Anthropic Claude response body correctly', async () => {
780-
const modelId: string = 'anthropic.claude-3-5-sonnet-20240620-v1:0';
781-
const mockRequestBody: string = JSON.stringify({
782-
anthropic_version: 'bedrock-2023-05-31',
783-
max_tokens: 1000,
784-
messages: [{ role: 'user', content: [{ type: 'text', text: 'test' }] }],
785-
});
786-
787-
// Mock response body - use standard object format (AWS SDK will handle type conversion)
749+
// Use standard object format - AWS SDK and instrumentation will handle the conversion
788750
const mockResponseBodyObj = {
789751
stop_reason: 'end_turn',
790752
usage: { input_tokens: 20, output_tokens: 15 },
@@ -814,24 +776,18 @@ describe('BedrockRuntime', () => {
814776
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_RESPONSE_FINISH_REASONS]).toEqual(['end_turn']);
815777
});
816778

817-
it('handles Buffer response body correctly', async () => {
779+
it('handles unexpected body type gracefully', async () => {
818780
const modelId: string = 'anthropic.claude-3-5-sonnet-20240620-v1:0';
819781
const mockRequestBody: string = JSON.stringify({
820782
anthropic_version: 'bedrock-2023-05-31',
821783
max_tokens: 1000,
822784
messages: [{ role: 'user', content: [{ type: 'text', text: 'test' }] }],
823785
});
824786

825-
// Mock response body as Buffer
826-
const mockResponseBodyObj = {
827-
stop_reason: 'max_tokens',
828-
usage: { input_tokens: 25, output_tokens: 18 },
829-
};
830-
const mockResponseBodyBuffer = Buffer.from(JSON.stringify(mockResponseBodyObj), 'utf8');
831-
787+
// Mock response body as unexpected type - using reply function to return a number
832788
nock(`https://bedrock-runtime.${region}.amazonaws.com`)
833789
.post(`/model/${encodeURIComponent(modelId)}/invoke`)
834-
.reply(200, mockResponseBodyBuffer);
790+
.reply(200, () => 12345 as any);
835791

836792
await bedrock
837793
.invokeModel({
@@ -847,26 +803,35 @@ describe('BedrockRuntime', () => {
847803
expect(invokeModelSpans.length).toBe(1);
848804
const invokeModelSpan = invokeModelSpans[0];
849805

850-
// Verify attributes are set correctly when body is Buffer
851-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_INPUT_TOKENS]).toBe(25);
852-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_OUTPUT_TOKENS]).toBe(18);
853-
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_RESPONSE_FINISH_REASONS]).toEqual([
854-
'max_tokens',
855-
]);
806+
// Verify that no AI attributes are set when body type is unexpected
807+
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_INPUT_TOKENS]).toBeUndefined();
808+
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_OUTPUT_TOKENS]).toBeUndefined();
809+
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_RESPONSE_FINISH_REASONS]).toBeUndefined();
810+
811+
// Note: We can't easily test diag.debug() output in unit tests, but the important part
812+
// is that the function returns early and doesn't crash when encountering unexpected types
813+
// Debug message will be: "Unexpected body type in Bedrock response: number for commandName InvokeModelCommand"
856814
});
857815

858-
it('handles unexpected body type gracefully', async () => {
816+
it('handles streaming response (SmithyMessageDecoderStream) gracefully', async () => {
859817
const modelId: string = 'anthropic.claude-3-5-sonnet-20240620-v1:0';
860818
const mockRequestBody: string = JSON.stringify({
861819
anthropic_version: 'bedrock-2023-05-31',
862820
max_tokens: 1000,
863821
messages: [{ role: 'user', content: [{ type: 'text', text: 'test' }] }],
864822
});
865823

866-
// Mock response body as unexpected type - using reply function to return a number
824+
// Mock response body as streaming object (constructor name matching)
825+
const mockStreamingBody = {
826+
constructor: { name: 'SmithyMessageDecoderStream' },
827+
[Symbol.asyncIterator]: function* () {
828+
yield { chunk: { bytes: new TextEncoder().encode('{"type":"chunk"}') } };
829+
},
830+
};
831+
867832
nock(`https://bedrock-runtime.${region}.amazonaws.com`)
868833
.post(`/model/${encodeURIComponent(modelId)}/invoke`)
869-
.reply(200, () => 12345 as any);
834+
.reply(200, mockStreamingBody);
870835

871836
await bedrock
872837
.invokeModel({
@@ -882,13 +847,13 @@ describe('BedrockRuntime', () => {
882847
expect(invokeModelSpans.length).toBe(1);
883848
const invokeModelSpan = invokeModelSpans[0];
884849

885-
// Verify that no AI attributes are set when body type is unexpected
850+
// Verify that no AI attributes are set when body is streaming (metrics not available in initial response)
886851
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_INPUT_TOKENS]).toBeUndefined();
887852
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_USAGE_OUTPUT_TOKENS]).toBeUndefined();
888853
expect(invokeModelSpan.attributes[AwsSpanProcessingUtil.GEN_AI_RESPONSE_FINISH_REASONS]).toBeUndefined();
889854

890-
// Note: We can't easily test diag.debug() output in unit tests, but the important part
891-
// is that the function returns early and doesn't crash when encountering unexpected types
855+
// Streaming responses should be skipped gracefully without crashing
856+
// TODO: support InvokeModel Streaming API and Converse APIs later
892857
});
893858
});
894859
});

sample-applications/simple-express-server/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
"author": "",
1212
"license": "Apache-2.0",
1313
"dependencies": {
14+
"@aws-sdk/client-bedrock-runtime": "3.574.0",
1415
"@aws-sdk/client-dynamodb": "^3.621.0",
1516
"@aws-sdk/client-s3": "^3.621.0",
1617
"@aws-sdk/client-sqs": "^3.621.0",
1718
"@aws-sdk/lib-dynamodb": "^3.616.0",
19+
"@aws/aws-distro-opentelemetry-node-autoinstrumentation": "file:../../aws-distro-opentelemetry-node-autoinstrumentation",
1820
"@types/express": "^4.17.21",
1921
"@types/node": "^20.14.6",
2022
"body-parser": "^1.20.2",

0 commit comments

Comments
 (0)