diff --git a/AGENTS.md b/AGENTS.md index ea34e56..8e18594 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,4 +8,64 @@ - You are using python 3.11. - All pip dependencies are installed in the environment. (Except packages related to locally running AI, due to their large size.) - You have the ability to directly push to the git repo over https (url already set). And you should when you finish your task and have tested it. -- If you encounter errors when pushing just leave it to the user to fix them. +- If you encounter any hard to fix errors when pushing just leave it to the user to fix them. Try fixing merge conflicts/not having work from the remote by yourself. +- You have a python script "tavily.py" in the project root, that you can use to search the web. + +# Tavily API Script Usage Instructions + +## Basic Usage +Search for information using simple queries: +```bash +python tavily.py "your search query" +``` + +## Examples +```bash +python tavily.py "latest AI developments 2024" +python tavily.py "how to make chocolate chip cookies" +python tavily.py "current weather in New York" +python tavily.py "best programming practices Python" +``` + +## Advanced Options + +### Search Depth +- **Basic search**: `python tavily.py "query"` (default) +- **Advanced search**: `python tavily.py "query" --depth advanced` + +### Control Results +- **Limit results**: `python tavily.py "query" --max-results 3` +- **Include images**: `python tavily.py "query" --include-images` +- **Skip AI answer**: `python tavily.py "query" --no-answer` + +### Domain Filtering +- **Include specific domains**: `python tavily.py "query" --include-domains reddit.com stackoverflow.com` +- **Exclude domains**: `python tavily.py "query" --exclude-domains wikipedia.org` + +### Output Format +- **Formatted output**: `python tavily.py "query"` (default - human readable) +- **Raw JSON**: `python tavily.py "query" --raw` (for programmatic processing) + +## Output Structure +The default formatted output includes: +- 🤖 **AI Answer**: Direct answer to your query +- 🔍 **Search Results**: Titles, URLs, and content snippets +- 🖼️ **Images**: Relevant images (when `--include-images` is used) + +## Command Combinations +```bash +# Advanced search with images, limited results +python tavily.py "machine learning tutorials" --depth advanced --include-images --max-results 3 + +# Search specific sites only, raw output +python tavily.py "Python best practices" --include-domains github.com stackoverflow.com --raw + +# Quick search without AI answer +python tavily.py "today's news" --no-answer --max-results 5 +``` + +## Tips +- Always quote your search queries to handle spaces and special characters +- Use `--max-results` to control response length and API usage +- Use `--raw` when you need to parse results programmatically +- Combine options as needed for specific use cases \ No newline at end of file diff --git a/tavily.py b/tavily.py new file mode 100644 index 0000000..3c89167 --- /dev/null +++ b/tavily.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +""" +Tavily API Script for AI Agents +Execute with: python tavily.py "your search query" +""" + +import os +import sys +import json +import requests +import argparse +from typing import Dict, List, Optional + +class TavilyAPI: + def __init__(self, api_key: str): + self.api_key = api_key + self.base_url = "https://api.tavily.com" + + def search(self, + query: str, + search_depth: str = "basic", + include_answer: bool = True, + include_images: bool = False, + include_raw_content: bool = False, + max_results: int = 5, + include_domains: Optional[List[str]] = None, + exclude_domains: Optional[List[str]] = None) -> Dict: + """ + Perform a search using Tavily API + + Args: + query: Search query string + search_depth: "basic" or "advanced" + include_answer: Include AI-generated answer + include_images: Include images in results + include_raw_content: Include raw HTML content + max_results: Maximum number of results (1-20) + include_domains: List of domains to include + exclude_domains: List of domains to exclude + + Returns: + Dictionary containing search results + """ + url = f"{self.base_url}/search" + + payload = { + "api_key": self.api_key, + "query": query, + "search_depth": search_depth, + "include_answer": include_answer, + "include_images": include_images, + "include_raw_content": include_raw_content, + "max_results": max_results + } + + if include_domains: + payload["include_domains"] = include_domains + if exclude_domains: + payload["exclude_domains"] = exclude_domains + + try: + response = requests.post(url, json=payload, timeout=30) + response.raise_for_status() + return response.json() + except requests.exceptions.RequestException as e: + return {"error": f"API request failed: {str(e)}"} + except json.JSONDecodeError: + return {"error": "Invalid JSON response from API"} + +def format_results(results: Dict) -> str: + """Format search results for display""" + if "error" in results: + return f"❌ Error: {results['error']}" + + output = [] + + # Add answer if available + if results.get("answer"): + output.append("🤖 AI Answer:") + output.append(f" {results['answer']}") + output.append("") + + # Add search results + if results.get("results"): + output.append("🔍 Search Results:") + for i, result in enumerate(results["results"], 1): + output.append(f" {i}. {result.get('title', 'No title')}") + output.append(f" URL: {result.get('url', 'No URL')}") + if result.get("content"): + # Truncate content to first 200 chars + content = result["content"][:200] + "..." if len(result["content"]) > 200 else result["content"] + output.append(f" Content: {content}") + output.append("") + + # Add images if available + if results.get("images"): + output.append("🖼️ Images:") + for img in results["images"][:3]: # Show first 3 images + output.append(f" {img}") + output.append("") + + return "\n".join(output) + +def main(): + parser = argparse.ArgumentParser(description="Search using Tavily API") + parser.add_argument("query", help="Search query") + parser.add_argument("--depth", choices=["basic", "advanced"], default="basic", + help="Search depth (default: basic)") + parser.add_argument("--max-results", type=int, default=5, + help="Maximum number of results (default: 5)") + parser.add_argument("--include-images", action="store_true", + help="Include images in results") + parser.add_argument("--no-answer", action="store_true", + help="Don't include AI-generated answer") + parser.add_argument("--include-domains", nargs="+", + help="Include only these domains") + parser.add_argument("--exclude-domains", nargs="+", + help="Exclude these domains") + parser.add_argument("--raw", action="store_true", + help="Output raw JSON response") + + args = parser.parse_args() + + # Get API key from environment + api_key = os.getenv("TAVILY_API_KEY") + if not api_key: + print("❌ Error: TAVILY_API_KEY environment variable not set") + print("Set it with: export TAVILY_API_KEY='your-api-key-here'") + sys.exit(1) + + # Initialize Tavily API + tavily = TavilyAPI(api_key) + + # Perform search + results = tavily.search( + query=args.query, + search_depth=args.depth, + include_answer=not args.no_answer, + include_images=args.include_images, + max_results=args.max_results, + include_domains=args.include_domains, + exclude_domains=args.exclude_domains + ) + + # Output results + if args.raw: + print(json.dumps(results, indent=2)) + else: + print(format_results(results)) + +if __name__ == "__main__": + main() \ No newline at end of file