Skip to content

Commit b725643

Browse files
authored
Migrating to AIAgent ctor, simpleSingleRunAgent deprecation (#222)
1 parent 6f0532f commit b725643

File tree

20 files changed

+134
-80
lines changed

20 files changed

+134
-80
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fun main() = runBlocking {
5151
// Before you run the example, assign a corresponding API key as an environment variable.
5252
val apiKey = System.getenv("OPENAI_API_KEY") // or Anthropic, Google, OpenRouter, etc.
5353

54-
val agent = simpleSingleRunAgent(
54+
val agent = AIAgent(
5555
executor = simpleOpenAIExecutor(apiKey), // or Anthropic, Google, OpenRouter, etc.
5656
systemPrompt = "You are a helpful assistant. Answer user questions concisely.",
5757
llmModel = OpenAIModels.Chat.GPT4o

agents/agents-core/QuickstartGuide.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ A single-run agent processes a single input and provides a response:
2929
fun main() = runBlocking {
3030
val apiToken = "YOUR_API_TOKEN"
3131

32-
val agent = simpleSingleRunAgent(
32+
val agent = AIAgent(
3333
executor = simpleOpenAIExecutor("API_TOKEN"),
3434
systemPrompt = "You are a code assistant. Provide concise code examples."
3535
)
@@ -42,7 +42,7 @@ Please note that the single-run agent doesn't have any tools by default.
4242

4343
## Configuration Options
4444

45-
`simpleSingleRunAgent` accept the following parameters:
45+
`AIAgent` accept the following parameters:
4646

4747
- `executor` (required): Your LLM prompt executor
4848
- `systemPrompt`: Initial system prompt for the agent (default: empty string)
@@ -116,7 +116,7 @@ val toolRegistry = ToolRegistry {
116116
// Add more tools as needed
117117
}
118118

119-
val agent = simpleSingleRunAgent(
119+
val agent = AIAgent(
120120
executor = simpleOpenAIExecutor("API_TOKEN"),
121121
systemPrompt = "You are a helpful assistant with calculator capabilities.",
122122
toolRegistry = toolRegistry
@@ -175,7 +175,7 @@ fun main() = runBlocking {
175175
tool(GenerateCodeTool)
176176
}
177177

178-
val agent = simpleSingleRunAgent(
178+
val agent = AIAgent(
179179
executor = simpleOpenAIExecutor("API_TOKEN"),
180180
systemPrompt = "You are a code assistant. Use the generate_code tool to create code examples.",
181181
toolRegistry = toolRegistry

agents/agents-core/src/commonMain/kotlin/ai/koog/agents/core/agent/AIAgent.kt

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.koog.agents.core.agent
22

3+
import ai.koog.agents.core.agent.config.AIAgentConfig
34
import ai.koog.agents.core.agent.config.AIAgentConfigBase
45
import ai.koog.agents.core.agent.entity.*
56
import ai.koog.agents.core.agent.context.AIAgentContext
@@ -19,8 +20,18 @@ import ai.koog.agents.core.tools.annotations.InternalAgentToolsApi
1920
import ai.koog.agents.features.common.config.FeatureConfig
2021
import ai.koog.agents.utils.Closeable
2122
import ai.koog.agents.core.agent.context.AIAgentLLMContext
23+
import ai.koog.agents.core.dsl.builder.forwardTo
24+
import ai.koog.agents.core.dsl.builder.strategy
25+
import ai.koog.agents.core.dsl.extension.nodeExecuteTool
26+
import ai.koog.agents.core.dsl.extension.nodeLLMRequest
27+
import ai.koog.agents.core.dsl.extension.nodeLLMSendToolResult
28+
import ai.koog.agents.core.dsl.extension.onAssistantMessage
29+
import ai.koog.agents.core.dsl.extension.onToolCall
30+
import ai.koog.prompt.dsl.prompt
2231
import ai.koog.prompt.executor.model.PromptExecutor
32+
import ai.koog.prompt.llm.LLModel
2333
import ai.koog.prompt.message.Message
34+
import ai.koog.prompt.params.LLMParams
2435
import ai.koog.prompt.text.TextContentBuilder
2536
import io.github.oshai.kotlinlogging.KotlinLogging
2637
import kotlinx.coroutines.CompletableDeferred
@@ -80,6 +91,41 @@ public open class AIAgent(
8091
private const val NO_RESULT = "Required tool argument value not found: \"${TerminationTool.ARG}\"!"
8192
}
8293

94+
/**
95+
* Creates an instance of [AIAgent] with the specified parameters.
96+
*
97+
* @param executor The [PromptExecutor] responsible for executing prompts.
98+
* @param strategy The [AIAgentStrategy] defining the agent's behavior. Default is a single-run strategy.
99+
* @param systemPrompt The system-level prompt context for the agent. Default is an empty string.
100+
* @param llmModel The language model to be used by the agent.
101+
* @param temperature The sampling temperature for the language model, controlling randomness. Default is 1.0.
102+
* @param toolRegistry The [ToolRegistry] containing tools available to the agent. Default is an empty registry.
103+
* @param maxIterations Maximum number of iterations for the agent's execution. Default is 50.
104+
* @param installFeatures A suspending lambda to install additional features for the agent's functionality. Default is an empty lambda.
105+
*/
106+
public constructor(
107+
executor: PromptExecutor,
108+
llmModel: LLModel,
109+
strategy: AIAgentStrategy = singleRunStrategy(),
110+
systemPrompt: String = "",
111+
temperature: Double = 1.0,
112+
toolRegistry: ToolRegistry = ToolRegistry.EMPTY,
113+
maxIterations: Int = 50,
114+
installFeatures: FeatureContext.() -> Unit = {}
115+
) : this(
116+
promptExecutor = executor,
117+
strategy = strategy,
118+
agentConfig = AIAgentConfig(
119+
prompt = prompt("chat", params = LLMParams(temperature = temperature)) {
120+
system(systemPrompt)
121+
},
122+
model = llmModel,
123+
maxAgentIterations = maxIterations,
124+
),
125+
toolRegistry = toolRegistry,
126+
installFeatures = installFeatures
127+
)
128+
83129
/**
84130
* The context for adding and configuring features in a Kotlin AI Agent instance.
85131
*
@@ -110,8 +156,8 @@ public open class AIAgent(
110156
FeatureContext(this).installFeatures()
111157
}
112158

113-
override suspend fun run(agentInput: String) {
114159

160+
override suspend fun run(agentInput: String) {
115161
runningMutex.withLock {
116162
if (isRunning) {
117163
throw IllegalStateException("Agent is already running")
@@ -164,8 +210,7 @@ public open class AIAgent(
164210
}
165211

166212
public suspend fun run(builder: suspend TextContentBuilder.() -> Unit) {
167-
val agentInput = TextContentBuilder().apply { this.builder() }.build()
168-
run(agentInput = agentInput)
213+
run(agentInput = TextContentBuilder().apply { this.builder() }.build())
169214
}
170215

171216
override suspend fun runAndGetResult(agentInput: String): String? {
@@ -368,3 +413,27 @@ public open class AIAgent(
368413

369414
//endregion Private Methods
370415
}
416+
417+
/**
418+
* Creates a single-run strategy for an AI agent.
419+
* This strategy defines a simple execution flow where the agent processes input,
420+
* calls tools, and sends results back to the agent.
421+
* The flow consists of the following steps:
422+
* 1. Start the agent.
423+
* 2. Call the LLM with the input.
424+
* 3. Execute a tool based on the LLM's response.
425+
* 4. Send the tool result back to the LLM.
426+
* 5. Repeat until LLM indicates no further tool calls are needed or the agent finishes.
427+
*/
428+
public fun singleRunStrategy(): AIAgentStrategy = strategy("single_run") {
429+
val nodeCallLLM by nodeLLMRequest("sendInput")
430+
val nodeExecuteTool by nodeExecuteTool("nodeExecuteTool")
431+
val nodeSendToolResult by nodeLLMSendToolResult("nodeSendToolResult")
432+
433+
edge(nodeStart forwardTo nodeCallLLM)
434+
edge(nodeCallLLM forwardTo nodeExecuteTool onToolCall { true })
435+
edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })
436+
edge(nodeExecuteTool forwardTo nodeSendToolResult)
437+
edge(nodeSendToolResult forwardTo nodeFinish onAssistantMessage { true })
438+
edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCall { true })
439+
}

agents/agents-ext/src/commonMain/kotlin/ai/koog/agents/ext/agent/AIAgentExt.kt

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package ai.koog.agents.ext.agent
33
import ai.koog.agents.core.agent.AIAgent
44
import ai.koog.agents.core.agent.config.AIAgentConfig
55
import ai.koog.agents.core.tools.ToolRegistry
6-
import ai.koog.agents.ext.tool.AskUser
7-
import ai.koog.agents.ext.tool.ExitTool
86
import ai.koog.prompt.dsl.prompt
97
import ai.koog.prompt.executor.model.PromptExecutor
108
import ai.koog.prompt.llm.LLModel
@@ -22,6 +20,7 @@ import ai.koog.prompt.params.LLMParams
2220
* @param installFeatures A suspending lambda to install additional features for the agent's functionality. Default is an empty lambda.
2321
* @return A configured instance of `AIAgent` with a single-run execution strategy.
2422
*/
23+
@Deprecated("Use AIAgent constructor instead", ReplaceWith("AIAgent(...)"))
2524
public fun simpleSingleRunAgent(
2625
executor: PromptExecutor,
2726
systemPrompt: String = "",
@@ -30,21 +29,13 @@ public fun simpleSingleRunAgent(
3029
toolRegistry: ToolRegistry = ToolRegistry.EMPTY,
3130
maxIterations: Int = 50,
3231
installFeatures: AIAgent.FeatureContext.() -> Unit = {}
33-
): AIAgent {
34-
35-
val agentConfig = AIAgentConfig(
36-
prompt = prompt("chat", params = LLMParams(temperature = temperature)) {
37-
system(systemPrompt)
38-
},
39-
model = llmModel,
40-
maxAgentIterations = maxIterations,
41-
)
42-
43-
return AIAgent(
44-
promptExecutor = executor,
45-
strategy = singleRunStrategy(),
46-
agentConfig = agentConfig,
47-
toolRegistry = toolRegistry,
48-
installFeatures = installFeatures
49-
)
50-
}
32+
): AIAgent = AIAgent(
33+
systemPrompt = systemPrompt,
34+
llmModel = llmModel,
35+
temperature = temperature,
36+
toolRegistry = toolRegistry,
37+
maxIterations = maxIterations,
38+
installFeatures = installFeatures,
39+
strategy = singleRunStrategy(),
40+
executor = executor
41+
)

agents/agents-test/src/jvmTest/kotlin/ai/koog/agents/test/SimpleAgentMockedTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
package ai.koog.agents.test
44

5+
import ai.koog.agents.core.agent.AIAgent
56
import ai.koog.agents.core.tools.SimpleTool
67
import ai.koog.agents.core.tools.Tool
78
import ai.koog.agents.core.tools.ToolDescriptor
89
import ai.koog.agents.core.tools.ToolException
910
import ai.koog.agents.core.tools.ToolParameterDescriptor
1011
import ai.koog.agents.core.tools.ToolParameterType
1112
import ai.koog.agents.core.tools.ToolRegistry
12-
import ai.koog.agents.ext.agent.simpleSingleRunAgent
1313
import ai.koog.agents.ext.tool.ExitTool
1414
import ai.koog.agents.ext.tool.SayToUser
1515
import ai.koog.agents.features.eventHandler.feature.EventHandler
@@ -161,8 +161,8 @@ class SimpleAgentMockedTest {
161161
}
162162

163163
@Test
164-
fun ` test simpleSingleRunAgent doesn't call tools by default`() = runBlocking {
165-
val agent = simpleSingleRunAgent(
164+
fun ` test AIAgent doesn't call tools by default`() = runBlocking {
165+
val agent = AIAgent(
166166
systemPrompt = systemPrompt,
167167
llmModel = OpenAIModels.Reasoning.GPT4oMini,
168168
temperature = 1.0,
@@ -173,7 +173,7 @@ class SimpleAgentMockedTest {
173173

174174
agent.run("Repeat after me: Hello, I'm good.")
175175

176-
// by default, a simpleSingleRunAgent has no tools underneath
176+
// by default, a AI Agent has no tools underneath
177177
assertTrue(actualToolCalls.isEmpty(), "No tools should be called")
178178
assertTrue(results.isNotEmpty(), "No agent run results were received")
179179
assertTrue(
@@ -183,12 +183,12 @@ class SimpleAgentMockedTest {
183183
}
184184

185185
@Test
186-
fun `test simpleSingleRunAgent calls a custom tool`() = runBlocking {
186+
fun `test AIAgent calls a custom tool`() = runBlocking {
187187
val toolRegistry = ToolRegistry {
188188
tool(SayToUser)
189189
}
190190

191-
val agent = simpleSingleRunAgent(
191+
val agent = AIAgent(
192192
systemPrompt = systemPrompt,
193193
llmModel = OpenAIModels.Reasoning.GPT4oMini,
194194
temperature = 1.0,
@@ -212,7 +212,7 @@ class SimpleAgentMockedTest {
212212
@ParameterizedTest
213213
@MethodSource("getToolRegistry")
214214
fun `test simpleSingleRunAgent handles non-registered tools`(toolRegistry: ToolRegistry) = runBlocking {
215-
val agent = simpleSingleRunAgent(
215+
val agent = AIAgent(
216216
systemPrompt = systemPrompt,
217217
llmModel = OpenAIModels.Reasoning.GPT4oMini,
218218
temperature = 1.0,
@@ -238,7 +238,7 @@ class SimpleAgentMockedTest {
238238
tool(ErrorTool)
239239
}
240240

241-
val agent = simpleSingleRunAgent(
241+
val agent = AIAgent(
242242
systemPrompt = systemPrompt,
243243
llmModel = OpenAIModels.Reasoning.GPT4oMini,
244244
temperature = 1.0,
@@ -268,7 +268,7 @@ class SimpleAgentMockedTest {
268268
tool(ConditionalTool)
269269
}
270270

271-
val successAgent = simpleSingleRunAgent(
271+
val successAgent = AIAgent(
272272
systemPrompt = systemPrompt,
273273
llmModel = OpenAIModels.Reasoning.GPT4oMini,
274274
temperature = 1.0,
@@ -296,7 +296,7 @@ class SimpleAgentMockedTest {
296296

297297
iterationCount = 0
298298

299-
val agent = simpleSingleRunAgent(
299+
val agent = AIAgent(
300300
systemPrompt = systemPrompt,
301301
llmModel = OpenAIModels.Reasoning.GPT4oMini,
302302
temperature = 1.0,

examples/src/main/kotlin/ai/koog/agents/example/banking/routing/RoutingViaAgentsAsTools.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.koog.agents.example.banking.routing
22

3+
import ai.koog.agents.core.agent.AIAgent
34
import ai.koog.agents.core.agent.asTool
45
import ai.koog.agents.core.tools.ToolRegistry
56
import ai.koog.agents.core.tools.reflect.asTools
@@ -8,7 +9,6 @@ import ai.koog.agents.example.banking.tools.MoneyTransferTools
89
import ai.koog.agents.example.banking.tools.TransactionAnalysisTools
910
import ai.koog.agents.example.banking.tools.bankingAssistantSystemPrompt
1011
import ai.koog.agents.example.banking.tools.transactionAnalysisPrompt
11-
import ai.koog.agents.ext.agent.simpleSingleRunAgent
1212
import ai.koog.agents.ext.tool.AskUser
1313
import ai.koog.prompt.executor.clients.openai.OpenAIModels
1414
import ai.koog.prompt.executor.llms.all.simpleOpenAIExecutor
@@ -18,23 +18,23 @@ fun main() = runBlocking {
1818
val apiKey = ApiKeyService.openAIApiKey // Your OpenAI API key
1919
val openAIExecutor = simpleOpenAIExecutor(apiKey)
2020

21-
val transferAgent = simpleSingleRunAgent(
21+
val transferAgent = AIAgent(
2222
executor = openAIExecutor,
2323
llmModel = OpenAIModels.Reasoning.GPT4oMini,
2424
systemPrompt = bankingAssistantSystemPrompt,
2525
temperature = 0.0,
2626
toolRegistry = ToolRegistry { tools(MoneyTransferTools().asTools()) }
2727
)
2828

29-
val analysisAgent = simpleSingleRunAgent(
29+
val analysisAgent = AIAgent(
3030
executor = openAIExecutor,
3131
llmModel = OpenAIModels.Reasoning.GPT4oMini,
3232
systemPrompt = bankingAssistantSystemPrompt + transactionAnalysisPrompt,
3333
temperature = 0.0,
3434
toolRegistry = ToolRegistry { tools(TransactionAnalysisTools().asTools()) }
3535
)
3636

37-
val classifierAgent = simpleSingleRunAgent(
37+
val classifierAgent = AIAgent(
3838
executor = openAIExecutor,
3939
llmModel = OpenAIModels.Reasoning.GPT4oMini,
4040
toolRegistry = ToolRegistry {

examples/src/main/kotlin/ai/koog/agents/example/banking/routing/RoutingViaGraph.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ fun main() = runBlocking {
114114
)
115115

116116
val agent = AIAgent(
117-
toolRegistry = toolRegistry,
117+
promptExecutor = simpleOpenAIExecutor(apiKey),
118118
strategy = strategy,
119119
agentConfig = agentConfig,
120-
promptExecutor = simpleOpenAIExecutor(apiKey),
120+
toolRegistry = toolRegistry,
121121
)
122122

123123
println("Banking Assistant started")

examples/src/main/kotlin/ai/koog/agents/example/banking/tools/MoneyTransferTools.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package ai.koog.agents.example.banking.tools
22

3+
import ai.koog.agents.core.agent.AIAgent
34
import ai.koog.agents.core.tools.ToolRegistry
45
import ai.koog.agents.core.tools.annotations.LLMDescription
56
import ai.koog.agents.core.tools.annotations.Tool
67
import ai.koog.agents.core.tools.reflect.ToolSet
78
import ai.koog.agents.core.tools.reflect.asTools
89
import ai.koog.agents.example.ApiKeyService
9-
import ai.koog.agents.ext.agent.simpleSingleRunAgent
1010
import ai.koog.prompt.executor.clients.openai.OpenAIModels
1111
import ai.koog.prompt.executor.llms.all.simpleOpenAIExecutor
1212
import kotlinx.coroutines.runBlocking
@@ -169,7 +169,7 @@ fun main() = runBlocking {
169169
tools(MoneyTransferTools().asTools())
170170
}
171171

172-
val agent = simpleSingleRunAgent(
172+
val agent = AIAgent(
173173
executor = simpleOpenAIExecutor(apiKey),
174174
llmModel = OpenAIModels.Reasoning.GPT4oMini,
175175
systemPrompt = bankingAssistantSystemPrompt,

examples/src/main/kotlin/ai/koog/agents/example/banking/tools/TransactionAnalysisTools.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package ai.koog.agents.example.banking.tools
22

3+
import ai.koog.agents.core.agent.AIAgent
34
import ai.koog.agents.core.tools.reflect.ToolSet
45
import ai.koog.agents.core.tools.annotations.Tool
56
import ai.koog.agents.core.tools.annotations.LLMDescription
67
import ai.koog.agents.core.tools.ToolRegistry
78
import ai.koog.agents.core.tools.reflect.asTools
89
import ai.koog.agents.example.ApiKeyService
9-
import ai.koog.agents.ext.agent.simpleSingleRunAgent
1010
import ai.koog.prompt.executor.clients.openai.OpenAIModels
1111
import ai.koog.prompt.executor.llms.all.simpleOpenAIExecutor
1212
import kotlinx.coroutines.runBlocking
@@ -141,7 +141,7 @@ fun main() = runBlocking {
141141
tools(TransactionAnalysisTools().asTools())
142142
}
143143

144-
val agent = simpleSingleRunAgent(
144+
val agent = AIAgent(
145145
executor = simpleOpenAIExecutor(apiKey),
146146
llmModel = OpenAIModels.Reasoning.GPT4oMini,
147147
systemPrompt = bankingAssistantSystemPrompt + transactionAnalysisPrompt,

0 commit comments

Comments
 (0)