Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.agentscope.core.message.ToolUseBlock;
import io.agentscope.core.model.ChatResponse;
import io.agentscope.core.model.ChatUsage;
import io.agentscope.core.util.JsonUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -66,9 +67,16 @@ public ChatResponse parseResponse(OllamaResponse response) {
// AgentScope requirement.
String callId = UUID.randomUUID().toString();

// Convert input to JSON string for validation in ToolExecutor
// For tools with no parameters, input will be an empty map {}
String argumentsJson = "{}";
if (input != null && !input.isEmpty()) {
argumentsJson = JsonUtils.getJsonCodec().toJson(input);
}
Comment on lines 70 to 77
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix correctly addresses the issue, but there's an inconsistency with how other formatters handle this case. OpenAI's approach (line 222-234 in OpenAIResponseParser) handles null arguments by setting them to empty string "", then parsing to create an empty map. Anthropic (line 72-75 in AnthropicResponseParser) uses an empty string "" when _input is null. For consistency across formatters and to handle potential null inputs more robustly, consider adding a null check: if (input == null || input.isEmpty()) { argumentsJson = "{}"; } instead of relying on the assumption that input is never null.

Copilot uses AI. Check for mistakes.

contentBlocks.add(
new ToolUseBlock(
callId, fn.getName(), input, null // raw content
callId, fn.getName(), input, argumentsJson, null // metadata
));
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline comment // metadata is misleading. Based on the ToolUseBlock constructor signature (5 parameters: id, name, input, content, metadata), the comment should be // raw content for the 4th parameter position (argumentsJson), not for the 5th parameter (null). The null value here is the metadata parameter.

Suggested change
callId, fn.getName(), input, argumentsJson, null // metadata
));
callId, fn.getName(), input, argumentsJson, // raw content
null));

Copilot uses AI. Check for mistakes.
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,46 @@ void testFallbackFinishReason() {
// Assert
assertEquals("stop", chatResponse.getFinishReason());
}

@Test
@DisplayName("Should parse tool call with no parameters (empty arguments map)")
void testParseToolCallWithNoParameters() {
// Arrange - This reproduces the bug from issue #569
// Ollama returns empty map {} for tools with no parameters
OllamaResponse response = new OllamaResponse();
response.setModel("test-model");

OllamaMessage message = new OllamaMessage("assistant", "");

OllamaToolCall toolCall = new OllamaToolCall();
OllamaFunction function = new OllamaFunction();
function.setName("getTime");
function.setArguments(Map.of()); // Empty map for no parameters
toolCall.setFunction(function);

message.setToolCalls(Arrays.asList(toolCall));
response.setMessage(message);

// Act
ChatResponse chatResponse = parser.parseResponse(response);

// Assert
assertNotNull(chatResponse);
List<ContentBlock> content = chatResponse.getContent();
assertEquals(1, content.size());
assertTrue(content.get(0) instanceof ToolUseBlock);

ToolUseBlock toolBlock = (ToolUseBlock) content.get(0);
assertEquals("getTime", toolBlock.getName());
assertTrue(toolBlock.getInput().isEmpty(), "Input should be empty map");

// Verify that getContent() returns "{}" (not null) for no-parameter tools
assertNotNull(
toolBlock.getContent(),
"ToolUseBlock content should not be null for validation in ToolExecutor");
assertEquals(
"{}",
toolBlock.getContent(),
"ToolUseBlock content should be empty JSON object string for no-parameter tools");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ void testNullSchema() {
assertNull(result);
}

@Test
@DisplayName("Should pass when input is empty object with empty schema")
void testEmptyInputWithEmptySchema() {
// This simulates a tool with no parameters (like getTime())
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of()); // Empty properties = no parameters

String result = ToolValidator.validateInput("{}", schema);
assertNull(result, "Empty object {} should pass validation with empty schema");
}

@Test
@DisplayName("Should pass when schema is empty")
void testEmptySchema() {
Expand Down
Loading