diff --git a/src/agents/tools/pdf-tool.helpers.test.ts b/src/agents/tools/pdf-tool.helpers.test.ts index c462b2de6a59..350b8d8a53d6 100644 --- a/src/agents/tools/pdf-tool.helpers.test.ts +++ b/src/agents/tools/pdf-tool.helpers.test.ts @@ -62,6 +62,10 @@ describe("parsePageRange", () => { expect(parsePageRange("1-100", 5)).toEqual([1, 2, 3, 4, 5]); }); + it("throws when no requested pages are within maxPages", () => { + expect(() => parsePageRange("999", 20)).toThrow('No PDF pages matched requested range "999"'); + }); + it("deduplicates and sorts", () => { expect(parsePageRange("5,3,1,3,5", 20)).toEqual([1, 3, 5]); }); diff --git a/src/agents/tools/pdf-tool.helpers.ts b/src/agents/tools/pdf-tool.helpers.ts index 19f4dbb1c784..962c666df8b5 100644 --- a/src/agents/tools/pdf-tool.helpers.ts +++ b/src/agents/tools/pdf-tool.helpers.ts @@ -74,7 +74,11 @@ export function parsePageRange(range: string, maxPages: number): number[] { } } } - return Array.from(pages).toSorted((a, b) => a - b); + const parsedPages = Array.from(pages).toSorted((a, b) => a - b); + if (parsedPages.length === 0) { + throw new Error(`No PDF pages matched requested range "${range}"`); + } + return parsedPages; } /** Converts a provider assistant message into PDF text or throws a model-labelled failure. */ diff --git a/src/agents/tools/pdf-tool.test.ts b/src/agents/tools/pdf-tool.test.ts index f32ccee457cd..25784032572d 100644 --- a/src/agents/tools/pdf-tool.test.ts +++ b/src/agents/tools/pdf-tool.test.ts @@ -548,6 +548,26 @@ describe("createPdfTool", () => { }); }); + it("rejects explicit page ranges that resolve to no pages before native PDF analysis", async () => { + await withTempPdfAgentDir(async (agentDir) => { + await stubPdfToolInfra(agentDir, { provider: "anthropic", input: ["text", "document"] }); + const nativeSpy = vi + .spyOn(pdfNativeProviders, "anthropicAnalyzePdf") + .mockResolvedValue("native summary"); + const cfg = withPdfModel(ANTHROPIC_PDF_MODEL); + const tool = requirePdfTool((await loadCreatePdfTool())({ config: cfg, agentDir })); + + await expect( + tool.execute("t1", { + prompt: "summarize", + pdf: "/tmp/doc.pdf", + pages: "999", + }), + ).rejects.toThrow('No PDF pages matched requested range "999"'); + expect(nativeSpy).not.toHaveBeenCalled(); + }); + }); + it("rejects password parameter for native PDF providers", async () => { await withTempPdfAgentDir(async (agentDir) => { await stubPdfToolInfra(agentDir, { provider: "anthropic", input: ["text", "document"] });