Skip to content

Commit 72c0562

Browse files
author
Yuriy Bezsonov
committed
feat(aiagent-agentcore): add currency conversion Lambda function
1 parent abad740 commit 72c0562

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.example</groupId>
8+
<artifactId>currency</artifactId>
9+
<version>1.0.0</version>
10+
<packaging>jar</packaging>
11+
12+
<name>Currency Tools Lambda</name>
13+
<description>AWS Lambda function for currency conversion</description>
14+
15+
<properties>
16+
<java.version>25</java.version>
17+
<maven.compiler.source>${java.version}</maven.compiler.source>
18+
<maven.compiler.target>${java.version}</maven.compiler.target>
19+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.amazonaws</groupId>
25+
<artifactId>aws-lambda-java-core</artifactId>
26+
<version>1.4.0</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>com.amazonaws</groupId>
30+
<artifactId>aws-lambda-java-events</artifactId>
31+
<version>3.16.1</version>
32+
</dependency>
33+
<dependency>
34+
<groupId>com.google.code.gson</groupId>
35+
<artifactId>gson</artifactId>
36+
<version>2.13.2</version>
37+
</dependency>
38+
</dependencies>
39+
40+
<build>
41+
<plugins>
42+
<plugin>
43+
<groupId>org.apache.maven.plugins</groupId>
44+
<artifactId>maven-compiler-plugin</artifactId>
45+
<version>3.13.0</version>
46+
<configuration>
47+
<release>${java.version}</release>
48+
</configuration>
49+
</plugin>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-shade-plugin</artifactId>
53+
<version>3.6.0</version>
54+
<executions>
55+
<execution>
56+
<phase>package</phase>
57+
<goals>
58+
<goal>shade</goal>
59+
</goals>
60+
<configuration>
61+
<createDependencyReducedPom>false</createDependencyReducedPom>
62+
<transformers>
63+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
64+
<mainClass>com.example.currency.CurrencyHandler</mainClass>
65+
</transformer>
66+
</transformers>
67+
</configuration>
68+
</execution>
69+
</executions>
70+
</plugin>
71+
</plugins>
72+
</build>
73+
</project>
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.example.currency;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import com.google.gson.Gson;
6+
import com.google.gson.JsonObject;
7+
8+
import java.net.URI;
9+
import java.net.http.HttpClient;
10+
import java.net.http.HttpRequest;
11+
import java.net.http.HttpResponse;
12+
import java.time.Duration;
13+
import java.util.Map;
14+
15+
/**
16+
* AWS Lambda handler for currency conversion tools.
17+
* Calls Frankfurter API for real-time exchange rates.
18+
*/
19+
public class CurrencyHandler implements RequestHandler<Map<String, Object>, Map<String, Object>> {
20+
21+
private static final String FRANKFURTER_API = "https://api.frankfurter.app";
22+
private static final HttpClient httpClient = HttpClient.newBuilder()
23+
.connectTimeout(Duration.ofSeconds(10))
24+
.build();
25+
private static final Gson gson = new Gson();
26+
27+
@Override
28+
public Map<String, Object> handleRequest(Map<String, Object> input, Context context) {
29+
// Log full input for debugging
30+
context.getLogger().log("Full input: " + gson.toJson(input));
31+
32+
// Gateway sends arguments directly, not wrapped in {name, arguments}
33+
// Detect tool from input structure:
34+
// - convertCurrency: has fromCurrency, toCurrency, amount
35+
// - getSupportedCurrencies: empty or no currency-related fields
36+
String toolName;
37+
Map<String, Object> arguments;
38+
39+
if (input.containsKey("name") && input.containsKey("arguments")) {
40+
// Direct invocation format: {name: "...", arguments: {...}}
41+
toolName = (String) input.get("name");
42+
if (toolName != null && toolName.contains("___")) {
43+
toolName = toolName.substring(toolName.indexOf("___") + 3);
44+
}
45+
@SuppressWarnings("unchecked")
46+
Map<String, Object> args = (Map<String, Object>) input.getOrDefault("arguments", Map.of());
47+
arguments = args;
48+
} else if (input.containsKey("fromCurrency") || input.containsKey("toCurrency") || input.containsKey("amount")) {
49+
// Gateway format for convertCurrency: arguments sent directly
50+
toolName = "convertCurrency";
51+
arguments = input;
52+
} else {
53+
// Gateway format for getSupportedCurrencies: empty or minimal input
54+
toolName = "getSupportedCurrencies";
55+
arguments = input;
56+
}
57+
58+
context.getLogger().log("Tool: " + toolName + ", Arguments: " + arguments);
59+
60+
try {
61+
return switch (toolName) {
62+
case "convertCurrency" -> convertCurrency(arguments);
63+
case "getSupportedCurrencies" -> getSupportedCurrencies();
64+
default -> Map.of("error", "Unknown tool: " + toolName);
65+
};
66+
} catch (Exception e) {
67+
context.getLogger().log("Error: " + e.getMessage());
68+
return Map.of("error", e.getMessage());
69+
}
70+
}
71+
72+
private Map<String, Object> convertCurrency(Map<String, Object> args) throws Exception {
73+
String from = ((String) args.get("fromCurrency")).toUpperCase().trim();
74+
String to = ((String) args.get("toCurrency")).toUpperCase().trim();
75+
double amount = ((Number) args.get("amount")).doubleValue();
76+
77+
if (from.equals(to)) {
78+
return Map.of("result", String.format("%.2f %s = %.2f %s (same currency)", amount, from, amount, to));
79+
}
80+
81+
String url = String.format("%s/latest?base=%s&symbols=%s", FRANKFURTER_API, from, to);
82+
HttpRequest request = HttpRequest.newBuilder()
83+
.uri(URI.create(url))
84+
.timeout(Duration.ofSeconds(10))
85+
.GET()
86+
.build();
87+
88+
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
89+
90+
if (response.statusCode() != 200) {
91+
return Map.of("error", "Currency API error: " + response.body());
92+
}
93+
94+
JsonObject json = gson.fromJson(response.body(), JsonObject.class);
95+
JsonObject rates = json.getAsJsonObject("rates");
96+
double rate = rates.get(to).getAsDouble();
97+
double converted = amount * rate;
98+
String date = json.get("date").getAsString();
99+
100+
String result = String.format(
101+
"%.2f %s = %.2f %s (rate: %.6f, date: %s)",
102+
amount, from, converted, to, rate, date
103+
);
104+
105+
return Map.of("result", result);
106+
}
107+
108+
private Map<String, Object> getSupportedCurrencies() throws Exception {
109+
String url = FRANKFURTER_API + "/currencies";
110+
HttpRequest request = HttpRequest.newBuilder()
111+
.uri(URI.create(url))
112+
.timeout(Duration.ofSeconds(10))
113+
.GET()
114+
.build();
115+
116+
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
117+
118+
if (response.statusCode() != 200) {
119+
return Map.of("error", "Currency API error: " + response.body());
120+
}
121+
122+
@SuppressWarnings("unchecked")
123+
Map<String, String> currencies = gson.fromJson(response.body(), Map.class);
124+
125+
StringBuilder sb = new StringBuilder("Supported currencies:\n");
126+
currencies.entrySet().stream()
127+
.sorted(Map.Entry.comparingByKey())
128+
.forEach(e -> sb.append(String.format("- %s: %s\n", e.getKey(), e.getValue())));
129+
130+
return Map.of("result", sb.toString().trim());
131+
}
132+
}

0 commit comments

Comments
 (0)