claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
237 lines (233 loc) • 14.1 kB
text/typescript
/**
* WASM Agent MCP Tools
*
* Exposes @ruvector/rvagent-wasm operations via MCP protocol.
* All tools gracefully degrade when the WASM package is not installed.
*/
import type { MCPTool } from './types.js';
import { validateIdentifier, validateText } from './validate-input.js';
async function loadAgentWasm() {
const mod = await import('../ruvector/agent-wasm.js');
return mod;
}
export const wasmAgentTools: MCPTool[] = [
{
name: 'wasm_agent_create',
description: 'Create a sandboxed WASM agent with virtual filesystem (no OS access). Optionally use a gallery template. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
template: { type: 'string', description: 'Gallery template name (coder, researcher, tester, reviewer, security, swarm)' },
model: { type: 'string', description: 'Model identifier (default: anthropic:claude-sonnet-4-6)' },
instructions: { type: 'string', description: 'System instructions for the agent' },
maxTurns: { type: 'number', description: 'Max conversation turns (default: 50)' },
},
},
handler: async (args: Record<string, unknown>) => {
if (args.template) { const v = validateIdentifier(args.template, 'template'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
if (args.model) { const v = validateIdentifier(args.model, 'model'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
if (args.instructions) { const v = validateText(args.instructions, 'instructions'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
if (args.template) {
const info = await wasm.createAgentFromTemplate(args.template as string);
return { content: [{ type: 'text', text: JSON.stringify({ success: true, agent: info, source: 'gallery' }, null, 2) }] };
}
const info = await wasm.createWasmAgent({
model: args.model as string,
instructions: args.instructions as string,
maxTurns: args.maxTurns as number,
});
return { content: [{ type: 'text', text: JSON.stringify({ success: true, agent: info }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_prompt',
description: 'Send a prompt to a WASM agent and get a response. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
agentId: { type: 'string', description: 'WASM agent ID' },
input: { type: 'string', description: 'User prompt to send' },
},
required: ['agentId', 'input'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.agentId, 'agentId'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
{ const v = validateText(args.input, 'input'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const result = await wasm.promptWasmAgent(args.agentId as string, args.input as string);
return { content: [{ type: 'text', text: result }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_tool',
description: 'Execute a tool on a WASM agent sandbox. Tools: read_file, write_file, edit_file, write_todos, list_files. Use flat format: {tool, path, content, ...}. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
agentId: { type: 'string', description: 'WASM agent ID' },
toolName: { type: 'string', description: 'Tool name (read_file, write_file, edit_file, write_todos, list_files)' },
toolInput: { type: 'object', description: 'Tool parameters (flat: {path, content, old_string, new_string, todos})' },
},
required: ['agentId', 'toolName'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.agentId, 'agentId'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
{ const v = validateIdentifier(args.toolName, 'toolName'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
// Flat format: {tool: 'write_file', path: '...', content: '...'}
const toolCall = {
tool: args.toolName as string,
...((args.toolInput as Record<string, unknown>) ?? {}),
};
const result = await wasm.executeWasmTool(args.agentId as string, toolCall);
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_list',
description: 'List all active WASM agents. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: { type: 'object' as const, properties: {} },
handler: async () => {
try {
const wasm = await loadAgentWasm();
const agents = wasm.listWasmAgents();
return { content: [{ type: 'text', text: JSON.stringify({ agents, count: agents.length }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_terminate',
description: 'Terminate a WASM agent and free resources. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
agentId: { type: 'string', description: 'WASM agent ID' },
},
required: ['agentId'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.agentId, 'agentId'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const ok = wasm.terminateWasmAgent(args.agentId as string);
return { content: [{ type: 'text', text: JSON.stringify({ success: ok }) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_files',
description: 'Get a WASM agent\'s available tools and info. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
agentId: { type: 'string', description: 'WASM agent ID' },
},
required: ['agentId'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.agentId, 'agentId'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const tools = wasm.getWasmAgentTools(args.agentId as string);
const info = wasm.getWasmAgent(args.agentId as string);
return { content: [{ type: 'text', text: JSON.stringify({ tools, fileCount: info?.fileCount ?? 0, turnCount: info?.turnCount ?? 0 }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_agent_export',
description: 'Export a WASM agent\'s full state (config, filesystem, conversation) as JSON. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
agentId: { type: 'string', description: 'WASM agent ID' },
},
required: ['agentId'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.agentId, 'agentId'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const state = wasm.exportWasmState(args.agentId as string);
return { content: [{ type: 'text', text: state }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_gallery_list',
description: 'List all available WASM agent gallery templates (Coder, Researcher, Tester, Reviewer, Security, Swarm). Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: { type: 'object' as const, properties: {} },
handler: async () => {
try {
const wasm = await loadAgentWasm();
const templates = await wasm.listGalleryTemplates();
return { content: [{ type: 'text', text: JSON.stringify({ templates, count: templates.length }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_gallery_search',
description: 'Search WASM agent gallery templates by query. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateText(args.query, 'query'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const results = await wasm.searchGalleryTemplates(args.query as string);
return { content: [{ type: 'text', text: JSON.stringify({ results, count: results.length }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
{
name: 'wasm_gallery_create',
description: 'Create a WASM agent from a gallery template. Use when native Task is wrong because the workload needs sandboxed isolation — untrusted code execution, browser-side run, deterministic replay. Pair with wasm_gallery_search to find a published agent, or wasm_agent_create to scaffold a fresh one. For trusted in-process work, native Task is fine.',
inputSchema: {
type: 'object' as const,
properties: {
template: { type: 'string', description: 'Template name (coder, researcher, tester, reviewer, security, swarm)' },
},
required: ['template'],
},
handler: async (args: Record<string, unknown>) => {
{ const v = validateIdentifier(args.template, 'template'); if (!v.valid) return { content: [{ type: 'text', text: JSON.stringify({ error: v.error }) }], isError: true }; }
try {
const wasm = await loadAgentWasm();
const info = await wasm.createAgentFromTemplate(args.template as string);
return { content: [{ type: 'text', text: JSON.stringify({ success: true, agent: info, template: args.template }, null, 2) }] };
} catch (err) {
return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
}
},
},
];