web-search-plus-plugin 1.3.0 → 1.3.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/index.ts +57 -40
- package/openclaw.plugin.json +2 -1
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
2
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import {
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
@@ -32,6 +32,46 @@ function loadEnvFile(envPath: string): Record<string, string> {
|
|
|
32
32
|
return env;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function runPython(
|
|
36
|
+
args: string[],
|
|
37
|
+
env: NodeJS.ProcessEnv,
|
|
38
|
+
timeoutMs: number,
|
|
39
|
+
): Promise<{ stdout: string; stderr: string; code: number }> {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
const child = spawn("python3", args, { env, shell: false });
|
|
42
|
+
let stdout = "";
|
|
43
|
+
let stderr = "";
|
|
44
|
+
let settled = false;
|
|
45
|
+
|
|
46
|
+
const timer = setTimeout(() => {
|
|
47
|
+
if (!settled) {
|
|
48
|
+
settled = true;
|
|
49
|
+
child.kill();
|
|
50
|
+
resolve({ stdout: "", stderr: "Search timed out", code: 1 });
|
|
51
|
+
}
|
|
52
|
+
}, timeoutMs);
|
|
53
|
+
|
|
54
|
+
child.stdout.on("data", (d: Buffer) => { stdout += d.toString(); });
|
|
55
|
+
child.stderr.on("data", (d: Buffer) => { stderr += d.toString(); });
|
|
56
|
+
|
|
57
|
+
child.on("close", (code: number | null) => {
|
|
58
|
+
if (!settled) {
|
|
59
|
+
settled = true;
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
resolve({ stdout, stderr, code: code ?? 1 });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
child.on("error", (err: Error) => {
|
|
66
|
+
if (!settled) {
|
|
67
|
+
settled = true;
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
resolve({ stdout: "", stderr: err.message, code: 1 });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
35
75
|
const PLUGIN_DIR = getPluginDir();
|
|
36
76
|
const scriptPath = path.join(PLUGIN_DIR, "scripts", "search.py");
|
|
37
77
|
|
|
@@ -43,7 +83,7 @@ export default definePluginEntry({
|
|
|
43
83
|
register(api) {
|
|
44
84
|
// Bridge OpenClaw config fields to env vars expected by search.py
|
|
45
85
|
const configEnv: Record<string, string> = {};
|
|
46
|
-
const pluginConfig: Record<string, string> = (api
|
|
86
|
+
const pluginConfig: Record<string, string> = (api.pluginConfig ?? {}) as Record<string, string>;
|
|
47
87
|
const configKeyMap: Record<string, string> = {
|
|
48
88
|
serperApiKey: "SERPER_API_KEY",
|
|
49
89
|
tavilyApiKey: "TAVILY_API_KEY",
|
|
@@ -139,6 +179,12 @@ export default definePluginEntry({
|
|
|
139
179
|
exclude_domains?: string[];
|
|
140
180
|
},
|
|
141
181
|
) {
|
|
182
|
+
if (!fs.existsSync(scriptPath)) {
|
|
183
|
+
return {
|
|
184
|
+
content: [{ type: "text", text: `Search failed: script not found at ${scriptPath}` }],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
142
188
|
const args = [scriptPath, "--query", params.query, "--compact"];
|
|
143
189
|
|
|
144
190
|
if (params.provider && params.provider !== "auto") {
|
|
@@ -146,10 +192,7 @@ export default definePluginEntry({
|
|
|
146
192
|
}
|
|
147
193
|
|
|
148
194
|
if (typeof params.count === "number" && Number.isFinite(params.count)) {
|
|
149
|
-
args.push(
|
|
150
|
-
"--max-results",
|
|
151
|
-
String(Math.max(1, Math.floor(params.count))),
|
|
152
|
-
);
|
|
195
|
+
args.push("--max-results", String(Math.max(1, Math.floor(params.count))));
|
|
153
196
|
}
|
|
154
197
|
|
|
155
198
|
if (params.depth && params.depth !== "normal") {
|
|
@@ -179,44 +222,18 @@ export default definePluginEntry({
|
|
|
179
222
|
}
|
|
180
223
|
const childEnv = { ...process.env, ...configEnv, ...fileEnv };
|
|
181
224
|
|
|
182
|
-
|
|
183
|
-
const child = spawnSync("python3", args, {
|
|
184
|
-
timeout: 75000,
|
|
185
|
-
env: childEnv,
|
|
186
|
-
shell: false,
|
|
187
|
-
encoding: "utf8",
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (child.error) {
|
|
191
|
-
return {
|
|
192
|
-
content: [
|
|
193
|
-
{ type: "text", text: `Search failed: ${child.error.message}` },
|
|
194
|
-
],
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (child.status !== 0) {
|
|
199
|
-
const stderr = child.stderr?.trim() || "Unknown error";
|
|
200
|
-
return {
|
|
201
|
-
content: [
|
|
202
|
-
{
|
|
203
|
-
type: "text",
|
|
204
|
-
text: `Search failed (exit ${child.status}): ${stderr}`,
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
};
|
|
208
|
-
}
|
|
225
|
+
const result = await runPython(args, childEnv, 75000);
|
|
209
226
|
|
|
227
|
+
if (result.code !== 0) {
|
|
228
|
+
const stderr = result.stderr.trim() || "Unknown error";
|
|
210
229
|
return {
|
|
211
|
-
content: [{ type: "text", text:
|
|
212
|
-
};
|
|
213
|
-
} catch (err: any) {
|
|
214
|
-
return {
|
|
215
|
-
content: [
|
|
216
|
-
{ type: "text", text: `Search failed: ${err?.message ?? err}` },
|
|
217
|
-
],
|
|
230
|
+
content: [{ type: "text", text: `Search failed (exit ${result.code}): ${stderr}` }],
|
|
218
231
|
};
|
|
219
232
|
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
content: [{ type: "text", text: result.stdout.trim() || "{}" }],
|
|
236
|
+
};
|
|
220
237
|
},
|
|
221
238
|
},
|
|
222
239
|
{ optional: true },
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "web-search-plus-plugin",
|
|
3
3
|
"name": "Web Search Plus",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.2",
|
|
5
5
|
"description": "Multi-provider web search (Serper/Google, Tavily, Querit/Multilingual AI Search, Exa/Neural+Deep, Perplexity, You.com, SearXNG) with intelligent auto-routing",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"serperApiKey": { "label": "Serper API Key", "placeholder": "sk-...", "sensitive": true },
|
|
22
22
|
"tavilyApiKey": { "label": "Tavily API Key", "placeholder": "tvly-...", "sensitive": true },
|
|
23
23
|
"queritApiKey": { "label": "Querit API Key", "placeholder": "querit-sk-...", "sensitive": true },
|
|
24
|
+
"queritApiKey": { "label": "Querit API Key", "placeholder": "querit-sk-...", "sensitive": true },
|
|
24
25
|
"exaApiKey": { "label": "Exa API Key", "placeholder": "exa-...", "sensitive": true },
|
|
25
26
|
"perplexityApiKey": { "label": "Perplexity API Key", "placeholder": "pplx-...", "sensitive": true },
|
|
26
27
|
"kilocodeApiKey": { "label": "Kilo Gateway API Key", "placeholder": "...", "sensitive": true },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web-search-plus-plugin",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "OpenClaw plugin: multi-provider web search (Serper/Google, Tavily, Querit/Multilingual AI Search, Exa/Neural+Deep, Perplexity, You.com, SearXNG) with intelligent auto-routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|