Commit graph

342 commits

Author SHA1 Message Date
Ajax Davis
8b5757c9aa fix: migrate playground to AI SDK v6 beta and resolve TypeScript errors
- Update @ai-sdk/react to v3.0.0-beta.131 for compatibility with AI SDK v6
- Fix tool execute method calls with type assertions in API routes
- Update chat components to use UIMessage types from AI SDK
- Move body option into DefaultChatTransport constructor
- Remove deprecated onResponse option from useChat hook
- Remove unused isCoreTool type guard function
- Fix Button variant from 'primary' to 'default'

Resolves all TypeScript compilation errors and build passes successfully.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 13:15:21 +10:00
Ajax Davis
54b504f661 fix: add non-null assertion for searchTpmjsToolsTool.execute
TypeScript was complaining that execute might be undefined, but tools created
with tool() from AI SDK always have an execute method. Added non-null assertion
with biome-ignore comment to fix the TypeScript build error.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:38:39 +10:00
Ajax Davis
d4ec877c6c fix: use inputSchema instead of parameters for AI SDK v6 tool
Changed debug logging to access inputSchema property which exists on AI SDK v6 tools,
instead of parameters which doesn't exist. This fixes the TypeScript build error.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:34:32 +10:00
Ajax Davis
e8ef703c6e fix: remove unused NextResponse import in playground chat route
Removed unused NextResponse import that was causing TypeScript build error.
The error handler already uses native Response constructor directly.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:31:11 +10:00
Ajax Davis
f127b47f08 feat: add playground sidebars with dynamic tools and env var management
Left Sidebar:
- Create /api/tools endpoint to fetch tools from registry
- Update ToolsSidebar to fetch and display tools dynamically
- Add filter input for searching tools by name/description/category
- Fix interface to use packageName/exportName from search registry

Right Sidebar:
- Create SettingsSidebar with environment variable management
- Add localStorage persistence for env vars
- Implement password masking for values
- Export useEnvVars() hook for accessing env vars

Environment Variable Forwarding:
- Update useChat hook to read and forward env vars to API
- Update chat route to extract env vars from request body
- Update dynamic-tool-loader to accept and forward env vars
- Update Railway executor to inject env vars into Deno environment
- Complete chain: localStorage → client → chat → Railway → Deno.env

Bug Fixes:
- Fix undefined property errors in tool detail page
- Add optional chaining for npmDownloadsLastMonth and qualityScore

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 11:00:20 +10:00
Ajax Davis
c18d1b7ea6 feat: add Zod v3 schema support via zod-to-json-schema
- Import zod-to-json-schema from esm.sh
- Add Strategy 3: detect Zod schemas via _def property
- Convert Zod v3/v4 schemas to JSON Schema
- Update error message to mention Zod v3 support
- Fixes firecrawl-aisdk tool schema extraction
2025-12-04 09:49:39 +10:00
Ajax Davis
b6cc98d1e0 feat: add fallback schema extraction with Zod v4 support
- Try Zod v4 toJSONSchema() or jsonSchema() first
- Fall back to AI SDK jsonSchema.schema property
- Fail gracefully with detailed debug info
- Supports both Zod-based and jsonSchema-based tools
2025-12-04 09:42:53 +10:00
Ajax Davis
b95edd8541 debug: add logging for inputSchema structure inspection 2025-12-04 09:33:09 +10:00
Ajax Davis
1e61ba1551 fix: use AI SDK tool() function to create proper tool wrappers
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 <noreply@anthropic.com>
2025-12-04 09:13:10 +10:00
Ajax Davis
b7d1accc6f fix: extract and serialize JSON Schema from AI SDK v6 tools correctly
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 <noreply@anthropic.com>
2025-12-04 09:00:00 +10:00
Ajax Davis
09df09c4df docs: document Zod schema serialization problem for external consultation 2025-12-04 08:53:26 +10:00
Ajax Davis
d3b928c97e fix: use Dockerfile instead of Nixpacks for Railway deployment
Railway is deprecating Nixpacks, so switching to a standard Dockerfile
with the official Deno image. This provides a cleaner and more maintainable
deployment configuration.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 08:35:50 +10:00
Ajax Davis
3450d7a6d5 fix: add nixpacks.toml to configure Deno for Railway deployment
Railway's Nixpacks builder needs explicit configuration to install Deno.
This adds nixpacks.toml to specify Deno as a required package.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 08:30:19 +10:00
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
Ajax Davis
0612eac5e2 feat: implement multi-tool package architecture with manual tool registry
BREAKING CHANGE: Complete refactoring from single-tool to multi-tool package support

