Skip to content

Commit 8fc3c1f

Browse files
authored
Add support for parameterless ops (vblagoje#11)
1 parent 80b10ae commit 8fc3c1f

File tree

5 files changed

+82
-28
lines changed

5 files changed

+82
-28
lines changed

openapi_llm/core/schema_conversion.py

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -156,41 +156,46 @@ def _convert_operation_to_openai_schema(
156156
"Invalid OpenAPI spec format provided. Could not extract function."
157157
)
158158
return {}
159+
159160
function_name = resolved_spec.get("operationId")
160161
description = resolved_spec.get("description") or resolved_spec.get("summary", "")
161-
schema: Dict[str, Any] = {"type": "object", "properties": {}}
162-
# requestBody section
163-
req_body_schema = (
164-
resolved_spec.get("requestBody", {})
165-
.get("content", {})
166-
.get("application/json", {})
167-
.get("schema", {})
168-
)
169-
if "properties" in req_body_schema:
170-
for prop_name, prop_schema in req_body_schema["properties"].items():
171-
schema["properties"][prop_name] = _parse_property_attributes(prop_schema)
172-
if "required" in req_body_schema:
173-
schema.setdefault("required", []).extend(req_body_schema["required"])
174-
175-
# parameters section
176-
for param in resolved_spec.get("parameters", []):
177-
if "schema" in param:
178-
schema_dict = _parse_property_attributes(param["schema"])
179-
# these attributes are not in param[schema] level but on param level
180-
useful_attributes = ["description", "pattern", "enum"]
181-
schema_dict.update(
182-
{key: param[key] for key in useful_attributes if param.get(key)}
183-
)
184-
schema["properties"][param["name"]] = schema_dict
185-
if param.get("required", False):
186-
schema.setdefault("required", []).append(param["name"])
187162

188-
if function_name and description and schema["properties"]:
163+
# Return valid schema even if no parameters are present
164+
if function_name and description:
165+
schema: Dict[str, Any] = {"type": "object", "properties": {}}
166+
167+
# requestBody section
168+
req_body_schema = (
169+
resolved_spec.get("requestBody", {})
170+
.get("content", {})
171+
.get("application/json", {})
172+
.get("schema", {})
173+
)
174+
if "properties" in req_body_schema:
175+
for prop_name, prop_schema in req_body_schema["properties"].items():
176+
schema["properties"][prop_name] = _parse_property_attributes(prop_schema)
177+
if "required" in req_body_schema:
178+
schema.setdefault("required", []).extend(req_body_schema["required"])
179+
180+
# parameters section
181+
for param in resolved_spec.get("parameters", []):
182+
if "schema" in param:
183+
schema_dict = _parse_property_attributes(param["schema"])
184+
# these attributes are not in param[schema] level but on param level
185+
useful_attributes = ["description", "pattern", "enum"]
186+
schema_dict.update(
187+
{key: param[key] for key in useful_attributes if param.get(key)}
188+
)
189+
schema["properties"][param["name"]] = schema_dict
190+
if param.get("required", False):
191+
schema.setdefault("required", []).append(param["name"])
192+
189193
return {
190194
"name": function_name,
191195
"description": description,
192196
parameters_name: schema,
193197
}
198+
194199
logger.warning(
195200
"Invalid OpenAPI spec format provided. Could not extract function from %s",
196201
resolved_spec,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
openapi: 3.0.0
2+
info:
3+
title: Parameterless API
4+
version: 1.0.0
5+
description: API with parameterless endpoints
6+
servers:
7+
- url: https://api.example.com
8+
paths:
9+
/status:
10+
get:
11+
operationId: getBatchStatus
12+
description: Get the status of all batch jobs
13+
responses:
14+
'200':
15+
description: Successful response
16+
content:
17+
application/json:
18+
schema:
19+
type: object
20+
properties:
21+
status:
22+
type: string
23+
enum: [idle, processing, completed]

test/test_openapi_client_live_openai.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_firecrawl(self):
104104
"""
105105
from openapi_llm.utils import HttpClientError
106106

107-
openapi_spec_url = "https://raw.githubusercontent.com/mendableai/firecrawl/main/apps/api/openapi.json"
107+
openapi_spec_url = "https://raw.githubusercontent.com/mendableai/firecrawl/main/apps/api/v1-openapi.json"
108108
config = ClientConfig(openapi_spec=create_openapi_spec(openapi_spec_url), credentials=os.getenv("FIRECRAWL_API_KEY"))
109109
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
110110
response = client.chat.completions.create(

test/test_openapi_cohere_conversion.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,13 @@ def test_complex_types(self, test_files_path):
163163
"required": True,
164164
},
165165
}
166+
167+
def test_parameterless(self, test_files_path):
168+
spec = OpenAPISpecification.from_file(test_files_path / "yaml" / "parameterless.yml")
169+
functions = cohere_converter(schema=spec)
170+
assert functions
171+
assert len(functions) == 1
172+
function = functions[0]
173+
assert function["name"] == "getBatchStatus"
174+
assert function["description"] == "Get the status of all batch jobs"
175+
assert function["parameter_definitions"] == {}

test/test_openapi_openai_conversion.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,19 @@ def test_complex_types(self, test_files_path, provider: str):
104104
"required": ["transaction_amount", "description", "payment_method_id", "payer"],
105105
}
106106
)
107+
108+
@pytest.mark.parametrize("provider", ["openai", "anthropic"])
109+
def test_parameterless(self, test_files_path, provider: str):
110+
spec = OpenAPISpecification.from_file(test_files_path / "yaml" / "parameterless.yml")
111+
functions = openai_converter(schema=spec) if provider == "openai" else anthropic_converter(schema=spec)
112+
assert functions
113+
assert len(functions) == 1
114+
function = functions[0]["function"] if provider == "openai" else functions[0]
115+
assert function["name"] == "getBatchStatus"
116+
assert function["description"] == "Get the status of all batch jobs"
117+
assert (
118+
function["parameters"]
119+
if provider == "openai"
120+
else function["input_schema"]
121+
== {"type": "object", "properties": {}}
122+
)

0 commit comments

Comments
 (0)