deepsearch-rb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +8 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +138 -0
  5. data/lib/deepsearch/configuration.rb +88 -0
  6. data/lib/deepsearch/engine/pipeline.rb +126 -0
  7. data/lib/deepsearch/engine/steps/data_aggregation/parsed_website.rb +122 -0
  8. data/lib/deepsearch/engine/steps/data_aggregation/process.rb +56 -0
  9. data/lib/deepsearch/engine/steps/data_aggregation/result.rb +28 -0
  10. data/lib/deepsearch/engine/steps/parallel_search/process.rb +42 -0
  11. data/lib/deepsearch/engine/steps/parallel_search/result.rb +28 -0
  12. data/lib/deepsearch/engine/steps/parallel_search/search.rb +95 -0
  13. data/lib/deepsearch/engine/steps/prepare_subqueries/process.rb +87 -0
  14. data/lib/deepsearch/engine/steps/prepare_subqueries/result.rb +30 -0
  15. data/lib/deepsearch/engine/steps/rag/chunker.rb +31 -0
  16. data/lib/deepsearch/engine/steps/rag/process.rb +79 -0
  17. data/lib/deepsearch/engine/steps/rag/similarity.rb +60 -0
  18. data/lib/deepsearch/engine/steps/rag/values/chunk.rb +23 -0
  19. data/lib/deepsearch/engine/steps/rag/values/query.rb +44 -0
  20. data/lib/deepsearch/engine/steps/rag/values/result.rb +33 -0
  21. data/lib/deepsearch/engine/steps/summarization/process.rb +53 -0
  22. data/lib/deepsearch/engine/steps/summarization/values/result.rb +31 -0
  23. data/lib/deepsearch/engine.rb +25 -0
  24. data/lib/deepsearch/logger.rb +32 -0
  25. data/lib/deepsearch/prompts_config.rb +82 -0
  26. data/lib/deepsearch/version.rb +5 -0
  27. data/lib/deepsearch.rb +39 -0
  28. data/lib/search_adapters/mock_adapter.rb +73 -0
  29. data/lib/search_adapters/serper_adapter.rb +106 -0
  30. data/lib/search_adapters/tavily_adapter.rb +113 -0
  31. data/lib/search_adapters.rb +24 -0
  32. metadata +186 -0
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepsearch
4
+ # Defines the default prompts used in various steps of the Deepsearch pipeline.
5
+ # Users can provide their own prompt configuration object to customize these prompts.
6
+ # The custom object should respond to the same methods as this class.
7
+ class PromptsConfig
8
+ # @param query [String] The original user query.
9
+ # @return [String] The prompt for generating subqueries.
10
+ def subquery_prompt(query:)
11
+ <<~PROMPT
12
+ You are a search query expansion expert. Given a search query, generate 3-5 related subqueries that would help find more comprehensive information about the topic.
13
+
14
+ Original query: "#{query}"
15
+
16
+ Please generate subqueries that:
17
+ 1. Cover different aspects of the topic
18
+ 2. Use varied terminology and synonyms
19
+ 3. Are specific enough to be useful but broad enough to capture relevant information
20
+ 4. Focus on different angles (technical, practical, conceptual, etc.)
21
+
22
+ Format your response as a simple list, one subquery per line, without numbering or bullet points.
23
+ PROMPT
24
+ end
25
+
26
+ # @param query [String] The user query to be enriched.
27
+ # @return [String] The prompt for enriching the query with tags for embedding.
28
+ def enrich_query_prompt(query:)
29
+ <<~PROMPT
30
+ You are a search query expansion assistant. Based on the user's query, generate 5 to 7 highly relevant tags or keywords that expand its core concepts. These tags are used to improve vector search results.
31
+
32
+ INSTRUCTIONS:
33
+ - Do NOT add any explanation, numbering, or introductory text.
34
+ - Provide ONLY a single line of comma-separated tags.
35
+
36
+ USER QUERY: "#{query}"
37
+
38
+ TAGS:
39
+ PROMPT
40
+ end
41
+
42
+ # @param query [String] The original user query.
43
+ # @param context_text [String] The aggregated text from relevant sources.
44
+ # @param sources_list [String] The formatted list of sources for citation.
45
+ # @return [String] The prompt for summarizing the context and answering the query.
46
+ def summarization_prompt(query:, context_text:, sources_list:)
47
+ <<~PROMPT
48
+ You are a research assistant. Your task is to synthesize a comprehensive answer to the user's query based *only* on the provided text snippets.
49
+
50
+ User Query: "#{query}"
51
+
52
+ Provided Context:
53
+ ---
54
+ #{context_text}
55
+ ---
56
+
57
+ Sources:
58
+ #{sources_list}
59
+
60
+ Instructions:
61
+ 0. Format: Markdown
62
+ 1. Carefully read the user's query and all the provided context from the sources.
63
+ 2. When you use information from a source, you MUST cite it using the following markdown link format: `[<source_number>](<source_link>)`.
64
+ * **To find the `<source_link>`:** The 'Sources' section provides a numbered list where each source is in the format `[<number>]: <url>`. Extract this URL for the specific source number you are citing.
65
+ * **Example Citation:** If a fact comes from source number 1, and the 'Sources' section lists `[1]: https://example.com/source1`, your citation should be `[1](https://example.com/source1)`.
66
+ * **Placement:** Place citations immediately after the sentence or clause where the information is used.
67
+ * **Multiple Sources:** If a single statement draws information from multiple sources, cite each source individually, for example: `[1](https://link1.com) [3](https://link3.com)`.
68
+ * **Crucial:** Always use the exact format `[<source_number>](<source_link>)` with square brackets around the number.
69
+ 3. Structure your response with clear headings and bullet points where appropriate.
70
+ 4. If the provided context does not contain enough information to answer the query, state that clearly: "I cannot answer this query based on the provided sources."
71
+ 5. At the end of your response, include a "## References" section that lists all used sources in the following format:
72
+ ```
73
+ ## References
74
+ 1. [Source Title](<source_link>)
75
+ 2. [Another Source](<another_link>)
76
+ ```
77
+ Where possible, extract meaningful titles from the context or use the domain name if no title is available.
78
+ 6. Do not include sources in the References section that you didn't actually cite in your response.
79
+ PROMPT
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepsearch
4
+ VERSION = "0.1.0"
5
+ end
data/lib/deepsearch.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "deepsearch/version"
4
+ require_relative "deepsearch/logger"
5
+ require_relative "deepsearch/configuration"
6
+ require_relative "deepsearch/engine"
7
+ require_relative "search_adapters"
8
+
9
+ # The main module for the Deepsearch gem.
10
+ # It provides the primary interface for configuration and for initiating searches.
11
+ module Deepsearch
12
+ # A generic error class for exceptions raised by the Deepsearch gem,
13
+ # from which more specific errors can inherit.
14
+ class Error < StandardError; end
15
+
16
+ class << self
17
+ def configuration
18
+ @configuration ||= Configuration.new
19
+ end
20
+
21
+ def configure
22
+ yield(configuration)
23
+ configuration.configure_llm!
24
+ end
25
+
26
+ def reset_configuration!
27
+ @configuration = Configuration.new
28
+ end
29
+
30
+ def search(query, adapter_type: nil, **options)
31
+ engine = Engine.new(adapter_type: adapter_type)
32
+ engine.search(query, **options)
33
+ end
34
+
35
+ def engine(adapter_type: nil)
36
+ Engine.new(adapter_type: adapter_type)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deepsearch
4
+ module SearchAdapters
5
+ # A mock search adapter for testing purposes.
6
+ # It returns a static, predefined set of search results without making any external API calls.
7
+ # This is useful for testing the pipeline's behavior in isolation from live search services.
8
+ class MockAdapter
9
+ def initialize(api_key = nil); end
10
+
11
+ def search(query, options = {})
12
+ return mock_results(query, options)
13
+ end
14
+
15
+ private
16
+
17
+ def mock_results(query, options = {})
18
+ max_results = options[:max_results] || 10
19
+ include_answer = options[:include_answer] != false
20
+
21
+ results = [
22
+ {
23
+ "title" => "Ruby (programming language) - Wikipedia",
24
+ "url" => "https://en.wikipedia.org/wiki/Ruby_(programming_language)",
25
+ "content" => "Ruby is a general-purpose programming language. It was designed with an emphasis on programming productivity and simplicity. In Ruby, everything is an object, including primitive data types. It was developed in the mid-1990s by Yukihiro Matsumoto in Japan.",
26
+ "published_date" => "2024-01-15"
27
+ },
28
+ {
29
+ "title" => "Ruby Programming Language - GeeksforGeeks",
30
+ "url" => "https://www.geeksforgeeks.org/ruby/ruby-programming-language/",
31
+ "content" => "Ruby is a dynamic, reflective, object-oriented, general-purpose programming language. Ruby is a pure object-oriented language developed by Yukihiro Matsumoto. Everything in Ruby is an object except the blocks but there are replacements too.",
32
+ "published_date" => "2024-02-10"
33
+ },
34
+ {
35
+ "title" => "Ruby Programming Language",
36
+ "url" => "https://www.ruby-lang.org/en/",
37
+ "content" => "# Ruby # Ruby is... A dynamic, open source programming language with a focus on natural to read and easy to write code. It has an elegant syntax that is natural to read and easy to write.",
38
+ "published_date" => "2024-03-01"
39
+ },
40
+ {
41
+ "title" => "About Ruby",
42
+ "url" => "https://www.ruby-lang.org/en/about/",
43
+ "content" => "About Ruby About Ruby About Ruby's Growth In Ruby, everything is an object. ruby Ruby follows the information-hiding principle where the implementation details are hidden and only the necessary information is exposed.",
44
+ "published_date" => "2024-02-20"
45
+ },
46
+ {
47
+ "title" => "What's Ruby used for most nowadays? - Reddit",
48
+ "url" => "https://www.reddit.com/r/ruby/comments/yhe3t4/whats_ruby_used_for_most_nowadays/",
49
+ "content" => "Ruby is mainly used in web app development because that's what makes money. However, Ruby is also used for automation, data processing, DevOps tools, and many other applications where its expressive syntax shines.",
50
+ "published_date" => "2024-01-30"
51
+ }
52
+ ]
53
+
54
+ limited_results = results.take(max_results)
55
+
56
+ response = {
57
+ "query" => query,
58
+ "follow_up_questions" => [],
59
+ "images" => [],
60
+ "results" => limited_results,
61
+ "search_depth" => options[:search_depth] || "basic",
62
+ "search_time" => 0.1
63
+ }
64
+
65
+ if include_answer
66
+ response["answer"] = "Ruby is a dynamic, open-source programming language with a focus on simplicity and productivity. It was created by Yukihiro Matsumoto in the mid-1990s and follows the principle that everything is an object. Ruby is particularly popular for web development, especially with the Ruby on Rails framework, but it's also used for automation, data processing, and various other applications."
67
+ end
68
+
69
+ response
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Deepsearch
8
+ module SearchAdapters
9
+ # An adapter for the Serper Search API (google.serper.dev).
10
+ class SerperAdapter
11
+ BASE_URL = 'https://google.serper.dev/search'
12
+
13
+ def initialize(api_key = nil)
14
+ @api_key = api_key || Deepsearch.configuration.serper_api_key
15
+ validate_api_key!
16
+ end
17
+
18
+ # @param query [String] The search query
19
+ # @param options [Hash] Additional search options
20
+ # @option options [Integer] :max_results Maximum number of results to return. Serper calls this `num`.
21
+ # @return [Hash] Parsed and transformed response from Serper API
22
+ # @raise [SerperError] If the API request fails
23
+ def search(query, options = {})
24
+ raise ArgumentError, "Query cannot be empty" if query.nil? || query.strip.empty?
25
+
26
+ payload = build_payload(query, options)
27
+ response = make_request(payload)
28
+ parsed_response = parse_response(response)
29
+ transform_response(parsed_response)
30
+ rescue Net::HTTPError, Net::ReadTimeout, Net::OpenTimeout => e
31
+ raise SerperError, "Network error: #{e.message}"
32
+ rescue JSON::ParserError => e
33
+ raise SerperError, "Invalid JSON response: #{e.message}"
34
+ end
35
+
36
+ private
37
+
38
+ def validate_api_key!
39
+ raise SerperError, "API key is required" if @api_key.nil? || @api_key.strip.empty?
40
+ end
41
+
42
+ def build_payload(query, options)
43
+ payload = {
44
+ q: query
45
+ }
46
+ # Tavily uses `max_results`, Serper uses `num`. Let's support `max_results` from options.
47
+ payload[:num] = options[:max_results] if options[:max_results]
48
+ payload
49
+ end
50
+
51
+ def make_request(payload)
52
+ uri = URI(BASE_URL)
53
+ http = Net::HTTP.new(uri.host, uri.port)
54
+ http.use_ssl = true
55
+ http.read_timeout = 15
56
+ http.open_timeout = 5
57
+
58
+ request = Net::HTTP::Post.new(uri)
59
+ request['Content-Type'] = 'application/json'
60
+ request['X-API-KEY'] = @api_key
61
+ request.body = payload.to_json
62
+
63
+ response = http.request(request)
64
+
65
+ handle_error_response(response) unless response.is_a?(Net::HTTPSuccess)
66
+
67
+ response
68
+ end
69
+
70
+ def parse_response(response)
71
+ JSON.parse(response.body)
72
+ rescue JSON::ParserError => e
73
+ raise SerperError, "Failed to parse response: #{e.message}"
74
+ end
75
+
76
+ def transform_response(response_body)
77
+ results = response_body['organic']&.map do |item|
78
+ {
79
+ 'url' => item['link'],
80
+ 'title' => item['title'],
81
+ 'content' => item['snippet']
82
+ }
83
+ end || []
84
+ { 'results' => results }
85
+ end
86
+
87
+ def handle_error_response(response)
88
+ case response.code.to_i
89
+ when 400
90
+ raise SerperError, "Bad request: #{response.body}"
91
+ when 401, 402
92
+ raise SerperError, "Unauthorized or payment required: #{response.body}"
93
+ when 429
94
+ raise SerperError, "Rate limit exceeded"
95
+ when 500..599
96
+ raise SerperError, "Server error: #{response.code}"
97
+ else
98
+ raise SerperError, "HTTP error: #{response.code} - #{response.body}"
99
+ end
100
+ end
101
+ end
102
+
103
+ # Custom error class for exceptions raised by the SerperAdapter.
104
+ class SerperError < StandardError; end
105
+ end
106
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Deepsearch
8
+ module SearchAdapters
9
+ # An adapter for the Tavily Search API.
10
+ class TavilyAdapter
11
+ BASE_URL = 'https://api.tavily.com/search'
12
+
13
+ def initialize(api_key = nil)
14
+ @api_key = api_key || Deepsearch.configuration.tavily_api_key
15
+ validate_api_key!
16
+ end
17
+
18
+ # @param query [String] The search query
19
+ # @param options [Hash] Additional search options
20
+ # @option options [Integer] :max_results Maximum number of results (default: 10)
21
+ # @option options [Array<String>] :include_domains Domains to include in search
22
+ # @option options [Array<String>] :exclude_domains Domains to exclude from search
23
+ # @option options [Boolean] :include_answer Whether to include AI-generated answer (default: true)
24
+ # @option options [Boolean] :include_raw_content Whether to include raw content (default: false)
25
+ # @option options [String] :search_depth Search depth: 'basic' or 'advanced' (default: 'basic')
26
+ # @return [Hash] Parsed response from Tavily API
27
+ # @raise [TavilyError] If the API request fails
28
+ def search(query, options = {})
29
+ raise ArgumentError, "Query cannot be empty" if query.nil? || query.strip.empty?
30
+
31
+ payload = build_payload(query, options)
32
+ response = make_request(payload)
33
+ parse_response(response)
34
+ rescue Net::HTTPError, Net::ReadTimeout, Net::OpenTimeout => e
35
+ raise TavilyError, "Network error: #{e.message}"
36
+ rescue JSON::ParserError => e
37
+ raise TavilyError, "Invalid JSON response: #{e.message}"
38
+ end
39
+
40
+ private
41
+
42
+ def validate_api_key!
43
+ if @api_key.nil? || @api_key.strip.empty?
44
+ raise TavilyError, "API key is required"
45
+ end
46
+
47
+ unless @api_key.start_with?('tvly-')
48
+ raise TavilyError, "Invalid API key format. Expected format: tvly-YOUR_API_KEY"
49
+ end
50
+ end
51
+
52
+ def build_payload(query, options)
53
+ payload = {
54
+ query: query,
55
+ max_results: options[:max_results] || 10,
56
+ include_answer: options.fetch(:include_answer, true),
57
+ include_raw_content: options.fetch(:include_raw_content, false),
58
+ search_depth: options[:search_depth] || 'basic'
59
+ }
60
+
61
+ payload[:include_domains] = options[:include_domains] if options[:include_domains]
62
+ payload[:exclude_domains] = options[:exclude_domains] if options[:exclude_domains]
63
+
64
+ payload
65
+ end
66
+
67
+ def make_request(payload)
68
+ uri = URI(BASE_URL)
69
+ http = Net::HTTP.new(uri.host, uri.port)
70
+ http.use_ssl = true
71
+ http.read_timeout = 15
72
+ http.open_timeout = 5
73
+
74
+ request = Net::HTTP::Post.new(uri)
75
+ request['Content-Type'] = 'application/json'
76
+ request['Authorization'] = "Bearer #{@api_key}"
77
+ request.body = payload.to_json
78
+
79
+ response = http.request(request)
80
+
81
+ unless response.is_a?(Net::HTTPSuccess)
82
+ handle_error_response(response)
83
+ end
84
+
85
+ response
86
+ end
87
+
88
+ def parse_response(response)
89
+ JSON.parse(response.body)
90
+ rescue JSON::ParserError => e
91
+ raise TavilyError, "Failed to parse response: #{e.message}"
92
+ end
93
+
94
+ def handle_error_response(response)
95
+ case response.code.to_i
96
+ when 400
97
+ raise TavilyError, "Bad request: #{response.body}"
98
+ when 401
99
+ raise TavilyError, "Unauthorized: Invalid API key"
100
+ when 429
101
+ raise TavilyError, "Rate limit exceeded"
102
+ when 500..599
103
+ raise TavilyError, "Server error: #{response.code}"
104
+ else
105
+ raise TavilyError, "HTTP error: #{response.code} - #{response.body}"
106
+ end
107
+ end
108
+ end
109
+
110
+ # Custom error class for exceptions raised by the TavilyAdapter.
111
+ class TavilyError < StandardError; end
112
+ end
113
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'search_adapters/tavily_adapter'
4
+ require_relative 'search_adapters/mock_adapter'
5
+ require_relative 'search_adapters/serper_adapter'
6
+
7
+ module Deepsearch
8
+ module SearchAdapters
9
+ def self.create(type, *args)
10
+ return type.new(*args) if type.is_a?(Class)
11
+
12
+ case type.to_sym
13
+ when :tavily
14
+ TavilyAdapter.new(*args)
15
+ when :serper
16
+ SerperAdapter.new(*args)
17
+ when :mock
18
+ MockAdapter.new(*args)
19
+ else
20
+ raise ArgumentError, "Unknown or invalid adapter type: #{type}"
21
+ end
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deepsearch-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Shagov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-01 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: nokogiri
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.10'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '1.10'
26
+ - !ruby/object:Gem::Dependency
27
+ name: async
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: ruby_llm
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: bundler
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rake
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '13.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '13.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: minitest
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '5.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '5.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: ostruct
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: yard
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0.9'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0.9'
124
+ description: A ruby gem for performing LLM-powered automated web search.
125
+ email:
126
+ - shagov.dev@outlook.com
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - CHANGELOG.md
132
+ - LICENSE.txt
133
+ - README.md
134
+ - lib/deepsearch.rb
135
+ - lib/deepsearch/configuration.rb
136
+ - lib/deepsearch/engine.rb
137
+ - lib/deepsearch/engine/pipeline.rb
138
+ - lib/deepsearch/engine/steps/data_aggregation/parsed_website.rb
139
+ - lib/deepsearch/engine/steps/data_aggregation/process.rb
140
+ - lib/deepsearch/engine/steps/data_aggregation/result.rb
141
+ - lib/deepsearch/engine/steps/parallel_search/process.rb
142
+ - lib/deepsearch/engine/steps/parallel_search/result.rb
143
+ - lib/deepsearch/engine/steps/parallel_search/search.rb
144
+ - lib/deepsearch/engine/steps/prepare_subqueries/process.rb
145
+ - lib/deepsearch/engine/steps/prepare_subqueries/result.rb
146
+ - lib/deepsearch/engine/steps/rag/chunker.rb
147
+ - lib/deepsearch/engine/steps/rag/process.rb
148
+ - lib/deepsearch/engine/steps/rag/similarity.rb
149
+ - lib/deepsearch/engine/steps/rag/values/chunk.rb
150
+ - lib/deepsearch/engine/steps/rag/values/query.rb
151
+ - lib/deepsearch/engine/steps/rag/values/result.rb
152
+ - lib/deepsearch/engine/steps/summarization/process.rb
153
+ - lib/deepsearch/engine/steps/summarization/values/result.rb
154
+ - lib/deepsearch/logger.rb
155
+ - lib/deepsearch/prompts_config.rb
156
+ - lib/deepsearch/version.rb
157
+ - lib/search_adapters.rb
158
+ - lib/search_adapters/mock_adapter.rb
159
+ - lib/search_adapters/serper_adapter.rb
160
+ - lib/search_adapters/tavily_adapter.rb
161
+ homepage: https://github.com/alexshagov/deepsearch-rb
162
+ licenses:
163
+ - MIT
164
+ metadata:
165
+ allowed_push_host: https://rubygems.org
166
+ homepage_uri: https://github.com/alexshagov/deepsearch-rb
167
+ source_code_uri: https://github.com/alexshagov/deepsearch-rb
168
+ changelog_uri: https://github.com/alexshagov/deepsearch-rb/blob/main/CHANGELOG.md
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: 3.2.0
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubygems_version: 3.6.9
184
+ specification_version: 4
185
+ summary: A ruby gem for performing LLM-powered automated web search.
186
+ test_files: []