Fix ToolCallingChatOptions isInternalToolExecutionEnabled

- The ModelOptionsUtils merges the ToolCallingChatOptions with the provider chat options
   - The underlying beanwrapper implementation expects the boolean option to have the getter method starting with "get" instad of "is" which makes the current `isInternalToolExecutionEnabled` not used by the merge operation at all. To fix this, rename the `isInternalToolExecutionEnabled` method to `getInternalToolExecutionEnabled` and deprecate the existing `isInternalToolExecutionEnabled` method.

Signed-off-by: Ilayaperumal Gopinathan <ilayaperumal.gopinathan@broadcom.com>
This commit is contained in:
Ilayaperumal Gopinathan
2025-04-14 12:38:09 +01:00
committed by Christian Tzolov
parent 257c91ccf2
commit 76a1dbe747
20 changed files with 65 additions and 49 deletions

View File

@@ -416,8 +416,8 @@ public class AnthropicChatModel implements ChatModel {
requestOptions.setHttpHeaders(
mergeHttpHeaders(runtimeOptions.getHttpHeaders(), this.defaultOptions.getHttpHeaders()));
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -427,7 +427,7 @@ public class AnthropicChatModel implements ChatModel {
}
else {
requestOptions.setHttpHeaders(this.defaultOptions.getHttpHeaders());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -108,7 +108,7 @@ public class AnthropicChatOptions implements ToolCallingChatOptions {
.toolCallbacks(
fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null)
.toolNames(fromOptions.getToolNames() != null ? new HashSet<>(fromOptions.getToolNames()) : null)
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
.toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null)
.httpHeaders(fromOptions.getHttpHeaders() != null ? new HashMap<>(fromOptions.getHttpHeaders()) : null)
.build();
@@ -216,7 +216,7 @@ public class AnthropicChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
@JsonIgnore
public Boolean isInternalToolExecutionEnabled() {
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}

View File

@@ -642,8 +642,8 @@ public class AzureOpenAiChatModel implements ChatModel {
// Jackson, used by ModelOptionsUtils.
if (runtimeOptions != null) {
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -652,7 +652,7 @@ public class AzureOpenAiChatModel implements ChatModel {
this.defaultOptions.getToolContext()));
}
else {
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -231,7 +231,7 @@ public class AzureOpenAiChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
@JsonIgnore
public Boolean isInternalToolExecutionEnabled() {
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}
@@ -265,7 +265,7 @@ public class AzureOpenAiChatOptions implements ToolCallingChatOptions {
.topLogprobs(fromOptions.getTopLogProbs())
.enhancements(fromOptions.getEnhancements())
.toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null)
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
.streamOptions(fromOptions.getStreamOptions())
.toolCallbacks(
fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null)

View File

@@ -301,9 +301,9 @@ public class BedrockProxyChatModel implements ChatModel {
: this.defaultOptions.getToolNames())
.toolContext(runtimeOptions.getToolContext() != null ? runtimeOptions.getToolContext()
: this.defaultOptions.getToolContext())
.internalToolExecutionEnabled(runtimeOptions.isInternalToolExecutionEnabled() != null
? runtimeOptions.isInternalToolExecutionEnabled()
: this.defaultOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(runtimeOptions.getInternalToolExecutionEnabled() != null
? runtimeOptions.getInternalToolExecutionEnabled()
: this.defaultOptions.getInternalToolExecutionEnabled())
.build();
}

View File

@@ -399,8 +399,8 @@ public class MistralAiChatModel implements ChatModel {
// Jackson, used by ModelOptionsUtils.
if (runtimeOptions != null) {
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -409,7 +409,7 @@ public class MistralAiChatModel implements ChatModel {
this.defaultOptions.getToolContext()));
}
else {
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -155,7 +155,7 @@ public class MistralAiChatOptions implements ToolCallingChatOptions {
.toolChoice(fromOptions.getToolChoice())
.toolCallbacks(fromOptions.getToolCallbacks())
.toolNames(fromOptions.getToolNames())
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
.toolContext(fromOptions.getToolContext())
.build();
}
@@ -287,8 +287,8 @@ public class MistralAiChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
@JsonIgnore
public Boolean isInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
public Boolean getInternalToolExecutionEnabled() {
return internalToolExecutionEnabled;
}
@Override

View File

@@ -92,7 +92,7 @@ public class MistralAiChatCompletionRequestTest {
Prompt prompt = chatModel.buildRequestPrompt(new Prompt("Test message content", runtimeOptions));
assertThat(((ToolCallingChatOptions) prompt.getOptions())).isNotNull();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).isInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()).hasSize(2);
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()
.stream()

View File

@@ -389,8 +389,8 @@ public class OllamaChatModel implements ChatModel {
// Jackson, used by ModelOptionsUtils.
if (runtimeOptions != null) {
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -399,7 +399,7 @@ public class OllamaChatModel implements ChatModel {
this.defaultOptions.getToolContext()));
}
else {
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -396,7 +396,7 @@ public class OllamaOptions implements ToolCallingChatOptions, EmbeddingOptions {
.penalizeNewline(fromOptions.getPenalizeNewline())
.stop(fromOptions.getStop())
.toolNames(fromOptions.getToolNames())
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
.toolCallbacks(fromOptions.getToolCallbacks())
.toolContext(fromOptions.getToolContext()).build();
}
@@ -736,9 +736,9 @@ public class OllamaOptions implements ToolCallingChatOptions, EmbeddingOptions {
@Override
@Nullable
@JsonIgnore
public Boolean isInternalToolExecutionEnabled() {
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}
}
@Override
@JsonIgnore

View File

@@ -65,7 +65,7 @@ class OllamaChatRequestTests {
Prompt prompt = chatModel.buildRequestPrompt(new Prompt("Test message content", runtimeOptions));
assertThat(((ToolCallingChatOptions) prompt.getOptions())).isNotNull();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).isInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()).hasSize(2);
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()
.stream()

View File

@@ -513,8 +513,8 @@ public class OpenAiChatModel implements ChatModel {
requestOptions.setHttpHeaders(
mergeHttpHeaders(runtimeOptions.getHttpHeaders(), this.defaultOptions.getHttpHeaders()));
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -524,7 +524,7 @@ public class OpenAiChatModel implements ChatModel {
}
else {
requestOptions.setHttpHeaders(this.defaultOptions.getHttpHeaders());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -255,7 +255,7 @@ public class OpenAiChatOptions implements ToolCallingChatOptions {
fromOptions.getToolCallbacks() != null ? new ArrayList<>(fromOptions.getToolCallbacks()) : null)
.toolNames(fromOptions.getToolNames() != null ? new HashSet<>(fromOptions.getToolNames()) : null)
.httpHeaders(fromOptions.getHttpHeaders() != null ? new HashMap<>(fromOptions.getHttpHeaders()) : null)
.internalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled())
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
.toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null)
.store(fromOptions.getStore())
.metadata(fromOptions.getMetadata())
@@ -444,7 +444,11 @@ public class OpenAiChatOptions implements ToolCallingChatOptions {
@Deprecated
@JsonIgnore
public Boolean getProxyToolCalls() {
return this.internalToolExecutionEnabled != null ? !this.internalToolExecutionEnabled : null;
return this.getToolExecutionEnabled() != null ? !this.internalToolExecutionEnabled : null;
}
private Boolean getToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}
@Deprecated
@@ -501,8 +505,8 @@ public class OpenAiChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
@JsonIgnore
public Boolean isInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
public Boolean getInternalToolExecutionEnabled() {
return internalToolExecutionEnabled;
}
@Override

View File

@@ -62,7 +62,7 @@ class ChatCompletionRequestTests {
Prompt prompt = chatModel.buildRequestPrompt(new Prompt("Test message content", runtimeOptions));
assertThat(((ToolCallingChatOptions) prompt.getOptions())).isNotNull();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).isInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getInternalToolExecutionEnabled()).isFalse();
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()).hasSize(2);
assertThat(((ToolCallingChatOptions) prompt.getOptions()).getToolCallbacks()
.stream()

View File

@@ -503,8 +503,8 @@ public class VertexAiGeminiChatModel implements ChatModel, DisposableBean {
// Jackson, used by ModelOptionsUtils.
if (runtimeOptions != null) {
requestOptions.setInternalToolExecutionEnabled(
ModelOptionsUtils.mergeOption(runtimeOptions.isInternalToolExecutionEnabled(),
this.defaultOptions.isInternalToolExecutionEnabled()));
ModelOptionsUtils.mergeOption(runtimeOptions.getInternalToolExecutionEnabled(),
this.defaultOptions.getInternalToolExecutionEnabled()));
requestOptions.setToolNames(ToolCallingChatOptions.mergeToolNames(runtimeOptions.getToolNames(),
this.defaultOptions.getToolNames()));
requestOptions.setToolCallbacks(ToolCallingChatOptions.mergeToolCallbacks(runtimeOptions.getToolCallbacks(),
@@ -518,7 +518,7 @@ public class VertexAiGeminiChatModel implements ChatModel, DisposableBean {
this.defaultOptions.getSafetySettings()));
}
else {
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.isInternalToolExecutionEnabled());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());

View File

@@ -148,7 +148,7 @@ public class VertexAiGeminiChatOptions implements ToolCallingChatOptions {
options.setResponseMimeType(fromOptions.getResponseMimeType());
options.setGoogleSearchRetrieval(fromOptions.getGoogleSearchRetrieval());
options.setSafetySettings(fromOptions.getSafetySettings());
options.setInternalToolExecutionEnabled(fromOptions.isInternalToolExecutionEnabled());
options.setInternalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled());
options.setToolContext(fromOptions.getToolContext());
return options;
}
@@ -287,7 +287,7 @@ public class VertexAiGeminiChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
public Boolean isInternalToolExecutionEnabled() {
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}

View File

@@ -109,7 +109,7 @@ public class DefaultToolCallingChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
public Boolean isInternalToolExecutionEnabled() {
public Boolean getInternalToolExecutionEnabled() {
return this.internalToolExecutionEnabled;
}
@@ -141,7 +141,7 @@ public class DefaultToolCallingChatOptions implements ToolCallingChatOptions {
@Override
@Nullable
public Boolean getProxyToolCalls() {
return isInternalToolExecutionEnabled() != null ? !isInternalToolExecutionEnabled() : null;
return getInternalToolExecutionEnabled() != null ? !getInternalToolExecutionEnabled() : null;
}
@Override
@@ -236,7 +236,7 @@ public class DefaultToolCallingChatOptions implements ToolCallingChatOptions {
options.setToolCallbacks(getToolCallbacks());
options.setToolNames(getToolNames());
options.setToolContext(getToolContext());
options.setInternalToolExecutionEnabled(isInternalToolExecutionEnabled());
options.setInternalToolExecutionEnabled(getInternalToolExecutionEnabled());
options.setModel(getModel());
options.setFrequencyPenalty(getFrequencyPenalty());
options.setMaxTokens(getMaxTokens());

View File

@@ -37,6 +37,7 @@ import org.springframework.util.CollectionUtils;
* including tool calling.
*
* @author Thomas Vitale
* @author Ilayaperumal Gopinathan
* @since 1.0.0
*/
public interface ToolCallingChatOptions extends FunctionCallingOptions {
@@ -68,7 +69,17 @@ public interface ToolCallingChatOptions extends FunctionCallingOptions {
* the model or if the tools should be executed directly by the caller.
*/
@Nullable
Boolean isInternalToolExecutionEnabled();
Boolean getInternalToolExecutionEnabled();
/**
* Whether the {@link ChatModel} is responsible for executing the tools requested by
* the model or if the tools should be executed directly by the caller.
*/
@Nullable
@Deprecated
default Boolean isInternalToolExecutionEnabled() {
return getInternalToolExecutionEnabled();
}
/**
* Set whether the {@link ChatModel} is responsible for executing the tools requested

View File

@@ -65,8 +65,9 @@ public interface ToolExecutionEligibilityChecker extends Function<ChatResponse,
Assert.notNull(chatOptions, "chatOptions cannot be null");
boolean internalToolExecutionEnabled;
if (chatOptions instanceof ToolCallingChatOptions toolCallingChatOptions
&& toolCallingChatOptions.isInternalToolExecutionEnabled() != null) {
internalToolExecutionEnabled = Boolean.TRUE.equals(toolCallingChatOptions.isInternalToolExecutionEnabled());
&& toolCallingChatOptions.getInternalToolExecutionEnabled() != null) {
internalToolExecutionEnabled = Boolean.TRUE
.equals(toolCallingChatOptions.getInternalToolExecutionEnabled());
}
else if (chatOptions instanceof FunctionCallingOptions functionCallingOptions
&& functionCallingOptions.getProxyToolCalls() != null) {

View File

@@ -150,7 +150,7 @@ class DefaultToolCallingChatOptionsTests {
assertThat(c.getToolCallbacks()).isEqualTo(original.getToolCallbacks());
assertThat(c.getToolNames()).isEqualTo(original.getToolNames());
assertThat(c.getToolContext()).isEqualTo(original.getToolContext());
assertThat(c.isInternalToolExecutionEnabled()).isEqualTo(original.isInternalToolExecutionEnabled());
assertThat(c.getInternalToolExecutionEnabled()).isEqualTo(original.getInternalToolExecutionEnabled());
assertThat(c.getModel()).isEqualTo(original.getModel());
assertThat(c.getTemperature()).isEqualTo(original.getTemperature());
});
@@ -195,7 +195,7 @@ class DefaultToolCallingChatOptionsTests {
assertThat(o.getToolCallbacks()).containsExactly(callback);
assertThat(o.getToolNames()).containsExactly("tool1");
assertThat(o.getToolContext()).isEqualTo(context);
assertThat(o.isInternalToolExecutionEnabled()).isTrue();
assertThat(o.getInternalToolExecutionEnabled()).isTrue();
assertThat(o.getModel()).isEqualTo("gpt-4");
assertThat(o.getTemperature()).isEqualTo(0.7);
assertThat(o.getMaxTokens()).isEqualTo(100);
@@ -236,7 +236,7 @@ class DefaultToolCallingChatOptionsTests {
assertThat(options.getProxyToolCalls()).isFalse();
options.setProxyToolCalls(true);
assertThat(options.isInternalToolExecutionEnabled()).isFalse();
assertThat(options.getInternalToolExecutionEnabled()).isFalse();
}
}