Files
OmniRoute/open-sse/mcp-server/tools/skillTools.ts
oyi77 e6e54822f5 feat: add Memory & Skill Injection from Proxy (Network Level)
Implements transparent memory and skill injection at the proxy layer,
enabling AI agents connecting through OmniRoute to automatically inherit
memory and tool capabilities without client-side code changes.

Memory System:
- SQLite-backed memory store with 4 types: factual, episodic, procedural, semantic
- Token budget retrieval with configurable max tokens (default 2000)
- Memory injection into chat requests (system message + message prefix)
- Memory fact extraction from responses
- Dashboard page: /dashboard/memory
- MCP tools: omniroute_memory_search, omniroute_memory_add, omniroute_memory_clear

Skills System:
- Skill registry with semver resolution (^, ~, >=, etc.)
- Docker sandbox runner with resource constraints (CPU 100ms, RAM 256MB)
- Skill executor with timeout handling
- Built-in skills: file_read, file_write, http_request, web_search, eval_code, execute_command
- Skill schema injection for OpenAI, Claude, Gemini formats
- Tool call interception and execution
- Dashboard page: /dashboard/skills
- MCP tools: omniroute_skills_list, omniroute_skills_enable, omniroute_skills_execute

Advanced Features:
- Browser automation skill (Playwright-based)
- A2A memory-aware routing skill
- Hybrid execution mode (direct/sandbox/auto-upgrade)
- Custom skill registration API
- Integration tests
- Memory caching layer
- Memory summarization
- Performance benchmarks

Resolves: GitHub Issue #812
2026-04-01 09:26:37 +07:00

121 lines
3.5 KiB
TypeScript

import { z } from "zod";
import { skillRegistry } from "@/lib/skills/registry";
import { skillExecutor } from "@/lib/skills/executor";
export const SkillListSchema = z.object({
apiKeyId: z.string().optional(),
name: z.string().optional(),
enabled: z.boolean().optional(),
});
export const SkillEnableSchema = z.object({
apiKeyId: z.string(),
skillId: z.string(),
enabled: z.boolean(),
});
export const SkillExecuteSchema = z.object({
apiKeyId: z.string(),
skillName: z.string(),
input: z.record(z.string(), z.unknown()),
sessionId: z.string().optional(),
});
export const skillTools = {
omniroute_skills_list: {
name: "omniroute_skills_list",
description: "List all registered skills with optional filtering by API key or name",
inputSchema: SkillListSchema,
handler: async (args: z.infer<typeof SkillListSchema>) => {
await skillRegistry.loadFromDatabase(args.apiKeyId);
const skills = skillRegistry.list(args.apiKeyId);
let filtered = skills;
if (args.name) {
filtered = filtered.filter((s) => s.name.includes(args.name!));
}
if (args.enabled !== undefined) {
filtered = filtered.filter((s) => s.enabled === args.enabled);
}
return {
skills: filtered.map((s) => ({
id: s.id,
name: s.name,
version: s.version,
description: s.description,
enabled: s.enabled,
createdAt: s.createdAt.toISOString(),
})),
count: filtered.length,
};
},
},
omniroute_skills_enable: {
name: "omniroute_skills_enable",
description: "Enable or disable a specific skill by ID",
inputSchema: SkillEnableSchema,
handler: async (args: z.infer<typeof SkillEnableSchema>) => {
const skill = skillRegistry.getSkill(args.skillId, args.apiKeyId);
if (!skill) {
throw new Error(`Skill not found: ${args.skillId}`);
}
await skillRegistry.register({
...skill,
enabled: args.enabled,
apiKeyId: args.apiKeyId,
});
return { success: true, skillId: args.skillId, enabled: args.enabled };
},
},
omniroute_skills_execute: {
name: "omniroute_skills_execute",
description: "Execute a skill with provided input and return the result",
inputSchema: SkillExecuteSchema,
handler: async (args: z.infer<typeof SkillExecuteSchema>) => {
const execution = await skillExecutor.execute(args.skillName, args.input, {
apiKeyId: args.apiKeyId,
sessionId: args.sessionId,
});
return {
id: execution.id,
skillId: execution.skillId,
status: execution.status,
output: execution.output,
error: execution.errorMessage,
duration: execution.durationMs,
createdAt: execution.createdAt.toISOString(),
};
},
},
omniroute_skills_executions: {
name: "omniroute_skills_executions",
description: "List recent skill execution history",
inputSchema: z.object({
apiKeyId: z.string().optional(),
limit: z.number().int().positive().max(100).optional(),
}),
handler: async (args: { apiKeyId?: string; limit?: number }) => {
const executions = skillExecutor.listExecutions(args.apiKeyId, args.limit || 50);
return {
executions: executions.map((e) => ({
id: e.id,
skillId: e.skillId,
status: e.status,
duration: e.durationMs,
error: e.errorMessage,
createdAt: e.createdAt.toISOString(),
})),
count: executions.length,
};
},
},
};