import assert from "node:assert/strict"; import test from "node:test"; import type { ToolInfo } from "@earendil-works/pi-coding-agent"; import { BUNDLE_GROUP_DEFINITIONS, createBundleCatalog } from "../extensions/bundle-groups.ts"; import { buildManifestHash, rankGroups, selectConfidentGroup } from "../extensions/catalog.ts"; function tool(name: string): ToolInfo { return { name, description: `Full description for ${name}`, parameters: { type: "object", properties: {} } as ToolInfo["parameters"], sourceInfo: { source: "extension", scope: "user", path: `/test/${name}.ts` } as unknown as ToolInfo["sourceInfo"], }; } const constraints = { maxToolsPerGroup: 8, groupOverrides: {} }; test("bundle seed names are unique and cover the declared my-pi tools", () => { const names = BUNDLE_GROUP_DEFINITIONS.flatMap((group) => group.tools); assert.equal(new Set(names).size, names.length); const tools = names.map(tool); const hash = buildManifestHash(tools, constraints); const result = createBundleCatalog(tools, hash, constraints); assert.deepEqual(result.unknownTools, []); assert.equal(result.coveredNames.size, names.length); assert.equal(result.catalog.tools.length, names.length); assert.equal(result.catalog.tools.find((card) => card.name === "ctx_purge")?.primaryGroup, "context-administration"); assert.equal(result.catalog.tools.find((card) => card.name === "tavily_web_fetch")?.primaryGroup, "web-tavily"); assert.equal(result.catalog.tools.find((card) => card.name === "hippo_recall")?.primaryGroup, "memory-recall"); assert.equal(result.catalog.tools.find((card) => card.name === "hippo_remember")?.primaryGroup, "memory-management"); assert.equal(result.catalog.tools.find((card) => card.name === "Agent")?.primaryGroup, "subagents"); assert.equal(result.catalog.tools.find((card) => card.name === "get_subagent_result")?.primaryGroup, "subagents"); assert.equal(result.catalog.tools.find((card) => card.name === "steer_subagent")?.primaryGroup, "subagents"); assert.equal(result.catalog.tools.find((card) => card.name === "ssh_find")?.primaryGroup, "ssh-remote-search"); assert.equal(result.catalog.tools.find((card) => card.name === "ssh_grep")?.primaryGroup, "ssh-remote-search"); assert.equal(result.catalog.tools.find((card) => card.name === "ask_user_question")?.primaryGroup, "user-interaction"); assert.equal(result.catalog.tools.find((card) => card.name === "chrome_snapshot")?.primaryGroup, "chrome-navigation"); assert.equal(result.catalog.tools.find((card) => card.name === "chrome_click")?.primaryGroup, "chrome-interaction"); assert.equal(result.catalog.tools.find((card) => card.name === "chrome_list_network_requests")?.primaryGroup, "chrome-debugging"); for (const query of ["read", "read banana", "search", "web search", "查找", "运行", "查找香蕉"]) { assert.equal(selectConfidentGroup(rankGroups(result.catalog, query), query), undefined); } assert.equal(selectConfidentGroup(rankGroups(result.catalog, "ssh_read"), "ssh_read")?.id, "ssh-remote-files"); assert.equal( selectConfidentGroup(rankGroups(result.catalog, "remote find grep"), "remote find grep")?.id, "ssh-remote-search", ); }); test("user overrides take priority and unknown tools retain deterministic fallback groups", () => { const tools = [tool("tavily_web_search"), tool("custom_analyze")]; const configured = { maxToolsPerGroup: 8, groupOverrides: { preferred: ["tavily_web_search"] } }; const hash = buildManifestHash(tools, configured); const result = createBundleCatalog(tools, hash, configured); assert.deepEqual(result.unknownTools.map((item) => item.name), ["custom_analyze"]); assert.equal(result.catalog.tools.find((card) => card.name === "tavily_web_search")?.primaryGroup, "preferred"); assert.equal(result.catalog.tools.find((card) => card.name === "custom_analyze")?.primaryGroup, "custom"); });