tpmjs/apps/playground/src/lib/tool-loader.ts
Ajax Davis ada3ffb341 refactor: rename exportName to name across entire codebase
- Database: Migrate column export_name to name in tools table
- Prisma schema: Update Tool model to use name field
- Sync routes: Update keyword and changes sync to use name
- Railway executor: Update API endpoints to use name parameter
- API routes: Update all tool routes to use name field
- Web app: Update all pages and components
- Playground: Update tool loader and sidebar
- create-basic-tools: Update types and generators
- Scripts: Update sync and test scripts

Database migration was done via direct SQL:
  ALTER TABLE tools RENAME COLUMN export_name TO name;

The unique constraint remains on (package_id, name).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-17 17:19:21 +10:00

94 lines
2.9 KiB
TypeScript

// Static imports for tools (required for Next.js/webpack)
import { helloNameTool, helloWorldTool } from '@tpmjs/hello';
/**
* Tool registry mapping package names + export names to actual tool functions
* This is a static mapping required for Next.js/webpack bundling
*/
const TOOL_REGISTRY: Record<string, Record<string, any>> = {
'@tpmjs/hello': {
helloWorldTool,
helloNameTool,
},
};
/**
* Load a specific TPMJS tool by package name and export name
* Uses static imports to work with Next.js/webpack bundling
*/
// biome-ignore lint/suspicious/noExplicitAny: Tool types from AI SDK are complex and using any is appropriate here
export async function loadTpmjsTool(packageName: string, name: string): Promise<any | null> {
try {
// Look up the package in the registry
const packageTools = TOOL_REGISTRY[packageName];
if (!packageTools) {
console.warn(`Package not found in registry: ${packageName}`);
return null;
}
// Look up the specific tool export
const tool = packageTools[name];
if (!tool) {
console.warn(
`Export '${name}' not found in package ${packageName}. Available exports:`,
Object.keys(packageTools)
);
return null;
}
return tool;
} catch (error) {
console.error(`Failed to load tool ${packageName}/${name}:`, error);
return null;
}
}
/**
* Sanitize tool name to match OpenAI's requirements
* Pattern: ^[a-zA-Z0-9_-]+$ (only letters, numbers, underscores, hyphens)
*/
export function sanitizeToolName(name: string): string {
return name
.replace(/@/g, '') // Remove @ symbols
.replace(/\//g, '_') // Replace / with _
.replace(/[^a-zA-Z0-9_-]/g, '_'); // Replace any other invalid chars with _
}
/**
* Load all installed TPMJS tools
* Returns a flat object with all tools keyed by sanitized packageName-name
*/
// biome-ignore lint/suspicious/noExplicitAny: Tool types from AI SDK are complex and using any is appropriate here
export async function loadAllTools(): Promise<Record<string, any>> {
// biome-ignore lint/suspicious/noExplicitAny: Tool types from AI SDK are complex and using any is appropriate here
const tools: Record<string, any> = {};
// Iterate through all registered packages
for (const [packageName, packageTools] of Object.entries(TOOL_REGISTRY)) {
for (const [name, tool] of Object.entries(packageTools)) {
// Create a unique, sanitized key for this tool
const toolKey = sanitizeToolName(`${packageName}-${name}`);
tools[toolKey] = tool;
}
}
return tools;
}
/**
* Get list of all available package names
*/
export function getAvailablePackages(): string[] {
return Object.keys(TOOL_REGISTRY);
}
/**
* Get list of all export names for a given package
*/
export function getPackageExports(packageName: string): string[] {
const packageTools = TOOL_REGISTRY[packageName];
if (!packageTools) {
return [];
}
return Object.keys(packageTools);
}