|
print() output comes back.tvly search --include-raw-content returns 8 results × 30-50K chars each = ~300K characters of raw page content. If this enters your context window, you burn tokens reading navigation bars, cookie banners, and boilerplate — and your reasoning quality degrades under the noise. By processing results inside a Python script, only your print() output enters context — typically 1-3K characters of pure signal. That's a 100-200x reduction.print() output reaches the model's context window.print() crosses into your context window. You write the filtering logic — you decide what matters for each query.tvly is not found on PATH, install it first:curl -fsSL https://cli.tavily.com/install.sh | bash && tvly login
tvly as a bare command. Always process output through Python so you control what enters your context.# WRONG — raw results flood your context
tvly search "quantum computing 2025" --json
# RIGHT — only your print() output enters context
tvly search "quantum computing 2025" --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data['results']:
print(f'[{r[\"score\"]:.2f}] {r[\"title\"]}')
print(f' {r[\"url\"]}')
"
{
"query": "string",
"answer": "string | null",
"results": [
{
"url": "string",
"title": "string",
"content": "string (snippet, ~500-1500 chars)",
"score": 0.0-1.0,
"raw_content": "string | null (full page, only with --include-raw-content)"
}
],
"response_time": 0.0
}
{
"results": [
{
"url": "string",
"title": "string",
"raw_content": "string (full page markdown)",
"images": []
}
],
"failed_results": [],
"response_time": 0.0
}
tvly search — returns titles, URLs, snippets, scores. Optionally includes full page content with --include-raw-content markdown.tvly extract — fetches full page content for specific URLs. Use when you found a URL from search and need more detail.python3 -c:tvly search "query" --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
# your filtering code here
"
python3 << 'PYEOF'
import json, subprocess
raw = subprocess.check_output(
['tvly', 'search', 'query', '--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
for r in data['results']:
print(f"[{r['score']:.2f}] {r['title']}")
print(f" {r['url']}")
PYEOF
<< 'PYEOF') don't interpret anything — no escaping needed. This is the default for most tasks./tmp/. If you run it once, use a heredoc./tmp/, not CODE. Writing /tmp/tavily_results.json (data for later turns) = good. Writing /tmp/my_filter.py (one-shot code) = wasteful — use a heredoc instead.python3 << 'PYEOF'
import json, subprocess
raw = subprocess.check_output(
['tvly', 'search', 'solid-state battery commercialization 2025',
'--include-raw-content', 'markdown', '--max-results', '8', '--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
# Save raw results — this stays on disk, never enters context
with open('/tmp/tavily_results.json', 'w') as f:
json.dump(data, f)
# Print only what you need to decide next steps
print(f'{len(data["results"])} results saved to /tmp/tavily_results.json\n')
for i, r in enumerate(data['results']):
print(f'[{i}] [{r["score"]:.2f}] {r["title"][:90]}')
print(f' {r["url"]}')
print(f' {r["content"][:150]}')
print()
PYEOF
/tmp/tavily_results.json, untouched.python3 << 'PYEOF'
import json
data = json.load(open('/tmp/tavily_results.json'))
# You chose these indices based on the titles you saw in turn 1
for i in [0, 2, 5]:
r = data['results'][i]
raw = r.get('raw_content', '') or ''
if not raw:
continue
print(f'## {r["title"]}')
print(f'URL: {r["url"]}\n')
# You write the filtering logic based on the query
# This example extracts paragraphs about specific companies
for para in raw.split('\n\n'):
para = para.strip()
if len(para) > 80 and any(kw in para.lower() for kw in
['toyota', 'quantumscape', 'samsung', 'commercializ', 'production']):
print(para)
print()
print('---\n')
PYEOF
python3 << 'PYEOF'
import json, subprocess
# Fetch a specific URL you identified
raw = subprocess.check_output(
['tvly', 'extract', 'https://example.com/article', '--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
page = data['results'][0]
content = page.get('raw_content', '')
# Save for potential further processing
with open('/tmp/page_detail.txt', 'w') as f:
f.write(content)
# Print only the section you care about
for line in content.split('\n'):
if any(kw in line.lower() for kw in ['timeline', '2025', '2026', 'mass production']):
print(line.strip())
PYEOF
tvly search "Python 3.13 release date" --max-results 5 --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data['results'][:3]:
print(f'{r[\"title\"]}')
print(f'{r[\"content\"][:300]}')
print()
"
python3 << 'PYEOF'
import json, subprocess
raw = subprocess.check_output(
['tvly', 'search', 'NVIDIA Q4 2025 earnings revenue',
'--include-raw-content', 'markdown', '--max-results', '5',
'--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
for r in data['results']:
raw_content = r.get('raw_content', '') or ''
# For financial queries, look for lines with numbers
financial_lines = [
line.strip() for line in raw_content.split('\n')
if any(kw in line.lower() for kw in
['revenue', 'eps', 'earnings', 'margin', 'guidance', 'billion'])
and any(c.isdigit() for c in line)
and len(line.strip()) > 30
]
if financial_lines:
print(f'## {r["title"]}')
print(f'URL: {r["url"]}')
for line in financial_lines[:15]:
print(f' {line}')
print()
PYEOF
python3 << 'PYEOF'
import json, subprocess
# Search from multiple angles
queries = [
('broad', 'EU AI Act implementation timeline 2025'),
('specific', 'EU AI Act high-risk AI systems obligations'),
]
all_results = []
for label, query in queries:
raw = subprocess.check_output(
['tvly', 'search', query, '--max-results', '8', '--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
for r in data['results']:
r['_query'] = label
all_results.extend(data['results'])
# Deduplicate by URL
seen = set()
unique = []
for r in all_results:
if r['url'] not in seen:
seen.add(r['url'])
unique.append(r)
# Save all results
with open('/tmp/eu_ai_results.json', 'w') as f:
json.dump(unique, f)
# Print triage
unique.sort(key=lambda r: r['score'], reverse=True)
print(f'{len(unique)} unique results from {len(queries)} queries\n')
for i, r in enumerate(unique[:10]):
print(f'[{i}] [{r["score"]:.2f}] ({r["_query"]}) {r["title"][:80]}')
print(f' {r["url"]}')
print(f' {r["content"][:120]}')
print()
PYEOF
python3 << 'PYEOF'
import json, subprocess
results = json.load(open('/tmp/eu_ai_results.json'))
# Fetch full content for the top 3 (you chose these based on turn 1)
for r in [results[0], results[2], results[4]]:
try:
raw = subprocess.check_output(
['tvly', 'extract', r['url'], '--json'],
stderr=subprocess.DEVNULL, timeout=30
)
page = json.loads(raw)
if not page.get('results'):
continue
content = page['results'][0].get('raw_content', '')
# Your filtering logic — tailored to this query
print(f'## {r["title"]}')
print(f'URL: {r["url"]}\n')
for para in content.split('\n\n'):
para = para.strip()
if len(para) > 100 and any(kw in para.lower() for kw in
['high-risk', 'prohibited', 'deadline', 'obligation',
'compliance', 'penalty', 'fine', 'article']):
print(para)
print()
print('---\n')
except Exception:
continue
PYEOF
python3 << 'PYEOF'
import json, subprocess
# Read the page you saved earlier
with open('/tmp/page_detail.txt') as f:
content = f.read()
# You noticed a reference to a specific regulation document
# Search for it specifically
raw = subprocess.check_output(
['tvly', 'search', 'EU AI Act Annex III high-risk list',
'--include-domains', 'eur-lex.europa.eu',
'--max-results', '3', '--json'],
stderr=subprocess.DEVNULL
)
data = json.loads(raw)
for r in data['results']:
print(f'## {r["title"]}')
print(f'URL: {r["url"]}')
print(r['content'])
print()
PYEOF
/tmp/, decide what to explore next, and write new filtering code as heredocs. The raw data accumulates on disk; your context stays lean.print(f'## {title}')
print(f'URL: {url}')
print(relevant_content)
print()
try:
raw = subprocess.check_output(['tvly', 'extract', url, '--json'],
stderr=subprocess.DEVNULL, timeout=30)
except Exception:
continue
print() output is what enters your context. Target 150-600 tokens per source. If you're printing 5000+ chars from a single page, you're probably not filtering enough. But if a source has a critical data table, it's fine to keep more.tvly search options work:| Option | Description |
|---|---|
--max-results | Number of results (default: 5, max: 20) |
--depth | ultra-fast, fast, basic (default), advanced |
--time-range | day, week, month, year |
--include-domains | Comma-separated whitelist |
--exclude-domains | Comma-separated blacklist |
--include-raw-content | Full page content (markdown or text) |
--country | Boost results from country |
python3 is unavailable, use jq for basic filtering:tvly search "query" --json 2>/dev/null | jq '[.results[] | select(.score > 0.5) | {title, url, content}]'