tpmjs/IMPLEMENTATION_STATUS.md
Ajax Davis 2158ee6dfd feat: add dynamic tool loading system with Railway executor
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>
2025-12-04 08:25:53 +10:00

6.7 KiB

Dynamic Tool Loading - Implementation Status

Completed

1. Search Tool Package (@tpmjs/search-registry)

  • Created package with AI SDK v6 JSON Schema format
  • Connects to search API endpoint
  • Returns tool metadata (packageName, exportName, version, importUrl)
  • Fixed schema format (was using Zod, now uses jsonSchema)
  • Location: packages/tools/search-registry/
  • Implemented simple text-based search (BM25 had dependency issues)
  • Searches by keywords in description, package name, keywords
  • Returns tools with import URLs for esm.sh
  • Location: apps/web/src/app/api/tools/search/route.ts

3. Pre-flight Tool Loading in Playground

  • Automatic search on every user message
  • Extracts user query from last message
  • Calls searchTpmjsTools automatically
  • Attempts to load discovered tools dynamically
  • Location: apps/playground/src/app/api/chat/route.ts

4. Dynamic Tool Loader (Railway Service Approach)

  • Updated to call Railway service instead of local imports
  • Calls /load-and-describe endpoint to get tool schema
  • Wraps tool with remote execution via /execute-tool endpoint
  • Caches tool wrappers locally
  • Location: apps/playground/src/lib/dynamic-tool-loader.ts

5. Documentation

  • DYNAMIC_IMPORT_ISSUE.md - Comprehensive problem analysis
  • RAILWAY_DYNAMIC_TOOL_LOADER.md - Railway implementation guide
  • This file - Implementation status

🚧 Pending (Railway Service Implementation)

Railway Service Endpoints Needed

You need to add these two endpoints to your existing Railway service:

1. POST /load-and-describe

Purpose: Load a tool from esm.sh and return its schema

Request:

{
  "packageName": "firecrawl-aisdk",
  "exportName": "webSearchTool",
  "version": "0.7.2",
  "importUrl": "https://esm.sh/firecrawl-aisdk@0.7.2"
}

Response:

{
  "success": true,
  "tool": {
    "exportName": "webSearchTool",
    "description": "Search the web using Firecrawl",
    "inputSchema": {
      "type": "object",
      "properties": {
        "query": { "type": "string" }
      }
    }
  }
}

Implementation Reference: See RAILWAY_DYNAMIC_TOOL_LOADER.md for full code

2. POST /execute-tool

Purpose: Execute a dynamically loaded tool with parameters

Request:

{
  "packageName": "firecrawl-aisdk",
  "exportName": "webSearchTool",
  "version": "0.7.2",
  "importUrl": "https://esm.sh/firecrawl-aisdk@0.7.2",
  "params": {
    "query": "latest AI news"
  }
}

Response:

{
  "success": true,
  "output": { "results": [...] },
  "executionTimeMs": 1234
}

Implementation Reference: See RAILWAY_DYNAMIC_TOOL_LOADER.md for full code

Deployment Requirements

  1. Railway Service:

    • Must run with --experimental-network-imports flag
    • Add to start command: node --experimental-network-imports server.js
  2. Environment Variables (Vercel):

    RAILWAY_SERVICE_URL=https://your-railway-service.up.railway.app
    # or reuse existing:
    SANDBOX_EXECUTOR_URL=https://your-railway-service.up.railway.app
    
  3. Local Testing (Railway service on port 3001):

    RAILWAY_SERVICE_URL=http://localhost:3001
    

🎯 Testing Checklist

Once Railway endpoints are deployed:

  • Test /load-and-describe endpoint directly with curl
  • Test /execute-tool endpoint directly with curl
  • Test full flow in playground:
    • Ask: "search the web for latest AI news"
    • Verify pre-flight search finds tools
    • Verify tools load via Railway
    • Verify tool execution works
    • Check console logs for debugging info

📊 Current Flow

User: "search the web for latest AI news"
                ↓
    Chat API extracts query
                ↓
    Automatically calls searchTpmjsTools
                ↓
    Search API returns matching tools
     (packageName, exportName, version)
                ↓
    loadToolsBatch() called for each tool
                ↓
    For each tool:
      1. Check local cache
      2. If not cached:
         → POST to Railway: /load-and-describe
         ← Get back: description + inputSchema
      3. Create wrapper tool with:
         - description from Railway
         - inputSchema from Railway
         - execute() → calls Railway /execute-tool
      4. Cache wrapper locally
                ↓
    All tools available to agent
                ↓
    Agent calls tool (wrapper)
                ↓
    Wrapper → POST to Railway: /execute-tool
                ↓
    Railway imports from esm.sh and executes
                ↓
    Result returned to agent
                ↓
    Agent uses result to answer user

🔍 Debugging

Check console logs for:

  • 📦 Loading from Railway - Tool loading initiated
  • ✅ Tool loaded from Railway - Tool schema received
  • 🚀 Executing ... remotely - Tool execution initiated
  • ✅ Tool executed successfully - Tool execution complete
  • ❌ Railway service error - Connection failed
  • ❌ Failed to load tool - Import failed

📁 Files Modified

  1. packages/tools/search-registry/src/index.ts - Search tool
  2. packages/tools/search-registry/package.json - AI SDK version
  3. apps/web/src/app/api/tools/search/route.ts - Search endpoint
  4. apps/playground/src/app/api/chat/route.ts - Pre-flight search
  5. apps/playground/src/lib/dynamic-tool-loader.ts - Railway integration
  6. apps/playground/next.config.ts - Added urlImports (unused)
  7. apps/playground/src/lib/tool-loader.ts - Removed firecrawl

🚀 Next Steps

  1. Deploy Railway endpoints using code from RAILWAY_DYNAMIC_TOOL_LOADER.md
  2. Set environment variables in Vercel
  3. Test locally with Railway service running on localhost:3001
  4. Deploy to production and test with real tools
  5. Monitor logs for any issues

💡 Key Insights

  • Next.js Limitation: Cannot do dynamic HTTP imports due to bundler
  • Railway Solution: Plain Node.js with --experimental-network-imports
  • Caching Strategy: Two-level cache (local wrapper + Railway module)
  • Execution Model: Remote execution in Railway, not Next.js
  • Security: Tools execute in Railway sandbox, not Vercel
  • Performance: First load ~1-2s (import), cached loads <10ms
  • DYNAMIC_IMPORT_ISSUE.md - Problem analysis and ChatGPT response
  • RAILWAY_DYNAMIC_TOOL_LOADER.md - Full Railway implementation guide
  • Plan file: ~/.claude/plans/jiggly-inventing-dragon.md

Status: Ready for Railway deployment Blocker: Railway /load-and-describe and /execute-tool endpoints need implementation ETA: 30-60 minutes to implement Railway endpoints + test