[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FAB1G01PQ2PYC9YT0RY89B":3,"skill-same:01M6FAB1G01PQ2PYC9YT0RY89B":79},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":56,"commitSha":57,"skillDirectory":58,"forksCount":59,"repositoryHtmlUrl":60,"repositoryHomepageUrl":61,"ownerHtmlUrl":62,"ownerBlogUrl":6,"ownerDescription":63,"updatedAt":64,"install":65,"resources":78},"01M6FAB1G01PQ2PYC9YT0RY89B","exa-data-handling",null,"Implement Exa search result processing, content extraction, caching, and RAG context management.\nUse when handling search results, implementing caching, building citation pipelines,\nor managing content payloads for LLM context windows.\nTrigger with phrases like \"exa data\", \"exa results processing\",\n\"exa cache\", \"exa RAG context\", \"exa content extraction\".","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-data-handling\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"exa data handling","data","exa","context","processing","trigger","io","context management","caching","use","payloads","openclaw","edit","write","read","exa search","search","code","rag","windows","2026-11-10 10:12:30",false,"---\nname: exa-data-handling\ndescription: |\n  Implement Exa search result processing, content extraction, caching, and RAG context management.\n  Use when handling search results, implementing caching, building citation pipelines,\n  or managing content payloads for LLM context windows.\n  Trigger with phrases like \"exa data\", \"exa results processing\",\n  \"exa cache\", \"exa RAG context\", \"exa content extraction\".\nallowed-tools: Read, Write, Edit\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\ncompatible-with: claude-code, codex, openclaw\ntags: [saas, exa, data, rag, caching]\n\n---\n# Exa Data Handling\n\n## Overview\nManage search result data from Exa's neural search API. Covers content extraction scope control (text vs highlights vs summary), result caching with TTL, citation deduplication, token budget management for LLM context windows, and structured summary extraction.\n\n## Prerequisites\n- `exa-js` SDK installed and configured\n- Optional: `lru-cache` for in-memory caching, `ioredis` for Redis\n- Understanding of Exa content options (text, highlights, summary)\n\n## Instructions\n\n### Step 1: Control Content Extraction Scope\n```typescript\nimport Exa from \"exa-js\";\n\nconst exa = new Exa(process.env.EXA_API_KEY);\n\n\u002F\u002F Tier 1: Metadata only (cheapest, fastest)\nasync function searchMetadataOnly(query: string) {\n  return exa.search(query, {\n    type: \"auto\",\n    numResults: 10,\n    \u002F\u002F No content options — returns URLs, titles, scores only\n  });\n}\n\n\u002F\u002F Tier 2: Highlights only (balanced cost\u002Fvalue)\nasync function searchWithHighlights(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    highlights: {\n      maxCharacters: 500,\n      query: query,  \u002F\u002F focus highlights on the original query\n    },\n  });\n}\n\n\u002F\u002F Tier 3: Full text with character limit\nasync function searchWithText(query: string, maxChars = 2000) {\n  return exa.searchAndContents(query, {\n    numResults: 5,\n    text: { maxCharacters: maxChars },\n    highlights: { maxCharacters: 300 },\n  });\n}\n\n\u002F\u002F Tier 4: Structured summary (LLM-generated per result)\nasync function searchWithSummary(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 5,\n    summary: { query: query },\n    \u002F\u002F summary returns a concise LLM-generated summary per result\n  });\n}\n```\n\n### Step 2: Result Caching with TTL\n```typescript\nimport { LRUCache } from \"lru-cache\";\nimport { createHash } from \"crypto\";\n\nconst searchCache = new LRUCache\u003Cstring, any>({\n  max: 500,\n  ttl: 1000 * 60 * 60, \u002F\u002F 1 hour default\n});\n\nfunction cacheKey(query: string, options: any): string {\n  return createHash(\"sha256\")\n    .update(JSON.stringify({ query, ...options }))\n    .digest(\"hex\");\n}\n\nasync function cachedSearch(query: string, options: any = {}, ttlMs?: number) {\n  const key = cacheKey(query, options);\n  const cached = searchCache.get(key);\n  if (cached) return cached;\n\n  const results = await exa.searchAndContents(query, options);\n  searchCache.set(key, results, { ttl: ttlMs });\n  return results;\n}\n```\n\n### Step 3: Token Budget Management for RAG\n```typescript\ninterface ProcessedResult {\n  url: string;\n  title: string;\n  score: number;\n  snippet: string;\n  tokenEstimate: number;\n}\n\nfunction processForRAG(results: any[], maxSnippetLength = 500): ProcessedResult[] {\n  return results.map(r => {\n    const snippet = (r.text || r.highlights?.join(\" \") || r.summary || \"\")\n      .slice(0, maxSnippetLength);\n    return {\n      url: r.url,\n      title: r.title || \"Untitled\",\n      score: r.score,\n      snippet,\n      tokenEstimate: Math.ceil(snippet.length \u002F 4),\n    };\n  });\n}\n\nfunction fitToTokenBudget(results: ProcessedResult[], maxTokens: number) {\n  const sorted = [...results].sort((a, b) => b.score - a.score);\n  const selected: ProcessedResult[] = [];\n  let tokenCount = 0;\n\n  for (const result of sorted) {\n    if (tokenCount + result.tokenEstimate > maxTokens) break;\n    selected.push(result);\n    tokenCount += result.tokenEstimate;\n  }\n\n  return { selected, tokenCount, dropped: sorted.length - selected.length };\n}\n\n\u002F\u002F Usage: fit search results into a 4K token context window\nconst results = await exa.searchAndContents(\"query\", {\n  numResults: 15,\n  text: { maxCharacters: 1500 },\n});\nconst processed = processForRAG(results.results);\nconst { selected, tokenCount } = fitToTokenBudget(processed, 4000);\n```\n\n### Step 4: Citation Deduplication\n```typescript\nfunction deduplicateResults(results: any[]): any[] {\n  const seen = new Map\u003Cstring, any>();\n\n  for (const result of results) {\n    const domain = new URL(result.url).hostname;\n    const key = `${domain}:${result.title}`;\n    if (!seen.has(key) || result.score > seen.get(key).score) {\n      seen.set(key, result);\n    }\n  }\n\n  return Array.from(seen.values());\n}\n```\n\n### Step 5: Structured Summary Extraction\n```typescript\n\u002F\u002F Use summary.schema for structured data extraction\nconst results = await exa.searchAndContents(\n  \"YC-backed AI startups Series A 2025\",\n  {\n    numResults: 10,\n    category: \"company\",\n    summary: {\n      query: \"company name, funding amount, what they do\",\n      \u002F\u002F schema can define JSON structure for the summary output\n    },\n  }\n);\n\n\u002F\u002F Each result.summary contains a structured summary\nfor (const r of results.results) {\n  console.log(`${r.title}: ${r.summary}`);\n}\n```\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Large response payload | Full text for many URLs | Use highlights or limit `maxCharacters` |\n| Cache stale for news | Default TTL too long | Use 5-minute TTL for time-sensitive queries |\n| Duplicate sources | Same article syndicated | Deduplicate by domain + title |\n| Token budget exceeded | Too much context for LLM | Use `fitToTokenBudget` to trim by score |\n| Missing `.text` field | Content not requested | Use `searchAndContents` not `search` |\n\n## Examples\n\n### RAG-Optimized Search Pipeline\n```typescript\nasync function ragSearch(query: string, tokenBudget = 4000) {\n  const results = await cachedSearch(query, {\n    numResults: 15,\n    type: \"neural\",\n    text: { maxCharacters: 1500 },\n    highlights: { maxCharacters: 300, query },\n  });\n\n  const deduped = deduplicateResults(results.results);\n  const processed = processForRAG(deduped);\n  const { selected, tokenCount } = fitToTokenBudget(processed, tokenBudget);\n\n  return {\n    context: selected.map((r, i) =>\n      `[${i + 1}] ${r.title} (${r.url})\\n${r.snippet}`\n    ).join(\"\\n\\n---\\n\\n\"),\n    sources: selected.map(r => ({ title: r.title, url: r.url })),\n    tokenCount,\n  };\n}\n```\n\n## Resources\n- [Exa Contents Retrieval](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fcontents-retrieval)\n- [Exa Search Reference](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fsearch)\n\n## Next Steps\nFor rate limit handling, see `exa-rate-limits`. For cost optimization, see `exa-cost-tuning`.\n\n","# Exa Data Handling\n\n## Overview\nManage search result data from Exa's neural search API. Covers content extraction scope control (text vs highlights vs summary), result caching with TTL, citation deduplication, token budget management for LLM context windows, and structured summary extraction.\n\n## Prerequisites\n- `exa-js` SDK installed and configured\n- Optional: `lru-cache` for in-memory caching, `ioredis` for Redis\n- Understanding of Exa content options (text, highlights, summary)\n\n## Instructions\n\n### Step 1: Control Content Extraction Scope\n```typescript\nimport Exa from \"exa-js\";\n\nconst exa = new Exa(process.env.EXA_API_KEY);\n\n\u002F\u002F Tier 1: Metadata only (cheapest, fastest)\nasync function searchMetadataOnly(query: string) {\n  return exa.search(query, {\n    type: \"auto\",\n    numResults: 10,\n    \u002F\u002F No content options — returns URLs, titles, scores only\n  });\n}\n\n\u002F\u002F Tier 2: Highlights only (balanced cost\u002Fvalue)\nasync function searchWithHighlights(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    highlights: {\n      maxCharacters: 500,\n      query: query,  \u002F\u002F focus highlights on the original query\n    },\n  });\n}\n\n\u002F\u002F Tier 3: Full text with character limit\nasync function searchWithText(query: string, maxChars = 2000) {\n  return exa.searchAndContents(query, {\n    numResults: 5,\n    text: { maxCharacters: maxChars },\n    highlights: { maxCharacters: 300 },\n  });\n}\n\n\u002F\u002F Tier 4: Structured summary (LLM-generated per result)\nasync function searchWithSummary(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 5,\n    summary: { query: query },\n    \u002F\u002F summary returns a concise LLM-generated summary per result\n  });\n}\n```\n\n### Step 2: Result Caching with TTL\n```typescript\nimport { LRUCache } from \"lru-cache\";\nimport { createHash } from \"crypto\";\n\nconst searchCache = new LRUCache\u003Cstring, any>({\n  max: 500,\n  ttl: 1000 * 60 * 60, \u002F\u002F 1 hour default\n});\n\nfunction cacheKey(query: string, options: any): string {\n  return createHash(\"sha256\")\n    .update(JSON.stringify({ query, ...options }))\n    .digest(\"hex\");\n}\n\nasync function cachedSearch(query: string, options: any = {}, ttlMs?: number) {\n  const key = cacheKey(query, options);\n  const cached = searchCache.get(key);\n  if (cached) return cached;\n\n  const results = await exa.searchAndContents(query, options);\n  searchCache.set(key, results, { ttl: ttlMs });\n  return results;\n}\n```\n\n### Step 3: Token Budget Management for RAG\n```typescript\ninterface ProcessedResult {\n  url: string;\n  title: string;\n  score: number;\n  snippet: string;\n  tokenEstimate: number;\n}\n\nfunction processForRAG(results: any[], maxSnippetLength = 500): ProcessedResult[] {\n  return results.map(r => {\n    const snippet = (r.text || r.highlights?.join(\" \") || r.summary || \"\")\n      .slice(0, maxSnippetLength);\n    return {\n      url: r.url,\n      title: r.title || \"Untitled\",\n      score: r.score,\n      snippet,\n      tokenEstimate: Math.ceil(snippet.length \u002F 4),\n    };\n  });\n}\n\nfunction fitToTokenBudget(results: ProcessedResult[], maxTokens: number) {\n  const sorted = [...results].sort((a, b) => b.score - a.score);\n  const selected: ProcessedResult[] = [];\n  let tokenCount = 0;\n\n  for (const result of sorted) {\n    if (tokenCount + result.tokenEstimate > maxTokens) break;\n    selected.push(result);\n    tokenCount += result.tokenEstimate;\n  }\n\n  return { selected, tokenCount, dropped: sorted.length - selected.length };\n}\n\n\u002F\u002F Usage: fit search results into a 4K token context window\nconst results = await exa.searchAndContents(\"query\", {\n  numResults: 15,\n  text: { maxCharacters: 1500 },\n});\nconst processed = processForRAG(results.results);\nconst { selected, tokenCount } = fitToTokenBudget(processed, 4000);\n```\n\n### Step 4: Citation Deduplication\n```typescript\nfunction deduplicateResults(results: any[]): any[] {\n  const seen = new Map\u003Cstring, any>();\n\n  for (const result of results) {\n    const domain = new URL(result.url).hostname;\n    const key = `${domain}:${result.title}`;\n    if (!seen.has(key) || result.score > seen.get(key).score) {\n      seen.set(key, result);\n    }\n  }\n\n  return Array.from(seen.values());\n}\n```\n\n### Step 5: Structured Summary Extraction\n```typescript\n\u002F\u002F Use summary.schema for structured data extraction\nconst results = await exa.searchAndContents(\n  \"YC-backed AI startups Series A 2025\",\n  {\n    numResults: 10,\n    category: \"company\",\n    summary: {\n      query: \"company name, funding amount, what they do\",\n      \u002F\u002F schema can define JSON structure for the summary output\n    },\n  }\n);\n\n\u002F\u002F Each result.summary contains a structured summary\nfor (const r of results.results) {\n  console.log(`${r.title}: ${r.summary}`);\n}\n```\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Large response payload | Full text for many URLs | Use highlights or limit `maxCharacters` |\n| Cache stale for news | Default TTL too long | Use 5-minute TTL for time-sensitive queries |\n| Duplicate sources | Same article syndicated | Deduplicate by domain + title |\n| Token budget exceeded | Too much context for LLM | Use `fitToTokenBudget` to trim by score |\n| Missing `.text` field | Content not requested | Use `searchAndContents` not `search` |\n\n## Examples\n\n### RAG-Optimized Search Pipeline\n```typescript\nasync function ragSearch(query: string, tokenBudget = 4000) {\n  const results = await cachedSearch(query, {\n    numResults: 15,\n    type: \"neural\",\n    text: { maxCharacters: 1500 },\n    highlights: { maxCharacters: 300, query },\n  });\n\n  const deduped = deduplicateResults(results.results);\n  const processed = processForRAG(deduped);\n  const { selected, tokenCount } = fitToTokenBudget(processed, tokenBudget);\n\n  return {\n    context: selected.map((r, i) =>\n      `[${i + 1}] ${r.title} (${r.url})\\n${r.snippet}`\n    ).join(\"\\n\\n---\\n\\n\"),\n    sources: selected.map(r => ({ title: r.title, url: r.url })),\n    tokenCount,\n  };\n}\n```\n\n## Resources\n- [Exa Contents Retrieval](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fcontents-retrieval)\n- [Exa Search Reference](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fsearch)\n\n## Next Steps\nFor rate limit handling, see `exa-rate-limits`. For cost optimization, see `exa-cost-tuning`.\n\n",{"name":5,"tags":49,"author":51,"license":15,"version":52,"description":53,"allowed-tools":54,"compatible-with":55},[50,26,25,42,32],"saas","Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Implement Exa search result processing, content extraction, caching, and RAG context management.\nUse when handling search results, implementing caching, building citation pipelines,\nor managing content payloads for LLM context windows.\nTrigger with phrases like \"exa data\", \"exa results processing\",\n\"exa cache\", \"exa RAG context\", \"exa content extraction\".\n","Read, Write, Edit","claude-code, codex, openclaw","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-data-handling",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill exa-data-handling",{"tool":71,"command":72},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill exa-data-handling",{"tool":74,"command":75},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill exa-data-handling","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-data-handling\u002FSKILL.md",true,[],[80,94,104,113,118,125],{"skillNo":81,"name":82,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":90,"publishedAt":44},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[91,92,93],"model","model hierarchy","model hierarchy skill",{"skillNo":95,"name":96,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":100,"publishedAt":44},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[99],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},[101,102,103],"MCP","zoom","zoom mcp",{"skillNo":105,"name":106,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":44},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[110,111,112,102],"sdk","zoom apps sdk","apps",{"skillNo":114,"name":43,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":44},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[43],{"skillNo":119,"name":120,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":121,"categories":122,"keywords":124,"publishedAt":44},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[123],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},[120],{"skillNo":126,"name":127,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":130,"publishedAt":44},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[127]]