|
29 | 29 | BytesValue, |
30 | 30 | ) |
31 | 31 | from google.protobuf.struct_pb2 import Struct |
| 32 | +from google.protobuf import json_format |
32 | 33 |
|
33 | 34 | MetadataDict = Dict[str, List[Union[bytes, str]]] |
34 | 35 | MetadataTuple = Tuple[Tuple[str, Union[bytes, str]], ...] |
@@ -149,8 +150,6 @@ def convert_value_to_struct(value: Dict[str, Any]) -> Struct: |
149 | 150 | if not isinstance(value, dict) and not isinstance(value, bytes): |
150 | 151 | raise ValueError(f'Value must be a dictionary, got {type(value)}') |
151 | 152 |
|
152 | | - from google.protobuf import json_format |
153 | | - |
154 | 153 | # Convert the value to a JSON-serializable format first |
155 | 154 | # Handle bytes by converting to base64 string for JSON compatibility |
156 | 155 | if isinstance(value, bytes): |
@@ -241,170 +240,3 @@ def convert_dict_to_grpc_dict_of_any(parameters: Optional[Dict[str, Any]]) -> Di |
241 | 240 | converted[key] = convert_value_to_grpc_any(value) |
242 | 241 |
|
243 | 242 | return converted |
244 | | - |
245 | | - |
246 | | -def create_tool_function( |
247 | | - name: str, |
248 | | - description: str, |
249 | | - parameters: Optional[Dict[str, Any]] = None, |
250 | | - required: Optional[List[str]] = None, |
251 | | -) -> 'ConversationToolsFunction': |
252 | | - """Create a tool function with automatic parameter conversion. |
253 | | -
|
254 | | - This helper automatically converts Python dictionaries to the proper JSON Schema |
255 | | - format required by the Dapr Conversation API. |
256 | | -
|
257 | | - The parameters map directly represents the JSON schema structure using proper protobuf types. |
258 | | -
|
259 | | - Args: |
260 | | - name: Function name |
261 | | - description: Human-readable description of what the function does |
262 | | - parameters: Parameter definitions (raw Python dict) |
263 | | - required: List of required parameter names |
264 | | -
|
265 | | - Returns: |
266 | | - ConversationToolsFunction ready to use with Alpha2 API |
267 | | -
|
268 | | - Examples: |
269 | | - # Simple approach - properties become JSON schema |
270 | | - >>> create_tool_function( |
271 | | - ... name="get_weather", |
272 | | - ... description="Get current weather", |
273 | | - ... parameters={ |
274 | | - ... "location": {"type": "string", "description": "City name"}, |
275 | | - ... "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} |
276 | | - ... }, |
277 | | - ... required=["location"] |
278 | | - ... ) |
279 | | - # Creates: parameters = { |
280 | | - # "type": StringValue("object"), |
281 | | - # "properties": Struct({...}), |
282 | | - # "required": ListValue([...]) |
283 | | - # } |
284 | | -
|
285 | | - # Full JSON Schema approach (already complete) |
286 | | - >>> create_tool_function( |
287 | | - ... name="calculate", |
288 | | - ... description="Perform calculations", |
289 | | - ... parameters={ |
290 | | - ... "type": "object", |
291 | | - ... "properties": { |
292 | | - ... "expression": {"type": "string", "description": "Math expression"} |
293 | | - ... }, |
294 | | - ... "required": ["expression"] |
295 | | - ... } |
296 | | - ... ) |
297 | | - # Maps schema fields directly to protobuf map |
298 | | -
|
299 | | - # No parameters |
300 | | - >>> create_tool_function( |
301 | | - ... name="get_time", |
302 | | - ... description="Get current time" |
303 | | - ... ) |
304 | | - # Creates: parameters = {} |
305 | | - """ |
306 | | - from dapr.clients.grpc._request import ConversationToolsFunction |
307 | | - |
308 | | - if parameters is None: |
309 | | - # No parameters - simple case |
310 | | - return ConversationToolsFunction(name=name, description=description, parameters={}) |
311 | | - |
312 | | - # Build the complete JSON Schema object |
313 | | - if isinstance(parameters, dict): |
314 | | - # Check if it's already a complete JSON schema |
315 | | - if 'type' in parameters and parameters['type'] == 'object': |
316 | | - # Complete JSON schema provided - use as-is |
317 | | - json_schema = parameters.copy() |
318 | | - # Add required field if provided separately and not already present |
319 | | - if required and 'required' not in json_schema: |
320 | | - json_schema['required'] = required |
321 | | - elif 'properties' in parameters: |
322 | | - # Properties provided directly - wrap in JSON schema |
323 | | - json_schema = {'type': 'object', 'properties': parameters['properties']} |
324 | | - if required: |
325 | | - json_schema['required'] = required |
326 | | - elif 'required' in parameters: |
327 | | - json_schema['required'] = parameters['required'] |
328 | | - else: |
329 | | - # Assume it's a direct mapping of parameter names to schemas |
330 | | - json_schema = {'type': 'object', 'properties': parameters} |
331 | | - if required: |
332 | | - json_schema['required'] = required |
333 | | - else: |
334 | | - raise ValueError(f'Parameters must be a dictionary, got {type(parameters)}') |
335 | | - |
336 | | - # Map JSON schema fields directly to protobuf map entries |
337 | | - # The parameters map directly represents the JSON schema structure |
338 | | - converted_params = {} |
339 | | - if json_schema: |
340 | | - for key, value in json_schema.items(): |
341 | | - converted_params[key] = convert_value_to_struct(value) |
342 | | - |
343 | | - return ConversationToolsFunction( |
344 | | - name=name, description=description, parameters=converted_params |
345 | | - ) |
346 | | - |
347 | | - |
348 | | -def create_tool( |
349 | | - name: str, |
350 | | - description: str, |
351 | | - parameters: Optional[Dict[str, Any]] = None, |
352 | | - required: Optional[List[str]] = None, |
353 | | -) -> 'ConversationTools': |
354 | | - """Create a complete tool with automatic parameter conversion. |
355 | | -
|
356 | | - Args: |
357 | | - name: Function name |
358 | | - description: Human-readable description of what the function does |
359 | | - parameters: JSON schema for function parameters (raw Python dict) |
360 | | - required: List of required parameter names |
361 | | -
|
362 | | - Returns: |
363 | | - ConversationTools ready to use with converse_alpha2() |
364 | | -
|
365 | | - Examples: |
366 | | - # Weather tool |
367 | | - >>> weather_tool = create_tool( |
368 | | - ... name="get_weather", |
369 | | - ... description="Get current weather for a location", |
370 | | - ... parameters={ |
371 | | - ... "location": { |
372 | | - ... "type": "string", |
373 | | - ... "description": "The city and state or country" |
374 | | - ... }, |
375 | | - ... "unit": { |
376 | | - ... "type": "string", |
377 | | - ... "enum": ["celsius", "fahrenheit"], |
378 | | - ... "description": "Temperature unit" |
379 | | - ... } |
380 | | - ... }, |
381 | | - ... required=["location"] |
382 | | - ... ) |
383 | | -
|
384 | | - # Calculator tool with full schema |
385 | | - >>> calc_tool = create_tool( |
386 | | - ... name="calculate", |
387 | | - ... description="Perform mathematical calculations", |
388 | | - ... parameters={ |
389 | | - ... "type": "object", |
390 | | - ... "properties": { |
391 | | - ... "expression": { |
392 | | - ... "type": "string", |
393 | | - ... "description": "Mathematical expression to evaluate" |
394 | | - ... } |
395 | | - ... }, |
396 | | - ... "required": ["expression"] |
397 | | - ... } |
398 | | - ... ) |
399 | | -
|
400 | | - # Simple tool with no parameters |
401 | | - >>> time_tool = create_tool( |
402 | | - ... name="get_current_time", |
403 | | - ... description="Get the current date and time" |
404 | | - ... ) |
405 | | - """ |
406 | | - from dapr.clients.grpc._request import ConversationTools |
407 | | - |
408 | | - function = create_tool_function(name, description, parameters, required) |
409 | | - |
410 | | - return ConversationTools(function=function) |
0 commit comments