3
3
* SPDX-License-Identifier: Apache-2.0
4
4
*/
5
5
6
- package org .opensearch .ml .engine . tools ;
6
+ package org .opensearch .ml .common . utils ;
7
7
8
8
import static org .opensearch .ml .common .CommonValue .TENANT_ID_FIELD ;
9
9
import static org .opensearch .ml .common .utils .StringUtils .gson ;
10
10
11
- import java .util .ArrayList ;
12
11
import java .util .HashMap ;
13
12
import java .util .List ;
14
13
import java .util .Map ;
19
18
import org .opensearch .ml .common .output .model .ModelTensor ;
20
19
import org .opensearch .ml .common .output .model .ModelTensorOutput ;
21
20
import org .opensearch .ml .common .output .model .ModelTensors ;
22
- import org .opensearch .ml .common .spi .tools .Tool ;
23
- import org .opensearch .ml .common .utils .StringUtils ;
24
21
25
22
import com .google .gson .reflect .TypeToken ;
26
23
import com .jayway .jsonpath .JsonPath ;
@@ -38,6 +35,19 @@ public class ToolUtils {
38
35
public static final String TOOL_OUTPUT_FILTERS_FIELD = "output_filter" ;
39
36
public static final String TOOL_REQUIRED_PARAMS = "required_parameters" ;
40
37
38
+ /**
39
+ * Extracts required parameters based on tool attributes specification.
40
+ * <p>
41
+ * The method performs the following:
42
+ * <ul>
43
+ * <li>If required parameters are specified in attributes, only those parameters are extracted</li>
44
+ * <li>If no required parameters are specified, all parameters are returned</li>
45
+ * </ul>
46
+ *
47
+ * @param parameters The input parameters map to extract from
48
+ * @param attributes The attributes map containing required parameter specifications
49
+ * @return Map containing only the required parameters
50
+ */
41
51
public static Map <String , String > extractRequiredParameters (Map <String , String > parameters , Map <String , ?> attributes ) {
42
52
Map <String , String > extractedParameters = new HashMap <>();
43
53
if (parameters == null ) {
@@ -56,6 +66,26 @@ public static Map<String, String> extractRequiredParameters(Map<String, String>
56
66
return extractedParameters ;
57
67
}
58
68
69
+ /**
70
+ * Extracts and processes input parameters, including handling "input" parameter.
71
+ * <p>
72
+ * The method performs the following steps:
73
+ * <ol>
74
+ * <li>Extracts required parameters based on tool attributes specification</li>
75
+ * <li>If an "input" parameter exists:
76
+ * <ul>
77
+ * <li>Substitutes any parameter placeholders</li>
78
+ * <li>Parses it as a JSON map</li>
79
+ * <li>Merges the parsed values with other parameters</li>
80
+ * </ul>
81
+ * </li>
82
+ * </ol>
83
+ *
84
+ * @param parameters The raw input parameters
85
+ * @param attributes The tool attributes containing parameter specifications
86
+ * @return Map of processed input parameters
87
+ * @throws IllegalArgumentException if input JSON parsing fails
88
+ */
59
89
public static Map <String , String > extractInputParameters (Map <String , String > parameters , Map <String , ?> attributes ) {
60
90
Map <String , String > extractedParameters = ToolUtils .extractRequiredParameters (parameters , attributes );
61
91
if (extractedParameters .containsKey ("input" )) {
@@ -73,6 +103,22 @@ public static Map<String, String> extractInputParameters(Map<String, String> par
73
103
return extractedParameters ;
74
104
}
75
105
106
+ /**
107
+ * Builds the final parameter map for tool execution.
108
+ * <p>
109
+ * The method performs the following steps:
110
+ * <ol>
111
+ * <li>Combines tool specification parameters with input parameters</li>
112
+ * <li>Processes tool-specific parameter prefixes</li>
113
+ * <li>Applies configuration overrides from tool specification</li>
114
+ * <li>Adds tenant identification</li>
115
+ * </ol>
116
+ *
117
+ * @param parameters The input parameters to process
118
+ * @param toolSpec The tool specification containing default parameters and configuration
119
+ * @param tenantId The identifier for the tenant
120
+ * @return Map of processed parameters ready for tool execution
121
+ */
76
122
public static Map <String , String > buildToolParameters (Map <String , String > parameters , MLToolSpec toolSpec , String tenantId ) {
77
123
Map <String , String > executeParams = new HashMap <>();
78
124
if (toolSpec .getParameters () != null ) {
@@ -102,30 +148,14 @@ public static Map<String, String> buildToolParameters(Map<String, String> parame
102
148
return executeParams ;
103
149
}
104
150
105
- public static Tool createTool (Map <String , Tool .Factory > toolFactories , Map <String , String > executeParams , MLToolSpec toolSpec ) {
106
- if (!toolFactories .containsKey (toolSpec .getType ())) {
107
- throw new IllegalArgumentException ("Tool not found: " + toolSpec .getType ());
108
- }
109
- Map <String , Object > toolParams = new HashMap <>();
110
- toolParams .putAll (executeParams );
111
- Map <String , Object > runtimeResources = toolSpec .getRuntimeResources ();
112
- if (runtimeResources != null ) {
113
- toolParams .putAll (runtimeResources );
114
- }
115
- Tool tool = toolFactories .get (toolSpec .getType ()).create (toolParams );
116
- String toolName = getToolName (toolSpec );
117
- tool .setName (toolName );
118
-
119
- if (toolSpec .getDescription () != null ) {
120
- tool .setDescription (toolSpec .getDescription ());
121
- }
122
- if (executeParams .containsKey (toolName + ".description" )) {
123
- tool .setDescription (executeParams .get (toolName + ".description" ));
124
- }
125
-
126
- return tool ;
127
- }
128
-
151
+ /**
152
+ * Filters tool output based on specified output filters in tool parameters.
153
+ * Uses JSONPath expressions to extract specific portions of the response.
154
+ *
155
+ * @param toolParams The tool parameters containing output filter specifications
156
+ * @param response The raw tool response to filter
157
+ * @return Filtered output if successful, original response if filtering fails
158
+ */
129
159
public static Object filterToolOutput (Map <String , String > toolParams , Object response ) {
130
160
if (toolParams != null && toolParams .containsKey (TOOL_OUTPUT_FILTERS_FIELD )) {
131
161
try {
@@ -142,6 +172,20 @@ public static Object filterToolOutput(Map<String, String> toolParams, Object res
142
172
return response ;
143
173
}
144
174
175
+ /**
176
+ * Parses different types of tool responses into a JSON string representation.
177
+ * <p>
178
+ * Handles the following special cases:
179
+ * <ul>
180
+ * <li>ModelTensors - converts to XContent JSON representation</li>
181
+ * <li>ModelTensor - converts to XContent JSON representation</li>
182
+ * <li>ModelTensorOutput - converts to XContent JSON representation</li>
183
+ * <li>Other types - converts to generic JSON string</li>
184
+ * </ul>
185
+ *
186
+ * @param output The tool output object to parse
187
+ * @return JSON string representation of the output
188
+ */
145
189
public static String parseResponse (Object output ) {
146
190
try {
147
191
if (output instanceof List && !((List ) output ).isEmpty () && ((List ) output ).get (0 ) instanceof ModelTensors ) {
@@ -159,16 +203,49 @@ public static String parseResponse(Object output) {
159
203
}
160
204
}
161
205
162
- public static List <String > getToolNames (Map <String , Tool > tools ) {
163
- final List <String > inputTools = new ArrayList <>();
164
- for (Map .Entry <String , Tool > entry : tools .entrySet ()) {
165
- String toolName = entry .getValue ().getName ();
166
- inputTools .add (toolName );
167
- }
168
- return inputTools ;
169
- }
170
-
206
+ /**
207
+ * Gets the tool name from a tool specification.
208
+ * Returns the specified name if available, otherwise returns the tool type.
209
+ *
210
+ * @param toolSpec The tool specification
211
+ * @return The name of the tool
212
+ */
171
213
public static String getToolName (MLToolSpec toolSpec ) {
172
214
return toolSpec .getName () != null ? toolSpec .getName () : toolSpec .getType ();
173
215
}
216
+
217
+ /**
218
+ * Converts various types of tool output into a standardized ModelTensor format.
219
+ * The conversion logic depends on the type of input:
220
+ * <ul>
221
+ * <li>For Map inputs: directly uses the map as data</li>
222
+ * <li>For List inputs: wraps the list in a map with "output" as the key</li>
223
+ * <li>For other types: converts to JSON string and attempts to parse as map,
224
+ * if parsing fails, wraps the original output in a map with "output" as the key</li>
225
+ * </ul>
226
+ *
227
+ * @param output The output object to be converted. Can be a Map, List, or any other object
228
+ * @param outputKey The key/name to be assigned to the resulting ModelTensor
229
+ * @return A ModelTensor containing the formatted output data
230
+ */
231
+ public static ModelTensor convertOutputToModelTensor (Object output , String outputKey ) {
232
+ ModelTensor modelTensor ;
233
+ if (output instanceof Map ) {
234
+ modelTensor = ModelTensor .builder ().name (outputKey ).dataAsMap ((Map ) output ).build ();
235
+ } else if (output instanceof List ) {
236
+ Map <String , Object > resultMap = new HashMap <>();
237
+ resultMap .put ("output" , output );
238
+ modelTensor = ModelTensor .builder ().name (outputKey ).dataAsMap (resultMap ).build ();
239
+ } else {
240
+ String outputJson = StringUtils .toJson (output );
241
+ Map <String , Object > resultMap ;
242
+ if (StringUtils .isJson (outputJson )) {
243
+ resultMap = StringUtils .fromJson (outputJson , "output" );
244
+ } else {
245
+ resultMap = Map .of ("output" , output );
246
+ }
247
+ modelTensor = ModelTensor .builder ().name (outputKey ).dataAsMap (resultMap ).build ();
248
+ }
249
+ return modelTensor ;
250
+ }
174
251
}
0 commit comments