ai-functions
Version:
Core AI primitives for building intelligent applications
101 lines • 3.61 kB
JavaScript
/**
* Simplified schema syntax for AI generation
*
* Converts human-readable schema definitions to Zod schemas:
* - 'description' → z.string().describe('description')
* - 'description (number)' → z.number().describe('description')
* - 'description (boolean)' → z.boolean().describe('description')
* - 'description (integer)' → z.number().int().describe('description')
* - 'description (date)' → z.string().datetime().describe('description')
* - 'opt1 | opt2 | opt3' → z.enum(['opt1', 'opt2', 'opt3'])
* - ['description'] → z.array(z.string()).describe('description')
* - { nested } → z.object() recursively
*
* @packageDocumentation
*/
import { z } from 'zod';
import { isZodSchema } from './type-guards.js';
/**
* Convert a simplified schema to a Zod schema
*
* @example
* ```ts
* import { schema } from 'ai-functions'
* import { z } from 'zod'
*
* // These are equivalent:
* const simple = schema({
* name: 'What is the recipe name?',
* ingredients: ['List all ingredients'],
* steps: ['List all cooking steps'],
* })
*
* const zod = z.object({
* name: z.string().describe('What is the recipe name?'),
* ingredients: z.array(z.string()).describe('List all ingredients'),
* steps: z.array(z.string()).describe('List all cooking steps'),
* })
* ```
*/
export function schema(input) {
return convertToZod(input);
}
function convertToZod(input) {
// Already a Zod schema - pass through
if (isZodSchema(input)) {
return input;
}
// String handling
if (typeof input === 'string') {
// Enum syntax: 'option1 | option2 | option3'
if (input.includes(' | ')) {
const options = input.split(' | ').map((s) => s.trim());
return z.enum(options);
}
// Type hint syntax: 'description (type)'
const typeMatch = input.match(/^(.+?)\s*\((number|boolean|integer|date)\)$/i);
if (typeMatch) {
const [, description, type] = typeMatch;
const desc = description.trim();
switch (type.toLowerCase()) {
case 'number':
return z.number().describe(desc);
case 'integer':
return z.number().int().describe(desc);
case 'boolean':
return z.boolean().describe(desc);
case 'date':
return z.string().datetime().describe(desc);
default:
return z.string().describe(desc);
}
}
// Regular string description → z.string().describe()
return z.string().describe(input);
}
// Array with single element → z.array().describe()
if (Array.isArray(input) && input.length === 1) {
const [desc] = input;
// [string] → z.array(z.string()).describe(string)
if (typeof desc === 'string') {
return z.array(z.string()).describe(desc);
}
// [number] → z.array(z.number()) - number as type indicator
if (typeof desc === 'number') {
return z.array(z.number());
}
// [SimpleSchema] → z.array(converted)
return z.array(convertToZod(desc));
}
// Object → z.object() with recursive conversion
if (typeof input === 'object' && input !== null) {
const shape = {};
for (const [key, value] of Object.entries(input)) {
shape[key] = convertToZod(value);
}
return z.object(shape);
}
// Fallback - shouldn't reach here
return z.unknown();
}
//# sourceMappingURL=schema.js.map