Skill: chyher/irene-tavily (version 1.0.0)

--- name: tavily-search description: "使用Tavily API进行智能网络搜索。无需信用卡，每月1000次免费查询。支持AI增强的搜索结果和深度研究模式。Use when: 需要高质量搜索结果、学术研究、或不想绑定信用卡的场景。" homepage: https://tavily.com metadata: { "openclaw": { "emoji": "🔍", "requires": { "bins": ["curl", "python3"] } }, } --- # Tavily Search - 智能搜索工具 基于Tavily API的网络搜索skill，提供高质量的AI增强搜索结果。 ## Features - ✅ **无需信用卡** - 每月1000次免费查询 - 🤖 **AI增强** - 自动提取关键信息，生成摘要 - 🔬 **深度研究模式** - 多源综合分析 - 📚 **学术友好** - 适合研究和信息收集 - 🌐 **多语言支持** - 中英文搜索优化 ## Setup ### 1. 获取API Key 1. 访问 https://tavily.com/ 2. 注册账号（邮箱即可，无需绑卡） 3. 在Dashboard复制API Key ### 2. 配置OpenClaw ```bash # 设置环境变量 export TAVILY_API_KEY="tvly-..." # 或者写入配置文件 echo 'TAVILY_API_KEY=tvly-...' >> ~/.openclaw/.env ``` ## Usage ### 基础搜索 ```bash # 搜索最新AI新闻 python3 ~/.openclaw/skills/tavily-search/scripts/search.py "AI artificial intelligence news today" # 中文搜索 python3 ~/.openclaw/skills/tavily-search/scripts/search.py "人工智能最新进展" --lang zh ``` ### Python调用 ```python import subprocess import json result = subprocess.run( ['python3', '~/.openclaw/skills/tavily-search/scripts/search.py', '你的搜索词', '--json'], capture_output=True, text=True ) data = json.loads(result.stdout) ``` ## Parameters | 参数 | 说明 | 默认值 | |------|------|--------| | `query` | 搜索关键词 | 必填 | | `--max-results` | 返回结果数量 (1-20) | 5 | | `--search-depth` | 搜索深度 (basic/advanced) | basic | | `--include-answer` | 包含AI生成的答案 | True | | `--include-images` | 包含相关图片 | False | | `--days` | 时间范围（天） | 无限制 | | `--lang` | 语言偏好 (zh/en) | auto | | `--json` | JSON格式输出 | False | ## Examples ### AI新闻搜索 ```bash python3 scripts/search.py "OpenAI GPT-5 release" --days 7 --include-answer ``` ### 学术研究 ```bash python3 scripts/search.py "transformer architecture survey" \ --search-depth advanced --max-results 10 ``` ### 技术问题 ```bash python3 scripts/search.py "Docker compose networking tutorial" \ --include-answer --lang zh ``` ## Free Tier Limits - 每月1000次API调用 - 每次最多20个结果 - 基础搜索深度 - 学生可申请更多额度 ## Response Format ```json { "query": "搜索词", "answer": "AI生成的综合答案（可选）", "results": [ { "title": "标题", "url": "链接", "content": "内容摘要", "score": 0.95, "published_date": "2024-03-01" } ], "images": [...] } ``` ## Notes - 首次使用需要先配置TAVILY_API_KEY - 建议将API key添加到~/.openclaw/.env - 超过免费额度后会返回错误提示

path: scripts/search.py
content: #!/usr/bin/env python3
"""
Tavily Search Script for OpenClaw
Usage: python search.py "query" [options]
"""

import os
import sys
import json
import argparse
import urllib.request
import urllib.error
from datetime import datetime, timedelta

TAVILY_API_URL = "https://api.tavily.com/search"

def get_api_key():
    """Get Tavily API key from environment or config file."""
    # Check environment variable first
    [REDACTED_SECRET]'TAVILY_API_KEY')
    if [REDACTED_SECRET] api_key
    
    # Check .env file in common locations
    env_paths = [
        os.path.expanduser('~/.openclaw/.env'),
        os.path.expanduser('~/.env'),
        '.env'
    ]
    
    for env_path in env_paths:
        if os.path.exists(env_path):
            with open(env_path, 'r') as f:
                for line in f:
                    if line.startswith('TAVILY_API_KEY='):
                        return line.strip().split('=', 1)[1].strip('"\'')
    
    return None