Database Schema:
- Split Tool model into Package (1) and Tool (many) with one-to-many relationship
- Package stores npm metadata and package-level tpmjs fields (category, env, frameworks, tier)
- Tool stores individual tool exports with tool-level metadata (exportName, description, parameters, returns, aiAgent)
- Unique constraint on (packageId, exportName) to prevent duplicate tools
- Cascade deletes when packages are removed

Type System:
- Updated tpmjs field schema to support tools array
- Each tool has exportName, description, parameters, returns, aiAgent
- Package-level fields: category, env, frameworks shared across all tools
- Backward compatible with legacy single-tool format (auto-migrates to exportName: "default")

API Updates:
- Updated all /api/tools routes to query Tool model with Package relations
- Updated /api/tools/[slug] to accept package/export path segments
- Updated tool-executor-agent to use actual exportName instead of hardcoded "default"
- Updated metrics sync to calculate quality scores per Tool

Frontend Updates:
- Updated tool search page to display exportName as primary heading
- Updated tool detail pages to show package name as secondary info
- Removed tag-based filtering (tags moved to package level)

Manual Tool Registry:
- Added manual-tools.ts with 23 curated tools from major providers
- Created sync-manual-tools.ts script to sync manual tools to database
- Added MANUAL_TOOLS.md documentation for manual tool system
- Added GitHub workflow for automated daily sync
- Includes tools from: Vercel, Exa, Firecrawl, AWS Bedrock, Perplexity, Tavily, Superagent, Valyu

Playground Updates:
- Updated tool loader to load multiple tools per package
- Added sanitizeToolName for OpenAI API compatibility

Sync System Updates:
- Updated changes feed sync to handle multi-tool packages
- Updated keyword sync to upsert multiple tools per package
- Added orphaned tool deletion when tools removed from package.json

Migration Strategy:
- Database uses same Neon instance for dev and prod
- Schema updated via prisma db push (no migration files yet)
- All data repopulates from npm via sync system

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 06:39:58 +10:00
Ajax Davis
fdd1b2c304 fix: sanitize tool names for OpenAI API compatibility in playground
Add sanitizeToolName function to convert package names to OpenAI-compatible
format that matches pattern ^[a-zA-Z0-9_-]+$. Removes @ symbols, replaces
/ with _, and replaces other invalid characters with _.

This fixes the error: "Invalid 'tools[0].name': string does not match pattern"
when loading tools in the playground chat interface.

Example transformations:
- @tpmjs/hello-helloWorldTool → tpmjs_hello-helloWorldTool
- firecrawl-aisdk-scrapeTool → firecrawl-aisdk-scrapeTool

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 06:29:33 +10:00
Ajax Davis
635fc96cac feat: implement playground app with AI SDK v6 tool execution
- Create new Next.js app at apps/playground for testing TPMJS tools
- Implement AI SDK v6 patterns with DefaultChatTransport and UIMessage format
- Create template tool package at packages/tools/hello with hello-world and hello-name tools
- Use tool() and jsonSchema() helpers to avoid Zod 4 conversion issues with OpenAI
- Add static tool loading system with switch statement (Next.js/webpack compatible)
- Implement chat interface with tool call visualization showing inputs/outputs
- Support multi-step tool execution with stepCountIs(5)
- Stream responses with toUIMessageStreamResponse() for full tool support
- Add sidebar showing available tools (static list)
- Use parts-based message rendering for text and tool calls
- Integrate firecrawl-aisdk tools (scrape, crawl, search)
- Add theme toggle in header (defaults to light mode)
- Fix responsive layout with max-width for message bubbles
- Use biome-ignore comments for legitimate any types in tool loading

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 02:51:02 +10:00
Ajax Davis
fcd6667357 feat: add author name to skipped packages in Discord notifications
API Changes:
- Track author name along with package name and reason
- Extract author from pkg.author (string or object with name field)
- Default to "unknown" if author info not available

