Implements a complete dynamic tool loading system that allows the playground to discover and load tools from the TPMJS registry at runtime. **Architecture:** - Search tool package (@tpmjs/search-registry) - Searches registry for tools - Search API endpoint (/api/tools/search) - Text-based search with scoring - Pre-flight tool loading - Automatically searches and loads tools on every message - Railway executor service (Deno) - Loads tools from esm.sh via HTTP imports - Dynamic tool loader - Calls Railway to load and execute tools remotely **Key Components:** 1. Railway Executor (apps/railway-executor/) - Deno-based service that natively supports HTTP imports - Endpoints: /load-and-describe, /execute-tool, /cache/stats, /cache/clear - Deploys to Railway with deno run --allow-net --allow-env server.ts 2. Search Tool Package (packages/tools/search-registry/) - AI SDK v6 tool for searching TPMJS registry - Uses jsonSchema + inputSchema pattern - Searches /api/tools/search endpoint 3. Search API (apps/web/src/app/api/tools/search/) - Text-based search with composite scoring - Scores: text relevance + quality boost + download boost - Returns tool metadata with importUrl for dynamic loading 4. Dynamic Tool Loader (apps/playground/src/lib/dynamic-tool-loader.ts) - Calls Railway service to load tools from esm.sh - Creates tool wrappers that execute remotely - Process-level module cache + per-conversation tracking 5. Pre-flight Loading (apps/playground/src/app/api/chat/route.ts) - Automatically searches for tools on every user message - Loads top 5 matching tools before agent processes request - Merges with static tools for seamless experience **Technical Decisions:** - Deno over Node.js: Native HTTP import support without flags - Remote execution: Tools run in Railway sandbox, not Vercel - Pre-flight loading: Better UX than two-turn search pattern - Text search: BM25 had dependency issues, simple scoring works well **Environment Variables:** - RAILWAY_SERVICE_URL: https://endearing-commitment-production.up.railway.app 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2.9 KiB
Railway Executor - Deployment Status
Issue Discovered
Node.js does not support HTTP(S) imports by default, even with --experimental-network-imports flag (that flag doesn't exist in current Node versions).
Solutions Considered
- Custom ESM Loader - Complex, requires Node.js 18.19+ with
--loaderflag - fetch + eval - Security concerns, doesn't handle ES modules properly
- Bundler approach - Would defeat the purpose of dynamic imports
- Deno - Supports HTTP imports natively, but different ecosystem
Recommended Solution
Since the core issue is that we need truly dynamic runtime imports from HTTP URLs, and Node.js doesn't support this, we have two viable paths:
Option A: Use Deno on Railway (RECOMMENDED)
Deno supports HTTP imports natively:
// server.ts (Deno)
import { serve } from "https://deno.land/std@0.208.0/http/server.ts";
const moduleCache = new Map();
async function loadTool(url: string, exportName: string) {
if (moduleCache.has(url)) {
return moduleCache.get(url);
}
// Deno supports this natively!
const module = await import(url);
const tool = module[exportName];
moduleCache.set(url, tool);
return tool;
}
serve(async (req) => {
// ... handle requests
}, { port: 3002 });
Deploy to Railway:
# In Railway dashboard:
# - Set Start Command: deno run --allow-net --allow-env server.ts
# - Or use railway.json with deno runtime
Option B: Pre-build Bundle Approach
Instead of truly dynamic imports, pre-fetch and cache tools:
- Playground searches for tools
- Backend fetches tool code once and caches it
- Use
vm2or similar to execute in sandbox - Not truly "dynamic" but works with Node.js
Current Status
The Railway executor service is created but not deployed because Node.js doesn't support the required HTTP imports.
Files created:
apps/railway-executor/package.jsonapps/railway-executor/server.js(incomplete - needs Deno or vm2 approach)apps/railway-executor/README.md
Next Steps
If using Deno (recommended):
- Rewrite server.js as server.ts for Deno
- Deploy to Railway with Deno runtime
- Test HTTP imports work
- Update playground to use Railway URL
If sticking with Node.js:
- Install
vm2package for sandboxed execution - Implement fetch + vm2 approach
- Deploy to Railway
- Accept limitations (less dynamic, more complex)
Alternative: Skip Railway, Use Different Architecture
Since the original issue is Next.js bundler limitations, consider:
Web Workers in Browser - Load tools client-side using native import()
- Pros: No server needed, truly dynamic
- Cons: Exposes API keys, security concerns
Serverless Functions with Pre-installed Tools - Deploy each tool as separate function
- Pros: Works with Vercel/Next.js
- Cons: Not truly dynamic, requires redeployment for new tools
Recommendation: Use Deno on Railway. It's designed for exactly this use case.