From 453fbab3d69aed3f5564683bf9b22591f76805d6 Mon Sep 17 00:00:00 2001 From: Nathalie Jonathan Date: Fri, 17 Oct 2025 15:01:38 -0700 Subject: [PATCH] Fix unsupported operation exception in execute tool API Signed-off-by: Nathalie Jonathan --- .../algorithms/tool/MLToolExecutor.java | 7 +++-- .../algorithms/tool/MLToolExecutorTest.java | 28 ++++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/ml-algorithms/src/main/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutor.java b/ml-algorithms/src/main/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutor.java index e92f722611..481e3b2dc2 100644 --- a/ml-algorithms/src/main/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutor.java +++ b/ml-algorithms/src/main/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutor.java @@ -83,13 +83,14 @@ public void execute(Input input, ActionListener listener) { } try { - Tool tool = toolFactory.create(new HashMap<>(parameters)); - if (!tool.validate(parameters)) { + Map mutableParams = new HashMap<>(parameters); + Tool tool = toolFactory.create(mutableParams); + if (!tool.validate(mutableParams)) { listener.onFailure(new IllegalArgumentException("Invalid parameters for tool: " + toolName)); return; } - tool.run(parameters, ActionListener.wrap(result -> { + tool.run(mutableParams, ActionListener.wrap(result -> { List modelTensors = new ArrayList<>(); processOutput(result, modelTensors); ModelTensors tensors = ModelTensors.builder().mlModelTensors(modelTensors).build(); diff --git a/ml-algorithms/src/test/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutorTest.java b/ml-algorithms/src/test/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutorTest.java index 6c76a88991..58bd2199c8 100644 --- a/ml-algorithms/src/test/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutorTest.java +++ b/ml-algorithms/src/test/java/org/opensearch/ml/engine/algorithms/tool/MLToolExecutorTest.java @@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -41,7 +42,6 @@ public class MLToolExecutorTest { private Client client; @Mock private SdkClient sdkClient; - private Settings settings; @Mock private ClusterService clusterService; @Mock @@ -176,4 +176,30 @@ public void test_EmptyInputData() { mlToolExecutor.execute(toolMLInput, actionListener); }); } + + @Test + public void test_ImmutableEmptyParametersMap() { + Map immutableEmptyMap = Collections.emptyMap(); + + when(toolMLInput.getToolName()).thenReturn("TestTool"); + when(toolMLInput.getInputDataset()).thenReturn(inputDataSet); + when(inputDataSet.getParameters()).thenReturn(immutableEmptyMap); + when(toolFactory.create(any())).thenReturn(tool); + when(tool.validate(any())).thenReturn(true); + + Mockito.doAnswer(invocation -> { + Map params = invocation.getArgument(0); + // Tool tries to modify parameters, should not throw exception + params.put("test_key", "test_value"); + ActionListener listener = invocation.getArgument(1); + listener.onResponse("test result"); + return null; + }).when(tool).run(any(), any()); + + mlToolExecutor.execute(toolMLInput, actionListener); + + Mockito.verify(actionListener).onResponse(outputCaptor.capture()); + Output output = outputCaptor.getValue(); + Assert.assertTrue(output instanceof ModelTensorOutput); + } }