2024-04-18 20:43:12 +00:00
package functions_test
2023-07-02 09:13:51 +00:00
import (
"strings"
2024-06-23 08:24:36 +00:00
"github.com/mudler/LocalAI/pkg/functions"
. "github.com/mudler/LocalAI/pkg/functions"
2023-07-02 09:13:51 +00:00
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
2024-07-18 15:52:22 +00:00
func createFunction ( field1 string , field2 string , name string , properties map [ string ] interface { } ) map [ string ] interface { } {
property := map [ string ] interface { } { }
property [ field1 ] = FunctionName { Const : name }
property [ field2 ] = Argument {
Type : "object" ,
Properties : properties ,
}
return property
}
var testFunctions = [ ] Item {
2024-05-15 18:03:18 +00:00
{
Type : "object" ,
2024-07-18 15:52:22 +00:00
Properties : createFunction (
"function" ,
"arguments" ,
"create_event" ,
map [ string ] interface { } {
"title" : map [ string ] string { "type" : "string" } ,
"date" : map [ string ] string { "type" : "string" } ,
"time" : map [ string ] string { "type" : "string" } ,
2024-05-15 18:03:18 +00:00
} ,
2024-07-18 15:52:22 +00:00
) ,
2024-05-15 18:03:18 +00:00
} ,
{
Type : "object" ,
2024-07-18 15:52:22 +00:00
Properties : createFunction (
"function" ,
"arguments" ,
"search" ,
map [ string ] interface { } {
"query" : map [ string ] string { "type" : "string" } ,
} ) ,
2024-05-15 18:03:18 +00:00
} ,
}
2024-07-18 15:52:22 +00:00
var testFunctionsName = [ ] Item {
2024-05-15 18:03:18 +00:00
{
Type : "object" ,
2024-07-18 15:52:22 +00:00
Properties : createFunction (
"name" ,
"arguments" ,
"create_event" ,
map [ string ] interface { } {
"title" : map [ string ] string { "type" : "string" } ,
"date" : map [ string ] string { "type" : "string" } ,
"time" : map [ string ] string { "type" : "string" } ,
2024-05-15 18:03:18 +00:00
} ,
2024-07-18 15:52:22 +00:00
) ,
2024-05-15 18:03:18 +00:00
} ,
{
Type : "object" ,
2024-07-18 15:52:22 +00:00
Properties : createFunction (
"name" ,
"arguments" ,
"search" ,
map [ string ] interface { } {
"query" : map [ string ] string { "type" : "string" } ,
} ) ,
2024-05-15 18:03:18 +00:00
} ,
}
func rootResult ( s string ) string {
return ` root - 0 - name : := "\"create_event\""
freestring : := (
[ ^ " \ \ ] |
"\\" ( [ "\\/bfnrt] | " u " [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - fA - F ] [ 0 - 9 a - 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-21 22:14:16 +00:00
grammar := NewJSONSchemaConverter ( "" ) . GrammarFromBytes ( [ ] byte ( testInput1 ) )
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-21 22:14:16 +00:00
grammar := NewJSONSchemaConverter ( "" ) . GrammarFromBytes ( [ ] byte ( testInput2 ) )
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-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctions }
2023-07-02 09:13:51 +00:00
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( )
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-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctions }
2024-02-20 20:58:45 +00:00
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . EnableMaybeArray )
results := strings . Split (
strings . Join ( [ ] string {
inputResult2 ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\n" )
2024-02-20 20:58:45 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-11 23:13:22 +00:00
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . EnableMaybeArray )
results := strings . Split (
strings . Join ( [ ] string {
inputResult4 ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-11 23:13:22 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar (
functions . SetPrefix ( "suffix" ) ,
functions . EnableMaybeArray ,
)
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` "suffix" arr | realvalue ` ) ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-15 18:03:18 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . SetPrefix ( "suffix" ) )
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` "suffix" realvalue ` ) ,
"mixedstring ::= freestring | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-15 18:03:18 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . SetPrefix ( "suffix" ) , functions . EnableMaybeString )
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` ( "suffix" realvalue | mixedstring ) ` ) ,
"mixedstring ::= freestring | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-15 18:03:18 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . SetPrefix ( "suffix" ) , functions . EnableMaybeString , functions . EnableMaybeArray )
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` ( "suffix" (arr | realvalue) | mixedstring ) ` ) ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-15 18:03:18 +00:00
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 ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-15 18:03:18 +00:00
OneOf : testFunctionsName }
2024-05-21 22:14:16 +00:00
grammar := structuredGrammar . Grammar ( functions . EnableMaybeString , functions . EnableMaybeArray )
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` mixedstring | arr | realvalue ` ) ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\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. Disables mixedstring" , func ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-21 22:14:16 +00:00
OneOf : testFunctionsName }
grammar := structuredGrammar . Grammar ( functions . EnableMaybeString , functions . EnableMaybeArray , functions . NoMixedFreeString )
results := strings . Split (
strings . Join ( [ ] string {
rootResult ( ` freestring | arr | realvalue ` ) ,
"mixedstring ::= freestring | freestring arr | freestring realvalue" } , "\n" ) ,
"\n" )
2024-05-15 18:03:18 +00:00
for _ , r := range results {
if r != "" {
Expect ( grammar ) . To ( ContainSubstring ( r ) )
}
}
Expect ( len ( results ) ) . To ( Equal ( len ( strings . Split ( grammar , "\n" ) ) ) , grammar )
} )
2024-05-23 17:16:08 +00:00
It ( "generates parallel tools without newlines in JSON" , func ( ) {
2024-07-18 15:52:22 +00:00
structuredGrammar := JSONFunctionStructure {
2024-05-23 17:16:08 +00:00
OneOf : testFunctionsName }
content := ` arr : :=
"[" (
realvalue
( "," realvalue ) *
) ? "]" `
grammar := structuredGrammar . Grammar ( functions . EnableMaybeString , functions . EnableMaybeArray , functions . DisableParallelNewLines )
results := strings . Split ( content , "\n" )
for _ , r := range results {
if r != "" {
Expect ( grammar ) . To ( ContainSubstring ( r ) )
}
}
} )
2023-07-02 09:13:51 +00:00
} )
} )