Skip to content

Commit 5a244ee

Browse files
author
Yuriy
committed
chore(java-spring-ai-agents): upgrade AgentCore to 1.0.0-RC9 and refactor SigV4 signing
1 parent d31fb3f commit 5a244ee

6 files changed

Lines changed: 72 additions & 34 deletions

File tree

apps/java-spring-ai-agents/aiagent/pom.xml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,11 @@
5454
<dependency>
5555
<groupId>org.springaicommunity</groupId>
5656
<artifactId>spring-ai-agentcore-code-interpreter</artifactId>
57-
<version>1.0.0-RC8</version>
5857
</dependency>
5958
<!-- AgentCore Browser -->
6059
<dependency>
6160
<groupId>org.springaicommunity</groupId>
6261
<artifactId>spring-ai-agentcore-browser</artifactId>
63-
<version>1.0.0-RC8</version>
6462
</dependency>
6563
<!-- Bedrock Runtime SDK for web grounding -->
6664
<dependency>
@@ -80,13 +78,11 @@
8078
<dependency>
8179
<groupId>org.springaicommunity</groupId>
8280
<artifactId>spring-ai-agentcore-memory</artifactId>
83-
<version>1.0.0-RC8</version>
8481
</dependency>
8582
<!-- AgentCore dependencies -->
8683
<dependency>
8784
<groupId>org.springaicommunity</groupId>
8885
<artifactId>spring-ai-agentcore-runtime-starter</artifactId>
89-
<version>1.0.0-RC8</version>
9086
</dependency>
9187
<dependency>
9288
<groupId>org.springframework.boot</groupId>
@@ -133,7 +129,7 @@
133129
<dependency>
134130
<groupId>org.springaicommunity</groupId>
135131
<artifactId>spring-ai-agentcore-bom</artifactId>
136-
<version>1.0.0-RC8</version>
132+
<version>1.0.0-RC9</version>
137133
<type>pom</type>
138134
<scope>import</scope>
139135
</dependency>

apps/java-spring-ai-agents/aiagent/src/main/java/com/example/agent/ChatService.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.springframework.util.MimeType;
2727
import org.springframework.util.MimeTypeUtils;
2828
import reactor.core.publisher.Flux;
29-
import tools.jackson.databind.json.JsonMapper;
3029

