"Tavily Integration SSOT"

Tavily Integration SSOT

Tavily is the live web retrieval leg of the Vox RAG pipeline. It provides real-time, AI-native, LLM-ready search results as a complement to Vox's static local corpora (Memory, KnowledgeGraph, DocumentChunks, etc.).

[!IMPORTANT] All Tavily secrets MUST be registered through vox-clavis. Never read TAVILY_API_KEY directly with std::env::var.


API Endpoint Reference

Credits: 1 (basic) / 2 (advanced)

Key parameters:

ParameterTypeDefaultNotes
querystringrequiredThe search query
search_depth"basic"│"advanced""basic"Advanced = deeper results, 2× cost
topic"general"│"news"│"finance""general"Domain hint
include_answerboolfalseReturns a synthesized answer string
max_resultsint5Max 10 (basic) or more (advanced)
time_range"day"│"week"│"month"│"year"nullFreshness filter
include_domainsstring[][]Whitelist specific domains
exclude_domainsstring[][]Blacklist specific domains

Response shape:

{
  "query": "string",
  "answer": "string|null",
  "results": [
    { "title": "...", "url": "...", "content": "clean text", "score": 0.97, "published_date": "..." }
  ],
  "response_time": 1.23
}

/extract — URL Content Extraction

Credits: 1 per 5 URLs (basic) / 2 per 5 URLs (advanced)

Key parameters:

ParameterTypeNotes
urlsstring[]Up to 20 URLs per call
querystringOptional — enables query-focused reranking/chunking
format"markdown"│"text"Output format
include_imagesboolDefault false
extract_depth"basic"│"advanced"Advanced handles JavaScript-rendered pages

Typical use:

Tavily /search → ranked URLs → Tavily /extract → clean markdown → embed → vector store

/research — Autonomous Deep Research

Credits: Variable (internally fires multiple search calls)

Purpose: "Agent-in-a-Box" — performs iterative multi-step research autonomously and returns a comprehensive, synthesized JSON report. GA'd early 2026.

Key parameters:

ParameterTypeNotes
querystringFull research topic
instructionsstringOptional guidance (e.g., "focus on Rust, ignore Python")

When to use: For Vox's intensive research mode (user requests "research X thoroughly"). Replaces a full multi-iteration search loop with a single API call.


/crawl — Site-Level Discovery

Credits: Map + Extract credits (combined)

Purpose: Crawl a specific site with natural-language instructions (e.g., documentation ingestion).

Key parameters:

ParameterNotes
urlRoot URL to crawl
instructionsNatural language crawl guidance
max_depthDefault 3
max_pagesCap on pages visited

Vox use case: Periodically crawl documentation sites into the DocumentChunks corpus.


Rust SDK

Crate: tavily = "2.1.0" (crates.io) Source: https://github.com/PierreLouisLetoquart/tavily-rs Backend: tokio + reqwest

[!WARNING] This is a community-maintained crate, not an official Tavily SDK. Pin to a specific version and test on upgrade.

Configuration in vox-search/Cargo.toml:

[dependencies]
tavily = { version = "2.1.0", optional = true }

[features]
tavily-search = ["dep:tavily"]

Safe usage pattern (via Clavis):

#![allow(unused)]
fn main() {
// Never do this:
let key = std::env::var("TAVILY_API_KEY").unwrap();

// Always do this:
use vox_clavis::{SecretId, resolve_secret};
let key = resolve_secret(SecretId::TavilyApiKey)
    .map_err(|e| format!("tavily_key_missing:{e}"))?;
}

Clavis Secret Lifecycle

Required Entries in crates/vox-clavis/src/lib.rs

#![allow(unused)]
fn main() {
SecretId::TavilyApiKey => SecretSpec {
    env_var: "TAVILY_API_KEY",
    description: "Tavily web search API key. Get at https://tavily.com. Free tier: 1,000 credits/mo.",
    required: false,
    deprecated_aliases: &["X_TAVILY_API_KEY"],
},
SecretId::TavilyProject => SecretSpec {
    env_var: "TAVILY_PROJECT",
    description: "Optional Tavily project ID for X-Project-ID header usage tracking.",
    required: false,
    deprecated_aliases: &[],
},
}

