node-llama-cpp
Version:
Run AI models locally on your machine with node.js bindings for llama.cpp. Enforce a JSON schema on the model output on the generation level
162 lines • 8.12 kB
JavaScript
import { isGbnfJsonArraySchema, isGbnfJsonBasicSchemaIncludesType, isGbnfJsonBasicStringSchema, isGbnfJsonConstSchema, isGbnfJsonEnumSchema, isGbnfJsonFormatStringSchema, isGbnfJsonObjectSchema, isGbnfJsonOneOfSchema } from "./gbnfJson/types.js";
const maxTypeRepetition = 10;
export function getTypeScriptTypeStringForGbnfJsonSchema(schema) {
if (isGbnfJsonOneOfSchema(schema)) {
const values = schema.oneOf
.map((altSchema) => getTypeScriptTypeStringForGbnfJsonSchema(altSchema));
return values.join(" | ");
}
else if (isGbnfJsonConstSchema(schema)) {
return JSON.stringify(schema.const) ?? "";
}
else if (isGbnfJsonEnumSchema(schema)) {
return schema.enum
.map((item) => JSON.stringify(item) ?? "")
.filter((item) => item !== "")
.join(" | ");
}
else if (isGbnfJsonObjectSchema(schema)) {
let addNewline = false;
const valueTypes = Object.entries(schema.properties ?? {})
.map(([propName, propSchema]) => {
const escapedValue = JSON.stringify(propName) ?? "";
const keyText = escapedValue.slice(1, -1) === propName ? propName : escapedValue;
const valueType = getTypeScriptTypeStringForGbnfJsonSchema(propSchema);
if (keyText === "" || valueType === "")
return "";
const mapping = keyText + ": " + valueType;
const description = (propSchema.description != null && propSchema.description !== "")
? [propSchema.description]
: [];
const propInfo = [];
if (isGbnfJsonBasicStringSchema(propSchema)) {
if (propSchema.minLength != null && propSchema.minLength > 0)
propInfo.push("minimum length: " + String(Math.floor(propSchema.minLength)));
if (propSchema.maxLength != null)
propInfo.push("maximum length: " + String(Math.floor(Math.max(propSchema.maxLength, propSchema.minLength ?? 0, 0))));
}
else if (isGbnfJsonFormatStringSchema(propSchema)) {
if (propSchema.format === "date-time")
propInfo.push("format: ISO 8601 date-time");
else
propInfo.push("format: " + String(propSchema.format));
}
else if (isGbnfJsonArraySchema(propSchema)) {
if (propSchema.minItems != null && propSchema.minItems > maxTypeRepetition)
propInfo.push("minimum items: " + String(Math.floor(propSchema.minItems)));
if (propSchema.maxItems != null)
propInfo.push("maximum items: " + String(Math.floor(Math.max(propSchema.maxItems, propSchema.minItems ?? 0, 0))));
}
else if (isGbnfJsonObjectSchema(propSchema)) {
if (propSchema.minProperties != null && propSchema.minProperties > 0)
propInfo.push("minimum number of properties: " + String(Math.floor(propSchema.minProperties)));
if (propSchema.maxProperties != null)
propInfo.push("maximum number of properties: " +
String(Math.floor(Math.max(propSchema.maxProperties, propSchema.minProperties ?? 0, 0))));
}
if (propInfo.length > 0)
description.push(propInfo.join(", "));
if (description.length > 0) {
addNewline = true;
return [
"\n",
"// ", description
.join("\n")
.split("\n")
.join("\n// "),
"\n",
mapping
].join("");
}
return mapping;
})
.filter((item) => item !== "");
const knownPropertiesMapSyntax = [
"{",
(addNewline && valueTypes.length > 0)
? [
"\n ",
valueTypes
.map((value) => value.split("\n").join("\n "))
.join(",\n ")
.trimStart(),
"\n"
].join("")
: valueTypes.join(", "),
"}"
].join("");
const additionalPropertiesMapSyntax = (schema.additionalProperties == null || schema.additionalProperties == false)
? undefined
: schema.additionalProperties === true
? "{[key: string]: any}"
: schema.additionalProperties != null
? ["{[key: string]: ", getTypeScriptTypeStringForGbnfJsonSchema(schema.additionalProperties), "}"].join("")
: undefined;
if (valueTypes.length === 0 && additionalPropertiesMapSyntax != null)
return additionalPropertiesMapSyntax;
else if (additionalPropertiesMapSyntax != null)
return [knownPropertiesMapSyntax, " & ", additionalPropertiesMapSyntax].join("");
return knownPropertiesMapSyntax;
}
else if (isGbnfJsonArraySchema(schema)) {
if (schema.maxItems === 0)
return "[]";
if (schema.prefixItems != null && schema.prefixItems.length > 0) {
const valueTypes = schema.prefixItems.map((item) => getTypeScriptTypeStringForGbnfJsonSchema(item));
const restType = schema.items != null
? getTypeScriptTypeStringForGbnfJsonSchema(schema.items)
: "any";
if (schema.minItems != null) {
for (let i = schema.prefixItems.length; i < Math.min(schema.prefixItems.length + maxTypeRepetition, schema.minItems); i++)
valueTypes.push(restType);
}
if (schema.maxItems == null || schema.maxItems > valueTypes.length)
valueTypes.push("..." + wrapWithParensIfNeeded(restType) + "[]");
return "[" + valueTypes.join(", ") + "]";
}
else if (schema.items != null) {
const valuesType = getTypeScriptTypeStringForGbnfJsonSchema(schema.items);
if (valuesType === "")
return "[]";
if (schema.minItems != null) {
if (schema.minItems === schema.maxItems) {
if (schema.minItems < maxTypeRepetition)
return "[" + (valuesType + ", ").repeat(schema.minItems).slice(0, -", ".length) + "]";
else
return [
"[",
(valuesType + ", ").repeat(maxTypeRepetition),
"...", wrapWithParensIfNeeded(valuesType), "[]",
"]"
].join("");
}
else if (schema.minItems <= 0)
return wrapWithParensIfNeeded(valuesType) + "[]";
else if (schema.minItems < maxTypeRepetition)
return "[" + (valuesType + ", ").repeat(schema.minItems) + "..." + wrapWithParensIfNeeded(valuesType) + "[]]";
else
return wrapWithParensIfNeeded(valuesType) + "[]";
}
return wrapWithParensIfNeeded(valuesType) + "[]";
}
return "any[]";
}
const types = [];
if (isGbnfJsonBasicSchemaIncludesType(schema, "string"))
types.push("string");
if (isGbnfJsonBasicSchemaIncludesType(schema, "number"))
types.push("number");
if (isGbnfJsonBasicSchemaIncludesType(schema, "integer"))
types.push("bigint");
if (isGbnfJsonBasicSchemaIncludesType(schema, "boolean"))
types.push("boolean");
if (isGbnfJsonBasicSchemaIncludesType(schema, "null"))
types.push("null");
return types.join(" | ");
}
function wrapWithParensIfNeeded(text) {
if (text.includes(" ") || text.includes("|") || text.includes("&") || text.includes("\n") || text.includes("\t"))
return "(" + text + ")";
return text;
}
//# sourceMappingURL=getTypeScriptTypeStringForGbnfJsonSchema.js.map