Initial commit: workspace setup with skills, memory, config
This commit is contained in:
41
skills/searxng/SKILL.md
Normal file
41
skills/searxng/SKILL.md
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
name: searxng
|
||||
description: Local SearXNG web search integration for OpenClaw
|
||||
metadata:
|
||||
openclaw:
|
||||
os: ["darwin", "linux", "win32"]
|
||||
---
|
||||
|
||||
# SearXNG Search Skill
|
||||
|
||||
This skill provides web search capabilities using a locally hosted SearXNG instance.
|
||||
|
||||
## Configuration
|
||||
|
||||
The skill connects to your local SearXNG instance at `http://10.0.0.8:8888/` by default.
|
||||
|
||||
## Usage
|
||||
|
||||
Use the `searx_search` tool to perform web searches:
|
||||
|
||||
```javascript
|
||||
// Basic search
|
||||
await searx_search({ query: "latest AI developments" });
|
||||
|
||||
// Search with more results
|
||||
await searx_search({ query: "quantum computing", count: 10 });
|
||||
|
||||
// Search with language preference
|
||||
await searx_search({ query: "bonjour", lang: "fr" });
|
||||
```
|
||||
|
||||
## Tool: searx_search
|
||||
|
||||
- `query` (required): The search query string
|
||||
- `count` (optional): Number of results to return (1-20, default: 5)
|
||||
- `lang` (optional): Language code for search results (e.g., "en", "de", "fr")
|
||||
- `safesearch` (optional): Safe search filter (0=off, 1=moderate, 2=strict, default: 0)
|
||||
|
||||
## Example Results
|
||||
|
||||
Results are returned in a structured format with title, URL, content snippet, and source engine information.
|
||||
92
skills/searxng/searx-search.js
Normal file
92
skills/searxng/searx-search.js
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* SearXNG Search Tool
|
||||
*
|
||||
* Provides web search via local SearXNG instance at http://10.0.0.8:8888/
|
||||
*/
|
||||
|
||||
const SEARXNG_BASE_URL = process.env.SEARXNG_URL || 'http://10.0.0.8:8888';
|
||||
|
||||
async function searxSearch(args) {
|
||||
const { query, count = 5, lang = 'en', safesearch = 0 } = args;
|
||||
|
||||
if (!query || typeof query !== 'string') {
|
||||
throw new Error('Missing required parameter: query');
|
||||
}
|
||||
|
||||
// Build the search URL
|
||||
const searchParams = new URLSearchParams({
|
||||
q: query,
|
||||
format: 'json',
|
||||
language: lang,
|
||||
safesearch: String(safesearch),
|
||||
});
|
||||
|
||||
const url = `${SEARXNG_BASE_URL}/search?${searchParams.toString()}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'OpenClaw-SearXNG-Skill/1.0',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`SearXNG returned HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Transform SearXNG results to a standard format
|
||||
const results = (data.results || []).slice(0, Math.min(count, 20)).map(result => ({
|
||||
title: result.title || '',
|
||||
url: result.url || '',
|
||||
snippet: result.content || '',
|
||||
engine: result.engine || 'unknown',
|
||||
engines: result.engines || [],
|
||||
thumbnail: result.thumbnail || null,
|
||||
publishedDate: result.publishedDate || null,
|
||||
}));
|
||||
|
||||
// Include infoboxes if available
|
||||
const infoboxes = (data.infoboxes || []).map(box => ({
|
||||
title: box.infobox || box.title || '',
|
||||
content: box.content || '',
|
||||
image: box.img_src || null,
|
||||
urls: box.urls || [],
|
||||
engine: box.engine || 'wikipedia',
|
||||
}));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
query: data.query || query,
|
||||
resultCount: results.length,
|
||||
totalResults: data.number_of_results || results.length,
|
||||
results,
|
||||
infoboxes: infoboxes.length > 0 ? infoboxes : undefined,
|
||||
unresponsiveEngines: data.unresponsive_engines || [],
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message,
|
||||
query,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// CLI execution
|
||||
if (require.main === module) {
|
||||
const args = JSON.parse(process.argv[2] || '{}');
|
||||
searxSearch(args).then(result => {
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
}).catch(error => {
|
||||
console.error(JSON.stringify({ success: false, error: error.message }));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { searxSearch };
|
||||
42
skills/searxng/tools.json
Normal file
42
skills/searxng/tools.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"name": "searx_search",
|
||||
"description": "Search the web using local SearXNG instance at http://10.0.0.8:8888",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The search query to perform"
|
||||
},
|
||||
"count": {
|
||||
"type": "integer",
|
||||
"description": "Number of results to return (1-20)",
|
||||
"default": 5,
|
||||
"minimum": 1,
|
||||
"maximum": 20
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "Language code for search results (e.g., 'en', 'de', 'fr')",
|
||||
"default": "en"
|
||||
},
|
||||
"safesearch": {
|
||||
"type": "integer",
|
||||
"description": "Safe search level: 0=off, 1=moderate, 2=strict",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
},
|
||||
"entry": {
|
||||
"type": "node",
|
||||
"path": "searx-search.js",
|
||||
"args": ["{{args}}"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user