Class: Tavily::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/tavily/client.rb

Overview

The main entry point for talking to the Tavily API.

Every endpoint method accepts the documented parameters as keyword arguments and forwards any additional keywords (‘**extra`) straight into the request body, so newly released API parameters work without a gem upgrade.

Examples:

client = Tavily::Client.new(api_key: "tvly-...")
response = client.search("who won the 2022 world cup?", include_answer: true)
response.answer # => "Argentina ..."

Constant Summary collapse

DEFAULT_POLL_INTERVAL =

Default polling interval (seconds) for #wait_for_research.

3.0
DEFAULT_POLL_TIMEOUT =

Default overall timeout (seconds) for #wait_for_research.

600

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key: nil, **options) ⇒ Client

Returns a new instance of Client.

Parameters:



30
31
32
33
# File 'lib/tavily/client.rb', line 30

def initialize(api_key: nil, **options)
  @config = build_config(api_key, options)
  @connection = Connection.new(@config)
end

Instance Attribute Details

#configConfiguration (readonly)

Returns the resolved configuration for this client.

Returns:

  • (Configuration)

    the resolved configuration for this client.



25
26
27
# File 'lib/tavily/client.rb', line 25

def config
  @config
end

Instance Method Details

#crawl(url, instructions: nil, chunks_per_source: nil, max_depth: nil, max_breadth: nil, limit: nil, select_paths: nil, select_domains: nil, exclude_paths: nil, exclude_domains: nil, allow_external: nil, include_images: nil, extract_depth: nil, format: nil, include_favicon: nil, timeout: nil, include_usage: nil, **extra) ⇒ CrawlResponse

Crawl a site starting from a root URL, following links.

Parameters:

  • url (String)

    root URL (required)

  • instructions (String, nil) (defaults to: nil)

    natural-language crawl guidance

  • chunks_per_source (Integer, nil) (defaults to: nil)

    1–5, only with instructions

  • max_depth (Integer, nil) (defaults to: nil)

    1–5

  • max_breadth (Integer, nil) (defaults to: nil)

    1–500 links per level

  • limit (Integer, nil) (defaults to: nil)

    total links to process

  • select_paths (Array<String>, nil) (defaults to: nil)

    regex path allowlist

  • select_domains (Array<String>, nil) (defaults to: nil)

    regex domain allowlist

  • exclude_paths (Array<String>, nil) (defaults to: nil)

    regex path blocklist

  • exclude_domains (Array<String>, nil) (defaults to: nil)

    regex domain blocklist

  • allow_external (Boolean, nil) (defaults to: nil)

    follow external domains (default true)

  • include_images (Boolean, nil) (defaults to: nil)
  • extract_depth (String, nil) (defaults to: nil)

    “basic” or “advanced”

  • format (String, nil) (defaults to: nil)

    “markdown” or “text”

  • include_favicon (Boolean, nil) (defaults to: nil)
  • timeout (Numeric, nil) (defaults to: nil)

    10–150s

  • include_usage (Boolean, nil) (defaults to: nil)
  • extra (Hash)

    any additional request-body parameters

Returns:



149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/tavily/client.rb', line 149

def crawl(url, instructions: nil, chunks_per_source: nil, max_depth: nil, max_breadth: nil,
          limit: nil, select_paths: nil, select_domains: nil, exclude_paths: nil,
          exclude_domains: nil, allow_external: nil, include_images: nil, extract_depth: nil,
          format: nil, include_favicon: nil, timeout: nil, include_usage: nil, **extra)
  body = {
    url: url, instructions: instructions, chunks_per_source: chunks_per_source,
    max_depth: max_depth, max_breadth: max_breadth, limit: limit, select_paths: select_paths,
    select_domains: select_domains, exclude_paths: exclude_paths, exclude_domains: exclude_domains,
    allow_external: allow_external, include_images: include_images, extract_depth: extract_depth,
    format: format, include_favicon: include_favicon, timeout: timeout, include_usage: include_usage
  }.merge(extra)
  CrawlResponse.new(@connection.post("/crawl", body))
end

#extract(urls, query: nil, chunks_per_source: nil, extract_depth: nil, include_images: nil, include_favicon: nil, format: nil, timeout: nil, include_usage: nil, **extra) ⇒ ExtractResponse

Extract clean content from one or more URLs.

Parameters:

  • urls (String, Array<String>)

    one URL or an array (max 20)

  • query (String, nil) (defaults to: nil)

    rerank extracted chunks by this intent

  • chunks_per_source (Integer, nil) (defaults to: nil)

    1–5, only with query

  • extract_depth (String, nil) (defaults to: nil)

    “basic” or “advanced”

  • include_images (Boolean, nil) (defaults to: nil)
  • include_favicon (Boolean, nil) (defaults to: nil)
  • format (String, nil) (defaults to: nil)

    “markdown” or “text”

  • timeout (Numeric, nil) (defaults to: nil)

    per-request extraction timeout (1.0–60.0s)

  • include_usage (Boolean, nil) (defaults to: nil)
  • extra (Hash)

    any additional request-body parameters

Returns:



118
119
120
121
122
123
124
125
126
# File 'lib/tavily/client.rb', line 118

def extract(urls, query: nil, chunks_per_source: nil, extract_depth: nil, include_images: nil,
            include_favicon: nil, format: nil, timeout: nil, include_usage: nil, **extra)
  body = {
    urls: urls, query: query, chunks_per_source: chunks_per_source, extract_depth: extract_depth,
    include_images: include_images, include_favicon: include_favicon, format: format,
    timeout: timeout, include_usage: include_usage
  }.merge(extra)
  ExtractResponse.new(@connection.post("/extract", body))
end

#map(url, instructions: nil, max_depth: nil, max_breadth: nil, limit: nil, select_paths: nil, select_domains: nil, exclude_paths: nil, exclude_domains: nil, allow_external: nil, timeout: nil, include_usage: nil, **extra) ⇒ MapResponse

Map the structure of a site, returning discovered URLs.

Parameters:

  • url (String)

    root URL (required)

  • instructions (String, nil) (defaults to: nil)

    natural-language mapping guidance

  • max_depth (Integer, nil) (defaults to: nil)

    1–5

  • max_breadth (Integer, nil) (defaults to: nil)

    1–500

  • limit (Integer, nil) (defaults to: nil)

    1–500

  • select_paths (Array<String>, nil) (defaults to: nil)

    regex path allowlist

  • select_domains (Array<String>, nil) (defaults to: nil)

    regex domain allowlist

  • exclude_paths (Array<String>, nil) (defaults to: nil)

    regex path blocklist

  • exclude_domains (Array<String>, nil) (defaults to: nil)

    regex domain blocklist

  • allow_external (Boolean, nil) (defaults to: nil)

    follow external domains (default true)

  • timeout (Numeric, nil) (defaults to: nil)

    10–150s

  • include_usage (Boolean, nil) (defaults to: nil)
  • extra (Hash)

    any additional request-body parameters

Returns:



179
180
181
182
183
184
185
186
187
188
189
# File 'lib/tavily/client.rb', line 179

def map(url, instructions: nil, max_depth: nil, max_breadth: nil, limit: nil, select_paths: nil,
        select_domains: nil, exclude_paths: nil, exclude_domains: nil, allow_external: nil,
        timeout: nil, include_usage: nil, **extra)
  body = {
    url: url, instructions: instructions, max_depth: max_depth, max_breadth: max_breadth,
    limit: limit, select_paths: select_paths, select_domains: select_domains,
    exclude_paths: exclude_paths, exclude_domains: exclude_domains, allow_external: allow_external,
    timeout: timeout, include_usage: include_usage
  }.merge(extra)
  MapResponse.new(@connection.post("/map", body))
end

#qna_search(query, **options) ⇒ String?

Convenience: run a search and return only the generated answer string.

Parameters:

  • query (String)
  • options (Hash)

    forwarded to #search

Returns:

  • (String, nil)

    the answer, or nil if none was produced



79
80
81
82
# File 'lib/tavily/client.rb', line 79

def qna_search(query, **options)
  options[:include_answer] = true unless options.key?(:include_answer)
  search(query, **options).answer
end

#research(input, model: nil, output_schema: nil, citation_format: nil, include_domains: nil, exclude_domains: nil, output_length: nil, files: nil, **extra) {|event| ... } ⇒ ResearchTask?

Start an asynchronous research task, or stream it live.

Without a block this creates the task and returns immediately with a ResearchTask whose status is “pending”; poll it with #research_task or #wait_for_research. With a block, the task is streamed and each Server-Sent Event is yielded as a ResearchEvent.

Parameters:

  • input (String)

    the research question (required)

  • model (String, nil) (defaults to: nil)

    “mini”, “pro”, or “auto”

  • output_schema (Hash, nil) (defaults to: nil)

    JSON Schema for structured output

  • citation_format (String, nil) (defaults to: nil)

    “numbered”, “mla”, “apa”, or “chicago”

  • include_domains (Array<String>, nil) (defaults to: nil)

    up to 20 preferred domains

  • exclude_domains (Array<String>, nil) (defaults to: nil)

    up to 20 blocked domains

  • output_length (String, nil) (defaults to: nil)

    “short”, “standard”, or “long”

  • files (Array<Hash>, nil) (defaults to: nil)

    up to 5 base64 file objects

  • extra (Hash)

    any additional request-body parameters

Yield Parameters:

Returns:

  • (ResearchTask, nil)

    the queued task, or nil when streaming



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/tavily/client.rb', line 209

def research(input, model: nil, output_schema: nil, citation_format: nil, include_domains: nil,
             exclude_domains: nil, output_length: nil, files: nil, **extra, &block)
  body = {
    input: input, model: model, output_schema: output_schema, citation_format: citation_format,
    include_domains: include_domains, exclude_domains: exclude_domains,
    output_length: output_length, files: files
  }.merge(extra)

  if block
    @connection.stream("/research", body.merge(stream: true), &block)
    nil
  else
    ResearchTask.new(@connection.post("/research", body))
  end
end

#research_task(request_id) ⇒ ResearchTask

Fetch the current status and (when finished) result of a research task.

Parameters:

  • request_id (String)

Returns:



228
229
230
# File 'lib/tavily/client.rb', line 228

def research_task(request_id)
  ResearchTask.new(@connection.get("/research/#{request_id}"))
end

#search(query, search_depth: nil, topic: nil, max_results: nil, chunks_per_source: nil, time_range: nil, days: nil, start_date: nil, end_date: nil, include_answer: nil, include_raw_content: nil, include_images: nil, include_image_descriptions: nil, include_favicon: nil, include_domains: nil, exclude_domains: nil, country: nil, auto_parameters: nil, include_usage: nil, **extra) ⇒ SearchResponse

Execute a web search.

Parameters:

  • query (String)

    the search query (required)

  • search_depth (String, nil) (defaults to: nil)

    “basic”, “advanced”, “fast”, or “ultra-fast”

  • topic (String, nil) (defaults to: nil)

    “general”, “news”, or “finance”

  • max_results (Integer, nil) (defaults to: nil)

    number of results (0–20, default 5)

  • chunks_per_source (Integer, nil) (defaults to: nil)

    1–3, advanced depth only

  • time_range (String, nil) (defaults to: nil)

    “day”/“week”/“month”/“year” (or d/w/m/y)

  • days (Integer, nil) (defaults to: nil)

    limit to the last N days (news topic)

  • start_date (String, nil) (defaults to: nil)

    “YYYY-MM-DD”

  • end_date (String, nil) (defaults to: nil)

    “YYYY-MM-DD”

  • include_answer (Boolean, String, nil) (defaults to: nil)

    true/false, “basic”, or “advanced”

  • include_raw_content (Boolean, String, nil) (defaults to: nil)

    true/false, “markdown”, or “text”

  • include_images (Boolean, nil) (defaults to: nil)
  • include_image_descriptions (Boolean, nil) (defaults to: nil)

    requires include_images: true

  • include_favicon (Boolean, nil) (defaults to: nil)
  • include_domains (Array<String>, nil) (defaults to: nil)

    up to 300 domains

  • exclude_domains (Array<String>, nil) (defaults to: nil)

    up to 150 domains

  • country (String, nil) (defaults to: nil)

    boost results from a country (general topic)

  • auto_parameters (Boolean, nil) (defaults to: nil)

    let Tavily choose parameters

  • include_usage (Boolean, nil) (defaults to: nil)

    include credit usage in the response

  • extra (Hash)

    any additional request-body parameters

Returns:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/tavily/client.rb', line 58

def search(query, search_depth: nil, topic: nil, max_results: nil, chunks_per_source: nil,
           time_range: nil, days: nil, start_date: nil, end_date: nil, include_answer: nil,
           include_raw_content: nil, include_images: nil, include_image_descriptions: nil,
           include_favicon: nil, include_domains: nil, exclude_domains: nil, country: nil,
           auto_parameters: nil, include_usage: nil, **extra)
  body = {
    query: query, search_depth: search_depth, topic: topic, max_results: max_results,
    chunks_per_source: chunks_per_source, time_range: time_range, days: days,
    start_date: start_date, end_date: end_date, include_answer: include_answer,
    include_raw_content: include_raw_content, include_images: include_images,
    include_image_descriptions: include_image_descriptions, include_favicon: include_favicon,
    include_domains: include_domains, exclude_domains: exclude_domains, country: country,
    auto_parameters: auto_parameters, include_usage: include_usage
  }.merge(extra)
  SearchResponse.new(@connection.post("/search", body))
end

#search_context(query, max_tokens: 4000, **options) ⇒ String

Convenience: run a search and return a compact context string suitable for RAG prompts: a JSON array of content objects trimmed to roughly max_tokens tokens (estimated at ~4 characters per token). The top result is always included, even if it alone exceeds the budget.

Parameters:

  • query (String)
  • max_tokens (Integer) (defaults to: 4000)

    approximate token budget for the context

  • options (Hash)

    forwarded to #search

Returns:

  • (String)

    JSON string of [{ “url” =>, “content” => }, …]



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/tavily/client.rb', line 92

def search_context(query, max_tokens: 4000, **options)
  budget = max_tokens * 4
  used = 0
  sources = []
  search(query, **options).results.each do |result|
    entry = { "url" => result.url, "content" => result.content }
    sources << entry
    used += JSON.generate(entry).length
    break if used >= budget
  end
  JSON.generate(sources)
end

#wait_for_research(request_id, poll_interval: DEFAULT_POLL_INTERVAL, timeout: DEFAULT_POLL_TIMEOUT) {|task| ... } ⇒ ResearchTask

Poll a research task until it completes or fails.

Parameters:

  • request_id (String)
  • poll_interval (Numeric) (defaults to: DEFAULT_POLL_INTERVAL)

    seconds between polls

  • timeout (Numeric) (defaults to: DEFAULT_POLL_TIMEOUT)

    overall timeout in seconds

Yield Parameters:

  • task (ResearchTask)

    optional progress callback on each poll

Returns:

Raises:

  • (Tavily::Error)

    if the task fails or the timeout is exceeded



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/tavily/client.rb', line 240

def wait_for_research(request_id, poll_interval: DEFAULT_POLL_INTERVAL,
                      timeout: DEFAULT_POLL_TIMEOUT)
  deadline = monotonic_now + timeout
  loop do
    task = research_task(request_id)
    yield task if block_given?
    return task if task.completed?
    raise Error, "Research task #{request_id} failed" if task.failed?

    if monotonic_now >= deadline
      raise TimeoutError,
            "Research task #{request_id} did not complete within #{timeout}s"
    end

    sleep(poll_interval)
  end
end