diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index 36cb8c49cab..28d79200b30 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -1236,6 +1236,44 @@ bedrock-runtime_InvokeModelWithResponseStream_MistralAi: services: bedrock-runtime: {InvokeModelWithResponseStream} +# Reasoning +bedrock-runtime_Converse_AnthropicClaudeReasoning: + title: Use Anthropic Claude 3.7 Sonnet's reasoning capability on &BR; + title_abbrev: Reasoning + synopsis: use Anthropic Claude 3.7 Sonnet's reasoning capability on &BR; + category: Anthropic Claude + languages: + Java: + versions: + - sdk_version: 2 + github: javav2/example_code/bedrock-runtime + excerpts: + - description: Use Anthropic Claude 3.7 Sonnet's reasoning capability with the asynchronous Bedrock runtime client. + snippet_tags: + - bedrock-runtime.java2.ConverseAsync_AnthropicClaudeReasoning + - description: Use Anthropic Claude 3.7 Sonnet's reasoning capability with the synchronous Bedrock runtime client. + snippet_tags: + - bedrock-runtime.java2.Converse_AnthropicClaudeReasoning + services: + bedrock-runtime: {Converse} + +bedrock-runtime_ConverseStream_AnthropicClaudeReasoning: + title: Use Anthropic Claude 3.7 Sonnet's reasoning capability on &BR; + title_abbrev: Reasoning with a streaming response + synopsis: use Anthropic Claude 3.7 Sonnet's reasoning capability on &BR; + category: Anthropic Claude + languages: + Java: + versions: + - sdk_version: 2 + github: javav2/example_code/bedrock-runtime + excerpts: + - description: Use Anthropic Claude 3.7 Sonnet's reasoning capability to generate streaming text responses. + snippet_tags: + - bedrock-runtime.java2.ConverseStream_AnthropicClaudeReasoning + services: + bedrock-runtime: {Converse} + # Image Generation Models bedrock-runtime_InvokeModel_AmazonNovaImageGeneration: title: Invoke Amazon Nova Canvas on &BR; to generate an image diff --git a/javav2/example_code/bedrock-runtime/README.md b/javav2/example_code/bedrock-runtime/README.md index c1d78a43adb..3eda403f21e 100644 --- a/javav2/example_code/bedrock-runtime/README.md +++ b/javav2/example_code/bedrock-runtime/README.md @@ -17,6 +17,7 @@ _Amazon Bedrock Runtime is a fully managed service that makes it easy to use fou * This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). +**Note: This project uses JDK 21** ## Code examples @@ -68,6 +69,8 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javav - [ConverseStream](src/main/java/com/example/bedrockruntime/models/anthropicClaude/ConverseStream.java#L6) - [InvokeModel](src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModel.java#L6) - [InvokeModelWithResponseStream](src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModelWithResponseStream.java#L6) +- [Reasoning](src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningAsync.java#L6) +- [Reasoning with a streaming response](src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningStream.java#L6) ### Cohere Command diff --git a/javav2/example_code/bedrock-runtime/pom.xml b/javav2/example_code/bedrock-runtime/pom.xml index 00c9a86fcd3..146df37aa94 100644 --- a/javav2/example_code/bedrock-runtime/pom.xml +++ b/javav2/example_code/bedrock-runtime/pom.xml @@ -8,7 +8,7 @@ 1.0-SNAPSHOT UTF-8 - 17 + 21 ${java.version} ${java.version} @@ -30,7 +30,7 @@ software.amazon.awssdk bom - 2.30.22 + 2.30.27 pom import diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/amazonTitanText/InvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/amazonTitanText/InvokeModelWithResponseStream.java index cc92fe60903..084c00ef738 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/amazonTitanText/InvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/amazonTitanText/InvokeModelWithResponseStream.java @@ -22,7 +22,7 @@ public class InvokeModelWithResponseStream { - public static String invokeModelWithResponseStream() throws ExecutionException, InterruptedException { + public static String invokeModelWithResponseStream() { // Create a Bedrock Runtime client in the AWS Region you want to use. // Replace the DefaultCredentialsProvider with your preferred credentials provider. diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Converse.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Converse.java index 9d081761ca6..9c9e284a7df 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Converse.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Converse.java @@ -48,7 +48,7 @@ public static String converse() { .topP(0.9F))); // Retrieve the generated text from Bedrock's response object. - var responseText = response.output().message().content().get(0).text(); + var responseText = response.output().message().content().getFirst().text(); System.out.println(responseText); return responseText; diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ConverseAsync.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ConverseAsync.java index 3671c49f8b9..dca17e0545a 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ConverseAsync.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ConverseAsync.java @@ -55,7 +55,7 @@ public static String converseAsync() { request.whenComplete((response, error) -> { if (error == null) { // Extract the generated text from Bedrock's response object. - String responseText = response.output().message().content().get(0).text(); + String responseText = response.output().message().content().getFirst().text(); future.complete(responseText); } else { future.completeExceptionally(error); diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModelWithResponseStream.java index fd28435b0b0..ba0883c3769 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/InvokeModelWithResponseStream.java @@ -23,7 +23,7 @@ public class InvokeModelWithResponseStream { - public static String invokeModelWithResponseStream() throws ExecutionException, InterruptedException { + public static String invokeModelWithResponseStream() { // Create a Bedrock Runtime client in the AWS Region you want to use. // Replace the DefaultCredentialsProvider with your preferred credentials provider. diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Reasoning.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Reasoning.java new file mode 100644 index 00000000000..33077761c96 --- /dev/null +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/Reasoning.java @@ -0,0 +1,96 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.bedrockruntime.models.anthropicClaude; + +// snippet-start:[bedrock-runtime.java2.Converse_AnthropicClaudeReasoning] + +import com.example.bedrockruntime.models.anthropicClaude.lib.ReasoningResponse; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.core.document.Document; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient; +import software.amazon.awssdk.services.bedrockruntime.model.*; + +/** + * This example demonstrates how to use Anthropic Claude 3.7 Sonnet's reasoning capability + * with the synchronous Amazon Bedrock runtime client. + * It shows how to: + * - Set up the Amazon Bedrock runtime client + * - Create a message + * - Configure reasoning parameters + * - Send a request with reasoning enabled + * - Process both the reasoning output and final response + */ +public class Reasoning { + + public static ReasoningResponse reasoning() { + + // Create the Amazon Bedrock runtime client + var client = BedrockRuntimeClient.builder() + .credentialsProvider(DefaultCredentialsProvider.create()) + .region(Region.US_EAST_1) + .build(); + + // Specify the model ID. For the latest available models, see: + // https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html + var modelId = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"; + + // Create the message with the user's prompt + var prompt = "Describe the purpose of a 'hello world' program in one line."; + var message = Message.builder() + .content(ContentBlock.fromText(prompt)) + .role(ConversationRole.USER) + .build(); + + // Configure reasoning parameters with a 2000 token budget + Document reasoningConfig = Document.mapBuilder() + .putDocument("thinking", Document.mapBuilder() + .putString("type", "enabled") + .putNumber("budget_tokens", 2000) + .build()) + .build(); + + try { + // Send message and reasoning configuration to the model + ConverseResponse bedrockResponse = client.converse(request -> request + .additionalModelRequestFields(reasoningConfig) + .messages(message) + .modelId(modelId) + ); + + + // Extract both reasoning and final response + var content = bedrockResponse.output().message().content(); + ReasoningContentBlock reasoning = null; + String text = null; + + // Process each content block to find reasoning and response text + for (ContentBlock block : content) { + if (block.reasoningContent() != null) { + reasoning = block.reasoningContent(); + } else if (block.text() != null) { + text = block.text(); + } + } + + return new ReasoningResponse(reasoning, text); + + } catch (SdkClientException e) { + System.err.printf("ERROR: Can't invoke '%s'. Reason: %s", modelId, e.getMessage()); + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + // Execute the example and display reasoning and final response + ReasoningResponse response = reasoning(); + System.out.println("\n"); + System.out.println(response.reasoning().reasoningText()); + System.out.println("\n"); + System.out.println(response.text()); + } +} + +// snippet-end:[bedrock-runtime.java2.Converse_AnthropicClaudeReasoning] diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningAsync.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningAsync.java new file mode 100644 index 00000000000..6506f6df613 --- /dev/null +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningAsync.java @@ -0,0 +1,99 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.bedrockruntime.models.anthropicClaude; + +// snippet-start:[bedrock-runtime.java2.ConverseAsync_AnthropicClaudeReasoning] + +import com.example.bedrockruntime.models.anthropicClaude.lib.ReasoningResponse; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.core.document.Document; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeAsyncClient; +import software.amazon.awssdk.services.bedrockruntime.model.*; + +import java.util.concurrent.CompletableFuture; + +/** + * This example demonstrates how to use Anthropic Claude 3.7 Sonnet's reasoning capability + * with an asynchronous Amazon Bedrock runtime client. + * It shows how to: + * - Set up the Amazon Bedrock async runtime client + * - Create a message + * - Configure reasoning parameters + * - Send an asynchronous request with reasoning enabled + * - Process both the reasoning output and final response + */ +public class ReasoningAsync { + + public static ReasoningResponse reasoningAsync() { + + // Create the Amazon Bedrock runtime client + var client = BedrockRuntimeAsyncClient.builder() + .credentialsProvider(DefaultCredentialsProvider.create()) + .region(Region.US_EAST_1) + .build(); + + // Specify the model ID. For the latest available models, see: + // https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html + var modelId = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"; + + // Create the message with the user's prompt + var prompt = "Describe the purpose of a 'hello world' program in one line."; + var message = Message.builder() + .content(ContentBlock.fromText(prompt)) + .role(ConversationRole.USER) + .build(); + + // Configure reasoning parameters with a 2000 token budget + Document reasoningConfig = Document.mapBuilder() + .putDocument("thinking", Document.mapBuilder() + .putString("type", "enabled") + .putNumber("budget_tokens", 2000) + .build()) + .build(); + + try { + // Send message and reasoning configuration to the model + CompletableFuture asyncResponse = client.converse(request -> request + .additionalModelRequestFields(reasoningConfig) + .messages(message) + .modelId(modelId) + ); + + // Process the response asynchronously + return asyncResponse.thenApply(response -> { + + var content = response.output().message().content(); + ReasoningContentBlock reasoning = null; + String text = null; + + // Process each content block to find reasoning and response text + for (ContentBlock block : content) { + if (block.reasoningContent() != null) { + reasoning = block.reasoningContent(); + } else if (block.text() != null) { + text = block.text(); + } + } + + return new ReasoningResponse(reasoning, text); + } + ).get(); + + } catch (Exception e) { + System.err.printf("Can't invoke '%s': %s", modelId, e.getMessage()); + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + // Execute the example and display reasoning and final response + ReasoningResponse response = reasoningAsync(); + System.out.println("\n"); + System.out.println(response.reasoning().reasoningText()); + System.out.println("\n"); + System.out.println(response.text()); + } +} +// snippet-end:[bedrock-runtime.java2.ConverseAsync_AnthropicClaudeReasoning] diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningStream.java new file mode 100644 index 00000000000..8ef19566c30 --- /dev/null +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/ReasoningStream.java @@ -0,0 +1,119 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.bedrockruntime.models.anthropicClaude; + +// snippet-start:[bedrock-runtime.java2.ConverseStream_AnthropicClaudeReasoning] + +import com.example.bedrockruntime.models.anthropicClaude.lib.ReasoningResponse; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.core.document.Document; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeAsyncClient; +import software.amazon.awssdk.services.bedrockruntime.model.*; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +/** + * This example demonstrates how to use Anthropic Claude 3.7 Sonnet's reasoning + * capability to generate streaming text responses. + * It shows how to: + * - Set up the Amazon Bedrock runtime client + * - Create a message + * - Configure a streaming request + * - Set up a stream handler to process the response chunks + * - Process the streaming response + */ +public class ReasoningStream { + + public static ReasoningResponse reasoningStream() { + + // Create the Amazon Bedrock runtime client + var client = BedrockRuntimeAsyncClient.builder() + .credentialsProvider(DefaultCredentialsProvider.create()) + .region(Region.US_EAST_1) + .build(); + + // Specify the model ID. For the latest available models, see: + // https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html + var modelId = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"; + + // Create the message with the user's prompt + var prompt = "Describe the purpose of a 'hello world' program in one line."; + var message = Message.builder() + .content(ContentBlock.fromText(prompt)) + .role(ConversationRole.USER) + .build(); + + // Configure reasoning parameters with a 2000 token budget + Document reasoningConfig = Document.mapBuilder() + .putDocument("thinking", Document.mapBuilder() + .putString("type", "enabled") + .putNumber("budget_tokens", 2000) + .build()) + .build(); + + // Configure the request with the message, model ID, and reasoning config + ConverseStreamRequest request = ConverseStreamRequest.builder() + .additionalModelRequestFields(reasoningConfig) + .messages(message) + .modelId(modelId) + .build(); + + StringBuilder reasoning = new StringBuilder(); + StringBuilder text = new StringBuilder(); + AtomicReference finalresponse = new AtomicReference<>(); + + // Set up the stream handler to processes chunks of the response as they arrive + var streamHandler = ConverseStreamResponseHandler.builder() + .subscriber(ConverseStreamResponseHandler.Visitor.builder() + .onContentBlockDelta(chunk -> { + ContentBlockDelta delta = chunk.delta(); + if (delta.reasoningContent() != null) { + if (reasoning.isEmpty()) { + System.out.println("\n"); + } + if (delta.reasoningContent().text() != null) { + System.out.print(delta.reasoningContent().text()); + reasoning.append(delta.reasoningContent().text()); + } + } else if (delta.text() != null) { + if (text.isEmpty()) { + System.out.println("\n\n"); + } + System.out.print(delta.text()); + text.append(delta.text()); + } + System.out.flush(); // Ensure immediate output of each chunk + }).build()) + .onComplete(() -> finalresponse.set(new ReasoningResponse( + ReasoningContentBlock.fromReasoningText(t -> t.text(reasoning.toString())), + text.toString() + ))) + .onError(err -> System.err.printf("Can't invoke '%s': %s", modelId, err.getMessage())) + .build(); + + // Step 6: Send the streaming request and process the response + // - Send the request to the model + // - Attach the handler to process response chunks as they arrive + // - Handle any errors during streaming + try { + client.converseStream(request, streamHandler).get(); + return finalresponse.get(); + + } catch (ExecutionException | InterruptedException e) { + System.err.printf("Can't invoke '%s': %s", modelId, e.getCause().getMessage()); + throw new RuntimeException(e); + } catch (Exception e) { + System.err.printf("Can't invoke '%s': %s", modelId, e.getMessage()); + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + reasoningStream(); + } +} + +// snippet-end:[bedrock-runtime.java2.ConverseStream_AnthropicClaudeReasoning] \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/lib/ReasoningResponse.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/lib/ReasoningResponse.java new file mode 100644 index 00000000000..5ca58426ee3 --- /dev/null +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/anthropicClaude/lib/ReasoningResponse.java @@ -0,0 +1,16 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.bedrockruntime.models.anthropicClaude.lib; + +import software.amazon.awssdk.services.bedrockruntime.model.ReasoningContentBlock; + +/** + * Represents the dual-part response from Claude 3.7 with reasoning enabled. + * Contains both the model's internal reasoning process and the final response text. + * + * @param reasoning The ReasoningContentBlock containing Claude's detailed thinking process + * @param text The final concise response generated after reasoning + */ +public record ReasoningResponse(ReasoningContentBlock reasoning, String text) { +} diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_InvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_InvokeModelWithResponseStream.java index 7c1415f393d..1ca32fcf63b 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_InvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_InvokeModelWithResponseStream.java @@ -22,7 +22,7 @@ public class Command_InvokeModelWithResponseStream { - public static String invokeModelWithResponseStream() throws ExecutionException, InterruptedException { + public static String invokeModelWithResponseStream() { // Create a Bedrock Runtime client in the AWS Region you want to use. // Replace the DefaultCredentialsProvider with your preferred credentials provider. diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_R_InvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_R_InvokeModelWithResponseStream.java index 00d521190ea..c0a0a61a602 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_R_InvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/cohereCommand/Command_R_InvokeModelWithResponseStream.java @@ -22,7 +22,7 @@ public class Command_R_InvokeModelWithResponseStream { - public static String invokeModelWithResponseStream() throws ExecutionException, InterruptedException { + public static String invokeModelWithResponseStream() { // Create a Bedrock Runtime client in the AWS Region you want to use. // Replace the DefaultCredentialsProvider with your preferred credentials provider. diff --git a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/mistral/InvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/mistral/InvokeModelWithResponseStream.java index 5223e1bbbd8..e460e2fdc3e 100644 --- a/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/mistral/InvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/main/java/com/example/bedrockruntime/models/mistral/InvokeModelWithResponseStream.java @@ -22,7 +22,7 @@ public class InvokeModelWithResponseStream { - public static String invokeModelWithResponseStream() throws ExecutionException, InterruptedException { + public static String invokeModelWithResponseStream() { // Create a Bedrock Runtime client in the AWS Region you want to use. // Replace the DefaultCredentialsProvider with your preferred credentials provider. diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/AbstractModelTest.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/AbstractModelTest.java index 02861891fe6..1bc710bd4f8 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/AbstractModelTest.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/AbstractModelTest.java @@ -3,12 +3,12 @@ package actions; +import com.example.bedrockruntime.models.anthropicClaude.lib.ReasoningResponse; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import java.lang.reflect.InvocationTargetException; -import java.util.Objects; +import java.util.function.Supplier; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -23,42 +23,28 @@ public abstract class AbstractModelTest { protected abstract Stream modelProvider(); /** - * Provide the method name to test. - * Each concrete test class must implement this method. - */ - protected abstract String getMethodName(); - - /** - * Validates the result of the model invocation. - * Can be overridden by concrete classes if needed. + * Validates the model invocation result isn't empty. */ protected void validateResult(Object result, String modelName) { - if (result instanceof String) { - assertFalse(Objects.requireNonNull((String) result).trim().isEmpty(), - "Empty result from " + modelName); - } else if (result instanceof byte[]) { - assertNotEquals(0, Objects.requireNonNull((byte[]) result).length, - "Empty result from " + modelName); - } else { - fail("Unexpected result type from " + modelName + ": " + result.getClass()); + switch (result) { + case String s -> assertFalse(s.trim().isEmpty(), "Empty result from " + modelName); + case byte[] b -> assertNotEquals(0, b.length, "Empty result from " + modelName); + case ReasoningResponse r -> { + assertFalse(r.reasoning().reasoningText().text().trim().isEmpty(), "No reasoning text from " + modelName); + assertFalse(r.text().trim().isEmpty(), "No response text from " + modelName); + } + case null -> fail("Null result from " + modelName); + default -> fail("Unexpected result type from " + modelName + ": " + result.getClass()); } } @ParameterizedTest(name = "Test {0}") @MethodSource("modelProvider") void testModel(ModelTest model) { - try { - Object result = model.cls().getMethod(getMethodName()).invoke(null); - validateResult(result, model.name()); - - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - fail("Test failed for " + model.name() + ": " + cause.getMessage(), cause); - } catch (NoSuchMethodException | IllegalAccessException e) { - fail("Test configuration error for " + model.name() + ": " + e.getMessage(), e); - } + Object result = model.methodToCall.get(); + validateResult(result, model.name()); } - protected record ModelTest(String name, Class cls) { + protected record ModelTest(String name, Supplier methodToCall) { } } \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverse.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverse.java index 861379eb83b..ff0a87d27ff 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverse.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverse.java @@ -6,18 +6,14 @@ import java.util.stream.Stream; public class TestConverse extends AbstractModelTest { - protected String getMethodName() { - return "converse"; - } - protected Stream modelProvider() { return Stream.of( - new ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.Converse.class), - new ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Converse.class), - new ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.Converse.class), - new ModelTest("Mistral", com.example.bedrockruntime.models.mistral.Converse.class), - new ModelTest("NovaText", com.example.bedrockruntime.models.amazon.nova.text.Converse.class), - new ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.Converse.class) + new ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.Converse::converse), + new ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Converse::converse), + new ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.Converse::converse), + new ModelTest("Mistral", com.example.bedrockruntime.models.mistral.Converse::converse), + new ModelTest("NovaText", com.example.bedrockruntime.models.amazon.nova.text.Converse::converse), + new ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.Converse::converse) ); } } \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverseAsync.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverseAsync.java index ea814d33c7d..89193026375 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverseAsync.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestConverseAsync.java @@ -6,18 +6,14 @@ import java.util.stream.Stream; public class TestConverseAsync extends AbstractModelTest { - protected String getMethodName() { - return "converseAsync"; - } - - protected Stream modelProvider() { + protected Stream modelProvider() { return Stream.of( - new TestConverseAsync.ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.ConverseAsync.class), - new TestConverseAsync.ModelTest("NovaText", com.example.bedrockruntime.models.amazon.nova.text.ConverseAsync.class), - new TestConverseAsync.ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.ConverseAsync.class), - new TestConverseAsync.ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.ConverseAsync.class), - new TestConverseAsync.ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.ConverseAsync.class), - new TestConverseAsync.ModelTest("Mistral", com.example.bedrockruntime.models.mistral.ConverseAsync.class) + new ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.ConverseAsync::converseAsync), + new ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.ConverseAsync::converseAsync), + new ModelTest("NovaText", com.example.bedrockruntime.models.amazon.nova.text.ConverseAsync::converseAsync), + new ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.ConverseAsync::converseAsync), + new ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.ConverseAsync::converseAsync), + new ModelTest("Mistral", com.example.bedrockruntime.models.mistral.ConverseAsync::converseAsync) ); } } \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestImageGeneration.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestImageGeneration.java index 3ed2cf58f77..b45139b9ef4 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestImageGeneration.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestImageGeneration.java @@ -6,17 +6,11 @@ import java.util.stream.Stream; public class TestImageGeneration extends AbstractModelTest { - @Override - protected String getMethodName() { - return "invokeModel"; - } - - @Override protected Stream modelProvider() { return Stream.of( - new TestInvokeModel.ModelTest("NovaCanvas", com.example.bedrockruntime.models.amazon.nova.canvas.InvokeModel.class), - new TestInvokeModel.ModelTest("StableDiffusion", com.example.bedrockruntime.models.stabilityAi.InvokeModel.class), - new TestInvokeModel.ModelTest("TitanImage", com.example.bedrockruntime.models.amazonTitanText.InvokeModel.class) + new ModelTest("NovaCanvas", com.example.bedrockruntime.models.amazon.nova.canvas.InvokeModel::invokeModel), + new ModelTest("StableDiffusion", com.example.bedrockruntime.models.stabilityAi.InvokeModel::invokeModel), + new ModelTest("TitanImage", com.example.bedrockruntime.models.amazonTitanText.InvokeModel::invokeModel) ); } } \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModel.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModel.java index b80d83ea6ea..b86bdfe18b8 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModel.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModel.java @@ -6,20 +6,16 @@ import java.util.stream.Stream; public class TestInvokeModel extends AbstractModelTest { - protected String getMethodName() { - return "invokeModel"; - } - - protected Stream modelProvider() { + protected Stream modelProvider() { return Stream.of( - new TestInvokeModel.ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.InvokeModel.class), - new TestInvokeModel.ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Command_InvokeModel.class), - new TestInvokeModel.ModelTest("CohereCommandR", com.example.bedrockruntime.models.cohereCommand.Command_R_InvokeModel.class), - new TestInvokeModel.ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.InvokeModel.class), - new TestInvokeModel.ModelTest("Llama", com.example.bedrockruntime.models.metaLlama.Llama3_InvokeModel.class), - new TestInvokeModel.ModelTest("Mistral", com.example.bedrockruntime.models.mistral.InvokeModel.class), - new TestInvokeModel.ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.InvokeModel.class), - new TestInvokeModel.ModelTest("TitanTextEmbeddings", com.example.bedrockruntime.models.amazonTitanText.InvokeModel.class) + new ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.InvokeModel::invokeModel), + new ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Command_InvokeModel::invokeModel), + new ModelTest("CohereCommandR", com.example.bedrockruntime.models.cohereCommand.Command_R_InvokeModel::invokeModel), + new ModelTest("Jurassic2", com.example.bedrockruntime.models.ai21LabsJurassic2.InvokeModel::invokeModel), + new ModelTest("Llama", com.example.bedrockruntime.models.metaLlama.Llama3_InvokeModel::invokeModel), + new ModelTest("Mistral", com.example.bedrockruntime.models.mistral.InvokeModel::invokeModel), + new ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.InvokeModel::invokeModel), + new ModelTest("TitanTextEmbeddings", com.example.bedrockruntime.models.amazonTitanText.InvokeModel::invokeModel) ); } } \ No newline at end of file diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModelWithResponseStream.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModelWithResponseStream.java index 4fc4669e5e8..2f8bd717488 100644 --- a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModelWithResponseStream.java +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestInvokeModelWithResponseStream.java @@ -6,18 +6,14 @@ import java.util.stream.Stream; public class TestInvokeModelWithResponseStream extends AbstractModelTest { - protected String getMethodName() { - return "invokeModelWithResponseStream"; - } - protected Stream modelProvider() { return Stream.of( - new TestInvokeModel.ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.InvokeModelWithResponseStream.class), - new TestInvokeModel.ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Command_InvokeModelWithResponseStream.class), - new TestInvokeModel.ModelTest("CohereCommandR", com.example.bedrockruntime.models.cohereCommand.Command_R_InvokeModelWithResponseStream.class), - new TestInvokeModel.ModelTest("Llama", com.example.bedrockruntime.models.metaLlama.Llama3_InvokeModelWithResponseStream.class), - new TestInvokeModel.ModelTest("Mistral", com.example.bedrockruntime.models.mistral.InvokeModelWithResponseStream.class), - new TestInvokeModel.ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.InvokeModelWithResponseStream.class) + new ModelTest("Claude", com.example.bedrockruntime.models.anthropicClaude.InvokeModelWithResponseStream::invokeModelWithResponseStream), + new ModelTest("CohereCommand", com.example.bedrockruntime.models.cohereCommand.Command_InvokeModelWithResponseStream::invokeModelWithResponseStream), + new ModelTest("CohereCommandR", com.example.bedrockruntime.models.cohereCommand.Command_R_InvokeModelWithResponseStream::invokeModelWithResponseStream), + new ModelTest("Llama", com.example.bedrockruntime.models.metaLlama.Llama3_InvokeModelWithResponseStream::invokeModelWithResponseStream), + new ModelTest("Mistral", com.example.bedrockruntime.models.mistral.InvokeModelWithResponseStream::invokeModelWithResponseStream), + new ModelTest("TitanText", com.example.bedrockruntime.models.amazonTitanText.InvokeModelWithResponseStream::invokeModelWithResponseStream) ); } } diff --git a/javav2/example_code/bedrock-runtime/src/test/java/actions/TestReasoning.java b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestReasoning.java new file mode 100644 index 00000000000..e326b6f3f1e --- /dev/null +++ b/javav2/example_code/bedrock-runtime/src/test/java/actions/TestReasoning.java @@ -0,0 +1,16 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package actions; + +import java.util.stream.Stream; + +public class TestReasoning extends AbstractModelTest { + protected Stream modelProvider() { + return Stream.of( + new ModelTest("Claude 3.7 (sync)", com.example.bedrockruntime.models.anthropicClaude.Reasoning::reasoning), + new ModelTest("Claude 3.7 (async)", com.example.bedrockruntime.models.anthropicClaude.ReasoningAsync::reasoningAsync), + new ModelTest("Claude 3.7 (stream)", com.example.bedrockruntime.models.anthropicClaude.ReasoningStream::reasoningStream) + ); + } +} \ No newline at end of file