diff --git a/core/http/endpoints/openai/chat.go b/core/http/endpoints/openai/chat.go index fbf5924ea..76efbca28 100644 --- a/core/http/endpoints/openai/chat.go +++ b/core/http/endpoints/openai/chat.go @@ -451,7 +451,7 @@ func ChatEndpoint(cl *config.ModelConfigLoader, ml *model.ModelLoader, evaluator } // Update input grammar or json_schema based on use_llama_grammar option - jsStruct := funcs.ToJSONStructure(config.FunctionsConfig.FunctionNameKey, config.FunctionsConfig.FunctionNameKey) + jsStruct := config.FunctionsConfig.ToJSONStructure(funcs) g, err := jsStruct.Grammar(config.FunctionsConfig.GrammarOptions()...) if err == nil { config.Grammar = g diff --git a/core/http/endpoints/openai/realtime_model.go b/core/http/endpoints/openai/realtime_model.go index b525eee26..a02696a1f 100644 --- a/core/http/endpoints/openai/realtime_model.go +++ b/core/http/endpoints/openai/realtime_model.go @@ -293,7 +293,7 @@ func (m *wrappedModel) Predict(ctx context.Context, messages schema.Messages, im } // Generate grammar from function definitions - jsStruct := functions.Functions(funcs).ToJSONStructure(turnCfg.FunctionsConfig.FunctionNameKey, turnCfg.FunctionsConfig.FunctionNameKey) + jsStruct := turnCfg.FunctionsConfig.ToJSONStructure(functions.Functions(funcs)) g, err := jsStruct.Grammar(turnCfg.FunctionsConfig.GrammarOptions()...) if err == nil { turnCfg.Grammar = g diff --git a/core/http/endpoints/openresponses/responses.go b/core/http/endpoints/openresponses/responses.go index d62fa7534..528737273 100644 --- a/core/http/endpoints/openresponses/responses.go +++ b/core/http/endpoints/openresponses/responses.go @@ -204,7 +204,7 @@ func ResponsesEndpoint(cl *config.ModelConfigLoader, ml *model.ModelLoader, eval } // Generate grammar to constrain model output to valid function calls - jsStruct := funcsWithNoAction.ToJSONStructure(cfg.FunctionsConfig.FunctionNameKey, cfg.FunctionsConfig.FunctionNameKey) + jsStruct := cfg.FunctionsConfig.ToJSONStructure(funcsWithNoAction) g, err := jsStruct.Grammar(cfg.FunctionsConfig.GrammarOptions()...) if err == nil { cfg.Grammar = g diff --git a/core/http/endpoints/openresponses/websocket.go b/core/http/endpoints/openresponses/websocket.go index 3a92f275a..f0cb4b331 100644 --- a/core/http/endpoints/openresponses/websocket.go +++ b/core/http/endpoints/openresponses/websocket.go @@ -381,7 +381,7 @@ func handleWSResponseCreate(connCtx context.Context, conn *lockedConn, connectio funcsWithNoAction = funcsWithNoAction.Select(cfg.FunctionToCall()) } - jsStruct := funcsWithNoAction.ToJSONStructure(cfg.FunctionsConfig.FunctionNameKey, cfg.FunctionsConfig.FunctionNameKey) + jsStruct := cfg.FunctionsConfig.ToJSONStructure(funcsWithNoAction) g, err := jsStruct.Grammar(cfg.FunctionsConfig.GrammarOptions()...) if err == nil { cfg.Grammar = g diff --git a/pkg/functions/functions.go b/pkg/functions/functions.go index 0686e4f9d..3e604d9df 100644 --- a/pkg/functions/functions.go +++ b/pkg/functions/functions.go @@ -89,6 +89,11 @@ func (f Functions) ToJSONStructure(name, args string) JSONFunctionStructure { return js } +// ToJSONStructure converts functions using the configured property keys. +func (c FunctionsConfig) ToJSONStructure(functions Functions) JSONFunctionStructure { + return functions.ToJSONStructure(c.FunctionNameKey, c.FunctionArgumentsKey) +} + // Select returns a list of functions containing the function with the given name func (f Functions) Select(name string) Functions { var funcs Functions diff --git a/pkg/functions/functions_test.go b/pkg/functions/functions_test.go index e0952c13f..7c10da473 100644 --- a/pkg/functions/functions_test.go +++ b/pkg/functions/functions_test.go @@ -65,6 +65,33 @@ var _ = Describe("LocalAI grammar functions", func() { Expect(fnName.Const).To(Equal("search")) Expect(fnArgs.Properties["query"].(map[string]any)["type"]).To(Equal("string")) }) + + It("keeps the name and the arguments in separate properties when both keys are customized", func() { + var functions Functions = []Function{ + { + Name: "get_weather", + Parameters: map[string]any{ + "properties": map[string]any{ + "city": map[string]any{ + "type": "string", + }, + }, + }, + }, + } + + config := FunctionsConfig{ + FunctionNameKey: "function", + FunctionArgumentsKey: "parameters", + } + js := config.ToJSONStructure(functions) + Expect(js.OneOf[0].Properties).To(HaveLen(2)) + + fnName := js.OneOf[0].Properties["function"].(FunctionName) + fnArgs := js.OneOf[0].Properties["parameters"].(Argument) + Expect(fnName.Const).To(Equal("get_weather")) + Expect(fnArgs.Properties["city"].(map[string]any)["type"]).To(Equal("string")) + }) }) Context("Select()", func() { It("selects one of the functions and returns a list containing only the selected one", func() {