feat: initial public release (MAESTRO)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import type { ToolDef } from '../llm/openai-compat.js';
|
||||
|
||||
const SLUG = /^[a-z0-9_-]{1,64}$/;
|
||||
|
||||
export function normalizeToolName(serverId: string, toolName: string): string {
|
||||
return `mcp__${serverId}__${toolName}`;
|
||||
}
|
||||
|
||||
export function parseToolName(name: string): { serverId: string; toolName: string } | null {
|
||||
if (!name.startsWith('mcp__')) return null;
|
||||
const parts = name.split('__');
|
||||
if (parts.length !== 3) return null;
|
||||
const [, serverId, toolName] = parts;
|
||||
if (!SLUG.test(serverId) || !SLUG.test(toolName)) return null;
|
||||
return { serverId, toolName };
|
||||
}
|
||||
|
||||
export function matchesAnyPattern(name: string, patterns: string[]): boolean {
|
||||
return patterns.some((p) => {
|
||||
if (p === name) return true;
|
||||
if (p.endsWith('__*')) {
|
||||
const prefix = p.slice(0, -1);
|
||||
return name.startsWith(prefix) && name.length > prefix.length;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
export interface CachedTool {
|
||||
serverId: string;
|
||||
toolName: string;
|
||||
description: string | null;
|
||||
inputSchema: string | null;
|
||||
}
|
||||
|
||||
const MAX_DESCRIPTION = 1000;
|
||||
|
||||
export function buildToolDefsFromCache(
|
||||
cache: CachedTool[],
|
||||
patterns: string[],
|
||||
serverNames: Map<string, string>,
|
||||
): ToolDef[] {
|
||||
const mcpPatterns = patterns.filter((p) => p.startsWith('mcp__'));
|
||||
if (mcpPatterns.length === 0) return [];
|
||||
|
||||
const defs: ToolDef[] = [];
|
||||
for (const tool of cache) {
|
||||
if (!SLUG.test(tool.serverId) || !SLUG.test(tool.toolName)) continue;
|
||||
const canonical = normalizeToolName(tool.serverId, tool.toolName);
|
||||
if (!matchesAnyPattern(canonical, mcpPatterns)) continue;
|
||||
|
||||
let params: unknown = { type: 'object', properties: {} };
|
||||
if (tool.inputSchema) {
|
||||
try {
|
||||
params = JSON.parse(tool.inputSchema);
|
||||
} catch {
|
||||
// Keep default object schema
|
||||
}
|
||||
}
|
||||
|
||||
const serverLabel = serverNames.get(tool.serverId) ?? tool.serverId;
|
||||
const rawDesc = tool.description ?? '';
|
||||
const description = `[外部ツール: ${serverLabel} 提供] ${rawDesc}`.slice(0, MAX_DESCRIPTION);
|
||||
|
||||
defs.push({
|
||||
type: 'function',
|
||||
function: {
|
||||
name: canonical,
|
||||
description,
|
||||
parameters: params as Record<string, unknown>,
|
||||
},
|
||||
});
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
Reference in New Issue
Block a user