Class: RubyLLM::Toolbox::Search::Tavily

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_llm/toolbox/search/tavily.rb

Overview

Default web_search backend. Tavily is built for agent use: one call returns cleaned result content and an optional synthesized answer. Swap in another adapter via config.search_adapter (anything responding to #search(query, max_results:) and returning { answer:, results: }).

Constant Summary collapse

ENDPOINT =
"https://api.tavily.com/search"

Instance Method Summary collapse

Constructor Details

#initialize(api_key:, user_agent: nil, timeout: 10) ⇒ Tavily

Returns a new instance of Tavily.



21
22
23
24
25
# File 'lib/ruby_llm/toolbox/search/tavily.rb', line 21

def initialize(api_key:, user_agent: nil, timeout: 10)
  @api_key = api_key
  @user_agent = user_agent
  @timeout = timeout
end

Instance Method Details

#post_json(url, payload) ⇒ Object

Seam for tests.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/ruby_llm/toolbox/search/tavily.rb', line 46

def post_json(url, payload)
  uri = URI.parse(url)
  request = Net::HTTP::Post.new(uri)
  request["Content-Type"] = "application/json"
  request["Accept"] = "application/json"
  request["User-Agent"] = @user_agent if @user_agent
  request.body = JSON.generate(payload)

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
                             open_timeout: @timeout, read_timeout: @timeout) do |http|
    http.request(request)
  end

  raise Error, "Tavily returned HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)

  JSON.parse(response.body)
rescue JSON::ParserError => e
  raise Error, "invalid JSON from Tavily (#{e.message})"
rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e
  raise Error, e.message
end

#search(query, max_results: 5) ⇒ Object

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ruby_llm/toolbox/search/tavily.rb', line 27

def search(query, max_results: 5)
  raise Error, "missing Tavily API key" if @api_key.nil? || @api_key.to_s.empty?

  data = post_json(ENDPOINT, {
                     api_key: @api_key,
                     query: query,
                     max_results: max_results,
                     include_answer: true
                   })

  {
    answer: data["answer"],
    results: Array(data["results"]).map do |r|
      { title: r["title"], url: r["url"], content: r["content"] }
    end
  }
end