2024-04-18 20:43:12 +00:00
|
|
|
package functions_test
|
2023-07-02 09:13:51 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
2024-04-18 20:43:12 +00:00
|
|
|
. "github.com/go-skynet/LocalAI/pkg/functions"
|
2023-07-02 09:13:51 +00:00
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
|
|
. "github.com/onsi/gomega"
|
|
|
|
)
|
|
|
|
|
2024-05-15 18:03:18 +00:00
|
|
|
var testFunctions = []ItemFunction{
|
|
|
|
{
|
|
|
|
Type: "object",
|
|
|
|
Properties: FunctionProperties{
|
|
|
|
Function: FunctionName{
|
|
|
|
Const: "create_event",
|
|
|
|
},
|
|
|
|
Arguments: Argument{ // this is OpenAI's parameter
|
|
|
|
Type: "object",
|
|
|
|
Properties: map[string]interface{}{
|
|
|
|
"title": map[string]string{"type": "string"},
|
|
|
|
"date": map[string]string{"type": "string"},
|
|
|
|
"time": map[string]string{"type": "string"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "object",
|
|
|
|
Properties: FunctionProperties{
|
|
|
|
Function: FunctionName{
|
|
|
|
Const: "search",
|
|
|
|
},
|
|
|
|
Arguments: Argument{
|
|
|
|
Type: "object",
|
|
|
|
Properties: map[string]interface{}{
|
|
|
|
"query": map[string]string{"type": "string"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var testFunctionsName = []ItemName{
|
|
|
|
{
|
|
|
|
Type: "object",
|
|
|
|
Properties: NameProperties{
|
|
|
|
Function: FunctionName{
|
|
|
|
Const: "create_event",
|
|
|
|
},
|
|
|
|
Arguments: Argument{ // this is OpenAI's parameter
|
|
|
|
Type: "object",
|
|
|
|
Properties: map[string]interface{}{
|
|
|
|
"title": map[string]string{"type": "string"},
|
|
|
|
"date": map[string]string{"type": "string"},
|
|
|
|
"time": map[string]string{"type": "string"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "object",
|
|
|
|
Properties: NameProperties{
|
|
|
|
Function: FunctionName{
|
|
|
|
Const: "search",
|
|
|
|
},
|
|
|
|
Arguments: Argument{
|
|
|
|
Type: "object",
|
|
|
|
Properties: map[string]interface{}{
|
|
|
|
"query": map[string]string{"type": "string"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func rootResult(s string) string {
|
|
|
|
return `root-0-name ::= "\"create_event\""
|
|
|
|
freestring ::= (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* space
|
|
|
|
root-0 ::= "{" space "\"arguments\"" space ":" space root-0-arguments "," space "\"name\"" space ":" space root-0-name "}" space
|
|
|
|
root-1-arguments ::= "{" space "\"query\"" space ":" space string "}" space
|
|
|
|
realvalue ::= root-0 | root-1
|
|
|
|
root ::= ` + s + `
|
|
|
|
space ::= " "?
|
|
|
|
root-0-arguments ::= "{" space "\"date\"" space ":" space string "," space "\"time\"" space ":" space string "," space "\"title\"" space ":" space string "}" space
|
|
|
|
root-1 ::= "{" space "\"arguments\"" space ":" space root-1-arguments "," space "\"name\"" space ":" space root-1-name "}" space
|
|
|
|
string ::= "\"" (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* "\"" space
|
|
|
|
arr ::=
|
|
|
|
"[\n" (
|
|
|
|
realvalue
|
|
|
|
(",\n" realvalue)*
|
|
|
|
)? "]"
|
|
|
|
root-1-name ::= "\"search\""`
|
|
|
|
}
|
|
|
|
|
2023-07-02 09:13:51 +00:00
|
|
|
const (
|
|
|
|
testInput1 = `
|
|
|
|
{
|
|
|
|
"oneOf": [
|
|
|
|
{
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"function": {"const": "create_event"},
|
|
|
|
"arguments": {
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"title": {"type": "string"},
|
|
|
|
"date": {"type": "string"},
|
|
|
|
"time": {"type": "string"}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"function": {"const": "search"},
|
|
|
|
"arguments": {
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"query": {"type": "string"}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
|
|
|
|
inputResult1 = `root-0-function ::= "\"create_event\""
|
2024-05-15 18:03:18 +00:00
|
|
|
freestring ::= (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* space
|
2023-07-02 09:13:51 +00:00
|
|
|
root-0 ::= "{" space "\"arguments\"" space ":" space root-0-arguments "," space "\"function\"" space ":" space root-0-function "}" space
|
|
|
|
root-1-arguments ::= "{" space "\"query\"" space ":" space string "}" space
|
|
|
|
root ::= root-0 | root-1
|
|
|
|
space ::= " "?
|
|
|
|
root-0-arguments ::= "{" space "\"date\"" space ":" space string "," space "\"time\"" space ":" space string "," space "\"title\"" space ":" space string "}" space
|
|
|
|
root-1 ::= "{" space "\"arguments\"" space ":" space root-1-arguments "," space "\"function\"" space ":" space root-1-function "}" space
|
2023-08-03 21:32:30 +00:00
|
|
|
string ::= "\"" (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* "\"" space
|
2024-02-20 20:58:45 +00:00
|
|
|
root-1-function ::= "\"search\""`
|
|
|
|
|
|
|
|
inputResult2 = `root-0-function ::= "\"create_event\""
|
2024-05-15 18:03:18 +00:00
|
|
|
freestring ::= (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* space
|
2024-02-20 20:58:45 +00:00
|
|
|
root-0 ::= "{" space "\"arguments\"" space ":" space root-0-arguments "," space "\"function\"" space ":" space root-0-function "}" space
|
|
|
|
root-1-arguments ::= "{" space "\"query\"" space ":" space string "}" space
|
|
|
|
realvalue ::= root-0 | root-1
|
|
|
|
root ::= arr | realvalue
|
|
|
|
space ::= " "?
|
|
|
|
root-0-arguments ::= "{" space "\"date\"" space ":" space string "," space "\"time\"" space ":" space string "," space "\"title\"" space ":" space string "}" space
|
|
|
|
root-1 ::= "{" space "\"arguments\"" space ":" space root-1-arguments "," space "\"function\"" space ":" space root-1-function "}" space
|
|
|
|
string ::= "\"" (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* "\"" space
|
|
|
|
arr ::=
|
|
|
|
"[\n" (
|
|
|
|
realvalue
|
|
|
|
(",\n" realvalue)*
|
|
|
|
)? "]"
|
2023-07-02 09:13:51 +00:00
|
|
|
root-1-function ::= "\"search\""`
|
2024-05-11 23:13:22 +00:00
|
|
|
|
|
|
|
testInput2 = `
|
|
|
|
{
|
|
|
|
"oneOf": [
|
|
|
|
{
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"name": {"const": "create_event"},
|
|
|
|
"arguments": {
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"title": {"type": "string"},
|
|
|
|
"date": {"type": "string"},
|
|
|
|
"time": {"type": "string"}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"name": {"const": "search"},
|
|
|
|
"arguments": {
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"query": {"type": "string"}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
|
|
|
|
inputResult3 = `root-0-name ::= "\"create_event\""
|
2024-05-15 18:03:18 +00:00
|
|
|
freestring ::= (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* space
|
2024-05-11 23:13:22 +00:00
|
|
|
root-0 ::= "{" space "\"arguments\"" space ":" space root-0-arguments "," space "\"name\"" space ":" space root-0-name "}" space
|
|
|
|
root-1-arguments ::= "{" space "\"query\"" space ":" space string "}" space
|
|
|
|
root ::= root-0 | root-1
|
|
|
|
space ::= " "?
|
|
|
|
root-0-arguments ::= "{" space "\"date\"" space ":" space string "," space "\"time\"" space ":" space string "," space "\"title\"" space ":" space string "}" space
|
|
|
|
root-1 ::= "{" space "\"arguments\"" space ":" space root-1-arguments "," space "\"name\"" space ":" space root-1-name "}" space
|
|
|
|
string ::= "\"" (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* "\"" space
|
|
|
|
root-1-name ::= "\"search\""`
|
|
|
|
|
|
|
|
inputResult4 = `root-0-name ::= "\"create_event\""
|
2024-05-15 18:03:18 +00:00
|
|
|
freestring ::= (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* space
|
2024-05-11 23:13:22 +00:00
|
|
|
root-0 ::= "{" space "\"arguments\"" space ":" space root-0-arguments "," space "\"name\"" space ":" space root-0-name "}" space
|
|
|
|
root-1-arguments ::= "{" space "\"query\"" space ":" space string "}" space
|
|
|
|
realvalue ::= root-0 | root-1
|
|
|
|
root ::= arr | realvalue
|
|
|
|
space ::= " "?
|
|
|
|
root-0-arguments ::= "{" space "\"date\"" space ":" space string "," space "\"time\"" space ":" space string "," space "\"title\"" space ":" space string "}" space
|
|
|
|
root-1 ::= "{" space "\"arguments\"" space ":" space root-1-arguments "," space "\"name\"" space ":" space root-1-name "}" space
|
|
|
|
string ::= "\"" (
|
|
|
|
[^"\\] |
|
|
|
|
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
|
|
|
|
)* "\"" space
|
|
|
|
arr ::=
|
|
|
|
"[\n" (
|
|
|
|
realvalue
|
|
|
|
(",\n" realvalue)*
|
|
|
|
)? "]"
|
|
|
|
root-1-name ::= "\"search\""`
|
2023-07-02 09:13:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ = Describe("JSON schema grammar tests", func() {
|
|
|
|
Context("JSON", func() {
|
|
|
|
It("generates a valid grammar from JSON schema", func() {
|
2024-05-15 18:03:18 +00:00
|
|
|
grammar := NewJSONSchemaConverter("").GrammarFromBytes("", []byte(testInput1), false, false)
|
2023-07-02 09:13:51 +00:00
|
|
|
results := strings.Split(inputResult1, "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))))
|
|
|
|
})
|
2024-05-11 23:13:22 +00:00
|
|
|
It("generates a valid grammar from JSON schema", func() {
|
2024-05-15 18:03:18 +00:00
|
|
|
grammar := NewJSONSchemaConverter("").GrammarFromBytes("", []byte(testInput2), false, false)
|
2024-05-11 23:13:22 +00:00
|
|
|
results := strings.Split(inputResult3, "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))))
|
|
|
|
})
|
2023-07-02 09:13:51 +00:00
|
|
|
It("generates a valid grammar from JSON Objects", func() {
|
|
|
|
|
2024-05-11 23:13:22 +00:00
|
|
|
structuredGrammar := JSONFunctionStructureFunction{
|
2024-05-15 18:03:18 +00:00
|
|
|
OneOf: testFunctions}
|
2023-07-02 09:13:51 +00:00
|
|
|
|
2024-05-15 18:03:18 +00:00
|
|
|
grammar := structuredGrammar.Grammar("", "", false, false)
|
2023-07-02 09:13:51 +00:00
|
|
|
results := strings.Split(inputResult1, "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))))
|
|
|
|
})
|
2024-02-20 20:58:45 +00:00
|
|
|
|
|
|
|
It("generates a valid grammar from JSON Objects for multiple function return", func() {
|
2024-05-11 23:13:22 +00:00
|
|
|
structuredGrammar := JSONFunctionStructureFunction{
|
2024-05-15 18:03:18 +00:00
|
|
|
OneOf: testFunctions}
|
2024-02-20 20:58:45 +00:00
|
|
|
|
2024-05-15 18:03:18 +00:00
|
|
|
grammar := structuredGrammar.Grammar("", "", true, false)
|
2024-02-20 20:58:45 +00:00
|
|
|
results := strings.Split(inputResult2, "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
2024-05-11 23:13:22 +00:00
|
|
|
|
|
|
|
It("generates a valid grammar from JSON Objects for multiple function return", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
2024-05-15 18:03:18 +00:00
|
|
|
OneOf: testFunctionsName}
|
2024-05-11 23:13:22 +00:00
|
|
|
|
2024-05-15 18:03:18 +00:00
|
|
|
grammar := structuredGrammar.Grammar("", "", true, false)
|
2024-05-11 23:13:22 +00:00
|
|
|
results := strings.Split(inputResult4, "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
2024-05-15 18:03:18 +00:00
|
|
|
|
|
|
|
It("generates a valid grammar from JSON Objects for multiple function return with a suffix and array", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
|
|
|
OneOf: testFunctionsName}
|
|
|
|
|
|
|
|
grammar := structuredGrammar.Grammar("suffix", "", true, false)
|
|
|
|
results := strings.Split(rootResult(`"suffix" arr | realvalue`), "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
|
|
|
It("generates a valid grammar from JSON Objects with a suffix", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
|
|
|
OneOf: testFunctionsName}
|
|
|
|
|
|
|
|
grammar := structuredGrammar.Grammar("suffix", "", false, false)
|
|
|
|
results := strings.Split(rootResult(`"suffix" realvalue`), "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
|
|
|
It("generates a valid grammar from JSON Objects with a suffix and could return string", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
|
|
|
OneOf: testFunctionsName}
|
|
|
|
|
|
|
|
grammar := structuredGrammar.Grammar("suffix", "", false, true)
|
|
|
|
results := strings.Split(rootResult(`( "suffix" realvalue | freestring )`), "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
|
|
|
It("generates a valid grammar from JSON Objects with a suffix that could return text or an array of tools", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
|
|
|
OneOf: testFunctionsName}
|
|
|
|
|
|
|
|
grammar := structuredGrammar.Grammar("suffix", "", true, true)
|
|
|
|
results := strings.Split(rootResult(`( "suffix" (arr | realvalue) | freestring )`), "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
|
|
|
|
|
|
|
It("generates a valid grammar from JSON Objects without a suffix that could return text or an array of tools or just string", func() {
|
|
|
|
structuredGrammar := JSONFunctionStructureName{
|
|
|
|
OneOf: testFunctionsName}
|
|
|
|
|
|
|
|
grammar := structuredGrammar.Grammar("", "", true, true)
|
|
|
|
results := strings.Split(rootResult(`freestring | arr | realvalue`), "\n")
|
|
|
|
for _, r := range results {
|
|
|
|
if r != "" {
|
|
|
|
Expect(grammar).To(ContainSubstring(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expect(len(results)).To(Equal(len(strings.Split(grammar, "\n"))), grammar)
|
|
|
|
})
|
2023-07-02 09:13:51 +00:00
|
|
|
})
|
|
|
|
})
|