@beparallel/langchain-ts
Version:
Extracts Langchain prompts and generates TypeScript types.
136 lines (135 loc) • 5.14 kB
JavaScript
import fs from 'fs';
import { toCamelCase, toPascalCase, toUpperCase } from './case.js';
export function generateTypes(prompts, outputPath) {
const lines = [
'// Auto-generated file by @beparallel/langchain-ts. Do not edit.\n',
'// For more information, visit https://github.com/beparallel/langchain-ts\n\n',
'import { z } from "zod";\n\n',
];
lines.push('export enum PromptName {');
for (const prompt of prompts) {
const promptName = getPromptName(prompt);
lines.push(` ${toUpperCase(promptName)} = "${promptName}",`);
}
lines.push('}\n\n');
for (const prompt of prompts) {
const inputSchema = prompt.inputVariables;
const promptName = getPromptName(prompt);
const promptDict = prompt.toJSON();
// @ts-ignore
const schema = promptDict.kwargs.schema_;
lines.push('\n');
lines.push(`/***********************************************/`);
lines.push(`// Prompt: ${promptName}`);
lines.push(`/***********************************************/`);
lines.push('\n');
// Input variables
lines.push(`export interface ${toPascalCase(promptName)}Variable {`, ` ${inputSchema.map((input) => `${input}: any`).join('\n ')}`, '}');
lines.push('\n');
// Output variables
lines.push(jsonSchemaToType(schema, promptName));
lines.push('\n');
// Zod schema
lines.push(jsonSchemaToZodType(schema, promptName));
}
fs.writeFileSync(outputPath, lines.join('\n'), 'utf-8');
}
const getPromptName = (prompt) => {
const promptName = String(prompt.metadata?.lc_hub_repo ?? '');
return promptName;
};
function jsonSchemaToType(schema, promptName, rootName = 'Root') {
const parseSchema = (schema, name, increment) => {
if (schema.type === 'object' && schema.properties) {
const required = schema.required || [];
const props = Object.entries(schema.properties)
.map(([key, value]) => {
const optional = required.includes(key) ? '' : '?';
return `${' '.repeat(increment + 1)}${key}${optional}: ${parseSchema(value, key, increment + 1)}`;
})
.join('\n');
return `{\n${' '.repeat(increment)}${props}${' '.repeat(increment)}\n}`;
}
else if (schema.type === 'array' && schema.items) {
return `${parseSchema(schema.items, name, increment + 1)}[]`;
}
else if (schema.type === 'string') {
return 'string';
}
else if (schema.type === 'number') {
return 'number';
}
else if (schema.type === 'boolean') {
return 'boolean';
}
else if (schema.type === 'null') {
return 'null';
}
else {
return 'any';
}
};
if (!schema) {
return '';
}
const typeDef = `${parseSchema(schema, rootName, 1)}`;
return [
`export interface ${toPascalCase(promptName)}Output`,
` ${typeDef}`,
'',
'',
`export interface ${toPascalCase(promptName)}OutputWrapper {`,
` ${schema.title || rootName}: ${toPascalCase(promptName)}Output`,
'}',
].join('\n');
}
function jsonSchemaToZodType(schema, promptName, rootName = 'Root') {
const parseSchema = (schema, name, increment) => {
if (schema.type === 'object' && schema.properties) {
const required = schema.required || [];
const props = Object.entries(schema.properties)
.map(([key, value]) => {
const zodType = parseSchema(value, key, increment + 1);
let prop = `${' '.repeat(increment + 1)}${key}: z.${zodType}`;
if (value.description) {
prop += `.describe(\`${value.description}\`)`;
}
if (!required.includes(key)) {
prop += '.optional()';
}
return prop;
})
.join(',\n');
return `object({\n${props}\n${' '.repeat(increment)}})`;
}
else if (schema.type === 'array' && schema.items) {
return `array(z.${parseSchema(schema.items, name, increment + 1)})`;
}
else if (schema.type === 'string') {
return 'string()';
}
else if (schema.type === 'number') {
return 'number()';
}
else if (schema.type === 'boolean') {
return 'boolean()';
}
else if (schema.type === 'null') {
return 'null()';
}
else {
return 'any()';
}
};
if (!schema) {
return '';
}
const zodSchema = `z.${parseSchema(schema, rootName, 1)}`;
return [
`export const ${toCamelCase(promptName)}OutputSchema = ${zodSchema}`,
'',
`export const ${toPascalCase(promptName)}OutputWrapperSchema = z.object({`,
` ${schema.title || rootName}: ${toCamelCase(promptName)}OutputSchema`,
'})',
].join('\n');
}