From bb672edf15a1c971fbd79038e89b2e735851e62e Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Thu, 4 Dec 2025 09:00:00 +1000 Subject: [PATCH] fix: extract and serialize JSON Schema from AI SDK v6 tools correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit THE BREAKTHROUGH: AI SDK v6 tools use jsonSchema() which wraps plain JSON Schema objects, NOT Zod schemas. JSON Schema is fully serializable. Changes: 1. Railway server: Extract raw JSON Schema from toolModule.inputSchema?.schema 2. Playground loader: Wrap received JSON Schema with { type: 'json_schema', schema: ... } 3. This matches AI SDK v6 format exactly - no Zod serialization needed How it works: - Tools define inputSchema: jsonSchema({ type: 'object', properties: {...} }) - AI SDK stores it as { type: 'json_schema', schema: {...} } - Railway extracts the plain JSON Schema (.schema property) - Sends it as plain JSON (fully serializable) - Playground wraps it back in AI SDK format - OpenAI receives valid JSON Schema for function calling This fixes both errors: ✅ No more "def.shape is not a function" (not using Zod) ✅ No more "Invalid schema type None" (proper JSON Schema provided) Note: Tools using Zod instead of jsonSchema() will need to migrate. TPMJS standard: All tools MUST use jsonSchema() with plain JSON Schema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- apps/playground/src/lib/dynamic-tool-loader.ts | 6 ++++-- apps/railway-executor/server.ts | 9 +++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/playground/src/lib/dynamic-tool-loader.ts b/apps/playground/src/lib/dynamic-tool-loader.ts index e0c2916..2591e59 100644 --- a/apps/playground/src/lib/dynamic-tool-loader.ts +++ b/apps/playground/src/lib/dynamic-tool-loader.ts @@ -67,10 +67,12 @@ export async function loadToolDynamically( console.log(`📋 Description: ${data.tool.description}`); // Create a tool wrapper that executes remotely - // Note: We don't include inputSchema because Zod schemas can't be serialized over HTTP - // The AI SDK will infer parameters from the description + // Railway returns plain JSON Schema - wrap it in the AI SDK jsonSchema format const tool = { description: data.tool.description, + inputSchema: data.tool.inputSchema + ? { type: 'json_schema' as const, schema: data.tool.inputSchema } + : undefined, // biome-ignore lint/suspicious/noExplicitAny: Tool params are dynamic execute: async (params: any) => { console.log(`🚀 Executing ${packageName}/${exportName} remotely with params:`, params); diff --git a/apps/railway-executor/server.ts b/apps/railway-executor/server.ts index f98776c..5f27d88 100644 --- a/apps/railway-executor/server.ts +++ b/apps/railway-executor/server.ts @@ -76,15 +76,16 @@ async function loadAndDescribe(req: Request): Promise { } // Extract tool definition - // Note: We don't send inputSchema because Zod schemas can't be serialized over JSON - // The playground will use the actual tool's inputSchema when creating the wrapper + // AI SDK v6 tools use jsonSchema() which wraps a plain JSON Schema object + // Extract the raw JSON Schema from toolModule.inputSchema.schema + const rawJsonSchema = toolModule.inputSchema?.schema ?? null; + return Response.json({ success: true, tool: { exportName, description: toolModule.description, - // Store reference that inputSchema exists (for validation) - hasInputSchema: !!toolModule.inputSchema, + inputSchema: rawJsonSchema, // Plain JSON Schema - fully serializable }, }); } catch (error) {