Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b1deeea
Simplify Tools API for multiplatform
nomisRev Aug 23, 2025
65b7fbc
fixup! Add missing Kdocs
Ololoshechkin Sep 8, 2025
3862530
Get rid of required finishTool in subgraphWithTask and support tools …
Ololoshechkin Sep 9, 2025
8fac2ba
fixup! Fix rebase issues
Ololoshechkin Sep 12, 2025
086da99
Refactor all usages and examples
Ololoshechkin Sep 12, 2025
8ffeec4
fixup! fix CE
Ololoshechkin Sep 12, 2025
9e3c25d
fixup! fix CE
Ololoshechkin Sep 12, 2025
1d40c3f
fixup! fix nested class property LLM descriptions
Ololoshechkin Sep 13, 2025
90ffce5
Rewrite trip-planning example with new simplified subgraphWithTask API
Ololoshechkin Sep 13, 2025
2616875
Add tests for more complex tool descriptor generation, fix bugs
Ololoshechkin Sep 13, 2025
3120cb3
fix Klint
Ololoshechkin Sep 13, 2025
cda7fc1
Refactor EditFileTool, ListDirectoryTool, etc. and introduce TextSeri…
Ololoshechkin Sep 14, 2025
e0f7a80
Rewrite all tools and examples with the new API
Ololoshechkin Sep 15, 2025
474bc2a
fixup! Fix broken Banking example
Ololoshechkin Sep 15, 2025
264eaec
Fix tests
Ololoshechkin Sep 15, 2025
0cb65ae
Fix tests, linter, and doc knit
Ololoshechkin Sep 15, 2025
43ee085
Fix tests, linter, and doc knit
Ololoshechkin Sep 15, 2025
ad2fe64
Fix doc knit
Ololoshechkin Sep 15, 2025
1b82d85
Fix ModelCapabilitiesIntegrationTest
aozherelyeva Sep 16, 2025
aab2b49
fix tests and lint
Ololoshechkin Sep 17, 2025
8db622f
Add missing feature installations to Ktor plugin
Ololoshechkin Sep 17, 2025
11e6c9d
Add missing feature installations to Ktor plugin
Ololoshechkin Sep 17, 2025
c69f6a1
Fix bug with Ktor Koog feature install self-recursion
Ololoshechkin Sep 17, 2025
79b04f5
Fix bug with primitives in subgraph
Ololoshechkin Sep 18, 2025
16f561e
Fix rebase and review comments
Ololoshechkin Sep 26, 2025
f9e31cc
fix
Ololoshechkin Sep 26, 2025
31acd81
fix
Ololoshechkin Sep 26, 2025
1dcfc8c
fix linter
Ololoshechkin Sep 26, 2025
c3bb59c
fix other things
Ololoshechkin Sep 26, 2025
4a8101d
fix other things
Ololoshechkin Sep 26, 2025
b0becb3
fix other things
Ololoshechkin Sep 26, 2025
748d07f
fix CE
Ololoshechkin Sep 26, 2025
14fe454
fix ktlint
Ololoshechkin Sep 26, 2025
463dcd6
fix ktlint and CE
Ololoshechkin Sep 26, 2025
147243e
fix ktlint !!!!!!!!!!! ___ANGRY___ ! VERY ANGRY!
Ololoshechkin Sep 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions agents/agents-core/QuickstartGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ You can create custom tools by extending the `SimpleTool` class:
```kotlin
object CalculatorTool : SimpleTool<CalculatorToolArgs>() {
@Serializable
data class Args(val expression: String) : ToolArgs
data class Args(val expression: String)

override val argsSerializer = Args.serializer()

Expand Down Expand Up @@ -140,7 +140,7 @@ val agent = AIAgent(
```kotlin
object GenerateCodeTool : SimpleTool<GenerateCodeToolArgs>() {
@Serializable
data class Args(val language: String, val task: String) : ToolArgs
data class Args(val language: String, val task: String)

override val argsSerializer = Args.serializer()

Expand Down Expand Up @@ -186,4 +186,4 @@ fun main() = runBlocking {
// Wait for the agent to complete
delay(Long.MAX_VALUE)
}
```
```
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ package ai.koog.agents.core.agent
import ai.koog.agents.core.agent.AIAgentTool.AgentToolArgs
import ai.koog.agents.core.agent.AIAgentTool.AgentToolResult
import ai.koog.agents.core.tools.Tool
import ai.koog.agents.core.tools.ToolArgs
import ai.koog.agents.core.tools.ToolDescriptor
import ai.koog.agents.core.tools.ToolParameterDescriptor
import ai.koog.agents.core.tools.ToolResult
import ai.koog.agents.core.tools.annotations.InternalAgentToolsApi
import ai.koog.agents.core.tools.asToolDescriptor
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
Expand All @@ -22,7 +21,9 @@ import kotlinx.serialization.serializer
*
* @param agentName Agent name that would be a tool name for this agent tool.
* @param agentDescription Agent description that would be a tool description for this agent tool.
* @param inputDescriptor Descriptor for the agent input.
* @param inputDescription An optional description of the agent's input. Required for primitive types only!
* * If not specified for a primitive input type (ex: String, Int, ...), an empty input description will be sent to LLM.
* * Does not have any effect for non-primitive [Input] type with @LLMDescription annotations.
* @param inputSerializer Serializer to deserialize tool arguments to agent input.
* @param outputSerializer Serializer to serialize agent output to tool result.
* @param json Optional [Json] instance to customize de/serialization behavior.
Expand All @@ -31,38 +32,42 @@ import kotlinx.serialization.serializer
public inline fun <reified Input, reified Output> AIAgent<Input, Output>.asTool(
agentName: String,
agentDescription: String,
inputDescriptor: ToolParameterDescriptor,
inputDescription: String? = null,
inputSerializer: KSerializer<Input> = serializer(),
outputSerializer: KSerializer<Output> = serializer(),
json: Json = Json.Default,
): Tool<AgentToolArgs, AgentToolResult> = AIAgentTool(
agent = this,
agentName = agentName,
agentDescription = agentDescription,
inputDescriptor = inputDescriptor,
inputDescription = inputDescription,
inputSerializer = inputSerializer,
outputSerializer = outputSerializer,
json = json,
)

/**
* AIAgentTool is a specialized tool that integrates an AI agent for processing tasks
* by leveraging input arguments and producing corresponding results.
* AIAgentTool is a generic tool that wraps an AI agent to facilitate integration
* with the context of a tool execution framework. It enables the serialization,
* deserialization, and execution of an AI agent's operations.
*
* This class extends the generic Tool interface with custom argument and result types.
*
* @constructor Creates an instance of AIAgentTool with the specified AI agent, its name,
* description, and an optional description for the request parameter.
*
* @param agent The AI agent that implements the AIAgentBase interface and handles task execution.
* @param agentName A name assigned to the tool that helps identify it.
* @param agentDescription A brief description of what the tool does.
* @param Input The type of input expected by the AI agent.
* @param Output The type of output produced by the AI agent.
* @property agent The AI agent to be executed.
* @property agentName A unique name for the agent.
* @property agentDescription A brief description of the agent's functionality.
* @property inputDescription An optional description of the agent's input. Required for primitive types only!
* If not specified for a primitive input type (ex: String, Int, ...), an empty input description will be sent to LLM.
* Does not have any effect for non-primitive [Input] type with @LLMDescription annotations.
* @property inputSerializer A serializer for converting the input type to/from JSON.
* @property outputSerializer A serializer for converting the output type to/from JSON.
* @property json The JSON configuration used for serialization and deserialization.
*/
public class AIAgentTool<Input, Output>(
private val agent: AIAgent<Input, Output>,
private val agentName: String,
private val agentDescription: String,
private val inputDescriptor: ToolParameterDescriptor,
private val inputDescription: String? = null,
private val inputSerializer: KSerializer<Input>,
private val outputSerializer: KSerializer<Output>,
private val json: Json = Json.Default,
Expand All @@ -74,7 +79,7 @@ public class AIAgentTool<Input, Output>(
* @property args The input the agent tool.
*/
@Serializable
public data class AgentToolArgs(val args: JsonObject) : ToolArgs
public data class AgentToolArgs(val args: JsonObject)

/**
* Represents the result of executing an agent tool operation.
Expand All @@ -88,9 +93,9 @@ public class AIAgentTool<Input, Output>(
val successful: Boolean,
val errorMessage: String? = null,
val result: JsonElement? = null
) : ToolResult.JSONSerializable<AgentToolResult> {
override fun getSerializer(): KSerializer<AgentToolResult> = serializer()
}
)

override val resultSerializer: KSerializer<AgentToolResult> = AgentToolResult.serializer()

override val argsSerializer: KSerializer<AgentToolArgs> = object : KSerializer<AgentToolArgs> {
private val innerSerializer = JsonObject.serializer()
Expand All @@ -106,15 +111,20 @@ public class AIAgentTool<Input, Output>(
}
}

override val descriptor: ToolDescriptor = ToolDescriptor(
name = agentName,
description = agentDescription,
requiredParameters = listOf(inputDescriptor)
)
override val name: String = agentName
override val description: String = agentDescription

@OptIn(InternalAgentToolsApi::class)
override val descriptor: ToolDescriptor =
inputSerializer.descriptor.asToolDescriptor(name, description, inputDescription)

@OptIn(InternalAgentToolsApi::class)
override suspend fun execute(args: AgentToolArgs): AgentToolResult {
return try {
val input = json.decodeFromJsonElement(inputSerializer, args.args.getValue(inputDescriptor.name))
val input = json.decodeFromJsonElement(
inputSerializer,
args.args.getValue(descriptor.requiredParameters.first().name)
)
val result = agent.run(input)

AgentToolResult(
Expand All @@ -124,9 +134,11 @@ public class AIAgentTool<Input, Output>(
} catch (e: Throwable) {
AgentToolResult(
successful = false,
errorMessage = "Error happened: ${e::class.simpleName}(${e.message})\n${e.stackTraceToString().take(
100
)}"
errorMessage = "Error happened: ${e::class.simpleName}(${e.message})\n${
e.stackTraceToString().take(
100
)
}"
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import ai.koog.agents.core.agent.config.AIAgentConfig
import ai.koog.agents.core.environment.AIAgentEnvironment
import ai.koog.agents.core.environment.SafeTool
import ai.koog.agents.core.tools.Tool
import ai.koog.agents.core.tools.ToolArgs
import ai.koog.agents.core.tools.ToolDescriptor
import ai.koog.agents.core.tools.ToolRegistry
import ai.koog.agents.core.tools.ToolResult
import ai.koog.agents.core.utils.ActiveProperty
import ai.koog.prompt.dsl.Prompt
import ai.koog.prompt.dsl.PromptBuilder
Expand Down Expand Up @@ -83,13 +81,13 @@ public class AIAgentLLMWriteSession internal constructor(
/**
* Executes the specified tool with the given arguments and returns the result within a [SafeTool.Result] wrapper.
*
* @param TArgs the type of arguments required by the tool, extending `ToolArgs`.
* @param TArgs the type of arguments required by the tool.
* @param TResult the type of result returned by the tool, implementing `ToolResult`.
* @param tool the tool to be executed.
* @param args the arguments required to execute the tool.
* @return a `SafeTool.Result` containing the tool's execution result of type `TResult`.
*/
public suspend inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> callTool(
public suspend inline fun <reified TArgs, reified TResult> callTool(
tool: Tool<TArgs, TResult>,
args: TArgs
): SafeTool.Result<TResult> {
Expand All @@ -100,24 +98,24 @@ public class AIAgentLLMWriteSession internal constructor(
* Executes a tool by its name with the provided arguments.
*
* @param toolName The name of the tool to be executed.
* @param args The arguments required to execute the tool, which must be a subtype of [ToolArgs].
* @param args The arguments required to execute the tool.
* @return A [SafeTool.Result] containing the result of the tool execution, which is a subtype of [ToolResult].
*/
public suspend inline fun <reified TArgs : ToolArgs> callTool(
public suspend inline fun <reified TArgs> callTool(
toolName: String,
args: TArgs
): SafeTool.Result<out ToolResult> {
): SafeTool.Result<out Any?> {
return findToolByName<TArgs>(toolName).execute(args)
}

/**
* Executes a tool identified by its name with the provided arguments and returns the raw string result.
*
* @param toolName The name of the tool to be executed.
* @param args The arguments to be passed to the tool, conforming to the [ToolArgs] type.
* @param args The arguments to be passed to the tool.
* @return The raw result of the tool's execution as a String.
*/
public suspend inline fun <reified TArgs : ToolArgs> callToolRaw(
public suspend inline fun <reified TArgs> callToolRaw(
toolName: String,
args: TArgs
): String {
Expand All @@ -133,7 +131,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @param args The arguments to be passed to the tool for its execution.
* @return A result wrapper containing either the successful result of the tool's execution or an error.
*/
public suspend inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> callTool(
public suspend inline fun <reified TArgs, reified TResult> callTool(
toolClass: KClass<out Tool<TArgs, TResult>>,
args: TArgs
): SafeTool.Result<TResult> {
Expand All @@ -144,13 +142,13 @@ public class AIAgentLLMWriteSession internal constructor(
/**
* Finds and retrieves a tool of the specified type from the tool registry.
*
* @param TArgs The type of arguments the tool accepts, extending from ToolArgs.
* @param TArgs The type of arguments the tool accepts.
* @param TResult The type of result the tool produces, extending from ToolResult.
* @param toolClass The KClass reference that specifies the type of tool to find.
* @return A SafeTool instance wrapping the found tool and its environment.
* @throws IllegalArgumentException if the specified tool is not found in the tool registry.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> findTool(
public inline fun <reified TArgs, reified TResult> findTool(
toolClass: KClass<out Tool<TArgs, TResult>>
): SafeTool<TArgs, TResult> {
@Suppress("UNCHECKED_CAST")
Expand All @@ -165,12 +163,12 @@ public class AIAgentLLMWriteSession internal constructor(
/**
* Invokes a tool of the specified type with the provided arguments.
*
* @param args The input arguments required for the tool execution, represented as an instance of `ToolArgs`.
* @param args The input arguments required for the tool execution.
* @return A `SafeTool.Result` containing the outcome of the tool's execution, which may be of any type that extends `ToolResult`.
*/
public suspend inline fun <reified ToolT : Tool<*, *>> callTool(
args: ToolArgs
): SafeTool.Result<out ToolResult> {
args: Any?
): SafeTool.Result<out Any?> {
val tool = findTool<ToolT>()
return tool.executeUnsafe(args)
}
Expand All @@ -192,13 +190,13 @@ public class AIAgentLLMWriteSession internal constructor(
/**
* Transforms a flow of arguments into a flow of results by asynchronously executing the given tool in parallel.
*
* @param TArgs the type of the arguments required by the tool, extending ToolArgs.
* @param TArgs the type of the arguments required by the tool.
* @param TResult the type of the result produced by the tool, extending ToolResult.
* @param safeTool the tool to be executed for each input argument.
* @param concurrency the maximum number of parallel executions allowed. Defaults to 16.
* @return a flow of results wrapped in SafeTool.Result for each input argument.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> Flow<TArgs>.toParallelToolCalls(
public inline fun <reified TArgs, reified TResult> Flow<TArgs>.toParallelToolCalls(
safeTool: SafeTool<TArgs, TResult>,
concurrency: Int = 16
): Flow<SafeTool.Result<TResult>> = flatMapMerge(concurrency) { args ->
Expand All @@ -215,7 +213,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @param concurrency The maximum number of parallel calls to the tool. Default is 16.
* @return A flow of string results derived from executing the tool's raw method.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> Flow<TArgs>.toParallelToolCallsRaw(
public inline fun <reified TArgs, reified TResult> Flow<TArgs>.toParallelToolCallsRaw(
safeTool: SafeTool<TArgs, TResult>,
concurrency: Int = 16
): Flow<String> = flatMapMerge(concurrency) { args ->
Expand All @@ -233,7 +231,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @param concurrency The maximum number of concurrent executions. Default value is 16.
* @return A flow emitting the results of the tool executions wrapped in a SafeTool.Result object.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> Flow<TArgs>.toParallelToolCalls(
public inline fun <reified TArgs, reified TResult> Flow<TArgs>.toParallelToolCalls(
tool: Tool<TArgs, TResult>,
concurrency: Int = 16
): Flow<SafeTool.Result<TResult>> = flatMapMerge(concurrency) { args ->
Expand All @@ -252,7 +250,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @param concurrency The maximum number of parallel executions allowed. Default is 16.
* @return A Flow containing the results of the tool executions, wrapped in `SafeTool.Result`.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> Flow<TArgs>.toParallelToolCalls(
public inline fun <reified TArgs, reified TResult> Flow<TArgs>.toParallelToolCalls(
toolClass: KClass<out Tool<TArgs, TResult>>,
concurrency: Int = 16
): Flow<SafeTool.Result<TResult>> {
Expand All @@ -269,7 +267,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @param concurrency the number of concurrent tool calls to be executed. Defaults to 16.
* @return a flow of raw string results from the parallel tool calls.
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> Flow<TArgs>.toParallelToolCallsRaw(
public inline fun <reified TArgs, reified TResult> Flow<TArgs>.toParallelToolCallsRaw(
toolClass: KClass<out Tool<TArgs, TResult>>,
concurrency: Int = 16
): Flow<String> {
Expand All @@ -288,7 +286,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @return the tool that matches the specified name and types
* @throws IllegalArgumentException if the tool is not defined or the types are incompatible
*/
public inline fun <reified TArgs : ToolArgs, reified TResult : ToolResult> findToolByNameAndArgs(
public inline fun <reified TArgs, reified TResult> findToolByNameAndArgs(
toolName: String
): Tool<TArgs, TResult> =
@Suppress("UNCHECKED_CAST")
Expand All @@ -305,7 +303,7 @@ public class AIAgentLLMWriteSession internal constructor(
* @throws IllegalArgumentException If the tool with the specified name is not defined or its arguments
* are incompatible with the expected type.
*/
public inline fun <reified TArgs : ToolArgs> findToolByName(toolName: String): SafeTool<TArgs, *> {
public inline fun <reified TArgs> findToolByName(toolName: String): SafeTool<TArgs, *> {
@Suppress("UNCHECKED_CAST")
val tool = (
toolRegistry.getTool(toolName) as? Tool<TArgs, *>
Expand Down
Loading
Loading