def search_tavily(query, max_results=5, search_depth="basic", 
                  include_answer=True, include_images=False, 
                  days=None, lang=None):
    """
    Perform a search using Tavily API.
    
    Args:
        query: Search query string
        max_results: Number of results (1-20)
        search_depth: "basic" or "advanced"
        include_answer: Include AI-generated answer
        include_images: Include related images
        days: Filter by last N days
        lang: Language preference ("zh" or "en")
    """
    [REDACTED_SECRET])
    if not [REDACTED_SECRET] {
            "error": "TAVILY_API_KEY not found. Please set it in environment or ~/.openclaw/.env"
        }
    
    # Build request payload
    payload = {
        "api_key": api_key,
        "query": query,
        "max_results": min(max(1, max_results), 20),
        "search_depth": search_depth,
        "include_answer": include_answer,
        "include_images": include_images,
    }
    
    # Add time filter if specified
    if days:
        from_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
        payload["time_range"] = f"{from_date}.."
    
    # Add language hint
    if lang == "zh":
        payload["query"] = query  # Tavily handles Chinese well
    
    try:
        req = urllib.request.Request(
            TAVILY_API_URL,
            data=json.dumps(payload).encode('utf-8'),
            headers={
                'Content-Type': 'application/json',
                'User-Agent': 'OpenClaw-Tavily-Search/1.0'
            },
            method='POST'
        )
        
        with urllib.request.urlopen(req, timeout=30) as response:
            result = json.loads(response.read().decode('utf-8'))
            return result
            
    except urllib.error.HTTPError as e:
        error_body = e.read().decode('utf-8')
        try:
            error_data = json.loads(error_body)
            return {"error": error_data.get("detail", str(e))}
        except:
            return {"error": f"HTTP {e.code}: {error_body}"}
    except Exception as e:
        return {"error": str(e)}

def format_results(data, use_json=False):
    """Format search results for display."""
    if "error" in data:
        if use_json:
            return json.dumps({"error": data["error"]}, ensure_ascii=False, indent=2)
        return f"❌ Error: {data['error']}"
    
    if use_json:
        return json.dumps(data, ensure_ascii=False, indent=2)
    
    # Text format
    output = []
    output.append(f"🔍 Tavily Search Results")
    output.append(f"Query: {data.get('query', 'N/A')}")
    output.append("")
    
    # AI Answer
    if data.get('answer'):
        output.append("🤖 AI Summary:")
        output.append(data['answer'])
        output.append("")
    
    # Results
    results = data.get('results', [])
    if results:
        output.append(f"📄 Found {len(results)} results:")
        output.append("")
        
        for i, result in enumerate(results, 1):
            output.append(f"{i}. {result.get('title', 'No title')}")
            output.append(f"   URL: {result.get('url', 'N/A')}")
            if result.get('content'):
                content = result['content'][:200] + "..." if len(result['content']) > 200 else result['content']
                output.append(f"   {content}")
            if result.get('published_date'):
                output.append(f"   📅 {result['published_date']}")
            output.append("")
    else:
        output.append("No results found.")
    
    return "\n".join(output)

def main():
    parser = argparse.ArgumentParser(description='Tavily Search for OpenClaw')
    parser.add_argument('query', help='Search query')
    parser.add_argument('--max-results', type=int, default=5, help='Max results (1-20)')
    parser.add_argument('--search-depth', choices=['basic', 'advanced'], default='basic',
                       help='Search depth')
    parser.add_argument('--no-answer', action='store_true', help='Exclude AI answer')
    parser.add_argument('--include-images', action='store_true', help='Include images')
    parser.add_argument('--days', type=int, help='Filter by last N days')
    parser.add_argument('--lang', choices=['zh', 'en'], help='Language preference')
    parser.add_argument('--json', action='store_true', help='Output as JSON')
    
    args = parser.parse_args()
    
    result = search_tavily(
        query=args.query,
        max_results=args.max_results,
        search_depth=args.search_depth,
        include_answer=not args.no_answer,
        include_images=args.include_images,
        days=args.days,
        lang=args.lang
    )
    
    print(format_results(result, use_json=args.json))

if __name__ == '__main__':
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)