diff options
| author | Adam Malczewski <[email protected]> | 2026-06-21 13:11:29 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-21 13:11:29 +0900 |
| commit | 8a4a624d16422467a8e85434c674bb591877e8ea (patch) | |
| tree | 54052da00bbc580742913e5c031b7cc1b160db19 /packages/tool-web-search/src/validate.test.ts | |
| parent | d23de3254374d4d63c8e15c6ab9311c3c6f4da5b (diff) | |
| download | dispatch-8a4a624d16422467a8e85434c674bb591877e8ea.tar.gz dispatch-8a4a624d16422467a8e85434c674bb591877e8ea.zip | |
feat(tool-web-search): Firecrawl-backed web search tool
New standard tool extension with one tool web_search supporting 4 modes
(search, scrape, crawl, map) against a self-hosted Firecrawl instance.
Pure core: validateArgs (discriminated union by mode) + format* functions
+ truncateOutput. Injected edge: FirecrawlClient (injectable fetchFn/sleep/now,
AbortSignal.any for per-request timeout + caller cancellation). concurrencySafe
true, capabilities network. 38 tests, zero vi.mock.
Live-verified: umans-glm-5.2 called web_search → real Firecrawl results (also
the first live Umans API call).
Diffstat (limited to 'packages/tool-web-search/src/validate.test.ts')
| -rw-r--r-- | packages/tool-web-search/src/validate.test.ts | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/packages/tool-web-search/src/validate.test.ts b/packages/tool-web-search/src/validate.test.ts new file mode 100644 index 0000000..30ae26c --- /dev/null +++ b/packages/tool-web-search/src/validate.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, it } from "vitest"; +import { + type CrawlArgs, + type MapArgs, + type ScrapeArgs, + type SearchArgs, + validateArgs, +} from "./validate.js"; + +describe("validateArgs", () => { + it("mode defaults to search when query present", () => { + const result = validateArgs({ query: "hello" }); + expect("error" in result).toBe(false); + if ("error" in result) return; + expect(result.mode).toBe("search"); + expect((result as SearchArgs).query).toBe("hello"); + }); + + it("mode defaults to scrape when url present (no query)", () => { + const result = validateArgs({ url: "http://example.com" }); + expect("error" in result).toBe(false); + if ("error" in result) return; + expect(result.mode).toBe("scrape"); + expect((result as ScrapeArgs).url).toBe("http://example.com"); + }); + + it("explicit mode overrides defaults", () => { + const result = validateArgs({ query: "hello", url: "http://x", mode: "map" }); + expect("error" in result).toBe(false); + if ("error" in result) return; + expect(result.mode).toBe("map"); + expect((result as MapArgs).url).toBe("http://x"); + }); + + it("search mode requires query", () => { + const result = validateArgs({ mode: "search" }); + expect(result).toHaveProperty("error"); + }); + + it("scrape/crawl/map modes require url", () => { + expect(validateArgs({ mode: "scrape" })).toHaveProperty("error"); + expect(validateArgs({ mode: "crawl" })).toHaveProperty("error"); + expect(validateArgs({ mode: "map" })).toHaveProperty("error"); + }); + + it("limit clamped to max 10", () => { + const result = validateArgs({ query: "hello", limit: 50 }); + expect("error" in result).toBe(false); + if ("error" in result) return; + expect((result as SearchArgs).limit).toBe(10); + }); + + it("limit defaults to 7 (search) / 3 (crawl)", () => { + const search = validateArgs({ query: "hello" }); + expect("error" in search).toBe(false); + if ("error" in search) return; + expect((search as SearchArgs).limit).toBe(7); + + const crawl = validateArgs({ url: "http://x", mode: "crawl" }); + expect("error" in crawl).toBe(false); + if ("error" in crawl) return; + expect((crawl as CrawlArgs).limit).toBe(3); + }); + + it("format defaults to markdown", () => { + const result = validateArgs({ query: "hello" }); + expect("error" in result).toBe(false); + if ("error" in result) return; + expect(result.format).toBe("markdown"); + }); + + it("rejects invalid mode", () => { + const result = validateArgs({ mode: "invalid" }); + expect(result).toHaveProperty("error"); + if (!("error" in result)) return; + expect(result.error).toContain("Invalid mode"); + }); + + it("rejects invalid format", () => { + const result = validateArgs({ url: "http://x", format: "pdf" }); + expect(result).toHaveProperty("error"); + if (!("error" in result)) return; + expect(result.error).toContain("Invalid format"); + }); + + it("returns error for null/non-object args", () => { + expect(validateArgs(null)).toHaveProperty("error"); + expect(validateArgs(undefined)).toHaveProperty("error"); + expect(validateArgs("string")).toHaveProperty("error"); + expect(validateArgs(42)).toHaveProperty("error"); + }); +}); |
