Skip to content

Commit 87a8236

Browse files
author
Yuriy Bezsonov
committed
feat(aiagent-agentcore): add backoffice tools and deployment scripts
1 parent 6491ed7 commit 87a8236

16 files changed

Lines changed: 2685 additions & 4 deletions
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.example.backoffice.expense;
2+
3+
import org.springframework.ai.tool.annotation.Tool;
4+
import org.springframework.ai.tool.annotation.ToolParam;
5+
import org.springframework.ai.tool.ToolCallbackProvider;
6+
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.stereotype.Component;
9+
10+
import java.math.BigDecimal;
11+
import java.time.LocalDate;
12+
import java.util.List;
13+
14+
@Component
15+
public class ExpenseTools {
16+
17+
private final ExpenseService service;
18+
19+
public ExpenseTools(ExpenseService service) {
20+
this.service = service;
21+
}
22+
23+
@Bean
24+
public ToolCallbackProvider expenseToolsProvider(ExpenseTools expenseTools) {
25+
return MethodToolCallbackProvider.builder()
26+
.toolObjects(expenseTools)
27+
.build();
28+
}
29+
30+
@Tool(description = "Create a new expense report. Optionally link to a trip.")
31+
public Expense createExpense(
32+
@ToolParam(description = "User ID") String userId,
33+
@ToolParam(description = "Amount") BigDecimal amount,
34+
@ToolParam(description = "Currency code (USD, EUR, etc.)") String currency,
35+
@ToolParam(description = "Expense date (YYYY-MM-DD)") LocalDate date,
36+
@ToolParam(description = "Description of expense") String description,
37+
@ToolParam(description = "Type: FLIGHT, HOTEL, MEALS, TRANSPORT, OTHER") Expense.ExpenseType type,
38+
@ToolParam(description = "Trip reference to link (optional, TRP-XXXXXXXX)") String tripReference) {
39+
return service.createExpense(userId, amount, currency, date, description, type, tripReference);
40+
}
41+
42+
@Tool(description = "Get all expenses for a user")
43+
public List<Expense> getExpenses(@ToolParam(description = "User ID") String userId) {
44+
return service.getExpenses(userId);
45+
}
46+
47+
@Tool(description = "Get expense details by reference number")
48+
public Expense getExpense(
49+
@ToolParam(description = "Expense reference (EXP-XXXXXXXX)") String expenseReference) {
50+
return service.getExpense(expenseReference);
51+
}
52+
53+
@Tool(description = "Get all expenses linked to a specific trip")
54+
public List<Expense> getExpensesForTrip(
55+
@ToolParam(description = "Trip reference (TRP-XXXXXXXX)") String tripReference) {
56+
return service.getExpensesForTrip(tripReference);
57+
}
58+
59+
@Tool(description = "Submit a draft expense for approval")
60+
public Expense submitExpense(
61+
@ToolParam(description = "Expense reference (EXP-XXXXXXXX)") String expenseReference) {
62+
return service.submitExpense(expenseReference);
63+
}
64+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.example.backoffice.trip;
2+
3+
import org.springframework.ai.tool.annotation.Tool;
4+
import org.springframework.ai.tool.annotation.ToolParam;
5+
import org.springframework.ai.tool.ToolCallbackProvider;
6+
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.stereotype.Component;
9+
10+
import java.time.LocalDate;
11+
import java.util.List;
12+
13+
@Component
14+
public class TripTools {
15+
16+
private final TripService service;
17+
18+
public TripTools(TripService service) {
19+
this.service = service;
20+
}
21+
22+
@Bean
23+
public ToolCallbackProvider tripToolsProvider(TripTools tripTools) {
24+
return MethodToolCallbackProvider.builder()
25+
.toolObjects(tripTools)
26+
.build();
27+
}
28+
29+
@Tool(description = "Register a new business trip. Returns trip reference for tracking.")
30+
public Trip registerTrip(
31+
@ToolParam(description = "User ID") String userId,
32+
@ToolParam(description = "Departure date (YYYY-MM-DD)") LocalDate departureDate,
33+
@ToolParam(description = "Return date (YYYY-MM-DD)") LocalDate returnDate,
34+
@ToolParam(description = "Origin city") String origin,
35+
@ToolParam(description = "Destination city") String destination,
36+
@ToolParam(description = "Trip purpose") String purpose) {
37+
return service.registerTrip(userId, departureDate, returnDate, origin, destination, purpose);
38+
}
39+
40+
@Tool(description = "Get all business trips registered by a user")
41+
public List<Trip> getTrips(@ToolParam(description = "User ID") String userId) {
42+
return service.getTrips(userId);
43+
}
44+
45+
@Tool(description = "Get trip details by reference number")
46+
public Trip getTrip(@ToolParam(description = "Trip reference (TRP-XXXXXXXX)") String tripReference) {
47+
return service.getTrip(tripReference);
48+
}
49+
50+
@Tool(description = "Cancel a planned trip")
51+
public Trip cancelTrip(@ToolParam(description = "Trip reference (TRP-XXXXXXXX)") String tripReference) {
52+
return service.cancelTrip(tripReference);
53+
}
54+
}

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

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "=============================================="
5+
echo "01-setup.sh - Environment Setup"
6+
echo "=============================================="
7+
8+
# Get account ID and region
9+
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text --no-cli-pager)
10+
AWS_REGION=$(aws configure get region)
11+
12+
echo "Account: ${ACCOUNT_ID}"
13+
echo "Region: ${AWS_REGION}"
14+
15+
## Creating the environment directory
16+
17+
echo ""
18+
echo "## Setting up environment"
19+
echo "1. Create environment directory and .envrc file"
20+
21+
mkdir -p ~/environment
22+
23+
if [ -f ~/environment/.envrc ]; then
24+
echo "Environment file already exists: ~/environment/.envrc"
25+
else
26+
echo "Creating environment file: ~/environment/.envrc"
27+
touch ~/environment/.envrc
28+
fi
29+
30+
## Copying application code
31+
32+
echo ""
33+
echo "2. Copy application code to ~/environment"
34+
35+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36+
37+
if [ -d ~/environment/aiagent ]; then
38+
echo "aiagent already exists in ~/environment"
39+
else
40+
echo "Copying aiagent..."
41+
cp -r "${SCRIPT_DIR}/../aiagent" ~/environment/aiagent
42+
fi
43+
44+
if [ -d ~/environment/backoffice ]; then
45+
echo "backoffice already exists in ~/environment"
46+
else
47+
echo "Copying backoffice (trip base)..."
48+
cp -r "${SCRIPT_DIR}/../backoffice/trip" ~/environment/backoffice
49+
50+
echo "Adding expense package..."
51+
cp -r "${SCRIPT_DIR}/../backoffice/expense" \
52+
~/environment/backoffice/src/main/java/com/example/backoffice/expense
53+
54+
echo "Adding TripTools.java..."
55+
cp "${SCRIPT_DIR}/../backoffice/tools/TripTools.java" \
56+
~/environment/backoffice/src/main/java/com/example/backoffice/trip/TripTools.java
57+
58+
echo "Adding ExpenseTools.java..."
59+
cp "${SCRIPT_DIR}/../backoffice/tools/ExpenseTools.java" \
60+
~/environment/backoffice/src/main/java/com/example/backoffice/expense/ExpenseTools.java
61+
fi
62+
63+
# Add basic variables if not present
64+
if ! grep -q "AWS_REGION=" ~/environment/.envrc 2>/dev/null; then
65+
echo "export AWS_REGION=${AWS_REGION}" >> ~/environment/.envrc
66+
fi
67+
68+
if ! grep -q "ACCOUNT_ID=" ~/environment/.envrc 2>/dev/null; then
69+
echo "export ACCOUNT_ID=${ACCOUNT_ID}" >> ~/environment/.envrc
70+
fi
71+
72+
## Setting up direnv
73+
74+
echo ""
75+
echo "3. Configure direnv"
76+
77+
if command -v direnv &> /dev/null; then
78+
cd ~/environment
79+
direnv allow .
80+
echo "direnv configured"
81+
else
82+
echo "Warning: direnv not installed. You'll need to source .envrc manually."
83+
fi
84+
85+
echo ""
86+
echo "=============================================="
87+
echo "Environment setup complete!"
88+
echo "=============================================="
89+
echo ""
90+
echo "Environment file: ~/environment/.envrc"
91+
echo "AWS_REGION=${AWS_REGION}"
92+
echo "ACCOUNT_ID=${ACCOUNT_ID}"
93+
echo ""
94+
echo "Next: Run 02-memory.sh to create AgentCore Memory"
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "=============================================="
5+
echo "02-memory.sh - AgentCore Memory Setup"
6+
echo "=============================================="
7+
8+
# Check if .envrc exists
9+
if [ ! -f ~/environment/.envrc ]; then
10+
echo "Creating ~/environment/.envrc"
11+
mkdir -p ~/environment
12+
touch ~/environment/.envrc
13+
fi
14+
15+
# Source existing environment
16+
source ~/environment/.envrc 2>/dev/null || true
17+
18+
## Creating the memory resource
19+
20+
# Check if memory already exists
21+
if [ -n "${AGENTCORE_MEMORY_MEMORY_ID}" ]; then
22+
echo "Memory resource already exists: ${AGENTCORE_MEMORY_MEMORY_ID}"
23+
MEMORY_STATUS=$(aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
24+
--no-cli-pager --query 'memory.status' --output text 2>/dev/null || echo "NOT_FOUND")
25+
26+
if [ "$MEMORY_STATUS" = "ACTIVE" ]; then
27+
echo "Memory resource is ACTIVE, skipping creation"
28+
elif [ "$MEMORY_STATUS" = "NOT_FOUND" ]; then
29+
echo "Memory resource not found, will create new one"
30+
unset AGENTCORE_MEMORY_MEMORY_ID
31+
else
32+
echo "Memory resource status: $MEMORY_STATUS"
33+
fi
34+
fi
35+
36+
if [ -z "${AGENTCORE_MEMORY_MEMORY_ID}" ]; then
37+
echo ""
38+
echo "## Creating the memory resource"
39+
echo "1. Create an AgentCore Memory resource and wait for it to become active (2-5 minutes)"
40+
41+
AGENTCORE_MEMORY_MEMORY_ID=$(aws bedrock-agentcore-control create-memory \
42+
--name "aiagent_memory" --event-expiry-duration 7 \
43+
--no-cli-pager --query "memory.id" --output text)
44+
echo "export AGENTCORE_MEMORY_MEMORY_ID=${AGENTCORE_MEMORY_MEMORY_ID}" >> ~/environment/.envrc
45+
echo "Created memory resource: ${AGENTCORE_MEMORY_MEMORY_ID}"
46+
47+
echo -n "Waiting for memory"
48+
while [ "$(aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
49+
--no-cli-pager --query 'memory.status' --output text)" != "ACTIVE" ]; do
50+
echo -n "."; sleep 5
51+
done && echo " ACTIVE"
52+
fi
53+
54+
## Adding LTM strategies
55+
56+
# Check if strategies already exist
57+
EXISTING_STRATEGIES=$(aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
58+
--no-cli-pager --query 'length(memory.strategies)' --output text 2>/dev/null || echo "0")
59+
60+
if [ "$EXISTING_STRATEGIES" -ge 2 ]; then
61+
echo ""
62+
echo "LTM strategies already configured (${EXISTING_STRATEGIES} strategies found)"
63+
else
64+
echo ""
65+
echo "2. Add LTM strategies and wait for them to become active"
66+
67+
aws bedrock-agentcore-control update-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" --no-cli-pager \
68+
--memory-strategies '{
69+
"addMemoryStrategies": [
70+
{"semanticMemoryStrategy": {"name": "SemanticFacts", "namespaces": ["/strategies/{memoryStrategyId}/actors/{actorId}"]}},
71+
{"userPreferenceMemoryStrategy": {"name": "UserPreferences", "namespaces": ["/strategies/{memoryStrategyId}/actors/{actorId}"]}}
72+
]
73+
}'
74+
75+
echo -n "Waiting for strategies"
76+
while aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
77+
--no-cli-pager --query 'memory.strategies[].status' --output text | grep -q "CREATING"; do
78+
echo -n "."; sleep 5
79+
done && echo " ACTIVE"
80+
fi
81+
82+
## Getting strategy IDs
83+
84+
echo ""
85+
echo "3. Get strategy IDs and save to environment file"
86+
87+
SEMANTIC_ID=$(aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
88+
--no-cli-pager --query "memory.strategies[?name=='SemanticFacts'].strategyId | [0]" --output text)
89+
PREFS_ID=$(aws bedrock-agentcore-control get-memory --memory-id "${AGENTCORE_MEMORY_MEMORY_ID}" \
90+
--no-cli-pager --query "memory.strategies[?name=='UserPreferences'].strategyId | [0]" --output text)
91+
92+
# Update .envrc only if values changed
93+
if ! grep -q "AGENTCORE_MEMORY_LONG_TERM_SEMANTIC_STRATEGY_ID=${SEMANTIC_ID}" ~/environment/.envrc 2>/dev/null; then
94+
# Remove old entries if they exist
95+
sed -i.bak '/AGENTCORE_MEMORY_LONG_TERM_SEMANTIC_STRATEGY_ID/d' ~/environment/.envrc 2>/dev/null || true
96+
echo "export AGENTCORE_MEMORY_LONG_TERM_SEMANTIC_STRATEGY_ID=${SEMANTIC_ID}" >> ~/environment/.envrc
97+
fi
98+
99+
if ! grep -q "AGENTCORE_MEMORY_LONG_TERM_USER_PREFERENCE_STRATEGY_ID=${PREFS_ID}" ~/environment/.envrc 2>/dev/null; then
100+
# Remove old entries if they exist
101+
sed -i.bak '/AGENTCORE_MEMORY_LONG_TERM_USER_PREFERENCE_STRATEGY_ID/d' ~/environment/.envrc 2>/dev/null || true
102+
echo "export AGENTCORE_MEMORY_LONG_TERM_USER_PREFERENCE_STRATEGY_ID=${PREFS_ID}" >> ~/environment/.envrc
103+
fi
104+
105+
# Clean up backup files
106+
rm -f ~/environment/.envrc.bak
107+
108+
echo ""
109+
echo "=============================================="
110+
echo "Memory setup complete!"
111+
echo "=============================================="
112+
echo ""
113+
echo "Environment variables saved to ~/environment/.envrc:"
114+
echo " AGENTCORE_MEMORY_MEMORY_ID=${AGENTCORE_MEMORY_MEMORY_ID}"
115+
echo " AGENTCORE_MEMORY_LONG_TERM_SEMANTIC_STRATEGY_ID=${SEMANTIC_ID}"
116+
echo " AGENTCORE_MEMORY_LONG_TERM_USER_PREFERENCE_STRATEGY_ID=${PREFS_ID}"

0 commit comments

Comments
 (0)