mirror of
https://github.com/mudler/LocalAI.git
synced 2026-02-05 12:12:39 -05:00
284 lines
8.4 KiB
Go
284 lines
8.4 KiB
Go
package functions_test
|
|
|
|
import (
|
|
. "github.com/mudler/LocalAI/pkg/functions"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("LocalAI grammar functions", func() {
|
|
Describe("ToJSONStructure()", func() {
|
|
It("converts a list of functions to a JSON structure that can be parsed to a grammar", func() {
|
|
var functions Functions = []Function{
|
|
{
|
|
Name: "create_event",
|
|
Parameters: map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"event_name": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
"event_date": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "search",
|
|
Parameters: map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"query": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
js := functions.ToJSONStructure("function", "arguments")
|
|
Expect(len(js.OneOf)).To(Equal(2))
|
|
fnName := js.OneOf[0].Properties["function"].(FunctionName)
|
|
fnArgs := js.OneOf[0].Properties["arguments"].(Argument)
|
|
Expect(fnName.Const).To(Equal("create_event"))
|
|
Expect(fnArgs.Properties["event_name"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
Expect(fnArgs.Properties["event_date"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
|
|
fnName = js.OneOf[1].Properties["function"].(FunctionName)
|
|
fnArgs = js.OneOf[1].Properties["arguments"].(Argument)
|
|
Expect(fnName.Const).To(Equal("search"))
|
|
Expect(fnArgs.Properties["query"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
|
|
// Test with custom keys
|
|
jsN := functions.ToJSONStructure("name", "arguments")
|
|
Expect(len(jsN.OneOf)).To(Equal(2))
|
|
|
|
fnName = jsN.OneOf[0].Properties["name"].(FunctionName)
|
|
fnArgs = jsN.OneOf[0].Properties["arguments"].(Argument)
|
|
|
|
Expect(fnName.Const).To(Equal("create_event"))
|
|
Expect(fnArgs.Properties["event_name"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
Expect(fnArgs.Properties["event_date"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
|
|
fnName = jsN.OneOf[1].Properties["name"].(FunctionName)
|
|
fnArgs = jsN.OneOf[1].Properties["arguments"].(Argument)
|
|
|
|
Expect(fnName.Const).To(Equal("search"))
|
|
Expect(fnArgs.Properties["query"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
})
|
|
})
|
|
Context("Select()", func() {
|
|
It("selects one of the functions and returns a list containing only the selected one", func() {
|
|
var functions Functions = []Function{
|
|
{
|
|
Name: "create_event",
|
|
},
|
|
{
|
|
Name: "search",
|
|
},
|
|
}
|
|
|
|
functions = functions.Select("create_event")
|
|
Expect(len(functions)).To(Equal(1))
|
|
Expect(functions[0].Name).To(Equal("create_event"))
|
|
})
|
|
})
|
|
Context("SanitizeTools()", func() {
|
|
It("returns empty slice when input is empty", func() {
|
|
tools := Tools{}
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(0))
|
|
})
|
|
|
|
It("converts null values in parameters.properties to empty objects", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "test_function",
|
|
Description: "A test function",
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"valid_param": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
"null_param": nil,
|
|
"another_valid": map[string]interface{}{
|
|
"type": "integer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(1))
|
|
Expect(sanitized[0].Function.Name).To(Equal("test_function"))
|
|
|
|
properties := sanitized[0].Function.Parameters["properties"].(map[string]interface{})
|
|
Expect(properties["valid_param"]).NotTo(BeNil())
|
|
Expect(properties["null_param"]).NotTo(BeNil())
|
|
Expect(properties["null_param"]).To(Equal(map[string]interface{}{}))
|
|
Expect(properties["another_valid"]).NotTo(BeNil())
|
|
})
|
|
|
|
It("preserves valid parameter structures unchanged", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "valid_function",
|
|
Description: "A function with valid parameters",
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"param1": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "First parameter",
|
|
},
|
|
"param2": map[string]interface{}{
|
|
"type": "integer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(1))
|
|
Expect(sanitized[0].Function.Name).To(Equal("valid_function"))
|
|
|
|
properties := sanitized[0].Function.Parameters["properties"].(map[string]interface{})
|
|
Expect(properties["param1"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
Expect(properties["param1"].(map[string]interface{})["description"]).To(Equal("First parameter"))
|
|
Expect(properties["param2"].(map[string]interface{})["type"]).To(Equal("integer"))
|
|
})
|
|
|
|
It("handles tools without parameters field", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "no_params_function",
|
|
Description: "A function without parameters",
|
|
},
|
|
},
|
|
}
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(1))
|
|
Expect(sanitized[0].Function.Name).To(Equal("no_params_function"))
|
|
Expect(sanitized[0].Function.Parameters).To(BeNil())
|
|
})
|
|
|
|
It("handles tools without properties field", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "no_properties_function",
|
|
Description: "A function without properties",
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(1))
|
|
Expect(sanitized[0].Function.Name).To(Equal("no_properties_function"))
|
|
Expect(sanitized[0].Function.Parameters["type"]).To(Equal("object"))
|
|
})
|
|
|
|
It("handles multiple tools with mixed valid and null values", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "function_with_nulls",
|
|
Parameters: map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"valid": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
"null1": nil,
|
|
"null2": nil,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "function_all_valid",
|
|
Parameters: map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"param1": map[string]interface{}{
|
|
"type": "string",
|
|
},
|
|
"param2": map[string]interface{}{
|
|
"type": "integer",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "function_no_params",
|
|
},
|
|
},
|
|
}
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
Expect(len(sanitized)).To(Equal(3))
|
|
|
|
// First tool should have nulls converted to empty objects
|
|
props1 := sanitized[0].Function.Parameters["properties"].(map[string]interface{})
|
|
Expect(props1["valid"]).NotTo(BeNil())
|
|
Expect(props1["null1"]).To(Equal(map[string]interface{}{}))
|
|
Expect(props1["null2"]).To(Equal(map[string]interface{}{}))
|
|
|
|
// Second tool should remain unchanged
|
|
props2 := sanitized[1].Function.Parameters["properties"].(map[string]interface{})
|
|
Expect(props2["param1"].(map[string]interface{})["type"]).To(Equal("string"))
|
|
Expect(props2["param2"].(map[string]interface{})["type"]).To(Equal("integer"))
|
|
|
|
// Third tool should remain unchanged
|
|
Expect(sanitized[2].Function.Parameters).To(BeNil())
|
|
})
|
|
|
|
It("does not modify the original tools slice", func() {
|
|
tools := Tools{
|
|
{
|
|
Type: "function",
|
|
Function: Function{
|
|
Name: "test_function",
|
|
Parameters: map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"null_param": nil,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
originalProperties := tools[0].Function.Parameters["properties"].(map[string]interface{})
|
|
originalNullValue := originalProperties["null_param"]
|
|
|
|
sanitized := SanitizeTools(tools)
|
|
|
|
// Original should still have nil
|
|
Expect(originalNullValue).To(BeNil())
|
|
|
|
// Sanitized should have empty object
|
|
sanitizedProperties := sanitized[0].Function.Parameters["properties"].(map[string]interface{})
|
|
Expect(sanitizedProperties["null_param"]).To(Equal(map[string]interface{}{}))
|
|
})
|
|
})
|
|
})
|