tpmjs/templates/vercel-executor/lib/executor.ts
Ajax Davis bc36d366bc feat: add hot-swappable executor support for collections and agents
- Add executor configuration to Collection and Agent models in Prisma schema
- Create ExecutorConfigPanel component for selecting default or custom executors
- Add executor resolution logic with cascade (Agent → Collection → System Default)
- Create /api/executors/verify endpoint to test custom executor connectivity
- Add executor documentation page at /docs/executors with API specification
- Create deployable Vercel executor template in templates/vercel-executor/
- Update MCP handlers and agent tool execution to use configurable executors
- Add executor types and schemas to @tpmjs/types package

Users can now deploy their own executor instances and configure collections
or agents to use custom executors instead of the TPMJS default executor.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-09 00:19:22 +10:00

101 lines
2.9 KiB
TypeScript

/**
* TPMJS Executor - Core Execution Logic
*
* This module handles dynamic import and execution of TPMJS tools.
* Tools are loaded from esm.sh and executed in a serverless environment.
*/
export interface ExecuteToolRequest {
/** NPM package name, e.g., "@tpmjs/hello" */
packageName: string;
/** Tool name within the package, e.g., "helloWorld" */
name: string;
/** Package version, e.g., "1.0.0" or "latest" */
version?: string;
/** Direct esm.sh URL override for the package */
importUrl?: string;
/** Tool parameters to pass to execute() */
params: Record<string, unknown>;
/** Environment variables to inject during execution */
env?: Record<string, string>;
}
export interface ExecuteToolResponse {
/** Whether the execution succeeded */
success: boolean;
/** Tool output on success */
output?: unknown;
/** Error message on failure */
error?: string;
/** Execution duration in milliseconds */
executionTimeMs: number;
}
/**
* Build the esm.sh URL for a package
*/
function buildEsmUrl(packageName: string, version?: string): string {
const resolvedVersion = version || 'latest';
return `https://esm.sh/${packageName}@${resolvedVersion}`;
}
/**
* Execute a TPMJS tool
*
* @param request - Execution request with package name, tool name, and parameters
* @returns Execution result
*/
export async function executeTool(request: ExecuteToolRequest): Promise<ExecuteToolResponse> {
const startTime = Date.now();
try {
// Build the import URL
const importUrl = request.importUrl || buildEsmUrl(request.packageName, request.version);
// Dynamically import the package from esm.sh
const module = await import(/* webpackIgnore: true */ importUrl);
// Get the tool export
// Try the specific tool name first, then fall back to default export
const tool = module[request.name] || module.default;
if (!tool) {
return {
success: false,
error: `Tool '${request.name}' not found in package '${request.packageName}'`,
executionTimeMs: Date.now() - startTime,
};
}
// Ensure the tool has an execute function
if (typeof tool.execute !== 'function') {
return {
success: false,
error: `Tool '${request.name}' does not have an execute() function`,
executionTimeMs: Date.now() - startTime,
};
}
// Inject environment variables if provided
if (request.env) {
for (const [key, value] of Object.entries(request.env)) {
process.env[key] = value;
}
}
// Execute the tool
const output = await tool.execute(request.params);
return {
success: true,
output,
executionTimeMs: Date.now() - startTime,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error),
executionTimeMs: Date.now() - startTime,
};
}
}