Workflow Changes:
- Display author in format: "package-name (by author) - reason"

Example Discord output:
📋 Skipped Packages
tpmjs-threejs-tool (by john-doe) - invalid tpmjs field
@scope/package-1 (by jane-smith) - missing tpmjs field

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 09:18:16 +10:00
Ajax Davis
14cd668a2b feat: add skip reasons to Discord notifications
API Changes:
- Track skip reason along with package name
- Changed skippedPackages from string[] to Array<{name, reason}>
- Reasons: "package not found", "missing tpmjs field", "invalid tpmjs field"

Workflow Changes:
- Format skipped packages as "package-name - reason"
- Display one package per line in Discord notification

Example Discord output:
📋 Skipped Packages
@scope/package-1 - missing tpmjs field
package-2 - invalid tpmjs field

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 08:59:33 +10:00
Ajax Davis
493cd96d7b feat: add skipped packages list to Discord notifications
API Changes:
- Track skipped package names in keyword sync endpoint
- Include skippedPackages array in API response

Workflow Changes:
- Extract skipped package names from sync response
- Display skipped packages in Discord notification as comma-separated list
- Only show "📋 Skipped Packages" field when packages are skipped
- Dynamic field construction using jq

Example Discord output:
📋 Skipped Packages
package-name-1, package-name-2, package-name-3

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 08:57:30 +10:00
Ajax Davis
2bf8565c1d fix: make example field optional and fix Discord webhook JSON escaping
Database Changes:
- Made `example` field optional in Prisma schema (String?)
- Added default empty arrays for `frameworks` and `tags`
- Allows tools to be synced without example field

Workflow Changes:
- Use jq to properly construct Discord webhook JSON
- Fixes "invalid JSON" error caused by unescaped special characters
- Properly escapes error messages with newlines and quotes

This fixes sync errors for packages missing the example field and
ensures Discord notifications are sent successfully.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 08:32:14 +10:00
Ajax Davis
7fab0440b3 feat: add detailed error logging to keyword sync workflow
API Changes:
- Return errorMessages array in sync response (first 5 errors)

Workflow Changes:
- Display error messages in GitHub Actions logs with formatting
- Include error details in Discord notifications (first 3 errors)
- Shows errors in both console output and Discord embed

Example output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️  SYNC ERRORS (4 total):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  • Failed to process pkg1: Invalid tpmjs field
  • Failed to process pkg2: Network timeout
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 08:22:04 +10:00
Ajax Davis
bc34f50705 feat: add Discord webhook notifications to keyword search sync workflow
- Captures sync API response and parses JSON results
- Sends formatted Discord embed with sync metrics:
  - Packages found, processed, skipped, errors
  - Duration and link to workflow logs
- Color-coded status: green for success, yellow for errors
- Runs on every sync (manual and scheduled)

Requires DISCORD_WEBHOOK secret to be set in GitHub repository.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 08:18:15 +10:00
Ajax Davis
4febe71d76 fix: split sync workflow into separate files to fix job skipping issue
The previous combined workflow had flawed conditional logic that caused
sync-keyword and sync-metrics jobs to be skipped. GitHub Actions doesn't
populate github.event.schedule with the cron expression, so the equality
checks never matched.

Replaced with three separate workflow files:
- sync-changes.yml: Runs every 2 minutes
- sync-keyword.yml: Runs every 15 minutes
- sync-metrics.yml: Runs every hour

