diff --git a/packages/codemode/src/tool-runtime.ts b/packages/codemode/src/tool-runtime.ts index f1e189f733..5200c13b26 100644 --- a/packages/codemode/src/tool-runtime.ts +++ b/packages/codemode/src/tool-runtime.ts @@ -342,7 +342,6 @@ export type DiscoveryPlan = { export type SearchEntry = { readonly description: ToolDescription - readonly namespace: string readonly searchText: string } @@ -373,7 +372,11 @@ const makeSearchTool = (searchIndex: ReadonlyArray): Tool => ({ const scoped = request.namespace === undefined ? searchIndex - : searchIndex.filter((entry) => entry.namespace === request.namespace) + : searchIndex.filter( + (entry) => + entry.description.path === request.namespace || + entry.description.path.startsWith(`${request.namespace}.`), + ) const trimmed = query.trim() const pathQuery = trimmed.startsWith("tools.") ? trimmed.slice("tools.".length) : trimmed const exact = @@ -428,7 +431,6 @@ export const searchSignature = (() => { const toSearchEntry = (path: string, tool: Tool, description: ToolDescription): SearchEntry => ({ description, - namespace: path.split(".", 1)[0]!, searchText: [ path, tool.description, diff --git a/packages/codemode/test/tool-paths.test.ts b/packages/codemode/test/tool-paths.test.ts index 3cc92d6dfc..b90b719444 100644 --- a/packages/codemode/test/tool-paths.test.ts +++ b/packages/codemode/test/tool-paths.test.ts @@ -54,6 +54,27 @@ describe("dotted tool names", () => { expect(flat.catalog()[0]?.path).toBe("issues.list") expect(await value(flat, `return await tools.issues.list({})`)).toBe("flat") }) + + test("search scopes to a nested namespace subtree", async () => { + const nested = CodeMode.make({ + tools: { + slack: { + admin: echo("Admin", "admin"), + "admin.invite": echo("Invite", "invite"), + "admin.users.list": echo("List users", "users"), + "administrator.list": echo("List administrators", "administrators"), + read: echo("Read Slack", "read"), + }, + }, + }) + + const result = await value(nested, `return search({ query: "", namespace: "slack.admin" })`) + expect((result as { items: Array<{ path: string }> }).items.map((item) => item.path)).toEqual([ + "tools.slack.admin", + "tools.slack.admin.invite", + "tools.slack.admin.users.list", + ]) + }) }) describe("callable namespaces", () => {