Class: RubyLLM::Toolbox::Search::Brave

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

Overview

Brave Search API adapter — a commercial drop-in alternative to Tavily. Auth is a subscription token sent in the X-Subscribe-Token header. The basic plan has no synthesized answer, so #search returns answer: nil and a list of web results.

Select it with config.search_adapter = :brave and config.brave_api_key.

Constant Summary collapse

ENDPOINT =
"https://api.search.brave.com/res/v1/web/search"

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Brave.



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

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

Instance Method Details

#get_json(url, params) ⇒ Object

Seam for tests.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ruby_llm/toolbox/search/brave.rb', line 40

def get_json(url, params)
  uri = URI.parse(url)
  uri.query = URI.encode_www_form(params)
  request = Net::HTTP::Get.new(uri)
  request["Accept"] = "application/json"
  request["X-Subscribe-Token"] = @api_key
  request["User-Agent"] = @user_agent if @user_agent

  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, "Brave returned HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)

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

#search(query, max_results: 5) ⇒ Object

Raises:



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ruby_llm/toolbox/search/brave.rb', line 26

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

  # Brave caps count at 20; keep within the tool's own 1..10 range anyway.
  count = max_results.clamp(1, 20)
  data = get_json(ENDPOINT, q: query, count: count)

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