feat: add maxToolCallRounds configuration and update default value

This commit is contained in:
extio-de
2026-08-02 15:42:07 +02:00
parent b0043dc9b6
commit e6af810c61
2 changed files with 14 additions and 14 deletions

View File

@@ -865,6 +865,7 @@ final var blogPostAgent = new Agent(
| `textTemplate()` | Optional user prompt template. | `null` |
| `toolDefinitions(context)` | Optional tool definitions for tool-capable chat models. | `null` |
| `toolCallData(context)` | Optional tool request configuration. Defaults to `ToolCallData.auto(toolDefinitions)`. | `null` |
| `maxToolCallRounds` | Optional configuration of maximum tool call rounds (relevant if the model does not support multi tool calls) | 6 |
| `supportsToolCalling(context, clientService)` | Reports whether the resolved client can handle tool calls. | derived from model/provider |
| `responseHandler(context)` | Parses the model response. | `new TextAgentResponseHandler("response")` |
| `preProcess(context)` | Runs before completion. | no-op |
@@ -884,7 +885,7 @@ Agents can declare tool definitions directly. For simple in-agent tool execution
- Return `true` to append the tool results to the conversation and let the model continue with another turn.
- Return `false` to stop the tool-call loop. The framework then passes the last completion to the delegate handler for normal response processing.
The tool-call loop is capped at six rounds. If the model returns no tool calls, `ToolCallHandler` is not invoked and the completion goes directly to the delegate.
The tool-call loop is capped at six rounds by default, this value can be overridden by maxToolCallRounds(). If the model returns no tool calls, `ToolCallHandler` is not invoked and the completion goes directly to the delegate.
#### Single tool call per turn (sequential)

View File

@@ -13,9 +13,6 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.jackson.core.JacksonException;
import tools.jackson.databind.ObjectMapper;
import de.extio.lmlib.agent.responsehandler.AgentResponseHandler;
import de.extio.lmlib.agent.responsehandler.StreamedAgentResponseHandler;
import de.extio.lmlib.agent.responsehandler.TextAgentResponseHandler;
@@ -25,12 +22,14 @@ import de.extio.lmlib.client.Client;
import de.extio.lmlib.client.ClientService;
import de.extio.lmlib.client.Completion;
import de.extio.lmlib.client.Conversation;
import de.extio.lmlib.client.ToolCallData;
import de.extio.lmlib.client.ToolDefinition;
import de.extio.lmlib.client.Conversation.Turn;
import de.extio.lmlib.client.Conversation.TurnType;
import de.extio.lmlib.client.ToolCallData;
import de.extio.lmlib.client.ToolDefinition;
import de.extio.lmlib.profile.ModelCategory;
import de.extio.lmlib.profile.ModelProfile;
import tools.jackson.core.JacksonException;
import tools.jackson.databind.ObjectMapper;
public interface BaseAgent {
@@ -38,7 +37,7 @@ public interface BaseAgent {
static final ObjectMapper objectMapper = new ObjectMapper();
int MAX_TOOL_CALL_ROUNDS = 6;
int DEFAULT_MAX_TOOL_CALL_ROUNDS = 8;
default String name() {
throw new UnsupportedOperationException("Name must be implemented in the agent");
@@ -91,6 +90,10 @@ public interface BaseAgent {
}
return clientService.supportsToolCalling(this.modelCategory(context));
}
default int maxToolCallRounds(final AgentContext context) {
return DEFAULT_MAX_TOOL_CALL_ROUNDS;
}
default AgentResponseHandler responseHandler(final AgentContext context) {
return new TextAgentResponseHandler("response");
@@ -232,11 +235,7 @@ public interface BaseAgent {
}
}
if (!completion.toolCalls().isEmpty() && responseHandler instanceof final ToolCallingAgentResponseHandler toolCallingAgentResponseHandler) {
if (toolCallRounds >= MAX_TOOL_CALL_ROUNDS) {
parseException = new IllegalStateException("Too many tool call rounds");
break;
}
if (!completion.toolCalls().isEmpty() && toolCallRounds < this.maxToolCallRounds(split.context()) && responseHandler instanceof final ToolCallingAgentResponseHandler toolCallingAgentResponseHandler) {
final var toolCallResults = new ToolCallingAgentResponseHandler.ToolCallResults();
if (toolCallingAgentResponseHandler.handleToolCalls(completion, split.context(), toolCallResults)) {
toolCallRounds++;
@@ -462,8 +461,8 @@ public interface BaseAgent {
return conversation;
}
private Conversation createConversation(String system, String user) {
var conversation = Conversation.create(system, user);
private Conversation createConversation(final String system, final String user) {
final var conversation = Conversation.create(system, user);
conversation.setMetadata("Agent: " + this.name());
return conversation;
}