Relaxed toolCallArguments validation

There seems to be some models not handling correctly the non-nullability of toolCallArguments when defining a tool call. For example, the Ollama implementation is always null-safe (if no tool argument, then '{}' is used). Other implementations might produce a null value.

This PR relaxes the toolCallArguments validation to support null toolCallArguments within ToolCallingObservationContext.

Fixes gh-3234

Signed-off-by: Thomas Vitale <ThomasVitale@users.noreply.github.com>
This commit is contained in:
Thomas Vitale
2025-05-18 14:58:29 +02:00
committed by Mark Pollack
parent 81137cae54
commit 46491c0426
2 changed files with 21 additions and 21 deletions

View File

@@ -47,14 +47,13 @@ public final class ToolCallingObservationContext extends Observation.Context {
private String toolCallResult;
private ToolCallingObservationContext(ToolDefinition toolDefinition, ToolMetadata toolMetadata,
String toolCallArguments, @Nullable String toolCallResult) {
@Nullable String toolCallArguments, @Nullable String toolCallResult) {
Assert.notNull(toolDefinition, "toolDefinition cannot be null");
Assert.notNull(toolMetadata, "toolMetadata cannot be null");
Assert.hasText(toolCallArguments, "toolCallArguments cannot be null or empty");
this.toolDefinition = toolDefinition;
this.toolMetadata = toolMetadata;
this.toolCallArguments = toolCallArguments;
this.toolCallArguments = toolCallArguments != null ? toolCallArguments : "{}";
this.toolCallResult = toolCallResult;
}

View File

@@ -32,11 +32,30 @@ class ToolCallingObservationContextTests {
@Test
void whenMandatoryRequestOptionsThenReturn() {
var observationContext = ToolCallingObservationContext.builder()
.toolDefinition(ToolDefinition.builder().name("toolA").description("description").inputSchema("{}").build())
.build();
assertThat(observationContext).isNotNull();
}
@Test
void whenToolArgumentsIsNullThenReturn() {
var observationContext = ToolCallingObservationContext.builder()
.toolDefinition(ToolDefinition.builder().name("toolA").description("description").inputSchema("{}").build())
.toolCallArguments(null)
.build();
assertThat(observationContext).isNotNull();
assertThat(observationContext.getToolCallArguments()).isEqualTo("{}");
}
@Test
void whenToolArgumentsIsNotNullThenReturn() {
var observationContext = ToolCallingObservationContext.builder()
.toolDefinition(ToolDefinition.builder().name("toolA").description("description").inputSchema("{}").build())
.toolCallArguments("lizard")
.build();
assertThat(observationContext).isNotNull();
assertThat(observationContext.getToolCallArguments()).isEqualTo("lizard");
}
@Test
@@ -55,22 +74,4 @@ class ToolCallingObservationContextTests {
.build()).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("toolMetadata cannot be null");
}
@Test
void whenToolCallInputIsNullThenThrow() {
assertThatThrownBy(() -> ToolCallingObservationContext.builder()
.toolDefinition(ToolDefinition.builder().name("toolA").description("description").inputSchema("{}").build())
.toolCallArguments(null)
.build()).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("toolCallArguments cannot be null or empty");
}
@Test
void whenToolCallInputIsEmptyThenThrow() {
assertThatThrownBy(() -> ToolCallingObservationContext.builder()
.toolDefinition(ToolDefinition.builder().name("toolA").description("description").inputSchema("{}").build())
.toolCallArguments("")
.build()).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("toolCallArguments cannot be null or empty");
}
}