Skip to content

Commit fa0a98f

Browse files
committed
Update Message API
1 parent eb3d6b8 commit fa0a98f

309 files changed

Lines changed: 15545 additions & 14500 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 13 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@ package ai.koog.agents.core.agent
44

55
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy
66
import ai.koog.agents.core.dsl.builder.strategy
7-
import ai.koog.agents.core.dsl.extension.nodeExecuteMultipleTools
8-
import ai.koog.agents.core.dsl.extension.nodeExecuteTool
7+
import ai.koog.agents.core.dsl.extension.asUserMessage
8+
import ai.koog.agents.core.dsl.extension.nodeExecuteTools
99
import ai.koog.agents.core.dsl.extension.nodeLLMRequest
10-
import ai.koog.agents.core.dsl.extension.nodeLLMRequestMultiple
11-
import ai.koog.agents.core.dsl.extension.nodeLLMSendMultipleToolResults
12-
import ai.koog.agents.core.dsl.extension.nodeLLMSendToolResult
13-
import ai.koog.agents.core.dsl.extension.onAssistantMessage
14-
import ai.koog.agents.core.dsl.extension.onMultipleAssistantMessages
15-
import ai.koog.agents.core.dsl.extension.onMultipleToolCalls
16-
import ai.koog.agents.core.dsl.extension.onToolCall
10+
import ai.koog.agents.core.dsl.extension.onTextParts
11+
import ai.koog.agents.core.dsl.extension.onToolCalls
1712
import kotlin.jvm.JvmName
1813
import kotlin.jvm.JvmOverloads
1914

