Skip to main content
Glama
zai.js3.29 kB
/** * zai.js * AI provider implementation for Z.ai (GLM) models. * Uses the OpenAI-compatible API endpoint. */ import { OpenAICompatibleProvider } from './openai-compatible.js'; /** * Z.ai provider supporting GLM models through OpenAI-compatible API. */ export class ZAIProvider extends OpenAICompatibleProvider { constructor() { super({ name: 'Z.ai', apiKeyEnvVar: 'ZAI_API_KEY', requiresApiKey: true, defaultBaseURL: 'https://api.z.ai/api/paas/v4/', supportsStructuredOutputs: true }); } /** * Override token parameter preparation for ZAI * ZAI API doesn't support max_tokens parameter * @returns {object} Empty object for ZAI (doesn't support maxOutputTokens) */ prepareTokenParam() { // ZAI API rejects max_tokens parameter with error code 1210 return {}; } /** * Introspects a Zod schema to find the property that expects an array * @param {import('zod').ZodType} schema - The Zod schema to introspect * @returns {string|null} The property name that expects an array, or null if not found */ findArrayPropertyInSchema(schema) { try { // Get the def object from Zod v4 API const def = schema._zod.def; // Check if schema is a ZodObject const isObject = def?.type === 'object' || def?.typeName === 'ZodObject'; if (!isObject) { return null; } // Get the shape - it can be a function, property, or getter let shape = def.shape; if (typeof shape === 'function') { shape = shape(); } if (!shape || typeof shape !== 'object') { return null; } // Find the first property that is an array for (const [key, value] of Object.entries(shape)) { // Get the def object for the property using Zod v4 API const valueDef = value._zod.def; // Check if the property is a ZodArray const isArray = valueDef?.type === 'array' || valueDef?.typeName === 'ZodArray'; if (isArray) { return key; } } return null; } catch (error) { // If introspection fails, log and return null console.warn('Failed to introspect Zod schema:', error.message); return null; } } /** * Override generateObject to normalize GLM's response format * GLM sometimes returns bare arrays instead of objects with properties, * even when the schema has multiple properties. * @param {object} params - Parameters for object generation * @returns {Promise<object>} Normalized response */ async generateObject(params) { const result = await super.generateObject(params); // If result.object is an array, wrap it based on schema introspection if (Array.isArray(result.object)) { // Try to find the array property from the schema const wrapperKey = this.findArrayPropertyInSchema(params.schema); if (wrapperKey) { return { ...result, object: { [wrapperKey]: result.object } }; } // Fallback: if we can't introspect the schema, use the object name // This handles edge cases where schema introspection might fail console.warn( `GLM returned a bare array for '${params.objectName}' but could not determine wrapper property from schema. Using objectName as fallback.` ); return { ...result, object: { [params.objectName]: result.object } }; } return result; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eyaltoledano/claude-task-master'

If you have feedback or need assistance with the MCP directory API, please join our Discord server