From df46a438b8a641fffb11a1d72e774b7059499762 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Wed, 8 Oct 2025 19:13:40 +0200 Subject: [PATCH] fix(grammars): handle empty parameters on object types (#6409) fix: handle empty parameters on object types Signed-off-by: Ettore Di Giacinto --- core/http/endpoints/openai/chat.go | 6 ++++ pkg/functions/grammars/json_schema.go | 6 +++- pkg/functions/grammars/json_schema_test.go | 34 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/core/http/endpoints/openai/chat.go b/core/http/endpoints/openai/chat.go index a19828450..4e91a5329 100644 --- a/core/http/endpoints/openai/chat.go +++ b/core/http/endpoints/openai/chat.go @@ -247,6 +247,8 @@ func ChatEndpoint(cl *config.ModelConfigLoader, ml *model.ModelLoader, evaluator g, err := fs.Grammar(config.FunctionsConfig.GrammarOptions()...) if err == nil { input.Grammar = g + } else { + log.Error().Err(err).Msg("Failed generating grammar") } } } @@ -286,11 +288,15 @@ func ChatEndpoint(cl *config.ModelConfigLoader, ml *model.ModelLoader, evaluator g, err := jsStruct.Grammar(config.FunctionsConfig.GrammarOptions()...) if err == nil { config.Grammar = g + } else { + log.Error().Err(err).Msg("Failed generating grammar") } case input.JSONFunctionGrammarObject != nil: g, err := input.JSONFunctionGrammarObject.Grammar(config.FunctionsConfig.GrammarOptions()...) if err == nil { config.Grammar = g + } else { + log.Error().Err(err).Msg("Failed generating grammar") } default: // Force picking one of the functions by the request diff --git a/pkg/functions/grammars/json_schema.go b/pkg/functions/grammars/json_schema.go index df4ca6a13..df05a914d 100644 --- a/pkg/functions/grammars/json_schema.go +++ b/pkg/functions/grammars/json_schema.go @@ -171,10 +171,14 @@ func (sc *JSONSchemaConverter) visit(schema map[string]interface{}, name string, } rule := fmt.Sprintf(`"[" space (%s ("," space %s)*)? "]" space`, itemRuleName, itemRuleName) return sc.addRule(ruleName, rule), nil + } else if properties, _ := schema["properties"].(map[string]interface{}); (schemaType == "object" || schemaType == "") && len(properties) == 0 { + // Handle empty object schema (no properties) + rule := `"{" space "}" space` + return sc.addRule(ruleName, rule), nil } else { primitiveRule, exists := PRIMITIVE_RULES[schemaType] if !exists { - return "", fmt.Errorf("unrecognized schema: %v", schema) + return "", fmt.Errorf("unrecognized schema: %v (type: %s)", schema, schemaType) } if ruleName == "root" { schemaType = "root" diff --git a/pkg/functions/grammars/json_schema_test.go b/pkg/functions/grammars/json_schema_test.go index 5fc4a6029..2b2c5d22b 100644 --- a/pkg/functions/grammars/json_schema_test.go +++ b/pkg/functions/grammars/json_schema_test.go @@ -442,5 +442,39 @@ realvalue } } }) + + It("handles empty object schema without properties", func() { + // Test case for the bug fix: schema with empty properties map + emptyObjectSchema := `{ + "type": "object", + "properties": {} + }` + + grammar, err := NewJSONSchemaConverter("").GrammarFromBytes([]byte(emptyObjectSchema)) + Expect(err).To(BeNil()) + Expect(grammar).To(ContainSubstring(`root ::= "{" space "}" space`)) + }) + + It("handles object schema without properties field", func() { + // Test case for object schema without properties field at all + objectWithoutProperties := `{ + "type": "object" + }` + + grammar, err := NewJSONSchemaConverter("").GrammarFromBytes([]byte(objectWithoutProperties)) + Expect(err).To(BeNil()) + Expect(grammar).To(ContainSubstring(`root ::= "{" space "}" space`)) + }) + + It("handles schema with properties but no type field", func() { + // Test case for the exact scenario causing the panic: schema with properties but no type + schemaWithPropertiesNoType := `{ + "properties": {} + }` + + grammar, err := NewJSONSchemaConverter("").GrammarFromBytes([]byte(schemaWithPropertiesNoType)) + Expect(err).To(BeNil()) + Expect(grammar).To(ContainSubstring(`root ::= "{" space "}" space`)) + }) }) })