Each workflow can be manually triggered via workflow_dispatch.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 04:36:38 +10:00
Ajax Davis
8e8e511e5a refactor: remove links, tags, and status fields from TPMJS spec
These fields are redundant as they already exist in package.json:
- links: Use package.json repository/homepage fields
- tags: Use package.json keywords field
- status: Not needed in tool metadata

Changes:
- Remove TpmjsLinksSchema type definition
- Remove links, tags, and status from TpmjsRichSchema
- Update validation logic to not check these fields
- Update all documentation (spec page, publish page, HOW_TO_PUBLISH_A_TOOL.md)
- Update example tool package.json
- Simplify field reference tables

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 05:53:48 +10:00
Ajax Davis
054bac9a53 refactor: rename envVars to env and remove example field from TPMJS spec
- Rename TpmjsEnvVarSchema to TpmjsEnvSchema
- Rename envVars field to env throughout codebase
- Remove example field from TpmjsMinimalSchema (no longer required)
- Update all documentation (spec page, publish page, HOW_TO_PUBLISH_A_TOOL.md)
- Update example tool package.json
- Simplify minimal tier requirements to only category and description

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 05:37:28 +10:00
Ajax Davis
4146f279e6 refactor: replace authentication field with envVars in TPMJS specification
Replace the authentication field with a more general envVars array that allows tools to specify required environment variables:

Changes to type definitions:
- Remove TpmjsAuthenticationSchema and TpmjsAuthentication type
- Add TpmjsEnvVarSchema with fields: name, description, required, default
- Replace authentication field with envVars array in TpmjsRichSchema
- Update validateTpmjsField to check envVars instead of authentication

Changes to documentation:
- Update /spec page to document envVars instead of authentication
- Update /publish page examples to use envVars
- Update HOW_TO_PUBLISH_A_TOOL.md with envVars examples
- Update validation errors section
- Remove authentication from @tpmjs/createblogpost example

The envVars field is more flexible and clearer - it lists all environment variables a tool needs (API keys, endpoints, config values) rather than trying to categorize authentication types.

Example:
```json
"envVars": [
  {
    "name": "OPENAI_API_KEY",
    "description": "API key for OpenAI services",
    "required": true
  }
]
```

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 05:21:30 +10:00
Ajax Davis
4dc53338f2 refactor: remove pricing field from TPMJS specification
Remove pricing field from the entire project as it doesn't make sense for tool metadata:

- Remove TpmjsPricingSchema and TpmjsPricing type from types package
- Remove pricing from TpmjsRichSchema validation
- Remove pricing from validateTpmjsField check
- Remove pricing documentation from /spec page
- Remove pricing examples from /publish page
- Remove pricing from HOW_TO_PUBLISH_A_TOOL.md
- Remove pricing from @tpmjs/createblogpost example package.json

The pricing field was removed from Tier 3 (Rich) metadata as it's not relevant for tool discovery and integration. Tools can document pricing in their README or documentation links instead.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 04:57:21 +10:00
Ajax Davis
251442f1d4 feat: add comprehensive TPMJS specification page
- Create /spec page with complete technical reference for TPMJS metadata
- Document all three tiers (Minimal, Basic, Rich) with field explanations
- Include field reference table with types and requirements
- Explain quality scoring algorithm and discovery mechanisms
- Add cross-links to /publish page for complementary content
- Update AppHeader to include Spec link in navigation (Tools > Playground > Spec > GitHub > Publish)

The spec page provides a balanced technical reference while the publish page remains the practical how-to guide.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 04:47:21 +10:00
Ajax Davis
c8ccab5cb8 refactor: create shared AppHeader component for consistent navigation across all pages
**Problem:**
- Each page had different header implementations with varying navigation links
- Inconsistent user experience across homepage, tools, playground, and publish pages
- Duplicate header code throughout the application

**Solution:**
- Created `AppHeader` component (apps/web/src/components/AppHeader.tsx) with consistent navigation:
  - TPMJS logo linking to homepage
  - Tools, Playground, and Publish Tool links
  - GitHub icon link
  - Sticky header with medium size
