UNPKG

@toolbox-sdk/core

Version:
155 lines (135 loc) 4.36 kB
// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import {z, ZodRawShape, ZodTypeAny, ZodObject} from 'zod'; // Define All Interfaces interface BaseParameter { name: string; description: string; authSources?: string[]; required?: boolean; } interface StringParameter extends BaseParameter { type: 'string'; } interface IntegerParameter extends BaseParameter { type: 'integer'; } interface FloatParameter extends BaseParameter { type: 'float'; } interface BooleanParameter extends BaseParameter { type: 'boolean'; } interface ArrayParameter extends BaseParameter { type: 'array'; items: ParameterSchema; // Recursive reference to the ParameterSchema type } export type ParameterSchema = | StringParameter | IntegerParameter | FloatParameter | BooleanParameter | ArrayParameter; // Get all Zod schema types const ZodBaseParameter = z.object({ name: z.string().min(1, 'Parameter name cannot be empty'), description: z.string(), authSources: z.array(z.string()).optional(), required: z.boolean().optional(), }); export const ZodParameterSchema = z.lazy(() => z.discriminatedUnion('type', [ ZodBaseParameter.extend({ type: z.literal('string'), }), ZodBaseParameter.extend({ type: z.literal('integer'), }), ZodBaseParameter.extend({ type: z.literal('float'), }), ZodBaseParameter.extend({ type: z.literal('boolean'), }), ZodBaseParameter.extend({ type: z.literal('array'), items: ZodParameterSchema, // Recursive reference for the item's definition }), ]), ) as z.ZodType<ParameterSchema>; export const ZodToolSchema = z.object({ description: z.string().min(1, 'Tool description cannot be empty'), parameters: z.array(ZodParameterSchema), authRequired: z.array(z.string()).optional(), }); export const ZodManifestSchema = z.object({ serverVersion: z.string().min(1, 'Server version cannot be empty'), tools: z.record( z.string().min(1, 'Tool name cannot be empty'), ZodToolSchema, ), }); export type ZodManifest = z.infer<typeof ZodManifestSchema>; /** * Recursively builds a Zod schema for a single parameter based on its TypeScript definition. * @param param The ParameterSchema (TypeScript type) to convert. * @returns A ZodTypeAny representing the schema for this parameter. */ function buildZodShapeFromParam(param: ParameterSchema): ZodTypeAny { let schema: ZodTypeAny; switch (param.type) { case 'string': schema = z.string(); break; case 'integer': schema = z.number().int(); break; case 'float': schema = z.number(); break; case 'boolean': schema = z.boolean(); break; case 'array': // Recursively build the schema for array items // Array items inherit the 'required' status of the parent array. param.items.required = param.required; schema = z.array(buildZodShapeFromParam(param.items)); break; default: { // This ensures exhaustiveness at compile time if ParameterSchema is a discriminated union const _exhaustiveCheck: never = param; throw new Error(`Unknown parameter type: ${_exhaustiveCheck['type']}`); } } if (param.required === false) { return schema.nullish(); } return schema; } /** * Creates a ZodObject schema from an array of ParameterSchema (TypeScript types). * This combined schema is used by ToolboxTool to validate its call arguments. * @param params Array of ParameterSchema objects. * @returns A ZodObject schema. */ export function createZodSchemaFromParams( params: ParameterSchema[], ): ZodObject<ZodRawShape> { const shape: {[k: string]: ZodTypeAny} = {}; for (const param of params) { shape[param.name] = buildZodShapeFromParam(param); } return z.object(shape).strict(); }