@langgraph-js/sdk
Version:
The UI SDK for LangGraph - seamlessly integrate your AI agents with frontend interfaces
120 lines (119 loc) • 4.6 kB
JavaScript
/**
* copy and modify from copilotkit
* https://github.com/copilotkit/copilotkit
*
* MIT License
*/
import { z } from "zod";
export function actionParametersToJsonSchema(actionParameters) {
// Create the parameters object based on the argumentAnnotations
let parameters = {};
for (let parameter of actionParameters || []) {
parameters[parameter.name] = convertAttribute(parameter);
}
let requiredParameterNames = [];
for (let arg of actionParameters || []) {
if (arg.required !== false) {
requiredParameterNames.push(arg.name);
}
}
// Create the ChatCompletionFunctions object
return {
type: "object",
properties: parameters,
required: requiredParameterNames,
};
}
function convertAttribute(attribute) {
switch (attribute.type) {
case "string":
return {
type: "string",
description: attribute.description,
...(attribute.enum && { enum: attribute.enum }),
};
case "number":
case "boolean":
return {
type: attribute.type,
description: attribute.description,
};
case "object":
case "object[]":
const properties = attribute.attributes?.reduce((acc, attr) => {
acc[attr.name] = convertAttribute(attr);
return acc;
}, {});
const required = attribute.attributes?.filter((attr) => attr.required !== false).map((attr) => attr.name);
if (attribute.type === "object[]") {
return {
type: "array",
items: {
type: "object",
...(properties && { properties }),
...(required && required.length > 0 && { required }),
},
description: attribute.description,
};
}
return {
type: "object",
description: attribute.description,
...(properties && { properties }),
...(required && required.length > 0 && { required }),
};
default:
// Handle arrays of primitive types and undefined attribute.type
if (attribute.type?.endsWith("[]")) {
const itemType = attribute.type.slice(0, -2);
return {
type: "array",
items: { type: itemType },
description: attribute.description,
};
}
// Fallback for undefined type or any other unexpected type
return {
type: "string",
description: attribute.description,
};
}
}
export function convertJsonSchemaToZodRawShape(jsonSchema) {
const spec = {};
for (const [key, value] of Object.entries(jsonSchema.properties)) {
spec[key] = convertJsonSchemaToZodSchema(value, jsonSchema.required ? jsonSchema.required.includes(key) : false);
}
return spec;
}
export function convertJsonSchemaToZodSchema(jsonSchema, required) {
if (jsonSchema.type === "object") {
const spec = {};
if (!jsonSchema.properties || !Object.keys(jsonSchema.properties).length) {
return !required ? z.object(spec).optional() : z.object(spec);
}
for (const [key, value] of Object.entries(jsonSchema.properties)) {
spec[key] = convertJsonSchemaToZodSchema(value, jsonSchema.required ? jsonSchema.required.includes(key) : false);
}
let schema = z.object(spec).describe(jsonSchema.description);
return required ? schema : schema.optional();
}
else if (jsonSchema.type === "string") {
let schema = z.string().describe(jsonSchema.description);
return required ? schema : schema.optional();
}
else if (jsonSchema.type === "number") {
let schema = z.number().describe(jsonSchema.description);
return required ? schema : schema.optional();
}
else if (jsonSchema.type === "boolean") {
let schema = z.boolean().describe(jsonSchema.description);
return required ? schema : schema.optional();
}
else if (jsonSchema.type === "array") {
let itemSchema = convertJsonSchemaToZodSchema(jsonSchema.items, true);
let schema = z.array(itemSchema).describe(jsonSchema.description);
return required ? schema : schema.optional();
}
throw new Error("Invalid JSON schema");
}