diff --git a/src/agents/sessions/tools/find.test.ts b/src/agents/sessions/tools/find.test.ts index 34da33b501bc..0f01d3b7bf6e 100644 --- a/src/agents/sessions/tools/find.test.ts +++ b/src/agents/sessions/tools/find.test.ts @@ -1,5 +1,6 @@ // find tool tests cover custom search operation wiring and result-limit // normalization for session file discovery. +import { Value } from "typebox/value"; import { describe, expect, it } from "vitest"; import { createFindToolDefinition, type FindOperations } from "./find.js"; @@ -17,7 +18,18 @@ function textContent( return first?.type === "text" ? (first.text ?? "") : ""; } +function execute(tool: ReturnType, limit: number) { + return tool.execute("call-1", { pattern: "*.ts", limit }, undefined, undefined, {} as never); +} + describe("find tool", () => { + it("rejects fractional limits", async () => { + const tool = createFindToolDefinition("/workspace", { operations: operations([]) }); + + expect(Value.Check(tool.parameters, { pattern: "*.ts", limit: 1.5 })).toBe(false); + await expect(execute(tool, 1.5)).rejects.toThrow("Limit must be an integer"); + }); + it("clamps non-positive limits before delegating to custom search operations", async () => { // Clamp before delegation so custom backends never receive a zero/negative // limit that could make real matches disappear. @@ -25,13 +37,7 @@ describe("find tool", () => { operations: operations(["/workspace/a.ts", "/workspace/b.ts"]), }); - const result = await tool.execute( - "call-1", - { pattern: "*.ts", limit: -4 }, - undefined, - undefined, - {} as never, - ); + const result = await execute(tool, -4); expect(textContent(result)).toBe("a.ts\n\n[1 results limit reached]"); expect(result.details?.resultLimitReached).toBe(1); @@ -42,13 +48,7 @@ describe("find tool", () => { operations: operations(["/workspace/a.ts", "/workspace/b.ts"]), }); - const result = await tool.execute( - "call-1", - { pattern: "*.ts", limit: Number.POSITIVE_INFINITY }, - undefined, - undefined, - {} as never, - ); + const result = await execute(tool, Number.POSITIVE_INFINITY); expect(textContent(result)).toBe("a.ts\nb.ts"); expect(result.details).toBeUndefined(); diff --git a/src/agents/sessions/tools/find.ts b/src/agents/sessions/tools/find.ts index b01acb14cd3a..2144cabedaf7 100644 --- a/src/agents/sessions/tools/find.ts +++ b/src/agents/sessions/tools/find.ts @@ -45,7 +45,7 @@ const findSchema = Type.Object({ description: "File glob, e.g. **/*.ts.", }), path: Type.Optional(Type.String({ description: "Search dir; default cwd." })), - limit: Type.Optional(Type.Number({ description: "Max results; default 1000." })), + limit: Type.Optional(Type.Integer({ description: "Max results; default 1000." })), }); const DEFAULT_LIMIT = 1000; @@ -192,6 +192,10 @@ export function createFindToolDefinition( void (async () => { try { + if (Number.isFinite(limit) && !Number.isInteger(limit)) { + settle(() => reject(new Error("Limit must be an integer"))); + return; + } const searchPath = resolveToCwd(searchDir || ".", cwd); const effectiveLimit = normalizePositiveLimit(limit, DEFAULT_LIMIT); const ops = customOps ?? defaultFindOperations;