3130
import java.util.ArrayList;
3231
import java.util.Base64;
@@ -48,8 +47,6 @@ public class ChatService {
4847
private final ChatClient documentClient;
4948
private final String documentModel;
5049

51-
private final JsonMapper jsonMapper = JsonMapper.builder().build();
52-
5350
private final ArtifactStore<GeneratedFile> browserArtifactStore;
5451
private final ArtifactStore<GeneratedFile> codeInterpreterArtifactStore;
5552

apps/java-spring-ai-agents/aiagent/src/main/java/com/example/agent/SigV4McpConfig.java

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.example.agent;
22

3-
import java.io.ByteArrayInputStream;
43
import java.util.Set;
54

65
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
@@ -9,10 +8,11 @@
98
import org.springframework.context.annotation.Bean;
109
import org.springframework.context.annotation.Configuration;
1110
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
12-
import software.amazon.awssdk.auth.signer.Aws4Signer;
13-
import software.amazon.awssdk.auth.signer.params.Aws4SignerParams;
14-
import software.amazon.awssdk.http.SdkHttpFullRequest;
11+
import software.amazon.awssdk.http.ContentStreamProvider;
1512
import software.amazon.awssdk.http.SdkHttpMethod;
13+
import software.amazon.awssdk.http.SdkHttpRequest;
14+
import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner;
15+
import software.amazon.awssdk.http.auth.spi.signer.SignedRequest;
1616
import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain;
1717

1818
@Configuration
@@ -23,31 +23,30 @@ public class SigV4McpConfig {
2323

2424
@Bean
2525
McpSyncHttpClientRequestCustomizer sigV4RequestCustomizer() {
26-
var signer = Aws4Signer.create();
27-
var credentialsProvider = DefaultCredentialsProvider.create();
26+
var signer = AwsV4HttpSigner.create();
27+
var credentialsProvider = DefaultCredentialsProvider.builder().build();
2828
var region = new DefaultAwsRegionProviderChain().getRegion();
2929
log.info("SigV4 MCP request customizer: region={}, service=bedrock-agentcore", region);
3030

3131
return (builder, method, endpoint, body, context) -> {
32-
byte[] bodyBytes = (body != null) ? body.getBytes(java.nio.charset.StandardCharsets.UTF_8) : null;
33-
34-
var sdkRequestBuilder = SdkHttpFullRequest.builder();
35-
sdkRequestBuilder.uri(endpoint);
36-
sdkRequestBuilder.method(SdkHttpMethod.valueOf(method));
37-
38-
if (bodyBytes != null && bodyBytes.length > 0) {
39-
sdkRequestBuilder.contentStreamProvider(() -> new ByteArrayInputStream(bodyBytes));
40-
sdkRequestBuilder.putHeader("Content-Length", String.valueOf(bodyBytes.length));
41-
}
42-
sdkRequestBuilder.putHeader("Content-Type", "application/json");
43-
44-
var signedRequest = signer.sign(sdkRequestBuilder.build(), Aws4SignerParams.builder()
45-
.signingName("bedrock-agentcore")
46-
.signingRegion(region)
47-
.awsCredentials(credentialsProvider.resolveCredentials())
48-
.build());
49-
50-
signedRequest.headers().forEach((name, values) -> {
32+
var httpRequest = SdkHttpRequest.builder()
33+
.uri(endpoint)
34+
.method(SdkHttpMethod.valueOf(method))
35+
.putHeader("Content-Type", "application/json")
36+
.build();
37+
38+
ContentStreamProvider payload = (body != null && !body.isEmpty())
39+
? ContentStreamProvider.fromUtf8String(body)
40+
: null;
41+
42+
SignedRequest signedRequest = signer.sign(r -> r
43+
.identity(credentialsProvider.resolveIdentity().join())
44+
.request(httpRequest)
45+
.payload(payload)
46+
.putProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, "bedrock-agentcore")
47+
.putProperty(AwsV4HttpSigner.REGION_NAME, region.id()));
48+
49+
signedRequest.request().headers().forEach((name, values) -> {
5150
if (!RESTRICTED_HEADERS.contains(name.toLowerCase())) {
5251
values.forEach(value -> builder.setHeader(name, value));
5352
}

apps/java-spring-ai-agents/aiagent/src/main/resources/application.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ spring.ai.bedrock.converse.chat.timeout=120s
99
spring.ai.bedrock.converse.chat.options.max-tokens=4096
1010
spring.ai.bedrock.converse.chat.options.model=global.anthropic.claude-sonnet-4-5-20250929-v1:0
1111
spring.ai.bedrock.converse.chat.options.temperature=0.7
12+
# AgentCore Browser - tool descriptions
13+
agentcore.browser.browse-url-description=Browse a web page and extract its text content. Returns the page title and body text. Use this to read and extract data from websites. For interactive sites, combine with fillForm and clickElement to navigate, then call browseUrl again to read the results.
14+
agentcore.browser.screenshot-description=Take a screenshot of a web page for the user to see. Does NOT return page content to you. Use browseUrl to extract data first, then takeScreenshot for visual evidence.

apps/java-spring-ai-agents/scripts/01-setup.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,49 @@ else
6060
~/environment/backoffice/src/main/resources/application.properties
6161
fi
6262

63+
# Create DynamoDB tables for backoffice
64+
if aws dynamodb describe-table --table-name "backoffice-trip" --region ${AWS_REGION} --no-cli-pager >/dev/null 2>&1; then
65+
echo "DynamoDB table backoffice-trip already exists"
66+
else
67+
echo "Creating DynamoDB table: backoffice-trip"
68+
aws dynamodb create-table \
69+
--table-name "backoffice-trip" \
70+
--attribute-definitions \
71+
AttributeName=pk,AttributeType=S \
72+
AttributeName=sk,AttributeType=S \
73+
AttributeName=tripReference,AttributeType=S \
74+
--key-schema AttributeName=pk,KeyType=HASH AttributeName=sk,KeyType=RANGE \
75+
--global-secondary-indexes \
76+
"IndexName=tripReference-index,KeySchema=[{AttributeName=tripReference,KeyType=HASH}],Projection={ProjectionType=ALL}" \
77+
--billing-mode PAY_PER_REQUEST \
78+
--region ${AWS_REGION} \
79+
--no-cli-pager
80+
aws dynamodb wait table-exists --table-name "backoffice-trip" --region ${AWS_REGION}
81+
echo "Table created: backoffice-trip"
82+
fi
83+
84+
if aws dynamodb describe-table --table-name "backoffice-expense" --region ${AWS_REGION} --no-cli-pager >/dev/null 2>&1; then
85+
echo "DynamoDB table backoffice-expense already exists"
86+
else
87+
echo "Creating DynamoDB table: backoffice-expense"
88+
aws dynamodb create-table \
89+
--table-name "backoffice-expense" \
90+
--attribute-definitions \
91+
AttributeName=pk,AttributeType=S \
92+
AttributeName=sk,AttributeType=S \
93+
AttributeName=expenseReference,AttributeType=S \
94+
AttributeName=tripReference,AttributeType=S \
95+
--key-schema AttributeName=pk,KeyType=HASH AttributeName=sk,KeyType=RANGE \
96+
--global-secondary-indexes \
97+
"IndexName=expenseReference-index,KeySchema=[{AttributeName=expenseReference,KeyType=HASH}],Projection={ProjectionType=ALL}" \
98+
"IndexName=tripReference-index,KeySchema=[{AttributeName=tripReference,KeyType=HASH}],Projection={ProjectionType=ALL}" \
99+
--billing-mode PAY_PER_REQUEST \
100+
--region ${AWS_REGION} \
101+
--no-cli-pager
102+
aws dynamodb wait table-exists --table-name "backoffice-expense" --region ${AWS_REGION}
103+
echo "Table created: backoffice-expense"
104+
fi
105+
63106
# Verify required environment variables
64107
if [ -z "${AWS_REGION}" ]; then
65108
echo "Error: AWS_REGION is not set"

apps/java-spring-ai-agents/scripts/99-cleanup.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ fi
402402
echo ""
403403
echo "## Deleting DynamoDB tables"
404404

405-
for TABLE in backoffice-trips backoffice-expenses; do
405+
for TABLE in backoffice-trip backoffice-expense; do
406406
delete_resource "${TABLE}" \
407407
"aws dynamodb describe-table --table-name ${TABLE} --region ${AWS_REGION} --no-cli-pager" \
408408
"aws dynamodb delete-table --table-name ${TABLE} --region ${AWS_REGION} --no-cli-pager"

0 commit comments

Comments
 (0)