Lifecycle Checklist

After adding the secret entries:

  1. Run vox ci secret-env-guard
  2. Run vox ci clavis-parity
  3. Update vox clavis doctor profile expectations
  4. Update this doc at docs/src/reference/clavis-ssot.md

Environment Variable Summary

VariablePurposeDefault
TAVILY_API_KEYAPI authentication(none — Tavily disabled)
TAVILY_PROJECTX-Project-ID header(none)
VOX_SEARCH_TAVILY_ENABLEDMaster switchfalse
VOX_SEARCH_TAVILY_DEPTHAPI search depth"basic"
VOX_SEARCH_TAVILY_MAX_RESULTSResults per query5
VOX_SEARCH_TAVILY_ON_EMPTYFire when all local corpora emptytrue
VOX_SEARCH_TAVILY_ON_WEAKCRAG mode — fire when evidence_quality < thresholdfalse
VOX_SEARCH_TAVILY_BUDGETMax credits per session50

Pricing (April 2026)

PlanCredits/MonthPriceNotes
Researcher (Free)1,000$0No card required. Good for dev.
Project4,000~$30/mo$0.0075/credit
Bootstrap15,000~$100/mo$0.0067/credit
Startup38,000~$220/mo$0.0058/credit
Growth100,000~$500/mo$0.005/credit
Pay-As-You-Go$0.008/credit

Credit costs:

  • /search basic: 1 credit
  • /search advanced: 2 credits
  • /extract basic: 1 credit/5 URLs
  • /extract advanced: 2 credits/5 URLs
  • /research: variable (multiple internal searches)

Session budget guard: VOX_SEARCH_TAVILY_BUDGET=50 limits the session to 50 credits (50 basic searches or 25 advanced searches) to prevent runaway costs.


Operational Safety Rules

  1. Fail-open always. Any Tavily error (network down, auth failure, rate limit, budget exceeded) MUST log to SearchExecution::warnings and allow the search to complete with local-only results. Never abort or panic.

  2. Content size limits. Truncate each Tavily result's content field to policy.tavily_max_content_chars (default 2,000) before injecting into any prompt or document chunk. Prevents context explosion.

  3. Credit budget tracking. Maintain a session-level atomic counter. When counter >= tavily_credit_budget_per_session, log a warning and disable Tavily for the remainder of the session.

  4. PII scrubbing. Never send user-identifying information (names, emails, account IDs) in Tavily queries. Strip PII from the query before the API call.

  5. Prompt injection protection. Tavily's built-in firewall scrubs content at the API level, but Vox should additionally treat Tavily content as untrusted user input — escape or truncate before LLM injection.

  6. A2A forwarding. When including Tavily results in an A2ARetrievalResponse destined for another agent, use durable artifact references (URI + short-lived auth token) rather than inline text. This prevents cross-agent prompt injection per the A2A evidence-sharing research (see research-agent-handoff-a2a-evidence-sharing-2026.md).


Tavily vs Firecrawl Decision Matrix

Use CaseToolReason
Real-time query answer groundingTavilySearch-first, ranked snippets, built-in safety
Full documentation site ingestionFirecrawlFull-page extraction, JS handling, structured schema
Multi-source research synthesisTavily /researchAutonomous multi-step, single API call
Knowledge base construction from URLsTavily /extract or FirecrawlDepends on JS complexity
Fresh news/events contextTavilytopic="news", time_range="day"

Recommended phasing:

  • Phase 1 (now): Tavily only — covers search, extract, and research use cases with a single vendor and Rust SDK
  • Phase 2 (later): Add Firecrawl HTTP client for specialized deep extraction into vox-corpus pipelines

Integration Test Checklist

Before enabling Tavily in CI:

  • vox clavis doctor reports TAVILY_API_KEY: resolved
  • vox search "test query" --tavily returns results from Tavily backend
  • SearchExecution::tavily_lines is non-empty in output
  • Credit counter increments per call
  • Budget cap stops further calls at limit
  • Network failure → warnings only, local results returned normally
  • A2ARetrievalResponse.tavily_excerpts populated when Tavily fires