scripts/mem0_doc_search.py
scripts/mem0_doc_search.pyBrowse 14 files
1,815 tokens
8,154 bytes
Token encoding: o200k_base
Snapshot 0df3e4b
← Back to SKILL.md
1#!/usr/bin/env python32"""3Mem0 Documentation Search Agent (Mintlify-based)4On-demand search tool for querying Mem0 documentation without storing content locally.5 6This tool leverages Mintlify's documentation structure to perform just-in-time7retrieval of technical information from docs.mem0.ai.8 9Usage:10 python mem0_doc_search.py --query "how to add graph memory"11 python mem0_doc_search.py --query "filter syntax for categories"12 python mem0_doc_search.py --page "/platform/features/graph-memory"13 python mem0_doc_search.py --index14 python mem0_doc_search.py --query "webhook events" --section platform15 16Purpose:17 - Avoid bloating local context with full documentation18 - Enable just-in-time retrieval of technical details19 - Query specific documentation pages on demand20 - Search across the full Mem0 documentation site21"""22 23import argparse24import json25import sys26import urllib.error27import urllib.parse28import urllib.request29 30DOCS_BASE = "https://docs.mem0.ai"31SEARCH_ENDPOINT = f"{DOCS_BASE}/api/search"32LLMS_INDEX = f"{DOCS_BASE}/llms.txt"33 34# Known documentation sections for targeted retrieval35SECTION_MAP = {36 "platform": [37 "/platform/overview",38 "/platform/quickstart",39 "/platform/features",40 "/platform/features/graph-memory",41 "/platform/features/selective-memory",42 "/platform/features/custom-categories",43 "/platform/features/v2-memory-filters",44 "/platform/features/async-client",45 "/platform/features/webhooks",46 "/platform/features/multimodal-support",47 ],48 "api": [49 "/api-reference/memory/add-memories",50 "/api-reference/memory/v2-search-memories",51 "/api-reference/memory/v2-get-memories",52 "/api-reference/memory/get-memory",53 "/api-reference/memory/update-memory",54 "/api-reference/memory/delete-memory",55 ],56 "open-source": [57 "/open-source/overview",58 "/open-source/python-quickstart",59 "/open-source/node-quickstart",60 "/open-source/features",61 "/open-source/features/graph-memory",62 "/open-source/features/rest-api",63 "/open-source/configure-components",64 ],65 "sdks": [66 "/sdks/python",67 "/sdks/js",68 ],69 "integrations": [70 "/integrations",71 ],72}73 74 75def fetch_url(url: str) -> str:76 """Fetch content from a URL."""77 req = urllib.request.Request(url, headers={"User-Agent": "Mem0DocSearchAgent/1.0"})78 try:79 with urllib.request.urlopen(req, timeout=15) as resp:80 return resp.read().decode("utf-8")81 except urllib.error.HTTPError as e:82 return f"HTTP Error {e.code}: {e.reason}"83 except urllib.error.URLError as e:84 return f"URL Error: {e.reason}"85 86 87def search_docs(query: str, section: str | None = None) -> dict:88 """89 Search Mem0 documentation using Mintlify's search API.90 Falls back to the llms.txt index for keyword matching if the API is unavailable.91 """92 # Try Mintlify search API first93 params = urllib.parse.urlencode({"query": query})94 search_url = f"{SEARCH_ENDPOINT}?{params}"95 96 try:97 result = fetch_url(search_url)98 data = json.loads(result)99 if isinstance(data, dict) and data.get("results"):100 results = data["results"]101 if section and section in SECTION_MAP:102 section_paths = SECTION_MAP[section]103 results = [r for r in results if any(r.get("url", "").startswith(p) for p in section_paths)]104 return {"source": "mintlify_search", "results": results}105 except (json.JSONDecodeError, Exception):106 pass107 108 # Fallback: search llms.txt index for matching URLs109 index_content = fetch_url(LLMS_INDEX)110 query_lower = query.lower()111 matching_urls = []112 113 for line in index_content.splitlines():114 line = line.strip()115 if not line or line.startswith("#"):116 continue117 if query_lower in line.lower():118 matching_urls.append(line)119 120 if section and section in SECTION_MAP:121 section_paths = SECTION_MAP[section]122 matching_urls = [u for u in matching_urls if any(p in u for p in section_paths)]123 124 return {125 "source": "llms_txt_index",126 "query": query,127 "matching_urls": matching_urls[:20],128 "suggestion": "Fetch specific URLs for detailed content",129 }130 131 132def fetch_page(page_path: str) -> dict:133 """Fetch a specific documentation page."""134 url = f"{DOCS_BASE}{page_path}" if page_path.startswith("/") else page_path135 content = fetch_url(url)136 return {"url": url, "content": content[:10000], "truncated": len(content) > 10000}137 138 139def get_index() -> dict:140 """Fetch the full documentation index from llms.txt."""141 content = fetch_url(LLMS_INDEX)142 urls = [line.strip() for line in content.splitlines() if line.strip() and not line.startswith("#")]143 return {"total_pages": len(urls), "urls": urls, "sections": list(SECTION_MAP.keys())}144 145 146def list_section(section: str) -> dict:147 """List all known pages in a documentation section."""148 if section not in SECTION_MAP:149 return {"error": f"Unknown section: {section}", "available": list(SECTION_MAP.keys())}150 return {151 "section": section,152 "pages": [f"{DOCS_BASE}{p}" for p in SECTION_MAP[section]],153 }154 155 156def main():157 parser = argparse.ArgumentParser(description="Search Mem0 documentation on demand")158 parser.add_argument("--query", help="Search query for documentation")159 parser.add_argument("--page", help="Fetch a specific page path (e.g., /platform/features/graph-memory)")160 parser.add_argument("--index", action="store_true", help="Show full documentation index")161 parser.add_argument("--section", help="Filter by section or list section pages")162 parser.add_argument("--json", action="store_true", help="Output as JSON")163 164 args = parser.parse_args()165 166 if args.index:167 result = get_index()168 elif args.section and not args.query:169 result = list_section(args.section)170 elif args.page:171 result = fetch_page(args.page)172 elif args.query:173 result = search_docs(args.query, section=args.section)174 else:175 parser.print_help()176 sys.exit(1)177 178 if args.json:179 print(json.dumps(result, indent=2))180 else:181 if isinstance(result, dict):182 if "results" in result:183 print(f"Source: {result.get('source', 'unknown')}")184 for r in result["results"]:185 print(f" - {r.get('title', 'N/A')}: {r.get('url', 'N/A')}")186 if r.get("description"):187 print(f" {r['description'][:200]}")188 elif "matching_urls" in result:189 print(f"Source: {result['source']}")190 print(f"Query: {result['query']}")191 for url in result["matching_urls"]:192 print(f" - {url}")193 if result.get("suggestion"):194 print(f"\n{result['suggestion']}")195 elif "urls" in result:196 print(f"Total documentation pages: {result['total_pages']}")197 print(f"Sections: {', '.join(result['sections'])}")198 for url in result["urls"][:30]:199 print(f" - {url}")200 if result["total_pages"] > 30:201 print(f" ... and {result['total_pages'] - 30} more")202 elif "pages" in result:203 print(f"Section: {result['section']}")204 for page in result["pages"]:205 print(f" - {page}")206 elif "content" in result:207 print(f"URL: {result['url']}")208 if result.get("truncated"):209 print("[Content truncated to 10000 chars]")210 print(result["content"])211 elif "error" in result:212 print(f"Error: {result['error']}")213 if result.get("available"):214 print(f"Available sections: {', '.join(result['available'])}")215 else:216 print(json.dumps(result, indent=2))217 218 219if __name__ == "__main__":220 main()221