@jzakirov/internet-search 0.2.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jamil Zakirov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # internet-search
2
+
3
+ Web search for [OpenClaw](https://openclaw.dev) agents, backed by a self-hosted [SearXNG](https://searxng.github.io/searxng/) instance.
4
+
5
+ Registers a single `internet-search` tool with category routing for general, news, academic, and social results.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ openclaw plugins install @jzakirov/internet-search
11
+ ```
12
+
13
+ Or from a local path (development):
14
+
15
+ ```bash
16
+ openclaw plugins install ./internet-search
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ Add to `openclaw.json` under `plugins.entries.internet-search.config`:
22
+
23
+ ```json
24
+ {
25
+ "searxngUrl": "https://search.example.com/",
26
+ "searxngToken": "optional-bearer-token"
27
+ }
28
+ ```
29
+
30
+ | Field | Required | Description |
31
+ |----------------|----------|-----------------------------------------------|
32
+ | `searxngUrl` | Yes | Base URL of your SearXNG instance |
33
+ | `searxngToken` | No | Token for SearXNG instances that require auth |
34
+
35
+ ## Replacing the built-in web search
36
+
37
+ To use this plugin as the sole web search (disabling the default Brave/Perplexity `web_search` tool), set `tools.web.search.enabled` to `false`:
38
+
39
+ ```json5
40
+ // openclaw.json
41
+ {
42
+ "tools": {
43
+ "web": {
44
+ "search": {
45
+ "enabled": false // disable built-in web_search tool
46
+ }
47
+ }
48
+ },
49
+ "plugins": {
50
+ "allow": ["internet-search"],
51
+ "entries": {
52
+ "internet-search": {
53
+ "enabled": true,
54
+ "config": {
55
+ "searxngUrl": "https://search.example.com/",
56
+ "searxngToken": "your-token"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ If you only want to add `internet-search` alongside the built-in tool (rather than replace it), omit the `tools.web.search.enabled` change.
65
+
66
+ ## Tool: `internet-search`
67
+
68
+ ```
69
+ internet-search(query, count?, category?)
70
+ ```
71
+
72
+ | Parameter | Type | Default | Description |
73
+ |------------|--------|-----------|--------------------------------------------------|
74
+ | `query` | string | — | Search query |
75
+ | `count` | number | 5 | Number of results to return (1–20, capped at 10) |
76
+ | `category` | string | `general` | Routing category (see below) |
77
+
78
+ ### Categories
79
+
80
+ | Value | Routes to |
81
+ |------------|--------------------------------|
82
+ | `general` | All configured SearXNG engines |
83
+ | `news` | SearXNG news category |
84
+ | `academic` | arXiv, Google Scholar, PubMed |
85
+ | `social` | Reddit |
86
+
87
+ ### Response
88
+
89
+ ```json
90
+ {
91
+ "results": [
92
+ {
93
+ "title": "Example result",
94
+ "url": "https://example.com/article",
95
+ "snippet": "A short excerpt from the page..."
96
+ }
97
+ ]
98
+ }
99
+ ```
100
+
101
+ HTML tags are stripped from snippets automatically.
102
+
103
+ ## Requirements
104
+
105
+ - OpenClaw ≥ 2025.0.0
106
+ - A running SearXNG instance with JSON format enabled (`search.formats: [json]` in SearXNG config)
107
+
108
+ ## License
109
+
110
+ MIT
package/index.ts ADDED
@@ -0,0 +1,80 @@
1
+ // internet-search plugin: SearXNG-backed search tool
2
+
3
+ function stripHtml(input: string) {
4
+ return input
5
+ .replace(/<[^>]*>/g, " ")
6
+ .replace(/\s+/g, " ")
7
+ .trim();
8
+ }
9
+
10
+ // Maps category → SearXNG query params.
11
+ // "general" uses all configured engines (no override).
12
+ // Others route to specialist engines for better signal.
13
+ const CATEGORY_ROUTING: Record<string, { categories?: string; engines?: string }> = {
14
+ general: {},
15
+ news: { categories: "news" },
16
+ academic: { engines: "arxiv,google scholar,pubmed" },
17
+ social: { engines: "reddit" },
18
+ };
19
+
20
+ export default function (api: any) {
21
+ api.registerTool({
22
+ name: "internet-search",
23
+ description:
24
+ "Search the web using a SearXNG instance. Use this to gather news and learn new information. " +
25
+ "Use category='news' for recent events, 'academic' for research papers, 'social' for opinions/discussions.",
26
+ parameters: {
27
+ type: "object",
28
+ additionalProperties: false,
29
+ properties: {
30
+ query: { type: "string" },
31
+ count: { type: "number", minimum: 1, maximum: 20, default: 5 },
32
+ category: {
33
+ type: "string",
34
+ enum: ["general", "news", "academic", "social"],
35
+ default: "general",
36
+ description:
37
+ "general=broad web search (default); news=recent news & events; " +
38
+ "academic=arxiv/Scholar/PubMed; social=Reddit discussions"
39
+ }
40
+ },
41
+ required: ["query"]
42
+ },
43
+ async execute(_id: string, params: any, signal: AbortSignal) {
44
+ const baseUrl = String(api.config?.searxngUrl ?? "").trim();
45
+ if (!baseUrl) {
46
+ throw new Error("searxngUrl is required in the internet-search plugin config");
47
+ }
48
+ const token = String(api.config?.searxngToken ?? "").trim();
49
+
50
+ const q = String(params.query ?? "").trim();
51
+ const count = Math.min(10, Math.max(1, Number(params.count ?? 5)));
52
+ const category = String(params.category ?? "general").trim();
53
+ const routing = CATEGORY_ROUTING[category] ?? {};
54
+
55
+ const url = new URL("/search", baseUrl);
56
+ url.searchParams.set("q", q);
57
+ url.searchParams.set("format", "json");
58
+ if (token) url.searchParams.set("token", token);
59
+ if (routing.categories) url.searchParams.set("categories", routing.categories);
60
+ if (routing.engines) url.searchParams.set("engines", routing.engines);
61
+
62
+ const res = await fetch(url.toString(), { signal });
63
+ if (!res.ok) throw new Error(`SearXNG HTTP ${res.status}`);
64
+
65
+ const data: any = await res.json();
66
+ const results = Array.isArray(data?.results) ? data.results : [];
67
+ const mapped = results.slice(0, count).map((r: any) => ({
68
+ title: String(r?.title ?? "").trim(),
69
+ url: String(r?.url ?? "").trim(),
70
+ snippet: stripHtml(String(r?.content ?? r?.snippet ?? ""))
71
+ }));
72
+
73
+ return {
74
+ content: [
75
+ { type: "text", text: JSON.stringify({ results: mapped }, null, 2) }
76
+ ]
77
+ };
78
+ }
79
+ });
80
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "id": "internet-search",
3
+ "kind": "web-search",
4
+ "name": "Internet Search",
5
+ "description": "Web search via SearXNG. Registers the internet-search tool.",
6
+ "version": "0.2.0",
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "searxngUrl": { "type": "string" },
12
+ "searxngToken": { "type": "string" }
13
+ },
14
+ "required": ["searxngUrl"]
15
+ },
16
+ "uiHints": {
17
+ "searxngUrl": { "label": "SearXNG URL", "placeholder": "https://search.example.com/" },
18
+ "searxngToken": { "label": "SearXNG Token", "sensitive": true }
19
+ }
20
+ }
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@jzakirov/internet-search",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "SearXNG-backed internet search plugin for OpenClaw",
6
+ "license": "MIT",
7
+ "keywords": ["openclaw", "openclaw-plugin", "searxng", "search", "internet-search", "web-search"],
8
+ "files": ["index.ts", "openclaw.plugin.json", "skills", "README.md", "LICENSE"],
9
+ "peerDependencies": {
10
+ "openclaw": ">=2025.0.0"
11
+ },
12
+ "openclaw": {
13
+ "extensions": ["./index.ts"]
14
+ }
15
+ }
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: internet-search
3
+ description: "How to use the internet-search tool effectively — category routing, query formulation, and multi-search strategies. Use whenever web search is needed: current events, research papers, community opinions, or any information beyond training knowledge."
4
+ ---
5
+
6
+ # Internet Search
7
+
8
+ Queries a self-hosted SearXNG instance aggregating multiple search engines.
9
+
10
+ ## Category Routing
11
+
12
+ Always set `category` based on the nature of the query.
13
+
14
+ | Category | When to use | Engines |
15
+ |------------|---------------------------------------------------------------------|--------------------------------------------------|
16
+ | `general` | Default. Facts, how-tos, products, people, broad web. | Brave, Bing, DDG, Startpage, Qwant, Wikipedia… |
17
+ | `news` | Recent events, breaking news, anything time-sensitive. | Bing News, DDG News |
18
+ | `academic` | Research papers, studies, medical literature, preprints. | arXiv, Google Scholar, PubMed |
19
+ | `social` | Opinions, community recommendations, "what do people think about X".| Reddit |
20
+
21
+ ## Query Formulation
22
+
23
+ Write queries as a search engine expects — keywords, not full sentences:
24
+
25
+ ```
26
+ # Bad
27
+ "what is the fastest async runtime for rust"
28
+
29
+ # Good
30
+ "rust async runtime benchmarks 2025"
31
+ ```
32
+
33
+ - **news**: include a time anchor — `"OpenAI o3 release 2025"` not just `"OpenAI o3"`
34
+ - **academic**: use field terminology — `"transformer attention efficiency survey"`
35
+ - **social**: phrase as community search — `"reddit best mechanical keyboard 2025"`
36
+
37
+ ## Count
38
+
39
+ - `count=5` (default) — sufficient for most tasks
40
+ - `count=10` — comparing many options, checking consensus
41
+ - `count=3` — quick fact checks
42
+
43
+ ## Multi-Search Strategy
44
+
45
+ Fire multiple focused searches rather than one broad one:
46
+
47
+ ```
48
+ # Bad: one vague search
49
+ internet-search("best way to deploy Node.js")
50
+
51
+ # Good: three targeted searches
52
+ internet-search("Node.js Docker deployment best practices 2025")
53
+ internet-search("Node.js PM2 vs Docker production", category="social")
54
+ internet-search("Node.js zero-downtime deployment strategies")
55
+ ```
56
+
57
+ Combine `general` + `social` for factual + sentiment coverage:
58
+
59
+ ```
60
+ internet-search("Bun runtime performance vs Node.js benchmarks")
61
+ internet-search("Bun runtime production experience", category="social")
62
+ ```
63
+
64
+ ## When NOT to Use
65
+
66
+ - Things you already know with high confidence
67
+ - Stable API docs or well-known syntax — use training knowledge
68
+ - Repeating a search that already answered the question
69
+
70
+ ## Common Mistakes
71
+
72
+ | Mistake | Fix |
73
+ |-------------------------------------------|-----------------------------------------------|
74
+ | `general` for a research paper | Use `category="academic"` |
75
+ | Searching "what happened today" | Use `category="news"` with a specific topic |
76
+ | One broad search for a multi-part question| Break into 2–3 focused searches |
77
+ | Repeating a failed search verbatim | Rephrase with different keywords |
78
+ | `count=20` for a simple fact | Default `count=5` is almost always enough |