summaryrefslogtreecommitdiffhomepage
path: root/packages/skills/src/tools-filter.ts
blob: 058f971d1b7515dbc8c9ad4eab384f53d32019c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { join, resolve } from "node:path";
import type { JsonSchemaProperty, ToolContract } from "@dispatch/kernel";
import type { ToolAssembly } from "@dispatch/session-orchestrator";
import { type SkillsDeps, scanSkillsDir } from "./load-skill.js";
import { mergeCatalog, renderDescription } from "./pure.js";

/**
 * Create a tools filter that rewrites the load_skill tool's description
 * and name parameter enum with the current skill catalog.
 */
export function makeSkillsToolFilter(deps: SkillsDeps) {
	const { homeDir, workdir } = deps;

	return async (asm: ToolAssembly): Promise<ToolAssembly> => {
		const effectiveBase = asm.cwd ? resolve(asm.cwd) : resolve(workdir);
		const cwdSkillsDir = join(effectiveBase, ".skills");
		const homeSkillsDir = join(resolve(homeDir), ".skills");

		let homeEntries: readonly import("./pure.js").SkillEntry[];
		let cwdEntries: readonly import("./pure.js").SkillEntry[];
		try {
			[homeEntries, cwdEntries] = await Promise.all([
				scanSkillsDir(homeSkillsDir),
				scanSkillsDir(cwdSkillsDir),
			]);
		} catch {
			return asm;
		}

		const catalog = mergeCatalog(homeEntries, cwdEntries);
		const names = catalog.map((e) => e.name);
		const description = renderDescription(catalog);

		return {
			...asm,
			tools: asm.tools.map((t: ToolContract) => {
				if (t.name !== "load_skill") return t;

				const nameProp = t.parameters.properties?.name;
				if (!nameProp) {
					return { ...t, description };
				}

				const updatedNameProp: JsonSchemaProperty =
					names.length > 0 ? { ...nameProp, enum: names } : { ...nameProp };

				const updatedProperties: Record<string, JsonSchemaProperty> = {
					...t.parameters.properties,
					name: updatedNameProp,
				};

				return {
					...t,
					description,
					parameters: {
						...t.parameters,
						properties: updatedProperties,
					},
				};
			}),
		};
	};
}