@@ -27,67 +22,16 @@ import kotlin.jvm.JvmOverloads
2722
* 3. Execute a tool based on the LLM's response.
2823
* 4. Send the tool result back to the LLM.
2924
* 5. Repeat until LLM indicates no further tool calls are needed or the agent finishes.
30-
* @param runMode The mode in which the single-run strategy should operate. Defaults to [ToolCalls.SEQUENTIAL].
31-
* - [ToolCalls.SEQUENTIAL]: Executes multiple tool calls sequentially.
32-
* - [ToolCalls.PARALLEL]: Executes multiple tool calls in parallel.
33-
* - [ToolCalls.SINGLE_RUN_SEQUENTIAL]: Executes a single tool call per step.
25+
* @param parallelTools if true, tools will be executed in parallel, otherwise sequentially
3426
* @return An instance of AIAgentStrategy configured according to the specified run mode.
3527
*/
3628
@JvmOverloads
37-
public fun singleRunStrategy(runMode: ToolCalls = ToolCalls.SEQUENTIAL): AIAgentGraphStrategy<String, String> =
38-
when (runMode) {
39-
ToolCalls.SEQUENTIAL -> singleRunWithParallelAbility(false)
40-
ToolCalls.PARALLEL -> singleRunWithParallelAbility(true)
41-
ToolCalls.SINGLE_RUN_SEQUENTIAL -> singleRunModeStrategy()
42-
}
43-
44-
private fun singleRunWithParallelAbility(parallelTools: Boolean) = strategy("single_run_sequential") {
45-
val nodeCallLLM by nodeLLMRequestMultiple()
46-
val nodeExecuteTool by nodeExecuteMultipleTools(parallelTools = parallelTools)
47-
val nodeSendToolResult by nodeLLMSendMultipleToolResults()
48-
49-
edge(nodeStart forwardTo nodeCallLLM)
50-
edge(nodeCallLLM forwardTo nodeExecuteTool onMultipleToolCalls { true })
51-
edge(
52-
nodeCallLLM forwardTo nodeFinish
53-
onMultipleAssistantMessages { true }
54-
transformed { it.joinToString("\n") { message -> message.content } }
55-
)
56-
57-
edge(nodeExecuteTool forwardTo nodeSendToolResult)
58-
59-
edge(nodeSendToolResult forwardTo nodeExecuteTool onMultipleToolCalls { true })
60-
61-
edge(
62-
nodeSendToolResult forwardTo nodeFinish
63-
onMultipleAssistantMessages { true }
64-
transformed { it.joinToString("\n") { message -> message.content } }
65-
)
66-
}
67-
68-
private fun singleRunModeStrategy() = strategy("single_run") {
69-
val nodeCallLLM by nodeLLMRequest()
70-
val nodeExecuteTool by nodeExecuteTool()
71-
val nodeSendToolResult by nodeLLMSendToolResult()
72-
73-
edge(nodeStart forwardTo nodeCallLLM)
74-
edge(nodeCallLLM forwardTo nodeExecuteTool onToolCall { true })
75-
edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })
76-
edge(nodeExecuteTool forwardTo nodeSendToolResult)
77-
edge(nodeSendToolResult forwardTo nodeFinish onAssistantMessage { true })
78-
edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCall { true })
79-
}
80-
81-
/**
82-
* Enum representing the modes in which a single-run strategy for an AI agent can be executed.
83-
*
84-
* These modes define how tasks or operations are processed during the agent's run:
85-
* - SEQUENTIAL: Multiple tool calls allowed but will be executed sequentially.
86-
* - PARALLEL: Tool calls executed in parallel.
87-
* - SINGLE: Multiple tool calls are not allowed.
88-
*/
89-
public enum class ToolCalls {
90-
SEQUENTIAL,
91-
PARALLEL,
92-
SINGLE_RUN_SEQUENTIAL
29+
public fun singleRunStrategy(parallelTools: Boolean = false): AIAgentGraphStrategy<String, String> = strategy<String, String>("single_run") {
30+
val nodeLLMRequest by nodeLLMRequest()
31+
val nodeExecuteTool by nodeExecuteTools(parallel = parallelTools)
32+
33+
edge(nodeStart forwardTo nodeLLMRequest asUserMessage { it })
34+
edge(nodeLLMRequest forwardTo nodeExecuteTool onToolCalls { true })
35+
edge(nodeLLMRequest forwardTo nodeFinish onTextParts { true })
36+
edge(nodeExecuteTool forwardTo nodeLLMRequest)
9337
}

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

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ai.koog.agents.core.agent.config
33
import ai.koog.agents.core.tools.ToolDescriptor
44
import ai.koog.prompt.dsl.Prompt
55
import ai.koog.prompt.message.Message
6+
import ai.koog.prompt.message.MessagePart
67

78
/**
89
* Determines how the tool calls which are present in the prompt, but whose definitions are not present in the request,
@@ -25,17 +26,49 @@ public abstract class MissingToolsConversionStrategy(private val format: ToolCal
2526

2627
/**
2728
* Converts the given message by formatting specific types of tool-related messages
28-
* (e.g., `Message.Tool.Call` and `Message.Tool.Result`) into descriptive messages.
29+
* (e.g., `MessagePart.Tool.Call` and `MessagePart.Tool.Result`) into descriptive messages.
2930
* If the message is not a tool-related message, it remains unchanged.
3031
*
3132
* @param message The input message to be converted.
33+
* @param toolNames The list of tool names used to determine which tools are present in the call.
34+
* If not, the message part should be converted.
3235
* @return The converted message, either modified if it's a tool-related message, or unchanged otherwise.
3336
*/
34-
public fun convertMessage(message: Message): Message {
35-
return when (message) {
36-
is Message.Tool.Call -> format.describeToolCall(message)
37-
is Message.Tool.Result -> format.describeToolResult(message)
38-
else -> message
37+
public fun convertMessage(message: Message, toolNames: List<String>): Message {
38+
when (message) {
39+
is Message.User -> {
40+
return message.copy(
41+
parts = message.parts.map { part ->
42+
when (part) {
43+
is MessagePart.Tool.Result -> {
44+
if (part.tool !in toolNames) {
45+
part
46+
} else {
47+
MessagePart.Text(format.describeToolResult(part))
48+
}
49+
}
50+
else -> part
51+
}
52+
}
53+
)
54+
}
55+
is Message.Assistant -> {
56+
return message.copy(
57+
parts = message.parts.map { part ->
58+
when (part) {
59+
is MessagePart.Tool.Call -> {
60+
if (part.tool !in toolNames) {
61+
part
62+
} else {
63+
MessagePart.Text(format.describeToolCall(part))
64+
}
65+
}
66+
else -> part
67+
}
68+
}
69+
)
70+
}
71+
is Message.System -> return message
3972
}
4073
}
4174

@@ -45,7 +78,7 @@ public abstract class MissingToolsConversionStrategy(private val format: ToolCal
4578
*/
4679
public class All(format: ToolCallDescriber) : MissingToolsConversionStrategy(format) {
4780
override fun convertPrompt(prompt: Prompt, tools: List<ToolDescriptor>): Prompt {
48-
return prompt.withMessages { messages -> messages.map { convertMessage(it) } }
81+
return prompt.withMessages { messages -> messages.map { convertMessage(it, emptyList()) } }
4982
}
5083
}
5184

@@ -59,11 +92,7 @@ public abstract class MissingToolsConversionStrategy(private val format: ToolCal
5992
val toolNames = tools.map { it.name }
6093
return prompt.withMessages { messages ->
6194
messages.map { message ->
62-
if (message is Message.Tool && message.tool !in toolNames) {
63-
convertMessage(message)
64-
} else {
65-
message
66-
}
95+
convertMessage(message, toolNames)
6796
}
6897
}
6998
}

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

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package ai.koog.agents.core.agent.config
22

3-
import ai.koog.prompt.message.Message
4-
import ai.koog.prompt.message.Message.Assistant
5-
import ai.koog.prompt.message.Message.User
3+
import ai.koog.prompt.message.MessagePart
64
import kotlinx.serialization.json.Json
75
import kotlinx.serialization.json.JsonPrimitive
86
import kotlinx.serialization.json.buildJsonObject
@@ -15,18 +13,18 @@ public interface ToolCallDescriber {
1513
/**
1614
* Composes a description of a tool call message.
1715
*
18-
* @param message The tool call message to be described. Must be an instance of Message.Tool.Call.
16+
* @param message The tool call message to be described. Must be an instance of MessagePart.Tool.Call.
1917
* @return A Message instance containing the description of the tool call.
2018
*/
21-
public fun describeToolCall(message: Message.Tool.Call): Message
19+
public fun describeToolCall(message: MessagePart.Tool.Call): String
2220

2321
/**
24-
* Describes the tool result by transforming it into a user-readable message object.
22+
* Describes the tool result by transforming it into a user-readable string.
2523
*
2624
* @param message The tool result message to be described. It contains the tool call id, tool name, and content details.
2725
* @return A transformed message representing the description of the tool result.
2826
*/
29-
public fun describeToolResult(message: Message.Tool.Result): Message
27+
public fun describeToolResult(message: MessagePart.Tool.Result): String
3028

3129
/**
3230
* JSON object implementing the `ToolCallDescriber` interface.
@@ -51,23 +49,21 @@ public interface ToolCallDescriber {
5149
/**
5250
* Formats a tool call message into a standardized Message.Assistant response.
5351
*
54-
* @param message the tool call message of type [Message.Tool.Call] containing details about the tool invocation,
52+
* @param message the tool call message of type [MessagePart.Tool.Call] containing details about the tool invocation,
5553
* such as tool ID, name, and arguments.
56-
* @return a [Message.Assistant] containing the serialized JSON representation of the tool call information.
54+
* @return a string containing the serialized JSON representation of the tool call information.
5755
*/
58-
override fun describeToolCall(message: Message.Tool.Call): Message {
59-
return Assistant(
60-
content = Json.encodeToString(
61-
buildJsonObject {
62-
message.id?.let { put("tool_call_id", JsonPrimitive(it)) }
63-
put("tool_name", JsonPrimitive(message.tool))
64-
message.contentJsonResult.fold(
65-
onSuccess = { put("tool_args", it) },
66-
onFailure = { put("tool_args_error", JsonPrimitive("Failed to parse tool arguments: $it")) }
67-
)
68-
}
69-
),
70-
metaInfo = message.metaInfo
56+
override fun describeToolCall(message: MessagePart.Tool.Call): String {
57+
return Json.encodeToString(
58+
buildJsonObject {
59+
message.id?.let { put("tool_call_id", JsonPrimitive(it)) }
60+
put("tool_name", JsonPrimitive(message.tool))
61+
put(
62+
"tool_args",
63+
runCatching { message.argsJson }
64+
.getOrElse { JsonPrimitive(message.args) }
65+
)
66+
}
7167
)
7268
}
7369

@@ -78,16 +74,13 @@ public interface ToolCallDescriber {
7874
* @param message The tool result message containing the tool's ID, name, and content.
7975
* @return A User message with a JSON-encoded representation of the tool result.
8076
*/
81-
override fun describeToolResult(message: Message.Tool.Result): Message {
82-
return User(
83-
content = Json.encodeToString(
84-
buildJsonObject {
85-
message.id?.let { put("tool_call_id", JsonPrimitive(it)) }
86-
put("tool_name", JsonPrimitive(message.tool))
87-
put("tool_result", JsonPrimitive(message.content))
88-
}
89-
),
90-
metaInfo = message.metaInfo
77+
override fun describeToolResult(message: MessagePart.Tool.Result): String {
78+
return Json.encodeToString(
79+
buildJsonObject {
80+
message.id?.let { put("tool_call_id", JsonPrimitive(it)) }
81+
put("tool_name", JsonPrimitive(message.tool))
82+
put("tool_result", JsonPrimitive(message.args))
83+
}
9184
)
9285
}
9386
}

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,6 @@ public interface AIAgentContext {
143143
* Retrieves the history of messages exchanged during the agent's execution.
144144
*/
145145
public suspend fun getHistory(): List<Message>
146-
147-
/**
148-
* Checks if the list of `Message.Response` contains any instances
149-
* of `Message.Tool.Call`.
150-
*
151-
* @receiver A list of `Message.Response` objects to evaluate.
152-
* @return `true` if there is at least one `Message.Tool.Call` in the list, otherwise `false`.
153-
*/
154-
public fun List<Message.Response>.containsToolCalls(): Boolean = this.any { it is Message.Tool.Call }
155146
}
156147

157148
/**

0 commit comments

Comments
 (0)