80 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
| import inspect
 | |
| from typing import get_type_hints, List, Dict, Any
 | |
| 
 | |
| 
 | |
| def doc_to_dict(docstring):
 | |
|     lines = docstring.split("\n")
 | |
|     description = lines[1].strip()
 | |
|     param_dict = {}
 | |
| 
 | |
|     for line in lines:
 | |
|         if ":param" in line:
 | |
|             line = line.replace(":param", "").strip()
 | |
|             param, desc = line.split(":", 1)
 | |
|             param_dict[param.strip()] = desc.strip()
 | |
|     ret_dict = {"description": description, "params": param_dict}
 | |
|     return ret_dict
 | |
| 
 | |
| 
 | |
| def get_tools_specs(tools) -> list[dict]:
 | |
|     function_list = [
 | |
|         {"name": func, "function": getattr(tools, func)}
 | |
|         for func in dir(tools)
 | |
|         if callable(getattr(tools, func))
 | |
|         and not func.startswith("__")
 | |
|         and not inspect.isclass(getattr(tools, func))
 | |
|     ]
 | |
| 
 | |
|     specs = []
 | |
|     for function_item in function_list:
 | |
|         function_name = function_item["name"]
 | |
|         function = function_item["function"]
 | |
| 
 | |
|         function_doc = doc_to_dict(function.__doc__ or function_name)
 | |
|         specs.append(
 | |
|             {
 | |
|                 "name": function_name,
 | |
|                 # TODO: multi-line desc?
 | |
|                 "description": function_doc.get("description", function_name),
 | |
|                 "parameters": {
 | |
|                     "type": "object",
 | |
|                     "properties": {
 | |
|                         param_name: {
 | |
|                             "type": param_annotation.__name__.lower(),
 | |
|                             **(
 | |
|                                 {
 | |
|                                     "enum": (
 | |
|                                         str(param_annotation.__args__)
 | |
|                                         if hasattr(param_annotation, "__args__")
 | |
|                                         else None
 | |
|                                     )
 | |
|                                 }
 | |
|                                 if hasattr(param_annotation, "__args__")
 | |
|                                 else {}
 | |
|                             ),
 | |
|                             "description": function_doc.get("params", {}).get(
 | |
|                                 param_name, param_name
 | |
|                             ),
 | |
|                         }
 | |
|                         for param_name, param_annotation in get_type_hints(
 | |
|                             function
 | |
|                         ).items()
 | |
|                         if param_name != "return"
 | |
|                         and not (
 | |
|                             param_name.startswith("__") and param_name.endswith("__")
 | |
|                         )
 | |
|                     },
 | |
|                     "required": [
 | |
|                         name
 | |
|                         for name, param in inspect.signature(
 | |
|                             function
 | |
|                         ).parameters.items()
 | |
|                         if param.default is param.empty
 | |
|                         and not (name.startswith("__") and name.endswith("__"))
 | |
|                     ],
 | |
|                 },
 | |
|             }
 | |
|         )
 | |
| 
 | |
|     return specs
 |