diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiRequestTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiRequestTests.cs index 877b80debf67..6d74f3a91e7e 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiRequestTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiRequestTests.cs @@ -694,6 +694,86 @@ public void FromPromptAndExecutionSettingsWithThinkingConfigReturnsInGenerationC Assert.Equal(executionSettings.ThinkingConfig.ThinkingBudget, request.Configuration?.ThinkingConfig?.ThinkingBudget); } + [Fact] + public void ResponseSchemaStripsUnsupportedFormatFields() + { + // Arrange + var prompt = "prompt-example"; + var schemaWithUnsupportedFormats = """ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "unique identifier" + }, + "email": { + "type": "string", + "format": "email", + "description": "user email" + }, + "status": { + "type": "string", + "format": "enum", + "enum": ["active", "inactive"], + "description": "user status" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "creation timestamp" + }, + "phoneNumber": { + "type": "string", + "format": "phone", + "description": "phone number" + } + } + } + """; + + var executionSettings = new GeminiPromptExecutionSettings + { + ResponseMimeType = "application/json", + ResponseSchema = JsonSerializer.Deserialize(schemaWithUnsupportedFormats) + }; + + // Act + var request = GeminiRequest.FromPromptAndExecutionSettings(prompt, executionSettings); + + // Assert + Assert.NotNull(request.Configuration?.ResponseSchema); + var properties = request.Configuration.ResponseSchema.Value.GetProperty("properties"); + + // UUID format should be stripped + var idProperty = properties.GetProperty("id"); + Assert.Equal("string", idProperty.GetProperty("type").GetString()); + Assert.False(idProperty.TryGetProperty("format", out _)); + + // Email format should be stripped + var emailProperty = properties.GetProperty("email"); + Assert.Equal("string", emailProperty.GetProperty("type").GetString()); + Assert.False(emailProperty.TryGetProperty("format", out _)); + + // Enum format should be preserved + var statusProperty = properties.GetProperty("status"); + Assert.Equal("string", statusProperty.GetProperty("type").GetString()); + Assert.True(statusProperty.TryGetProperty("format", out var statusFormat)); + Assert.Equal("enum", statusFormat.GetString()); + + // Date-time format should be preserved + var createdAtProperty = properties.GetProperty("createdAt"); + Assert.Equal("string", createdAtProperty.GetProperty("type").GetString()); + Assert.True(createdAtProperty.TryGetProperty("format", out var createdAtFormat)); + Assert.Equal("date-time", createdAtFormat.GetString()); + + // Phone format should be stripped + var phoneProperty = properties.GetProperty("phoneNumber"); + Assert.Equal("string", phoneProperty.GetProperty("type").GetString()); + Assert.False(phoneProperty.TryGetProperty("format", out _)); + } + private sealed class DummyContent(object? innerContent, string? modelId = null, IReadOnlyDictionary? metadata = null) : KernelContent(innerContent, modelId, metadata); diff --git a/dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs b/dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs index 5d4b917ee1e7..ad933e0cfd52 100644 --- a/dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs +++ b/dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs @@ -375,7 +375,23 @@ static void TransformOpenApi3Object(JsonObject obj) { propertyObj["type"] = JsonValue.Create("string"); } - else if (propertyObj.TryGetPropertyValue("type", out JsonNode? typeNode)) + + // Strip unsupported format fields for string types + // Google API only supports "enum" and "date-time" formats for string types + if (propertyObj.TryGetPropertyValue("type", out JsonNode? typeNode) && + typeNode is JsonValue typeValue && + typeValue.GetValue() == "string" && + propertyObj.TryGetPropertyValue("format", out JsonNode? formatNode) && + formatNode is JsonValue formatValue) + { + var format = formatValue.GetValue(); + if (format != "enum" && format != "date-time") + { + propertyObj.Remove("format"); + } + } + + if (propertyObj.TryGetPropertyValue("type", out typeNode)) { if (typeNode is JsonArray typeArray) { @@ -387,7 +403,7 @@ static void TransformOpenApi3Object(JsonObject obj) propertyObj["nullable"] = JsonValue.Create(true); } } - else if (typeNode is JsonValue typeValue && typeValue.GetValue() == "array") + else if (typeNode is JsonValue typeVal && typeVal.GetValue() == "array") { if (propertyObj.TryGetPropertyValue("items", out JsonNode? itemsNode) && itemsNode is JsonObject itemsObj) {