This package is designed to solve two problems that are especially relevant for JSON output from LLMs:
- Parsing JSON while the response is still streaming
- Correcting hallucinated properties and other schema inconsistencies
Usage
This package exposes one method.
aiJson(jsonString: string, options?: AiJsonOptions): T | null
The basic usage of this method is very similar to JSON.parse(...)
. You can call aiJson('{ "pi": 3.14 }')
to get the object { pi: 3.14 }
. In the basic usage, the difference is that it avoids throwing errors and instead returns as much data as it can parse before input ends.
Examples
Input | JSON.parse | aiJson |
---|---|---|
"{ "pi": 3.14 }" |
{ pi: 3.14 } |
{ pi: 3.14 } |
"{ "pi": 3.14" |
Error | { pi: 3.14 } |
"{ "pi":" |
Error | { pi: null } |
"{ pi: 3.14 }" |
Error | Error |
AiJsonOptions
All options are optional. You can call aiJson(...)
without any options if you just want a lax version of JSON.parse
.
schema
This is a JSON schema. If you are using ChatGPT functions, you can use the same schema that you've defined for the function parameters
as the schema
for this parser.
Callbacks will be fired for any places where the parsed value doesn't match the provided schema.
Note: Not all schema rules are validated. Specifically, this package validates the
type
of each field, and theproperties
of objects (making sure required fields are present, handling unexpected properties).
onError(error)
This is a catch-all error handling callback. If specified, all types of errors will call onError
with information about the error that occurred. The specific error types are also listed below with their specific callback options.
onInvalidType(error)
This is called when a value doesn't match the expected type (or enum) of the schema. The error object has these properties:
Property | Type | Example |
---|---|---|
type | 'InvalidType' | |
path | Path | ['foo', 0] |
expected | JsonSchema | { type: 'string' } |
value | any |
onMissingProperty(error)
This is called when an object is missing a required property from the schema. The error object has these properties:
Property | Type | Example |
---|---|---|
type | 'MissingProperty' | |
path | Path | ['foo', 0] |
expected | JsonSchema | { type: 'string' } |
object | object | |
property | string | 'name' |
onUnexpectedProperty(error)
This is called when an object has a property that is not in the schema. The error object has these properties:
Property | Type | Example |
---|---|---|
type | 'UnexpectedProperty' | |
path | Path | ['foo', 0] |
expected | JsonSchema | { type: 'string' } |
object | object | |
property | string | 'nonsenseName' |
Example
To handle JSON data from a ChatGPT response while it's streaming:
import { aiJson } from "@wits/ai-json";
const json = aiJson(completion, {
schema: {
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
type: "number",
},
required: ["foo", "bar"],
},
},
onError: (error) => {
if (error.type === "MissingProperty") {
switch (error.property) {
case "foo":
error.object.foo = "";
break;
case "bar":
error.object.bar = 0;
break;
default:
break;
}
} else if (error.type === "UnexpectedProperty") {
delete error.object[error.property];
} else if (error.type === "InvalidType") {
if (error.expected.type === "string") {
return "";
} else if (error.expected.type === "number") {
return 0;
}
}
},
});
// json will have an object with the expected shape
// as soon as the first `{` is present