From 3b21494867e1e1538efae243cf9a8d1edc5ab29f Mon Sep 17 00:00:00 2001 From: nldhuyen0047 Date: Thu, 2 Apr 2026 17:08:46 +0700 Subject: [PATCH] fix: inject default items schema for array parameters in Gemini normalization --- crates/openfang-types/src/tool.rs | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/crates/openfang-types/src/tool.rs b/crates/openfang-types/src/tool.rs index a252e8f604..200d6b3ddd 100644 --- a/crates/openfang-types/src/tool.rs +++ b/crates/openfang-types/src/tool.rs @@ -169,6 +169,19 @@ fn normalize_schema_recursive(schema: &serde_json::Value) -> serde_json::Value { result.insert(key.clone(), value.clone()); } + // Gemini requires `items` for every array-typed parameter. + // JSON Schema allows arrays without `items`, but the Gemini API rejects + // such schemas with INVALID_ARGUMENT. Inject a default string items schema + // so MCP tools (and any other source) don't break Gemini requests. + if result.get("type").and_then(|t| t.as_str()) == Some("array") + && !result.contains_key("items") + { + result.insert( + "items".to_string(), + serde_json::json!({"type": "string"}), + ); + } + serde_json::Value::Object(result) } @@ -616,6 +629,38 @@ mod tests { assert!(payload_prop.get("anyOf").is_none()); } + #[test] + fn test_normalize_injects_items_for_array_without_items() { + // MCP tools often send array params without `items` — Gemini rejects these. + let schema = serde_json::json!({ + "type": "object", + "properties": { + "fields": { "type": "array", "description": "List of fields" }, + "filters": { "type": "array" } + } + }); + let result = normalize_schema_for_provider(&schema, "gemini"); + // Both array properties must have `items` injected + assert_eq!(result["properties"]["fields"]["items"]["type"], "string"); + assert_eq!(result["properties"]["filters"]["items"]["type"], "string"); + } + + #[test] + fn test_normalize_preserves_existing_items() { + // If `items` already exists, it must not be overwritten + let schema = serde_json::json!({ + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { "type": "integer" } + } + } + }); + let result = normalize_schema_for_provider(&schema, "gemini"); + assert_eq!(result["properties"]["ids"]["items"]["type"], "integer"); + } + #[test] fn test_normalize_combined_issue_488() { // Real-world schema combining multiple #488 issues