@brightdata/brightdata-plugin 1.0.0

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.
@@ -0,0 +1,69 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { jsonResult, readNumberParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
3
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime";
4
+ import { runBrightDataScrape } from "./brightdata-client.js";
5
+
6
+ function optionalStringEnum<const T extends readonly string[]>(
7
+ values: T,
8
+ options: { description?: string } = {},
9
+ ) {
10
+ return Type.Optional(
11
+ Type.Unsafe<T[number]>({
12
+ type: "string",
13
+ enum: [...values],
14
+ ...options,
15
+ }),
16
+ );
17
+ }
18
+
19
+ const BrightDataScrapeToolSchema = Type.Object(
20
+ {
21
+ url: Type.String({ description: "HTTP or HTTPS URL to scrape via Bright Data." }),
22
+ extractMode: optionalStringEnum(["markdown", "text", "html"] as const, {
23
+ description: 'Extraction mode ("markdown", "text", or "html"). Default: markdown.',
24
+ }),
25
+ maxChars: Type.Optional(
26
+ Type.Number({
27
+ description: "Maximum characters to return.",
28
+ minimum: 100,
29
+ }),
30
+ ),
31
+ timeoutSeconds: Type.Optional(
32
+ Type.Number({
33
+ description: "Timeout in seconds for the Bright Data scrape request.",
34
+ minimum: 1,
35
+ }),
36
+ ),
37
+ },
38
+ { additionalProperties: false },
39
+ );
40
+
41
+ export function createBrightDataScrapeTool(api: OpenClawPluginApi) {
42
+ return {
43
+ name: "brightdata_scrape",
44
+ label: "Bright Data Scrape",
45
+ description:
46
+ "Fetch and extract a page directly through Bright Data Web Unlocker. Use this tool when you specifically want Bright Data-backed web fetching, including bot-protected pages.",
47
+ parameters: BrightDataScrapeToolSchema,
48
+ execute: async (_toolCallId: string, rawParams: Record<string, unknown>) => {
49
+ const url = readStringParam(rawParams, "url", { required: true });
50
+ const extractModeRaw = readStringParam(rawParams, "extractMode");
51
+ const extractMode =
52
+ extractModeRaw === "text" || extractModeRaw === "html" ? extractModeRaw : "markdown";
53
+ const maxChars = readNumberParam(rawParams, "maxChars", { integer: true });
54
+ const timeoutSeconds = readNumberParam(rawParams, "timeoutSeconds", {
55
+ integer: true,
56
+ });
57
+
58
+ return jsonResult(
59
+ await runBrightDataScrape({
60
+ pluginConfig: api.pluginConfig,
61
+ url,
62
+ extractMode,
63
+ maxChars,
64
+ timeoutSeconds,
65
+ }),
66
+ );
67
+ },
68
+ };
69
+ }
@@ -0,0 +1,76 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import {
3
+ enablePluginInConfig,
4
+ resolveProviderWebSearchPluginConfig,
5
+ setProviderWebSearchPluginConfigValue,
6
+ type WebSearchProviderPlugin,
7
+ } from "openclaw/plugin-sdk/provider-web-search";
8
+ import { runBrightDataSearch } from "./brightdata-client.js";
9
+
10
+ const GenericBrightDataSearchSchema = Type.Object(
11
+ {
12
+ query: Type.String({ description: "Search query string." }),
13
+ count: Type.Optional(
14
+ Type.Number({
15
+ description: "Number of results to return (1-10).",
16
+ minimum: 1,
17
+ maximum: 10,
18
+ }),
19
+ ),
20
+ },
21
+ { additionalProperties: false },
22
+ );
23
+
24
+ function getScopedCredentialValue(searchConfig?: Record<string, unknown>): unknown {
25
+ const scoped = searchConfig?.brightdata;
26
+ if (!scoped || typeof scoped !== "object" || Array.isArray(scoped)) {
27
+ return undefined;
28
+ }
29
+ return (scoped as Record<string, unknown>).apiKey;
30
+ }
31
+
32
+ function setScopedCredentialValue(
33
+ searchConfigTarget: Record<string, unknown>,
34
+ value: unknown,
35
+ ): void {
36
+ const scoped = searchConfigTarget.brightdata;
37
+ if (!scoped || typeof scoped !== "object" || Array.isArray(scoped)) {
38
+ searchConfigTarget.brightdata = { apiKey: value };
39
+ return;
40
+ }
41
+ (scoped as Record<string, unknown>).apiKey = value;
42
+ }
43
+
44
+ export function createBrightDataWebSearchProvider(): WebSearchProviderPlugin {
45
+ return {
46
+ id: "brightdata",
47
+ label: "Bright Data Search",
48
+ hint: "SERP results via Google/Bing/Yandex with bot bypass",
49
+ envVars: ["BRIGHTDATA_API_TOKEN"],
50
+ placeholder: "...",
51
+ signupUrl: "https://brightdata.com/",
52
+ docsUrl: "https://docs.openclaw.ai/tools/brightdata",
53
+ autoDetectOrder: 65,
54
+ credentialPath: "plugins.entries.brightdata.config.webSearch.apiKey",
55
+ inactiveSecretPaths: ["plugins.entries.brightdata.config.webSearch.apiKey"],
56
+ getCredentialValue: getScopedCredentialValue,
57
+ setCredentialValue: setScopedCredentialValue,
58
+ getConfiguredCredentialValue: (config) =>
59
+ resolveProviderWebSearchPluginConfig(config, "brightdata")?.apiKey,
60
+ setConfiguredCredentialValue: (configTarget, value) => {
61
+ setProviderWebSearchPluginConfigValue(configTarget, "brightdata", "apiKey", value);
62
+ },
63
+ applySelectionConfig: (config) => enablePluginInConfig(config, "brightdata").config,
64
+ createTool: (ctx) => ({
65
+ description:
66
+ "Search the web using Bright Data. Returns structured search results. Use brightdata_search for Bright Data-specific knobs like engine, cursor, or geo_location.",
67
+ parameters: GenericBrightDataSearchSchema,
68
+ execute: async (args) =>
69
+ await runBrightDataSearch({
70
+ pluginConfig: ctx.searchConfig ? { webSearch: ctx.searchConfig } : undefined,
71
+ query: typeof args.query === "string" ? args.query : "",
72
+ count: typeof args.count === "number" ? args.count : undefined,
73
+ }),
74
+ }),
75
+ };
76
+ }
@@ -0,0 +1,88 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { jsonResult, readNumberParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
3
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime";
4
+ import { runBrightDataSearch } from "./brightdata-client.js";
5
+
6
+ function optionalStringEnum<const T extends readonly string[]>(
7
+ values: T,
8
+ options: { description?: string } = {},
9
+ ) {
10
+ return Type.Optional(
11
+ Type.Unsafe<T[number]>({
12
+ type: "string",
13
+ enum: [...values],
14
+ ...options,
15
+ }),
16
+ );
17
+ }
18
+
19
+ const BrightDataSearchToolSchema = Type.Object(
20
+ {
21
+ query: Type.String({ description: "Search query string." }),
22
+ engine: optionalStringEnum(["google", "bing", "yandex"] as const, {
23
+ description: 'Search engine ("google", "bing", or "yandex"). Default: google.',
24
+ }),
25
+ count: Type.Optional(
26
+ Type.Number({
27
+ description: "Number of results to return (1-10).",
28
+ minimum: 1,
29
+ maximum: 10,
30
+ }),
31
+ ),
32
+ cursor: Type.Optional(
33
+ Type.String({
34
+ description: "Pagination cursor for the next page.",
35
+ }),
36
+ ),
37
+ geo_location: Type.Optional(
38
+ Type.String({
39
+ description: '2-letter country code for geo-targeted results, for example "us" or "uk".',
40
+ minLength: 2,
41
+ maxLength: 2,
42
+ }),
43
+ ),
44
+ timeoutSeconds: Type.Optional(
45
+ Type.Number({
46
+ description: "Timeout in seconds for the Bright Data Search request.",
47
+ minimum: 1,
48
+ }),
49
+ ),
50
+ },
51
+ { additionalProperties: false },
52
+ );
53
+
54
+ export function createBrightDataSearchTool(api: OpenClawPluginApi) {
55
+ return {
56
+ name: "brightdata_search",
57
+ label: "Bright Data Search",
58
+ description:
59
+ "Search the web using Bright Data SERP scraping. Supports Google, Bing, and Yandex with pagination and geo targeting.",
60
+ parameters: BrightDataSearchToolSchema,
61
+ execute: async (_toolCallId: string, rawParams: Record<string, unknown>) => {
62
+ const query = readStringParam(rawParams, "query", { required: true });
63
+ const engineRaw = readStringParam(rawParams, "engine");
64
+ const engine =
65
+ engineRaw === "google" || engineRaw === "bing" || engineRaw === "yandex"
66
+ ? engineRaw
67
+ : undefined;
68
+ const count = readNumberParam(rawParams, "count", { integer: true });
69
+ const cursor = readStringParam(rawParams, "cursor");
70
+ const geoLocation = readStringParam(rawParams, "geo_location");
71
+ const timeoutSeconds = readNumberParam(rawParams, "timeoutSeconds", {
72
+ integer: true,
73
+ });
74
+
75
+ return jsonResult(
76
+ await runBrightDataSearch({
77
+ pluginConfig: api.pluginConfig,
78
+ query,
79
+ engine,
80
+ count,
81
+ cursor,
82
+ geoLocation,
83
+ timeoutSeconds,
84
+ }),
85
+ );
86
+ },
87
+ };
88
+ }