From c1e8e5540932a6135a7608c41f0f43031f650c99 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Thu, 4 Dec 2025 09:13:10 +1000 Subject: [PATCH] fix: use AI SDK tool() function to create proper tool wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL FIX: Was creating plain objects instead of using tool() from AI SDK. The issue: - Creating { description, inputSchema, execute } plain objects - OpenAI receives invalid tool format: "type: None" - AI SDK needs tools created with tool() function The fix: - Import tool() and jsonSchema() from 'ai' - Use tool() to wrap the remote execution - Use jsonSchema() to wrap the JSON Schema received from Railway - Matches the format used in packages/tools/hello Example from hello tool: ```ts tool({ description: "...", inputSchema: jsonSchema({ type: 'object', properties: {...} }), execute: async (params) => {...} }) ``` Now the playground creates tools the same way! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- apps/playground/src/lib/dynamic-tool-loader.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/playground/src/lib/dynamic-tool-loader.ts b/apps/playground/src/lib/dynamic-tool-loader.ts index 2591e59..f9f237b 100644 --- a/apps/playground/src/lib/dynamic-tool-loader.ts +++ b/apps/playground/src/lib/dynamic-tool-loader.ts @@ -1,3 +1,5 @@ +import { tool, jsonSchema } from 'ai'; + // Cache for tool wrappers (process-level) const moduleCache = new Map(); @@ -66,13 +68,13 @@ export async function loadToolDynamically( console.log(`✅ Tool loaded from Railway: ${cacheKey}`); console.log(`📋 Description: ${data.tool.description}`); - // Create a tool wrapper that executes remotely - // Railway returns plain JSON Schema - wrap it in the AI SDK jsonSchema format - const tool = { + // Create a proper AI SDK tool wrapper that executes remotely + // Railway returns plain JSON Schema - wrap it with jsonSchema() for AI SDK + const toolWrapper = tool({ description: data.tool.description, inputSchema: data.tool.inputSchema - ? { type: 'json_schema' as const, schema: data.tool.inputSchema } - : undefined, + ? jsonSchema(data.tool.inputSchema) + : jsonSchema({ type: 'object', properties: {}, additionalProperties: false }), // biome-ignore lint/suspicious/noExplicitAny: Tool params are dynamic execute: async (params: any) => { console.log(`🚀 Executing ${packageName}/${exportName} remotely with params:`, params); @@ -99,13 +101,13 @@ export async function loadToolDynamically( console.log(`✅ Tool executed successfully in ${result.executionTimeMs}ms`); return result.output; }, - }; + }); // Cache the wrapper - moduleCache.set(cacheKey, tool); + moduleCache.set(cacheKey, toolWrapper); console.log(`✅ Cached tool wrapper: ${cacheKey}`); - return tool; + return toolWrapper; } catch (error) { console.error(`❌ Failed to load ${packageName}#${exportName}:`, error); console.error(` Stack:`, error instanceof Error ? error.stack : 'No stack trace');