- Updated all pages to use the shared component:
  - apps/web/src/app/page.tsx (homepage)
  - apps/web/src/app/tool/tool-search/page.tsx (tools search)
  - apps/web/src/app/playground/page.tsx (component playground)
  - apps/web/src/app/publish/page.tsx (publish guide)
  - apps/web/src/app/tool/[...slug]/page.tsx (tool detail pages)

**Benefits:**
- Consistent header across all pages
- Single source of truth for navigation
- Easier to maintain and update navigation links
- Improved user experience with predictable navigation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 21:03:33 +10:00
Ajax Davis
0b4a314bd1 docs: add comprehensive NPM package sync documentation and GitHub Actions workflow
**Documentation (CLAUDE.md):**
- Document all three sync endpoints (changes feed, keyword search, metrics)
- Explain Vercel Cron configuration and schedules
- Detail quality score calculation algorithm
- Add database schema documentation for sync tables
- Provide manual sync trigger examples with curl
- Include monitoring and debugging instructions
- Document error handling patterns (partial/complete failures)
- Add package discovery flow diagram
- List future improvements and potential enhancements

**GitHub Actions Workflow (.github/workflows/sync.yml):**
- Add backup sync automation via GitHub Actions cron
- Support manual trigger via workflow_dispatch with sync type selection
- Run changes feed every 2 minutes
- Run keyword search every 15 minutes
- Run metrics sync every hour
- Use concurrency control to prevent overlapping runs
- Call production Vercel endpoints with CRON_SECRET auth

