Unverified Commit ac96d192 authored by Yeuoly's avatar Yeuoly Committed by GitHub

fix: parameter type handling in API tool and parser (#2574)

parent 07fbeb6c
...@@ -200,7 +200,7 @@ class ApiTool(Tool): ...@@ -200,7 +200,7 @@ class ApiTool(Tool):
# replace path parameters # replace path parameters
for name, value in path_params.items(): for name, value in path_params.items():
url = url.replace(f'{{{name}}}', value) url = url.replace(f'{{{name}}}', f'{value}')
# parse http body data if needed, for GET/HEAD/OPTIONS/TRACE, the body is ignored # parse http body data if needed, for GET/HEAD/OPTIONS/TRACE, the body is ignored
if 'Content-Type' in headers: if 'Content-Type' in headers:
......
import re
import uuid
from json import loads as json_loads from json import loads as json_loads
from requests import get from requests import get
...@@ -46,7 +48,7 @@ class ApiBasedToolSchemaParser: ...@@ -46,7 +48,7 @@ class ApiBasedToolSchemaParser:
parameters = [] parameters = []
if 'parameters' in interface['operation']: if 'parameters' in interface['operation']:
for parameter in interface['operation']['parameters']: for parameter in interface['operation']['parameters']:
parameters.append(ToolParameter( tool_parameter = ToolParameter(
name=parameter['name'], name=parameter['name'],
label=I18nObject( label=I18nObject(
en_US=parameter['name'], en_US=parameter['name'],
...@@ -61,7 +63,14 @@ class ApiBasedToolSchemaParser: ...@@ -61,7 +63,14 @@ class ApiBasedToolSchemaParser:
form=ToolParameter.ToolParameterForm.LLM, form=ToolParameter.ToolParameterForm.LLM,
llm_description=parameter.get('description'), llm_description=parameter.get('description'),
default=parameter['schema']['default'] if 'schema' in parameter and 'default' in parameter['schema'] else None, default=parameter['schema']['default'] if 'schema' in parameter and 'default' in parameter['schema'] else None,
)) )
# check if there is a type
typ = ApiBasedToolSchemaParser._get_tool_parameter_type(parameter)
if typ:
tool_parameter.type = typ
parameters.append(tool_parameter)
# create tool bundle # create tool bundle
# check if there is a request body # check if there is a request body
if 'requestBody' in interface['operation']: if 'requestBody' in interface['operation']:
...@@ -80,13 +89,14 @@ class ApiBasedToolSchemaParser: ...@@ -80,13 +89,14 @@ class ApiBasedToolSchemaParser:
root = root[ref] root = root[ref]
# overwrite the content # overwrite the content
interface['operation']['requestBody']['content'][content_type]['schema'] = root interface['operation']['requestBody']['content'][content_type]['schema'] = root
# parse body parameters # parse body parameters
if 'schema' in interface['operation']['requestBody']['content'][content_type]: if 'schema' in interface['operation']['requestBody']['content'][content_type]:
body_schema = interface['operation']['requestBody']['content'][content_type]['schema'] body_schema = interface['operation']['requestBody']['content'][content_type]['schema']
required = body_schema['required'] if 'required' in body_schema else [] required = body_schema['required'] if 'required' in body_schema else []
properties = body_schema['properties'] if 'properties' in body_schema else {} properties = body_schema['properties'] if 'properties' in body_schema else {}
for name, property in properties.items(): for name, property in properties.items():
parameters.append(ToolParameter( tool = ToolParameter(
name=name, name=name,
label=I18nObject( label=I18nObject(
en_US=name, en_US=name,
...@@ -101,7 +111,14 @@ class ApiBasedToolSchemaParser: ...@@ -101,7 +111,14 @@ class ApiBasedToolSchemaParser:
form=ToolParameter.ToolParameterForm.LLM, form=ToolParameter.ToolParameterForm.LLM,
llm_description=property['description'] if 'description' in property else '', llm_description=property['description'] if 'description' in property else '',
default=property['default'] if 'default' in property else None, default=property['default'] if 'default' in property else None,
)) )
# check if there is a type
typ = ApiBasedToolSchemaParser._get_tool_parameter_type(property)
if typ:
tool.type = typ
parameters.append(tool)
# check if parameters is duplicated # check if parameters is duplicated
parameters_count = {} parameters_count = {}
...@@ -119,7 +136,11 @@ class ApiBasedToolSchemaParser: ...@@ -119,7 +136,11 @@ class ApiBasedToolSchemaParser:
path = interface['path'] path = interface['path']
if interface['path'].startswith('/'): if interface['path'].startswith('/'):
path = interface['path'][1:] path = interface['path'][1:]
path = path.replace('/', '_') # remove special characters like / to ensure the operation id is valid ^[a-zA-Z0-9_-]{1,64}$
path = re.sub(r'[^a-zA-Z0-9_-]', '', path)
if not path:
path = str(uuid.uuid4())
interface['operation']['operationId'] = f'{path}_{interface["method"]}' interface['operation']['operationId'] = f'{path}_{interface["method"]}'
bundles.append(ApiBasedToolBundle( bundles.append(ApiBasedToolBundle(
...@@ -134,7 +155,23 @@ class ApiBasedToolSchemaParser: ...@@ -134,7 +155,23 @@ class ApiBasedToolSchemaParser:
)) ))
return bundles return bundles
@staticmethod
def _get_tool_parameter_type(parameter: dict) -> ToolParameter.ToolParameterType:
parameter = parameter or {}
typ = None
if 'type' in parameter:
typ = parameter['type']
elif 'schema' in parameter and 'type' in parameter['schema']:
typ = parameter['schema']['type']
if typ == 'integer' or typ == 'number':
return ToolParameter.ToolParameterType.NUMBER
elif typ == 'boolean':
return ToolParameter.ToolParameterType.BOOLEAN
elif typ == 'string':
return ToolParameter.ToolParameterType.STRING
@staticmethod @staticmethod
def parse_openapi_yaml_to_tool_bundle(yaml: str, extra_info: dict = None, warning: dict = None) -> list[ApiBasedToolBundle]: def parse_openapi_yaml_to_tool_bundle(yaml: str, extra_info: dict = None, warning: dict = None) -> list[ApiBasedToolBundle]:
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment