@openclaw/firecrawl-plugin 2026.7.2-beta.7 → 2026.8.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as runFirecrawlScrape } from "./firecrawl-client-DZohiNQK.js";
1
+ import { n as runFirecrawlScrape } from "./firecrawl-client-Aw46OXVC.js";
2
2
  import { readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  //#region extensions/firecrawl/api.ts
4
4
  async function fetchFirecrawlContent(params) {
@@ -1,10 +1,9 @@
1
1
  import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
2
- import { DEFAULT_CACHE_TTL_MINUTES, markdownToText, normalizeCacheKey, readCache, readResponseText, resolveCacheTtlMs, resolvePositiveTimeoutSeconds, truncateText, withSelfHostedWebToolsEndpoint, withStrictWebToolsEndpoint, writeCache } from "openclaw/plugin-sdk/provider-web-fetch";
2
+ import { DEFAULT_CACHE_TTL_MINUTES, markdownToText, normalizeCacheKey, readCache, readResponseText, resolveCacheTtlMs, resolvePositiveTimeoutSeconds, withSelfHostedWebToolsEndpoint, withStrictWebToolsEndpoint, writeCache } from "openclaw/plugin-sdk/provider-web-fetch";
3
3
  import { normalizeSecretInput, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
4
- import { wrapExternalContent, wrapWebContent } from "openclaw/plugin-sdk/security-runtime";
4
+ import { truncateSanitizedExternalContent, wrapExternalContent, wrapWebContent } from "openclaw/plugin-sdk/security-runtime";
5
5
  import { SsrFBlockedError, isBlockedHostnameOrIp, isPrivateIpAddress, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
8
7
  import { canResolveEnvSecretRefInReadOnlyPath } from "openclaw/plugin-sdk/extension-shared";
9
8
  //#region \0rolldown/runtime.js
10
9
  var __defProp = Object.defineProperty;
@@ -103,7 +102,6 @@ function resolveFirecrawlSearchTimeoutSeconds(override) {
103
102
  //#endregion
104
103
  //#region extensions/firecrawl/src/firecrawl-client.ts
105
104
  var firecrawl_client_exports = /* @__PURE__ */ __exportAll({
106
- __testing: () => testing,
107
105
  assertFirecrawlScrapeTargetAllowed: () => assertFirecrawlScrapeTargetAllowed,
108
106
  parseFirecrawlScrapePayload: () => parseFirecrawlScrapePayload,
109
107
  runFirecrawlScrape: () => runFirecrawlScrape,
@@ -113,9 +111,14 @@ var firecrawl_client_exports = /* @__PURE__ */ __exportAll({
113
111
  const SEARCH_CACHE = /* @__PURE__ */ new Map();
114
112
  const SCRAPE_CACHE = /* @__PURE__ */ new Map();
115
113
  const DEFAULT_SEARCH_COUNT = 5;
114
+ const FIRECRAWL_SEARCH_MAX_RESULTS = 100;
115
+ const FIRECRAWL_SEARCH_MAX_CONTENT_CHARS = 2e4;
116
116
  const DEFAULT_SCRAPE_MAX_CHARS = 5e4;
117
+ const FIRECRAWL_SCRAPE_METADATA_MAX_CHARS = 4e3;
118
+ const FIRECRAWL_RESULT_URL_MAX_CHARS = 2048;
117
119
  const FIRECRAWL_SCRAPE_RESPONSE_MAX_BYTES = 64 * 1024 * 1024;
118
120
  const ALLOWED_FIRECRAWL_HOSTS = /* @__PURE__ */ new Set(["api.firecrawl.dev"]);
121
+ const FIRECRAWL_PUBLISHED_DATE_RE = /^\d{4}-\d{2}-\d{2}(?:[T ][\d:.+Z-]{0,20})?$/u;
119
122
  const FIRECRAWL_SELF_HOSTED_PRIVATE_ERROR = "Firecrawl custom baseUrl must target a private or internal self-hosted endpoint.";
120
123
  const FIRECRAWL_HTTP_PRIVATE_ERROR = "Firecrawl HTTP baseUrl must target a private or internal self-hosted endpoint. Use https:// for public hosts.";
121
124
  async function readFirecrawlJsonResponse(response, label, opts) {
@@ -176,6 +179,7 @@ async function postFirecrawlJson(params, parse) {
176
179
  return await ((params.mode ?? await validateFirecrawlBaseUrl(params.url)) === "selfHosted" ? withSelfHostedWebToolsEndpoint : withStrictWebToolsEndpoint)({
177
180
  url: params.url,
178
181
  timeoutSeconds: params.timeoutSeconds,
182
+ ...params.signal ? { signal: params.signal } : {},
179
183
  init: {
180
184
  method: "POST",
181
185
  headers: {
@@ -204,7 +208,7 @@ async function postFirecrawlJson(params, parse) {
204
208
  const errorBody = await readResponseText(response, { maxBytes: 64e3 });
205
209
  if (errorBody.text) detail = errorBody.text;
206
210
  }
207
- const safeDetail = wrapWebContent(truncateUtf16Safe(detail, 1e3), "web_fetch");
211
+ const safeDetail = wrapWebContent(truncateSanitizedExternalContent(detail, 1e3).text, "web_fetch");
208
212
  throw new Error(`${params.errorLabel} API error (${response.status}): ${safeDetail}`);
209
213
  }
210
214
  return await parse(response);
@@ -217,6 +221,16 @@ function resolveSiteName(urlRaw) {
217
221
  return;
218
222
  }
219
223
  }
224
+ function normalizeFirecrawlResultUrl(value) {
225
+ if (typeof value !== "string" || value.length > FIRECRAWL_RESULT_URL_MAX_CHARS) return;
226
+ try {
227
+ const url = new URL(value);
228
+ if (url.protocol !== "http:" && url.protocol !== "https:" || url.href.length > FIRECRAWL_RESULT_URL_MAX_CHARS) return;
229
+ return url.href === `${value}/` ? value : url.href;
230
+ } catch {
231
+ return;
232
+ }
233
+ }
220
234
  function resolveSearchItems(payload) {
221
235
  const rawItems = [
222
236
  payload.data,
@@ -228,16 +242,17 @@ function resolveSearchItems(payload) {
228
242
  ].find((candidate) => Array.isArray(candidate));
229
243
  if (!Array.isArray(rawItems)) return [];
230
244
  const items = [];
231
- for (const entry of rawItems) {
245
+ for (const entry of rawItems.slice(0, FIRECRAWL_SEARCH_MAX_RESULTS)) {
232
246
  if (!entry || typeof entry !== "object") continue;
233
247
  const record = entry;
234
248
  const metadata = record.metadata && typeof record.metadata === "object" ? record.metadata : void 0;
235
- const url = typeof record.url === "string" && record.url || typeof record.sourceURL === "string" && record.sourceURL || typeof record.sourceUrl === "string" && record.sourceUrl || typeof metadata?.sourceURL === "string" && metadata.sourceURL || "";
249
+ const url = normalizeFirecrawlResultUrl(typeof record.url === "string" && record.url || typeof record.sourceURL === "string" && record.sourceURL || typeof record.sourceUrl === "string" && record.sourceUrl || typeof metadata?.sourceURL === "string" && metadata.sourceURL || "");
236
250
  if (!url) continue;
237
251
  const title = typeof record.title === "string" && record.title || typeof metadata?.title === "string" && metadata.title || "";
238
252
  const description = typeof record.description === "string" && record.description || typeof record.snippet === "string" && record.snippet || typeof record.summary === "string" && record.summary || void 0;
239
253
  const content = typeof record.markdown === "string" && record.markdown || typeof record.content === "string" && record.content || typeof record.text === "string" && record.text || void 0;
240
- const published = typeof record.publishedDate === "string" && record.publishedDate || typeof record.published === "string" && record.published || typeof metadata?.publishedTime === "string" && metadata.publishedTime || typeof metadata?.publishedDate === "string" && metadata.publishedDate || void 0;
254
+ const rawPublished = typeof record.publishedDate === "string" && record.publishedDate || typeof record.published === "string" && record.published || typeof metadata?.publishedTime === "string" && metadata.publishedTime || typeof metadata?.publishedDate === "string" && metadata.publishedDate || void 0;
255
+ const published = rawPublished && FIRECRAWL_PUBLISHED_DATE_RE.test(rawPublished) ? rawPublished : void 0;
241
256
  items.push({
242
257
  title,
243
258
  url,
@@ -250,6 +265,22 @@ function resolveSearchItems(payload) {
250
265
  return items;
251
266
  }
252
267
  function buildSearchPayload(params) {
268
+ let remainingContentChars = FIRECRAWL_SEARCH_MAX_CONTENT_CHARS;
269
+ let truncated = false;
270
+ const wrapBoundedContent = (value) => {
271
+ const bounded = truncateSanitizedExternalContent(value, remainingContentChars);
272
+ truncated ||= bounded.truncated;
273
+ remainingContentChars -= bounded.text.length;
274
+ return wrapWebContent(bounded.text, "web_search");
275
+ };
276
+ const results = params.items.map((entry) => ({
277
+ title: entry.title ? wrapBoundedContent(entry.title) : "",
278
+ url: entry.url,
279
+ description: entry.description ? wrapBoundedContent(entry.description) : "",
280
+ ...entry.published ? { published: entry.published } : {},
281
+ ...entry.siteName ? { siteName: entry.siteName } : {},
282
+ ...params.scrapeResults && entry.content ? { content: wrapBoundedContent(entry.content) } : {}
283
+ }));
253
284
  return {
254
285
  query: params.query,
255
286
  provider: params.provider,
@@ -261,17 +292,12 @@ function buildSearchPayload(params) {
261
292
  provider: params.provider,
262
293
  wrapped: true
263
294
  },
264
- results: params.items.map((entry) => ({
265
- title: entry.title ? wrapWebContent(entry.title, "web_search") : "",
266
- url: entry.url,
267
- description: entry.description ? wrapWebContent(entry.description, "web_search") : "",
268
- ...entry.published ? { published: entry.published } : {},
269
- ...entry.siteName ? { siteName: entry.siteName } : {},
270
- ...params.scrapeResults && entry.content ? { content: wrapWebContent(entry.content, "web_search") } : {}
271
- }))
295
+ results,
296
+ ...truncated ? { truncated: true } : {}
272
297
  };
273
298
  }
274
299
  async function runFirecrawlSearch(params) {
300
+ params.signal?.throwIfAborted();
275
301
  const keyless = params.access === "keyless";
276
302
  const providerId = keyless ? "firecrawl-free" : "firecrawl";
277
303
  const apiKey = keyless ? void 0 : resolveFirecrawlApiKey(params.cfg);
@@ -328,19 +354,20 @@ async function runFirecrawlSearch(params) {
328
354
  timeoutSeconds,
329
355
  apiKey,
330
356
  body,
331
- errorLabel: "Firecrawl Search"
357
+ errorLabel: "Firecrawl Search",
358
+ ...params.signal ? { signal: params.signal } : {}
332
359
  }, async (response) => {
333
360
  const payloadValue = await readFirecrawlJsonResponse(response, "Firecrawl Search API error");
334
361
  if (payloadValue.success === false) {
335
- const error = typeof payloadValue.error === "string" ? payloadValue.error : typeof payloadValue.message === "string" ? payloadValue.message : "unknown error";
336
- throw new Error(`Firecrawl Search API error: ${error}`);
362
+ const safeError = wrapWebContent(truncateSanitizedExternalContent(typeof payloadValue.error === "string" ? payloadValue.error : typeof payloadValue.message === "string" ? payloadValue.message : "unknown error", 1e3).text, "web_search");
363
+ throw new Error(`Firecrawl Search API error: ${safeError}`);
337
364
  }
338
365
  return payloadValue;
339
366
  });
340
367
  const result = buildSearchPayload({
341
368
  query: params.query,
342
369
  provider: providerId,
343
- items: resolveSearchItems(payload),
370
+ items: resolveSearchItems(payload).slice(0, count),
344
371
  tookMs: Date.now() - start,
345
372
  scrapeResults
346
373
  });
@@ -358,23 +385,28 @@ function parseFirecrawlScrapePayload(params) {
358
385
  const markdown = typeof data.markdown === "string" && data.markdown || typeof data.content === "string" && data.content || "";
359
386
  if (!markdown) throw new Error("Firecrawl scrape returned no content.");
360
387
  const rawText = params.extractMode === "text" ? markdownToText(markdown) : markdown;
361
- const truncated = truncateText(rawText, params.maxChars);
362
- const wrappedText = wrapExternalContent(truncated.text, {
388
+ const boundedText = truncateSanitizedExternalContent(rawText, params.maxChars);
389
+ let truncated = boundedText.truncated;
390
+ let remainingMetadataChars = FIRECRAWL_SCRAPE_METADATA_MAX_CHARS;
391
+ const wrapBoundedMetadata = (value) => {
392
+ const bounded = truncateSanitizedExternalContent(value, remainingMetadataChars);
393
+ truncated ||= bounded.truncated;
394
+ remainingMetadataChars -= bounded.text.length;
395
+ return wrapExternalContent(bounded.text, {
396
+ source: "web_fetch",
397
+ includeWarning: false
398
+ });
399
+ };
400
+ const wrappedText = wrapExternalContent(boundedText.text, {
363
401
  source: "web_fetch",
364
402
  includeWarning: false
365
403
  });
366
404
  const status = typeof metadata?.statusCode === "number" && metadata.statusCode || typeof data.statusCode === "number" && data.statusCode || void 0;
367
- const title = typeof metadata?.title === "string" && metadata.title ? wrapExternalContent(metadata.title, {
368
- source: "web_fetch",
369
- includeWarning: false
370
- }) : void 0;
371
- const warning = typeof params.payload.warning === "string" && params.payload.warning ? wrapExternalContent(params.payload.warning, {
372
- source: "web_fetch",
373
- includeWarning: false
374
- }) : void 0;
405
+ const title = typeof metadata?.title === "string" && metadata.title ? wrapBoundedMetadata(metadata.title) : void 0;
406
+ const warning = typeof params.payload.warning === "string" && params.payload.warning ? wrapBoundedMetadata(params.payload.warning) : void 0;
375
407
  return {
376
408
  url: params.url,
377
- finalUrl: typeof metadata?.sourceURL === "string" && metadata.sourceURL || typeof data.url === "string" && data.url || params.url,
409
+ finalUrl: normalizeFirecrawlResultUrl(metadata?.sourceURL) ?? normalizeFirecrawlResultUrl(data.url) ?? params.url,
378
410
  ...status !== void 0 ? { status } : {},
379
411
  ...title ? { title } : {},
380
412
  extractor: "firecrawl",
@@ -384,7 +416,7 @@ function parseFirecrawlScrapePayload(params) {
384
416
  source: "web_fetch",
385
417
  wrapped: true
386
418
  },
387
- truncated: truncated.truncated,
419
+ truncated,
388
420
  rawLength: rawText.length,
389
421
  length: wrappedText.length,
390
422
  text: wrappedText,
@@ -392,6 +424,7 @@ function parseFirecrawlScrapePayload(params) {
392
424
  };
393
425
  }
394
426
  async function runFirecrawlScrape(params) {
427
+ params.signal?.throwIfAborted();
395
428
  assertFirecrawlScrapeTargetAllowed(params.url);
396
429
  const apiKey = resolveFirecrawlApiKey(params.cfg);
397
430
  if (!apiKey && params.access !== "keyless") throw new Error("firecrawl_scrape needs a Firecrawl API key. Set FIRECRAWL_API_KEY in the Gateway environment, or configure plugins.entries.firecrawl.config.webFetch.apiKey.");
@@ -401,7 +434,10 @@ async function runFirecrawlScrape(params) {
401
434
  const maxAgeMs = resolveFirecrawlMaxAgeMs(params.cfg, params.maxAgeMs);
402
435
  const proxy = params.proxy ?? "auto";
403
436
  const storeInCache = params.storeInCache ?? true;
404
- const maxChars = typeof params.maxChars === "number" && Number.isFinite(params.maxChars) && params.maxChars > 0 ? Math.floor(params.maxChars) : DEFAULT_SCRAPE_MAX_CHARS;
437
+ const configuredMaxCharsCap = params.cfg?.tools?.web?.fetch?.maxCharsCap;
438
+ const maxCharsCap = typeof configuredMaxCharsCap === "number" && Number.isFinite(configuredMaxCharsCap) && configuredMaxCharsCap > 0 ? Math.floor(configuredMaxCharsCap) : DEFAULT_SCRAPE_MAX_CHARS;
439
+ const requestedMaxChars = typeof params.maxChars === "number" && Number.isFinite(params.maxChars) && params.maxChars > 0 ? Math.floor(params.maxChars) : DEFAULT_SCRAPE_MAX_CHARS;
440
+ const maxChars = Math.min(requestedMaxChars, maxCharsCap);
405
441
  const cacheKey = normalizeCacheKey(JSON.stringify({
406
442
  type: "firecrawl-scrape",
407
443
  url: params.url,
@@ -426,6 +462,7 @@ async function runFirecrawlScrape(params) {
426
462
  timeoutSeconds,
427
463
  apiKey,
428
464
  errorLabel: "Firecrawl",
465
+ ...params.signal ? { signal: params.signal } : {},
429
466
  body: {
430
467
  url: params.url,
431
468
  formats: ["markdown"],
@@ -439,7 +476,7 @@ async function runFirecrawlScrape(params) {
439
476
  const payloadLocal = await readFirecrawlJsonResponse(response, "Firecrawl fetch failed", { maxBytes: FIRECRAWL_SCRAPE_RESPONSE_MAX_BYTES });
440
477
  if (payloadLocal.success === false) {
441
478
  const detail = typeof payloadLocal.error === "string" ? payloadLocal.error : typeof payloadLocal.message === "string" ? payloadLocal.message : response.statusText;
442
- throw new Error(`Firecrawl fetch failed (${response.status}): ${wrapWebContent(detail, "web_fetch")}`.trim());
479
+ throw new Error(`Firecrawl fetch failed (${response.status}): ${wrapWebContent(truncateSanitizedExternalContent(detail, FIRECRAWL_SCRAPE_METADATA_MAX_CHARS).text, "web_fetch")}`.trim());
443
480
  }
444
481
  return payloadLocal;
445
482
  }),
@@ -456,7 +493,6 @@ const testing = {
456
493
  postFirecrawlJson,
457
494
  readFirecrawlJsonResponse,
458
495
  resolveEndpoint,
459
- validateFirecrawlBaseUrl,
460
496
  resolveSearchItems
461
497
  };
462
498
  //#endregion
@@ -4,7 +4,7 @@ import { enablePluginInConfig } from "openclaw/plugin-sdk/provider-web-fetch-con
4
4
  //#region extensions/firecrawl/src/firecrawl-fetch-provider.ts
5
5
  let firecrawlClientModulePromise;
6
6
  function loadFirecrawlClientModule() {
7
- firecrawlClientModulePromise ??= import("./firecrawl-client-DZohiNQK.js").then((n) => n.t);
7
+ firecrawlClientModulePromise ??= import("./firecrawl-client-Aw46OXVC.js").then((n) => n.t);
8
8
  return firecrawlClientModulePromise;
9
9
  }
10
10
  function createFirecrawlWebFetchProvider() {
@@ -2,7 +2,7 @@ import { buildFirecrawlFreeWebSearchProviderBase, buildFirecrawlWebSearchProvide
2
2
  import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
3
3
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
4
  //#region extensions/firecrawl/src/firecrawl-search-provider.ts
5
- const loadFirecrawlClientModule$1 = createLazyRuntimeModule(() => import("./firecrawl-client-DZohiNQK.js").then((n) => n.t));
5
+ const loadFirecrawlClientModule$1 = createLazyRuntimeModule(() => import("./firecrawl-client-Aw46OXVC.js").then((n) => n.t));
6
6
  const GenericFirecrawlSearchSchema = {
7
7
  type: "object",
8
8
  properties: {
@@ -25,7 +25,8 @@ function createFirecrawlWebSearchProvider() {
25
25
  createTool: (ctx) => ({
26
26
  description: "Search the web using Firecrawl. Returns structured results with snippets from Firecrawl Search. Use firecrawl_search for Firecrawl-specific knobs like sources or categories.",
27
27
  parameters: GenericFirecrawlSearchSchema,
28
- execute: async (args) => {
28
+ execute: async (args, executionContext) => {
29
+ executionContext?.signal?.throwIfAborted();
29
30
  const { runFirecrawlSearch } = await loadFirecrawlClientModule$1();
30
31
  return await runFirecrawlSearch({
31
32
  cfg: ctx.config,
@@ -33,7 +34,8 @@ function createFirecrawlWebSearchProvider() {
33
34
  count: readPositiveIntegerParam(args, "count", {
34
35
  message: "count must be an integer from 1 to 10",
35
36
  max: 10
36
- })
37
+ }),
38
+ ...executionContext?.signal ? { signal: executionContext.signal } : {}
37
39
  });
38
40
  }
39
41
  })
@@ -43,7 +45,7 @@ function createFirecrawlWebSearchProvider() {
43
45
  //#region extensions/firecrawl/src/firecrawl-free-search-provider.ts
44
46
  let firecrawlClientModulePromise;
45
47
  function loadFirecrawlClientModule() {
46
- firecrawlClientModulePromise ??= import("./firecrawl-client-DZohiNQK.js").then((n) => n.t);
48
+ firecrawlClientModulePromise ??= import("./firecrawl-client-Aw46OXVC.js").then((n) => n.t);
47
49
  return firecrawlClientModulePromise;
48
50
  }
49
51
  function createFirecrawlFreeWebSearchProvider() {
@@ -52,7 +54,8 @@ function createFirecrawlFreeWebSearchProvider() {
52
54
  createTool: (ctx) => ({
53
55
  description: "Search the web using Firecrawl's free hosted starter tier (no API key required). Returns structured results with snippets. Use firecrawl_search for Firecrawl-specific knobs like sources or categories.",
54
56
  parameters: GenericFirecrawlSearchSchema,
55
- execute: async (args) => {
57
+ execute: async (args, executionContext) => {
58
+ executionContext?.signal?.throwIfAborted();
56
59
  const { runFirecrawlSearch } = await loadFirecrawlClientModule();
57
60
  return await runFirecrawlSearch({
58
61
  cfg: ctx.config,
@@ -61,7 +64,8 @@ function createFirecrawlFreeWebSearchProvider() {
61
64
  message: "count must be an integer from 1 to 10",
62
65
  max: 10
63
66
  }),
64
- access: "keyless"
67
+ access: "keyless",
68
+ ...executionContext?.signal ? { signal: executionContext.signal } : {}
65
69
  });
66
70
  }
67
71
  })
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { n as runFirecrawlScrape, r as runFirecrawlSearch } from "./firecrawl-client-DZohiNQK.js";
2
- import { t as createFirecrawlWebFetchProvider } from "./firecrawl-fetch-provider-DXmd_5yB.js";
3
- import { n as createFirecrawlWebSearchProvider, t as createFirecrawlFreeWebSearchProvider } from "./firecrawl-free-search-provider-D_QqmJGK.js";
1
+ import { n as runFirecrawlScrape, r as runFirecrawlSearch } from "./firecrawl-client-Aw46OXVC.js";
2
+ import { t as createFirecrawlWebFetchProvider } from "./firecrawl-fetch-provider-CYViV-li.js";
3
+ import { n as createFirecrawlWebSearchProvider, t as createFirecrawlFreeWebSearchProvider } from "./firecrawl-free-search-provider-nqgr2mhw.js";
4
4
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
5
5
  import { optionalStringEnum } from "openclaw/plugin-sdk/channel-actions";
6
6
  import { jsonResult, readNonNegativeIntegerParam, readPositiveIntegerParam, readStringArrayParam, readStringParam } from "openclaw/plugin-sdk/provider-web-search";
@@ -33,9 +33,11 @@ function createFirecrawlScrapeTool(api) {
33
33
  return {
34
34
  name: "firecrawl_scrape",
35
35
  label: "Firecrawl Scrape",
36
+ resultContentSource: "network",
36
37
  description: "Scrape a page using Firecrawl v2/scrape. Useful for JS-heavy or bot-protected pages where plain web_fetch is weak.",
37
38
  parameters: FirecrawlScrapeToolSchema,
38
- execute: async (_toolCallId, rawParams) => {
39
+ execute: async (_toolCallId, rawParams, signal) => {
40
+ signal?.throwIfAborted();
39
41
  const url = readStringParam(rawParams, "url", { required: true });
40
42
  const extractMode = readStringParam(rawParams, "extractMode") === "text" ? "text" : "markdown";
41
43
  const maxChars = readPositiveIntegerParam(rawParams, "maxChars");
@@ -54,7 +56,8 @@ function createFirecrawlScrapeTool(api) {
54
56
  maxAgeMs,
55
57
  proxy,
56
58
  storeInCache,
57
- timeoutSeconds
59
+ timeoutSeconds,
60
+ ...signal ? { signal } : {}
58
61
  }));
59
62
  }
60
63
  };
@@ -85,9 +88,11 @@ function createFirecrawlSearchTool(api) {
85
88
  return {
86
89
  name: "firecrawl_search",
87
90
  label: "Firecrawl Search",
91
+ resultContentSource: "network",
88
92
  description: "Search the web using Firecrawl v2/search. Supports includeDomains/excludeDomains filtering and tbs time filters (day/week/month/year). Can optionally include scraped content from result pages.",
89
93
  parameters: FirecrawlSearchToolSchema,
90
- execute: async (_toolCallId, rawParams) => {
94
+ execute: async (_toolCallId, rawParams, signal) => {
95
+ signal?.throwIfAborted();
91
96
  const query = readStringParam(rawParams, "query", { required: true });
92
97
  const count = readPositiveIntegerParam(rawParams, "count", {
93
98
  max: 100,
@@ -114,7 +119,8 @@ function createFirecrawlSearchTool(api) {
114
119
  tbs,
115
120
  location,
116
121
  country,
117
- scrapeResults
122
+ scrapeResults,
123
+ ...signal ? { signal } : {}
118
124
  }));
119
125
  }
120
126
  };
@@ -1,2 +1,2 @@
1
- import { t as createFirecrawlWebFetchProvider } from "./firecrawl-fetch-provider-DXmd_5yB.js";
1
+ import { t as createFirecrawlWebFetchProvider } from "./firecrawl-fetch-provider-CYViV-li.js";
2
2
  export { createFirecrawlWebFetchProvider };
@@ -1,2 +1,2 @@
1
- import { n as createFirecrawlWebSearchProvider, t as createFirecrawlFreeWebSearchProvider } from "./firecrawl-free-search-provider-D_QqmJGK.js";
1
+ import { n as createFirecrawlWebSearchProvider, t as createFirecrawlFreeWebSearchProvider } from "./firecrawl-free-search-provider-nqgr2mhw.js";
2
2
  export { createFirecrawlFreeWebSearchProvider, createFirecrawlWebSearchProvider };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/firecrawl-plugin",
3
- "version": "2026.7.2-beta.7",
3
+ "version": "2026.8.1-beta.2",
4
4
  "description": "OpenClaw Firecrawl plugin.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,10 +21,10 @@
21
21
  "minHostVersion": ">=2026.6.8"
22
22
  },
23
23
  "compat": {
24
- "pluginApi": ">=2026.7.2-beta.7"
24
+ "pluginApi": ">=2026.8.1-beta.2"
25
25
  },
26
26
  "build": {
27
- "openclawVersion": "2026.7.2-beta.7",
27
+ "openclawVersion": "2026.8.1-beta.2",
28
28
  "bundledDist": false
29
29
  },
30
30
  "release": {
@@ -41,7 +41,7 @@
41
41
  "README.md"
42
42
  ],
43
43
  "peerDependencies": {
44
- "openclaw": ">=2026.7.2-beta.7"
44
+ "openclaw": ">=2026.8.1-beta.2"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "openclaw": {