**Key Features:**
- Dual automation strategy: Vercel Cron (primary) + GitHub Actions (backup)
- Idempotent endpoints allow both systems to run simultaneously
- Manual trigger capability for debugging and testing
- Comprehensive documentation for future maintenance

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 20:46:57 +10:00
Ajax Davis
61ac2aa5dd feat: display raw JSON output and human-readable preview in playground 2025-11-30 20:41:30 +10:00
Ajax Davis
47ddc4dea7 fix: refactor tool execution to use generateText with proper tool handling
Major changes:
- Fixed package executor URL protocol handling (add https:// if missing)
- Switched from streamText to generateText for proper tool execution
- AI now calls tool AND generates natural language response
- Tool results no longer show raw JSON metadata

Tool executor (tool-executor-agent.ts):
- Use generateText() instead of streamText() for tool execution
- Add system prompt to guide AI to summarize tool results
- Return result.text for natural language output
- Tool definition uses inputSchema (AI SDK v6 format)

Package executor:
- Add getSandboxUrl() to ensure URL has https:// protocol
- Fixes "Failed to parse URL" error in production

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 20:30:01 +10:00
Ajax Davis
45da32e8ec fix: extract tool results from messages array in AI SDK v6
- In AI SDK v6, tool results are in fullResponse.messages with role 'tool'
- Updated result extraction to iterate through messages array
- Added detailed logging to debug response structure
- Handle both text output and tool-only responses

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 20:05:41 +10:00
Ajax Davis
266a6ef74c debug: add logging to diagnose streaming issue in AI SDK v6 2025-11-30 19:50:41 +10:00
Ajax Davis
2a05e68aa3 fix: preserve streamed output and add markdown rendering to playground
**Problem:**
- Tool playground was only showing partial output
- When 'complete' event arrived, it replaced streamed text with final output
- Output was displayed as plain text instead of formatted markdown

**Changes:**
- Fixed streaming bug in ToolPlayground component
  - Removed line that overwrote accumulated text on 'complete' event
  - Now preserves all streamed chunks for full output display
- Added react-markdown with GitHub Flavored Markdown support
  - Install react-markdown and remark-gfm packages
  - Added @tailwindcss/typography plugin for prose styling
  - Replaced plain <pre> with <ReactMarkdown> component
  - Applied prose classes for proper markdown formatting
- Added type="button" to button elements for accessibility

**Files changed:**
- apps/web/src/components/ToolPlayground.tsx
  - Comment out setOutput(data.output) on complete event
  - Import ReactMarkdown and remarkGfm
  - Replace pre element with ReactMarkdown component
  - Add prose styling classes
  - Add type="button" to buttons
- apps/web/tailwind.config.ts
  - Add @tailwindcss/typography plugin

**Result:**
- Full streamed output now displays correctly
- Markdown is rendered with proper formatting (headings, lists, code blocks, etc.)
- Better UX for AI-generated tool responses

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 19:28:53 +10:00
Ajax Davis
78c72b85f3 feat: upgrade to AI SDK v6 beta and Zod v4 to fix tool schema errors
OpenAI was rejecting tool definitions with error "schema must be a JSON Schema of 'type: "object"'". This was caused by AI SDK v5 not properly converting Zod schemas to JSON Schema format.

**Changes:**
- Upgrade AI SDK from v5.0.104 to v6.0.0-beta.124
- Upgrade @ai-sdk/openai from v2.0.74 to v3.0.0-beta.22
- Upgrade Zod from v3.25.76 to v4.1.13 across all packages

**AI SDK v6 breaking changes:**
- Tool definition API: `parameters` renamed to `inputSchema`
- Removed `aiTool()` wrapper - use plain object with description, inputSchema, execute
- Streaming API: Use `textStream` async iterator instead of onChunk callback
- Zod schemas now properly converted to JSON Schema for OpenAI

**Zod v4 breaking changes:**
- `z.record()` now requires two arguments: `z.record(keySchema, valueSchema)`
- `z.enum()` params changed: `errorMap` removed, use `message` instead
- Type system improvements require explicit type parameters
- Fixed type errors in @tpmjs/env, @tpmjs/npm-client, @tpmjs/types

**Files changed:**
- apps/web/src/lib/ai-agent/tool-executor-agent.ts
  - Updated tool definition to use `inputSchema` instead of `parameters`
  - Removed `aiTool()` wrapper
  - Fixed streaming to use `textStream` iterator
- packages/env/src/index.ts
  - Updated type constraint from `z.ZodRawShape` to `Record<string, z.ZodTypeAny>`
- packages/npm-client/src/package.ts
  - Fixed `z.record()` calls to include both key and value schemas
  - Added type assertions for record indexing
- packages/types/src/tpmjs.ts
  - Changed `errorMap` to `message` in z.enum() calls

**Testing:**
-  Type-check passes
-  Production build succeeds
-  All routes compile correctly

This fixes the tool execution error where OpenAI rejected tool schemas with invalid format.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 19:14:01 +10:00
Ajax Davis
59da95ce85 feat: update homepage to use real database data
- Add server component to fetch live stats from database
  - Tool count from Tool table
  - Invocations from successful Simulation records
  - Average latency from recent executions
  - Category distribution stats

- Add featured tools section
  - Display top 6 tools by quality score
  - Show tool cards with name, description, category, tags
  - Include quality score and download metrics
  - Official badge for verified tools
  - Click-through to tool detail pages

- Update HeroSection component
  - Accept stats prop with real database metrics
  - Format large numbers (e.g., "1.2K", "5.3M")
  - Add functional search navigation
  - Enter key and button click navigate to tool-search
  - Empty search browses all tools

- Optimize database queries
  - Use Promise.all() for parallel execution
  - Calculate avg latency from last 100 simulations
  - Graceful error handling with fallback values

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 15:33:10 +10:00
Ajax Davis
1cdbf8c891 debug: add detailed logging to tool executor to diagnose OpenAI schema error
Add console.log statements to track:
- Tool parameters array and length
- Generated Zod schema details
- Tool definition structure
- Sanitized tool name
- Complete tools config sent to OpenAI

This will help diagnose why OpenAI is still receiving 'type: "None"'
for empty parameter schemas despite the fix.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 05:46:13 +10:00
Ajax Davis
c0383f5440 fix(vercel): run install command from monorepo root to access workspace packages
**Problem:**
Vercel deployments were failing with:
```
ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE: No matching version found for @tpmjs/eslint-config@* inside the workspace
```

The `installCommand` was running `pnpm install` from `apps/web`, which couldn't access workspace packages defined at the monorepo root.

**Solution:**
Change `installCommand` from `pnpm install` to `cd ../.. && pnpm install` to run from the monorepo root, matching the `buildCommand` behavior.

**Impact:**
- Vercel can now find and install all workspace packages
- Deployments should succeed
- All previous tool execution fixes can now actually deploy

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 05:07:28 +10:00
Ajax Davis
ad4fde7e79 fix(ci): skip Lefthook installation in CI/Vercel environments
**Problem:**
Vercel deployments were failing during `pnpm install` because the `prepare` script tried to run `lefthook install`, which requires a git repository. Vercel's build environment doesn't have a proper `.git` directory, causing:
```
fatal: not a git repository (or any parent up to mount point /vercel)
Error: exit status 128
```

**Solution:**
Skip Lefthook installation when running in CI or Vercel environments by checking `process.env.CI` and `process.env.VERCEL` before attempting to install git hooks.

**Impact:**
- Vercel deployments will now succeed
- Local development still gets git hooks installed
- GitHub Actions CI will skip hook installation (not needed in CI)
- All previous tool execution fixes can now actually deploy

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 05:00:00 +10:00
Ajax Davis
4705af6b1a fix: ensure tool parameters schema is always a valid JSON Schema object
Problem: OpenAI API error 'got type: None' when tool has no/invalid parameters

Solution: Add guard to explicitly create empty object schema with description when no parameters exist

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 02:45:32 +10:00
Ajax Davis
8f3c6a2910 fix: sanitize npm package names for OpenAI tool names and update lockfile
Problem: OpenAI tool names must match ^[a-zA-Z0-9_-]+ but npm package names like @tpmjs/createblogpost contain @ and /

Solution: Add sanitizeToolName() function and update pnpm-lock.yaml

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 02:28:42 +10:00
Ajax Davis
fdfc721d40 fix: remove tiktoken dependency to resolve WASM runtime error in serverless
**Problem:**
The Interactive Playground was failing with "Missing tiktoken_bg.wasm" error in production. Tiktoken requires WASM files which don't work in Vercel's serverless environment.

**Solution:**
- Remove tiktoken import from tool-executor-agent
- Replace tiktoken-based token counting with character estimation (~4 chars/token)
- Remove tiktoken from package.json dependencies
- Remove unused biome-ignore comment

**Impact:**
- Token counting is now approximate but consistent
- No more WASM-related runtime errors
- Serverless deployment works properly
- Tool execution now functional in production

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 02:19:05 +10:00
Ajax Davis
cc13e7cb09 fix: remove tiktoken dependency to resolve WASM runtime error in serverless
**Problem:**
The Interactive Playground was failing with "Missing tiktoken_bg.wasm" error in production. Tiktoken requires WASM files which don't work in Vercel's serverless environment.

**Solution:**
- Remove tiktoken import from tool-executor-agent
- Replace tiktoken-based token counting with character estimation (~4 chars/token)
- Remove tiktoken from package.json dependencies
- Remove experimental webpack WASM config (no longer needed)

**Impact:**
- Token counting is now approximate but consistent
- No more WASM-related runtime errors
- Serverless deployment works properly
- Tool execution now functional in production

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 02:15:58 +10:00
Ajax Davis
492a7221c9 fix: update dependency cruiser config to allow TypeScript path aliases and workspace packages
- Add `^@/` to pathNot to allow Next.js `@/` path alias
- Add `^@tpmjs/` to pathNot to allow workspace package imports
- Fixes architecture check failures in CI
- Apply Biome formatting to check-tool.mjs and sync-single-tool.mjs

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 01:55:51 +10:00
Ajax Davis
664bbdad57 fix: use dynamic import for AI SDK to resolve tiktoken WASM build error
Convert static import of executeToolWithAgent to dynamic import inside the
POST handler. This prevents the AI SDK (and its tiktoken dependency) from
being loaded at build time, which was causing WASM loading errors.

**Why this fix works:**
- Next.js 16 + Turbopack tries to analyze routes at build time
- tiktoken requires tiktoken_bg.wasm which can't load during static analysis
- Dynamic imports defer loading until runtime, avoiding build-time WASM issues

**Changes:**
- Remove: `import { executeToolWithAgent } from '@/lib/ai-agent/tool-executor-agent'`
- Add: `const { executeToolWithAgent } = await import('@/lib/ai-agent/tool-executor-agent')`
  inside the stream start() handler

Build now completes successfully. Route is properly marked as dynamic (ƒ).

Resolves: "Error: Missing tiktoken_bg.wasm" during Next.js build

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 01:50:49 +10:00
Ajax Davis
140a2fa218 fix: mark AI tool execution route as dynamic to prevent build-time WASM error
Add `export const dynamic = 'force-dynamic'` to `/api/tools/execute/[...slug]`
to prevent Next.js from attempting static generation at build time.

The AI SDK (used via executeToolWithAgent) requires tiktoken_bg.wasm which
cannot be loaded during static generation. Marking as dynamic ensures the
route is only executed at runtime.

Note: This partially addresses the build error but further investigation needed
for complete resolution of tiktoken WASM loading in Next.js 16 + Turbopack.

Relates to: "Error: Missing tiktoken_bg.wasm"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 01:42:04 +10:00
Ajax Davis
2ce37ae2aa feat: integrate Railway sandbox microservice for secure package execution
**Replace VM2 with Railway Microservice:**
- Remove VM2 dependency (incompatible with Next.js Turbopack bundling)
- Create Express sandbox service at `/services/sandbox-executor/`
- Uses isolated-vm for V8-level isolation with 128MB memory limit
- 10-second execution timeout with proper error handling

**Package Executor Client:**
- Rewrite `@tpmjs/package-executor` to call remote sandbox via HTTP
- Add `executePackage()`, `clearCache()`, `checkHealth()` functions
- Use AbortController for timeout handling
- Proper TypeScript type assertions for API responses
- Reads `SANDBOX_EXECUTOR_URL` from environment (defaults to localhost:3000)

**Sandbox Service Features:**
- `/execute` - Execute npm packages in isolated environment
- `/health` - Health check endpoint with service info
- `/cache/clear` - Clear npm package cache
- Package caching in `/tmp/.tpmjs-cache` for faster subsequent runs
- CORS support for web app integration
- Automatic ESM/CommonJS package detection

**Deployment Configuration:**
- Dockerfile with isolated-vm native dependencies (python3, make, g++)
- Railway.json with health checks and restart policies
- Environment variables: PORT, PACKAGE_CACHE_DIR, ALLOWED_ORIGINS
- Production URL: https://tpmjs-production.up.railway.app

**Integration:**
- Add SANDBOX_EXECUTOR_URL to .env.local
- Update Next.js config to mark package-executor as external
- Maintain existing API routes at `/api/tools/execute/[...slug]`

This architectural change enables secure package execution on Vercel
by moving sandboxing to a dedicated microservice on Railway.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 01:30:47 +10:00
Ajax Davis
b176ae54df feat: add Railway-based sandbox executor microservice
**New Sandbox Service:**
- Separate microservice for secure npm package execution
- Uses isolated-vm for V8-level isolation
- 128MB memory limit, 10s timeout
- Package caching for performance
- Express API with /execute, /health, /cache/clear endpoints

**Why Microservice:**
- VM2 doesn't work with Next.js Turbopack (requires runtime file access)
- isolated-vm doesn't work in Vercel serverless (native bindings)
- Microservice allows full Node environment with proper sandboxing
- Industry standard approach (Replit, CodeSandbox, RunKit)

**Deployment:**
- Dockerfile with isolated-vm build dependencies
- Railway.json configuration
- Health checks and auto-restart policies
- CORS configuration for Next.js integration

**Next Steps:**
1. Deploy to Railway:
   cd services/sandbox-executor
   railway init
   railway up
2. Set SANDBOX_EXECUTOR_URL in Next.js env
3. Update API routes to call sandbox service

This provides secure, production-ready package execution outside Vercel's constraints.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 01:07:24 +10:00