From a320f265b3db064031351d1ffe8a360ddb0c68a9 Mon Sep 17 00:00:00 2001 From: Zaki Manian Date: Sat, 21 Feb 2026 23:52:34 -0800 Subject: [PATCH] Fix tool schema OpenAI compatibility (#301) * fix: remove union type arrays from tool schemas for OpenAI compatibility OpenAI rejects JSON Schema union types containing "array" without an "items" subschema. The http tool's "body" and json tool's "data" params used union types to accept any value. Replace with freeform (untyped) schemas which OpenAI treats as accepting any JSON value. Co-Authored-By: Claude Opus 4.6 * fix: update schema tests to assert type is absent, fix missed json.rs test - http.rs test: assert body has no "type" (not just has description) - json.rs test: update to match the freeform schema change (was still asserting type is present) Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- src/tools/builtin/http.rs | 12 +++++++----- src/tools/builtin/json.rs | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tools/builtin/http.rs b/src/tools/builtin/http.rs index cfe3fd54..88a19fec 100644 --- a/src/tools/builtin/http.rs +++ b/src/tools/builtin/http.rs @@ -231,8 +231,7 @@ impl Tool for HttpTool { } }, "body": { - "type": ["object", "array", "string", "number", "boolean", "null"], - "description": "Request body (for POST/PUT/PATCH)" + "description": "Request body (for POST/PUT/PATCH). Can be a JSON object, array, string, or other value." }, "timeout_secs": { "type": "integer", @@ -561,16 +560,19 @@ mod tests { } #[test] - fn test_http_tool_schema_body_has_type() { + fn test_http_tool_schema_body_is_freeform() { let schema = HttpTool::new().parameters_schema(); let body = schema .get("properties") .and_then(|p| p.get("body")) .expect("body schema missing"); + // Body is intentionally freeform (no "type" constraint) for OpenAI + // compatibility. OpenAI rejects union types containing "array" unless + // "items" is also specified, and body accepts any JSON value. assert!( - body.get("type").is_some(), - "body schema must include a type for OpenAI-compatible tool validation" + body.get("type").is_none(), + "body schema should not have a 'type' to be freeform for OpenAI compatibility" ); } diff --git a/src/tools/builtin/json.rs b/src/tools/builtin/json.rs index 5c077ee7..cf4c7f82 100644 --- a/src/tools/builtin/json.rs +++ b/src/tools/builtin/json.rs @@ -28,8 +28,7 @@ impl Tool for JsonTool { "description": "The JSON operation to perform" }, "data": { - "type": ["string", "object", "array", "number", "boolean", "null"], - "description": "JSON input data. Pass a string for parse, any type otherwise." + "description": "JSON input data. Pass a string for parse, or any JSON value (object, array, string, number, boolean, null) otherwise." }, "path": { "type": "string", @@ -192,16 +191,19 @@ mod tests { } #[test] - fn test_json_tool_schema_data_has_type() { + fn test_json_tool_schema_data_is_freeform() { let schema = JsonTool.parameters_schema(); let data = schema .get("properties") .and_then(|p| p.get("data")) .expect("data schema missing"); + // Data is intentionally freeform (no "type" constraint) for OpenAI + // compatibility. OpenAI rejects union types containing "array" unless + // "items" is also specified. assert!( - data.get("type").is_some(), - "data schema must include a type for OpenAI-compatible tool validation" + data.get("type").is_none(), + "data schema should not have a 'type' to be freeform for OpenAI compatibility" ); } }