Skip to content

Commit 08b4d93

Browse files
authored
AWS Bedrock support (#285)
1 parent 1cdef4e commit 08b4d93

File tree

29 files changed

+2684
-33
lines changed

29 files changed

+2684
-33
lines changed

examples/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ dependencies {
2929
api(project(":prompt:prompt-structure"))
3030
api(project(":prompt:prompt-executor:prompt-executor-clients:prompt-executor-openai-client"))
3131
api(project(":prompt:prompt-executor:prompt-executor-clients:prompt-executor-anthropic-client"))
32+
api(project(":prompt:prompt-executor:prompt-executor-clients:prompt-executor-bedrock-client"))
3233
api(project(":prompt:prompt-executor:prompt-executor-llms"))
3334
api(project(":prompt:prompt-executor:prompt-executor-llms-all"))
3435

@@ -80,6 +81,7 @@ registerRunExampleTask("runExampleInstagramPostDescriber", "ai.koog.agents.examp
8081
registerRunExampleTask("runExampleRoutingViaGraph", "ai.koog.agents.example.banking.routing.RoutingViaGraphKt")
8182
registerRunExampleTask("runExampleRoutingViaAgentsAsTools", "ai.koog.agents.example.banking.routing.RoutingViaAgentsAsToolsKt")
8283
registerRunExampleTask("runExampleFeatureOpenTelemetry", "ai.koog.agents.example.feature.OpenTelemetryKt")
84+
registerRunExampleTask("runExampleBedrockAgent", "ai.koog.agents.example.client.BedrockAgentKt")
8385

8486
dokka {
8587
dokkaSourceSets.named("main") {

examples/env.template.properties

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@
66

77
OPENAI_API_KEY=
88

9-
ANTHROPIC_API_KEY=
9+
ANTHROPIC_API_KEY=
10+
11+
AWS_ACCESS_KEY_ID=
12+
AWS_SECRET_ACCESS_KEY=

examples/src/main/kotlin/ai/koog/agents/example/ApiKeyService.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,10 @@ internal object ApiKeyService {
1212

1313
val openRouterApiKey: String
1414
get() = System.getenv("OPENROUTER_API_KEY") ?: throw IllegalArgumentException("OPENROUTER_API_KEY env is not set")
15+
16+
val awsAccessKey: String
17+
get() = System.getenv("AWS_ACCESS_KEY_ID") ?: throw IllegalArgumentException("AWS_ACCESS_KEY_ID env is not set")
18+
19+
val awsSecretAccessKey: String
20+
get() = System.getenv("AWS_SECRET_ACCESS_KEY") ?: throw IllegalArgumentException("AWS_SECRET_ACCESS_KEY env is not set")
1521
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package ai.koog.agents.example.client
2+
3+
import ai.koog.agents.core.agent.AIAgent
4+
import ai.koog.agents.core.tools.ToolRegistry
5+
import ai.koog.agents.core.tools.reflect.asTools
6+
import ai.koog.agents.example.ApiKeyService
7+
import ai.koog.agents.example.simpleapi.Switch
8+
import ai.koog.agents.example.simpleapi.SwitchTools
9+
import ai.koog.prompt.executor.clients.bedrock.BedrockClientSettings
10+
import ai.koog.prompt.executor.clients.bedrock.BedrockModels
11+
import ai.koog.prompt.executor.llms.all.simpleBedrockExecutor
12+
import kotlinx.coroutines.runBlocking
13+
14+
fun main(): Unit = runBlocking {
15+
val switch = Switch()
16+
17+
val toolRegistry = ToolRegistry {
18+
tools(SwitchTools(switch).asTools())
19+
}
20+
21+
// Create Bedrock client settings
22+
val bedrockSettings = BedrockClientSettings(
23+
region = "us-east-1", // Change this to your preferred region
24+
maxRetries = 3
25+
)
26+
27+
// Create Bedrock LLM client
28+
val executor = simpleBedrockExecutor(
29+
awsAccessKeyId = ApiKeyService.awsAccessKey,
30+
awsSecretAccessKey = ApiKeyService.awsSecretAccessKey,
31+
settings = bedrockSettings
32+
)
33+
34+
val agent = AIAgent(
35+
executor = executor,
36+
llmModel = BedrockModels.AnthropicClaude35SonnetV2, // Use Claude 3.5 Sonnet
37+
systemPrompt = "You're responsible for running a Switch and perform operations on it by request",
38+
temperature = 0.0,
39+
toolRegistry = toolRegistry
40+
)
41+
42+
println("Bedrock Agent with Switch Tools - Chat started")
43+
println("You can ask me to turn the switch on/off or check its current state.")
44+
println("Type your request:")
45+
46+
val input = readln()
47+
agent.run(input)
48+
}

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ kover = "0.9.1"
2121
spring-boot = "3.5.3"
2222
spring-management = "1.1.7"
2323
opentelemetry = "1.51.0"
24+
aws-sdk-kotlin = "1.4.119"
2425

2526
[libraries]
2627
jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" }
@@ -55,6 +56,7 @@ opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref
5556
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" }
5657
opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp" }
5758
opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging" }
59+
aws-sdk-kotlin-bedrockruntime = { module = "aws.sdk.kotlin:bedrockruntime", version.ref = "aws-sdk-kotlin" }
5860

5961
# Spring
6062
spring-boot-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot" }

koog-agents/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ val included = setOf(
3939
":prompt:prompt-executor:prompt-executor-clients:prompt-executor-openai-client",
4040
":prompt:prompt-executor:prompt-executor-clients:prompt-executor-openrouter-client",
4141
":prompt:prompt-executor:prompt-executor-clients:prompt-executor-ollama-client",
42+
":prompt:prompt-executor:prompt-executor-clients:prompt-executor-bedrock-client",
4243
":prompt:prompt-executor:prompt-executor-llms",
4344
":prompt:prompt-executor:prompt-executor-llms-all",
4445
":prompt:prompt-executor:prompt-executor-model",

prompt/prompt-executor/prompt-executor-clients/prompt-executor-anthropic-client/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ kotlin {
5454
}
5555

5656
explicitApi()
57+
compilerOptions {
58+
freeCompilerArgs.add("-opt-in=ai.koog.prompt.executor.clients.InternalLLMClientApi")
59+
}
5760
}
5861

5962
publishToMaven()
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package ai.koog.prompt.executor.clients.anthropic
22

3+
import ai.koog.prompt.executor.clients.InternalLLMClientApi
34
import kotlinx.serialization.EncodeDefault
45
import kotlinx.serialization.EncodeDefault.Mode.ALWAYS
56
import kotlinx.serialization.SerialName
67
import kotlinx.serialization.Serializable
78
import kotlinx.serialization.json.JsonObject
89

10+
@InternalLLMClientApi
911
@Serializable
10-
internal data class AnthropicMessageRequest(
12+
public data class AnthropicMessageRequest(
1113
val model: String,
1214
val messages: List<AnthropicMessage>,
1315
val maxTokens: Int = 2048,
@@ -18,90 +20,98 @@ internal data class AnthropicMessageRequest(
1820
val toolChoice: AnthropicToolChoice? = null,
1921
)
2022

23+
@InternalLLMClientApi
2124
@Serializable
22-
internal data class AnthropicMessage(
25+
public data class AnthropicMessage(
2326
val role: String,
2427
val content: List<AnthropicContent>
2528
)
2629

30+
@InternalLLMClientApi
2731
@Serializable
28-
internal data class SystemAnthropicMessage(
32+
public data class SystemAnthropicMessage(
2933
val text: String,
3034
@EncodeDefault(ALWAYS) val type: String = "text"
3135
)
3236

37+
@InternalLLMClientApi
3338
@Serializable
34-
internal sealed class AnthropicContent {
39+
public sealed class AnthropicContent {
3540
@Serializable
3641
@SerialName("text")
37-
data class Text(val text: String) : AnthropicContent()
42+
public data class Text(val text: String) : AnthropicContent()
3843

3944
@Serializable
4045
@SerialName("image")
41-
data class Image(val source: ImageSource) : AnthropicContent()
46+
public data class Image(val source: ImageSource) : AnthropicContent()
4247

4348
@Serializable
4449
@SerialName("document")
45-
data class Document(val source: DocumentSource) : AnthropicContent()
50+
public data class Document(val source: DocumentSource) : AnthropicContent()
4651

4752
@Serializable
4853
@SerialName("tool_use")
49-
data class ToolUse(
54+
public data class ToolUse(
5055
val id: String,
5156
val name: String,
5257
val input: JsonObject
5358
) : AnthropicContent()
5459

5560
@Serializable
5661
@SerialName("tool_result")
57-
data class ToolResult(
62+
public data class ToolResult(
5863
val toolUseId: String,
5964
val content: String
6065
) : AnthropicContent()
6166
}
6267

68+
@InternalLLMClientApi
6369
@Serializable
64-
internal sealed interface ImageSource {
70+
public sealed interface ImageSource {
6571
@Serializable
6672
@SerialName("url")
67-
data class Url(val url: String) : ImageSource
73+
public data class Url(val url: String) : ImageSource
6874

6975
@Serializable
7076
@SerialName("base64")
71-
data class Base64(val data: String, val mediaType: String) : ImageSource
77+
public data class Base64(val data: String, val mediaType: String) : ImageSource
7278
}
7379

80+
@InternalLLMClientApi
7481
@Serializable
75-
internal sealed interface DocumentSource {
82+
public sealed interface DocumentSource {
7683
@Serializable
7784
@SerialName("url")
78-
data class Url(val url: String) : DocumentSource
85+
public data class Url(val url: String) : DocumentSource
7986

8087
@Serializable
8188
@SerialName("base64")
82-
data class Base64(val data: String, val mediaType: String) : DocumentSource
89+
public data class Base64(val data: String, val mediaType: String) : DocumentSource
8390

8491
@Serializable
8592
@SerialName("text")
86-
data class PlainText(val data: String, val mediaType: String) : DocumentSource
93+
public data class PlainText(val data: String, val mediaType: String) : DocumentSource
8794
}
8895

96+
@InternalLLMClientApi
8997
@Serializable
90-
internal data class AnthropicTool(
98+
public data class AnthropicTool(
9199
val name: String,
92100
val description: String,
93101
val inputSchema: AnthropicToolSchema
94102
)
95103

104+
@InternalLLMClientApi
96105
@Serializable
97-
internal data class AnthropicToolSchema(
106+
public data class AnthropicToolSchema(
98107
val type: String = "object",
99108
val properties: JsonObject,
100109
val required: List<String>
101110
)
102111

112+
@InternalLLMClientApi
103113
@Serializable
104-
internal data class AnthropicResponse(
114+
public data class AnthropicResponse(
105115
val id: String,
106116
val type: String,
107117
val role: String,
@@ -111,57 +121,62 @@ internal data class AnthropicResponse(
111121
val usage: AnthropicUsage? = null
112122
)
113123

124+
@InternalLLMClientApi
114125
@Serializable
115-
internal sealed class AnthropicResponseContent {
126+
public sealed class AnthropicResponseContent {
116127
@Serializable
117128
@SerialName("text")
118-
data class Text(val text: String) : AnthropicResponseContent()
129+
public data class Text(val text: String) : AnthropicResponseContent()
119130

120131
@Serializable
121132
@SerialName("tool_use")
122-
data class ToolUse(
133+
public data class ToolUse(
123134
val id: String,
124135
val name: String,
125136
val input: JsonObject
126137
) : AnthropicResponseContent()
127138
}
128139

140+
@InternalLLMClientApi
129141
@Serializable
130-
internal data class AnthropicUsage(
142+
public data class AnthropicUsage(
131143
val inputTokens: Int,
132144
val outputTokens: Int
133145
)
134146

147+
@InternalLLMClientApi
135148
@Serializable
136-
internal data class AnthropicStreamResponse(
149+
public data class AnthropicStreamResponse(
137150
val type: String,
138151
val delta: AnthropicStreamDelta? = null,
139152
val message: AnthropicResponse? = null
140153
)
141154

155+
@InternalLLMClientApi
142156
@Serializable
143-
internal data class AnthropicStreamDelta(
157+
public data class AnthropicStreamDelta(
144158
val type: String,
145159
val text: String? = null,
146160
val toolUse: AnthropicResponseContent.ToolUse? = null
147161
)
148162

149163

164+
@InternalLLMClientApi
150165
@Serializable
151-
internal sealed interface AnthropicToolChoice {
166+
public sealed interface AnthropicToolChoice {
152167
@Serializable
153168
@SerialName("auto")
154-
data object Auto : AnthropicToolChoice
169+
public data object Auto : AnthropicToolChoice
155170

156171
@Serializable
157172
@SerialName("any")
158-
data object Any : AnthropicToolChoice
173+
public data object Any : AnthropicToolChoice
159174

160175
@Serializable
161176
@SerialName("none")
162-
data object None : AnthropicToolChoice
177+
public data object None : AnthropicToolChoice
163178

164179
@Serializable
165180
@SerialName("tool")
166-
data class Tool(val name: String) : AnthropicToolChoice
181+
public data class Tool(val name: String) : AnthropicToolChoice
167182
}

0 commit comments

Comments
 (0)