2023-06-20 14:23:46 +00:00
import test from 'ava'
import { z } from 'zod'
import {
2023-06-21 18:33:15 +00:00
extractJSONFromString ,
2023-06-20 14:23:46 +00:00
parseArrayOutput ,
parseBooleanOutput ,
parseNumberOutput ,
2023-06-20 14:54:53 +00:00
parseObjectOutput ,
parseOutput
2023-06-20 14:23:46 +00:00
} from '@/llms/parse-output'
2023-06-21 18:33:15 +00:00
test ( 'extractJSONFromString should extract JSON object from string' , ( t ) = > {
let jsonStr = 'Some text {"name":"John Doe"} more text'
let result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , { name : 'John Doe' } )
jsonStr =
'Some text {"name":"John Doe","age":42,"address":{"street":"Main Street","number":42}} more text'
result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , {
name : 'John Doe' ,
age : 42 ,
address : { street : 'Main Street' , number : 42 }
} )
jsonStr = 'foo {"name":"John Doe","school":"St. John\'s"} bar'
result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , { name : 'John Doe' , school : "St. John's" } )
} )
test ( 'extractJSONFromString should extract an invalid JSON object from string' , ( t ) = > {
let jsonStr = 'Some text {"name":\'John Doe\'} more text'
let result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , { name : 'John Doe' } )
jsonStr = 'Some text {"name":"John Doe","age":42,} more text'
result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , { name : 'John Doe' , age : 42 } )
} )
test ( 'extractJSONFromString should extract multiple JSON objects from string' , ( t ) = > {
let jsonStr = 'Some text {"name":"John Doe"} more text {"name":"Jane Doe"}'
let result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , { name : 'John Doe' } )
t . deepEqual ( result [ 1 ] , { name : 'Jane Doe' } )
jsonStr =
'Some text {"name":"John Doe","age":42,"address":{"street":"Main Street","number":42}} more text {"name":"Jane Doe","age":42,"address":{"street":"Main Street","number":42}}'
result = extractJSONFromString ( jsonStr , 'object' )
t . deepEqual ( result [ 0 ] , {
name : 'John Doe' ,
age : 42 ,
address : { street : 'Main Street' , number : 42 }
} )
t . deepEqual ( result [ 1 ] , {
name : 'Jane Doe' ,
age : 42 ,
address : { street : 'Main Street' , number : 42 }
} )
} )
test ( 'extractJSONFromString should extract JSON array from string' , ( t ) = > {
let jsonString = 'Some text [1,2,3] more text'
let result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result [ 0 ] , [ 1 , 2 , 3 ] )
jsonString = 'Some text ["foo","bar","\'quoted\'"] more text'
result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result [ 0 ] , [ 'foo' , 'bar' , "'quoted'" ] )
} )
test ( 'extractJSONFromString should extract an invalid JSON array from string' , ( t ) = > {
let jsonString = 'Some text [1,2,3,] more text'
let result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result [ 0 ] , [ 1 , 2 , 3 ] )
jsonString = "Some text ['foo','bar'] more text"
result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result [ 0 ] , [ 'foo' , 'bar' ] )
} )
test ( 'extractJSONFromString should extract multiple JSON arrays from string' , ( t ) = > {
const jsonString = 'Some text [1,2,3] more text [4,5,6]'
const result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result [ 0 ] , [ 1 , 2 , 3 ] )
t . deepEqual ( result [ 1 ] , [ 4 , 5 , 6 ] )
} )
test ( 'extractJSONFromString should return an empty array if no JSON object is found' , ( t ) = > {
const jsonString = 'Some text'
const result = extractJSONFromString ( jsonString , 'object' )
t . deepEqual ( result , [ ] )
} )
test ( 'extractJSONFromString should return an empty array if no JSON array is found' , ( t ) = > {
const jsonString = 'Some text'
const result = extractJSONFromString ( jsonString , 'array' )
t . deepEqual ( result , [ ] )
} )
2023-06-20 14:23:46 +00:00
test ( 'parseArrayOutput - handles valid arrays correctly' , ( t ) = > {
const output1 = parseArrayOutput ( '[1,2,3]' )
const output2 = parseArrayOutput ( '["a", "b", "c"]' )
const output3 = parseArrayOutput ( '[{"a": 1}, {"b": 2}]' )
t . snapshot ( output1 , 'should return [1, 2, 3] for "[1,2,3]"' )
t . snapshot ( output2 , 'should return ["a", "b", "c"] for "["a", "b", "c"]' )
t . snapshot (
output3 ,
'should return [{"a": 1}, {"b": 2}] for [{"a": 1}, {"b": 2}]'
)
} )
test ( 'parseArrayOutput - handles arrays surrounded by text correctly' , ( t ) = > {
const output1 = parseArrayOutput ( 'The array is [1,2,3]' )
const output2 = parseArrayOutput ( 'Array: ["a", "b", "c"]. That\'s all!' )
const output3 = parseArrayOutput (
'This is the array [{"a": 1}, {"b": 2}] in the text'
)
t . snapshot ( output1 , 'should return [1, 2, 3] for "The array is [1,2,3]"' )
t . snapshot (
output2 ,
'should return ["a", "b", "c"] for "Array: ["a", "b", "c"]. That\'s all!"'
)
t . snapshot (
output3 ,
'should return [{"a": 1}, {"b": 2}] for "This is the array [{"a": 1}, {"b": 2}] in the text"'
)
} )
test ( 'parseArrayOutput - throws error for invalid arrays' , ( t ) = > {
const error = t . throws (
( ) = > {
parseArrayOutput ( 'not a valid array' )
} ,
{ instanceOf : Error }
)
t . snapshot ( error ? . message )
} )
test ( 'parseObjectOutput - handles valid objects correctly' , ( t ) = > {
const output1 = parseObjectOutput ( '{"a":1,"b":2,"c":3}' )
const output2 = parseObjectOutput (
'{"name":"John","age":30,"city":"New York"}'
)
t . snapshot (
output1 ,
'should return {"a":1,"b":2,"c":3} for {"a":1,"b":2,"c":3}'
)
t . snapshot (
output2 ,
'should return {"name":"John","age":30,"city":"New York"} for {"name":"John","age":30,"city":"New York"}'
)
} )
test ( 'parseObjectOutput - handles objects surrounded by text correctly' , ( t ) = > {
const output1 = parseObjectOutput ( 'The object is {"a":1,"b":2,"c":3}' )
const output2 = parseObjectOutput (
'Object: {"name":"John","age":30,"city":"New York"}. That\'s all!'
)
t . snapshot (
output1 ,
'should return {"a":1,"b":2,"c":3} for "The object is {"a":1,"b":2,"c":3}"'
)
t . snapshot (
output2 ,
'should return {"name":"John","age":30,"city":"New York"} for "Object: {"name":"John","age":30,"city":"New York"}. That\'s all!"'
)
} )
test ( 'parseObjectOutput - handles JSON array of objects' , ( t ) = > {
const output = parseObjectOutput ( '[{"a":1,"b":2},{"c":3,"d":4}]' )
t . snapshot (
output ,
'should return first object {"a":1,"b":2} for [{"a":1,"b":2},{"c":3,"d":4}]'
)
} )
test ( 'parseObjectOutput - throws error for invalid objects' , ( t ) = > {
const error = t . throws (
( ) = > {
parseObjectOutput ( 'not a valid object' )
} ,
{ instanceOf : Error }
)
t . snapshot ( error ? . message )
} )
test ( 'parseBooleanOutput - handles `true` outputs correctly' , ( t ) = > {
const output1 = parseBooleanOutput ( 'True' )
const output2 = parseBooleanOutput ( 'TRUE' )
const output3 = parseBooleanOutput ( 'true.' )
t . snapshot ( output1 , 'should return true for "True"' )
t . snapshot ( output2 , 'should return true for "TRUE"' )
t . snapshot ( output3 , 'should return true for "true."' )
} )
test ( 'parseBooleanOutput - handles `false` outputs correctly' , ( t ) = > {
const output1 = parseBooleanOutput ( 'False' )
const output2 = parseBooleanOutput ( 'FALSE' )
const output3 = parseBooleanOutput ( 'false!' )
t . snapshot ( output1 , 'should return false for "False"' )
t . snapshot ( output2 , 'should return false for "FALSE"' )
t . snapshot ( output3 , 'should return false for "false!"' )
} )
test ( 'parseBooleanOutput - throws error for invalid outputs' , ( t ) = > {
const error = t . throws (
( ) = > {
parseBooleanOutput ( 'NotBooleanValue' )
} ,
{ instanceOf : Error }
)
t . snapshot ( error ? . message )
} )
test ( 'parseNumberOutput - handles integer outputs correctly' , ( t ) = > {
const output1 = parseNumberOutput ( '42' , z . number ( ) . int ( ) )
const output2 = parseNumberOutput ( ' -5 ' , z . number ( ) . int ( ) )
t . snapshot ( output1 , 'should return 42 for "42"' )
t . snapshot ( output2 , 'should return -5 for " -5 "' )
} )
test ( 'parseNumberOutput - handles float outputs correctly' , ( t ) = > {
const output1 = parseNumberOutput ( '42.42' , z . number ( ) )
const output2 = parseNumberOutput ( ' -5.5 ' , z . number ( ) )
t . snapshot ( output1 , 'should return 42.42 for "42.42"' )
t . snapshot ( output2 , 'should return -5.5 for " -5.5 "' )
} )
test ( 'parseNumberOutput - throws error for invalid outputs' , ( t ) = > {
const error = t . throws (
( ) = > {
parseNumberOutput ( 'NotANumber' , z . number ( ) )
} ,
{ instanceOf : Error }
)
t . snapshot ( error ? . message )
} )
2023-06-20 14:54:53 +00:00
test ( 'parseOutput - handles arrays correctly' , ( t ) = > {
const arraySchema = z . array ( z . number ( ) )
const output = '[1, 2, 3]'
const result = parseOutput ( output , arraySchema )
t . snapshot ( result , 'should parse and return [1, 2, 3] for "[1, 2, 3]"' )
} )
test ( 'parseOutput - handles objects correctly' , ( t ) = > {
const objectSchema = z . object ( { a : z.number ( ) , b : z.string ( ) } )
const output = '{"a": 1, "b": "two"}'
const result = parseOutput ( output , objectSchema )
t . snapshot (
result ,
'should parse and return {"a": 1, "b": "two"} for "{"a": 1, "b": "two"}"'
)
} )
test ( 'parseOutput - handles booleans correctly' , ( t ) = > {
const booleanSchema = z . boolean ( )
const output = 'True'
const result = parseOutput ( output , booleanSchema )
t . snapshot ( result , 'should parse and return true for "True"' )
} )
test ( 'parseOutput - handles numbers correctly' , ( t ) = > {
const numberSchema = z . number ( )
const output = '123.45'
const result = parseOutput ( output , numberSchema )
t . snapshot ( result , 'should parse and return 123.45 for "123.45"' )
} )
test ( 'parseOutput - throws error for invalid data' , ( t ) = > {
const numberSchema = z . number ( )
const output = 'not a number'
const error = t . throws (
( ) = > {
parseOutput ( output , numberSchema )
} ,
{ instanceOf : Error }
)
t . snapshot ( error ? . message )
} )