// src/tools/skills/search-skills.ts // Copyright (C) 2025 DTP Technologies, LLC // All Rights Reserved import type { ToolDefinition } from "../../lib/ai-client.js"; import { DtpTool, type ToolArguments, type ToolContext, } from "../../lib/tool.js"; import { AiSkill } from "../../models/ai-skill.js"; import { ChatSessionMode } from "../../models/chat-session.js"; export class SearchSkillsTool extends DtpTool { get name(): string { return "SearchSkillsTool"; } get slug(): string { return "search-skills"; } get metadata() { return { name: this.definition.function.name || "search_skills", category: "skills", tags: ["skill", "search", "find", "query"], modes: [ ChatSessionMode.Plan, ChatSessionMode.Build, ChatSessionMode.Test, ChatSessionMode.Ship, ChatSessionMode.Develop, ], }; } public definition: ToolDefinition = { type: "function", function: { name: "search_skills", description: "Search for skills using text search. Matches against skill names, descriptions, and tags. Returns a list of matching skills with their basic info. Use this to find relevant skills when you need guidance on a specific task, then fetch the skill(s) you need by ID to read their full content.", parameters: { type: "object", properties: { query: { type: "string", description: "The search query. Use keywords that match skill names, descriptions, or tags.", }, }, required: ["query"], }, }, }; public async execute( _context: ToolContext, args: ToolArguments, ): Promise { const query = args.query as string | undefined; if (!query || query.trim().length === 0) { return this.error("INVALID_PARAMETER", "query is required.", { parameter: "query", }); } try { const skills = await AiSkill.find( { $text: { $search: query } }, { score: { $meta: "textScore" } }, ) .sort({ score: { $meta: "textScore" } }) .limit(10) .lean(); if (skills.length === 0) { return this.success( { skills: [], total: 0 }, `No skills found matching "${query}".`, ); } const results = skills.map((s) => ({ skillId: s._id.toString(), name: s.name, description: s.description, tags: s.tags, modes: s.modes, isGlobal: s.user === null, })); return this.success( { results, total: results.length }, `Found ${results.length} skill(s).`, ); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return this.error( "OPERATION_FAILED", `Failed to search skills: ${errorMessage}`, ); } } } export default new SearchSkillsTool();