@toolbox-sdk/core
Version:
JavaScript Base SDK for interacting with the Toolbox service
155 lines (135 loc) • 4.36 kB
text/typescript
// 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();
}