Skip to content

Commit fe9e018

Browse files
VectorPeakchatgpt-codex-connector[bot]steipete
authored
fix(tavily): reject blank extract URLs (#111333)
* fix(tavily): reject blank extract URLs Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com> * fix(tavily): normalize tool string arrays Co-authored-by: VectorPeak <[email protected]> --------- Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com> Co-authored-by: Peter Steinberger <[email protected]>
1 parent 359859d commit fe9e018

3 files changed

Lines changed: 32 additions & 14 deletions

File tree

extensions/tavily/src/tavily-extract-tool.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime";
33
import {
44
jsonResult,
55
readPositiveIntegerParam,
6+
readStringArrayParam,
67
readStringParam,
78
} from "openclaw/plugin-sdk/provider-web-search";
89
import { Type } from "typebox";
@@ -49,9 +50,7 @@ export function createTavilyExtractTool(api: OpenClawPluginApi, ctx?: TavilyTool
4950
"Extract clean content from one or more URLs using Tavily. Handles JS-rendered pages. Supports query-focused chunking.",
5051
parameters: TavilyExtractToolSchema,
5152
execute: async (_toolCallId: string, rawParams: Record<string, unknown>) => {
52-
const urls = Array.isArray(rawParams.urls)
53-
? (rawParams.urls as string[]).filter(Boolean)
54-
: [];
53+
const urls = readStringArrayParam(rawParams, "urls") ?? [];
5554
if (urls.length === 0) {
5655
throw new Error("tavily_extract requires at least one URL.");
5756
}

extensions/tavily/src/tavily-search-tool.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime";
33
import {
44
jsonResult,
55
readPositiveIntegerParam,
6+
readStringArrayParam,
67
readStringParam,
78
} from "openclaw/plugin-sdk/provider-web-search";
89
import { Type } from "typebox";
@@ -65,12 +66,8 @@ export function createTavilySearchTool(api: OpenClawPluginApi, ctx?: TavilyToolC
6566
});
6667
const includeAnswer = rawParams.include_answer === true;
6768
const timeRange = readStringParam(rawParams, "time_range") || undefined;
68-
const includeDomains = Array.isArray(rawParams.include_domains)
69-
? (rawParams.include_domains as string[]).filter(Boolean)
70-
: undefined;
71-
const excludeDomains = Array.isArray(rawParams.exclude_domains)
72-
? (rawParams.exclude_domains as string[]).filter(Boolean)
73-
: undefined;
69+
const includeDomains = readStringArrayParam(rawParams, "include_domains");
70+
const excludeDomains = readStringArrayParam(rawParams, "exclude_domains");
7471

7572
return jsonResult(
7673
await runTavilySearch({
@@ -81,8 +78,8 @@ export function createTavilySearchTool(api: OpenClawPluginApi, ctx?: TavilyToolC
8178
maxResults,
8279
includeAnswer,
8380
timeRange,
84-
includeDomains: includeDomains?.length ? includeDomains : undefined,
85-
excludeDomains: excludeDomains?.length ? excludeDomains : undefined,
81+
includeDomains,
82+
excludeDomains,
8683
}),
8784
);
8885
},

extensions/tavily/src/tavily-tools.test.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ describe("tavily tools", () => {
179179
max_results: 5,
180180
include_answer: true,
181181
time_range: "week",
182-
include_domains: ["docs.openclaw.ai", "", "openclaw.ai"],
183-
exclude_domains: ["bad.example", ""],
182+
include_domains: [" docs.openclaw.ai ", " ", "openclaw.ai"],
183+
exclude_domains: [" bad.example ", ""],
184184
});
185185

186186
expect(runTavilySearch).toHaveBeenCalledWith({
@@ -313,7 +313,7 @@ describe("tavily tools", () => {
313313
await expect(
314314
searchTool.execute("call-2", {
315315
query: "simple",
316-
include_domains: [""],
316+
include_domains: [" "],
317317
exclude_domains: [],
318318
}),
319319
).resolves.toEqual({
@@ -351,6 +351,28 @@ describe("tavily tools", () => {
351351
expect(runTavilyExtract).not.toHaveBeenCalled();
352352
});
353353

354+
it("rejects blank extract URLs before Tavily calls and trims valid URLs", async () => {
355+
const tool = createTavilyExtractTool(fakeApi());
356+
357+
await expect(
358+
tool.execute("extract-call", {
359+
urls: [" "],
360+
}),
361+
).rejects.toThrow("tavily_extract requires at least one URL.");
362+
363+
expect(runTavilyExtract).not.toHaveBeenCalled();
364+
365+
await tool.execute("extract-call", {
366+
urls: [" https://example.com/article "],
367+
});
368+
369+
const extractParams = requireFirstMockArg(
370+
runTavilyExtract,
371+
"Tavily extract params",
372+
) as TavilyExtractParams;
373+
expect(extractParams.urls).toEqual(["https://example.com/article"]);
374+
});
375+
354376
it("rejects fractional and out-of-range integer options before Tavily calls", async () => {
355377
const searchTool = createTavilySearchTool(fakeApi());
356378
await expect(

0 commit comments

Comments
 (0)