exa-ai 0.9.0 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 192ebafa0e355cadad770196faef4841992b4f9ea9f115526edd09b26ef786ec
4
- data.tar.gz: 01c5dfd469dceea4108ba22a91ba2f03941908a3509b6241f4b0e0e63f3e09e9
3
+ metadata.gz: ffa1108ddff0ff951dc18d12eeef57f74020a4c0425916a394fac95e4699fef5
4
+ data.tar.gz: 43c40cc61a7bee139dc3c179fe9d11c40b04dd506d53c22f88e312705ae9dfe3
5
5
  SHA512:
6
- metadata.gz: 2bb8c7dcb3c1940ca2ab84eef4a6f08b93f65a23cf86547b2736e0eefd1dbc012d954dca5626f0c723f28d4527de4112cab46972546bb725c01f0ad0946a6e3e
7
- data.tar.gz: 3b232fe9fa3a95aa86553825373f2b6596910edc84144af3995486c90a96f6f6ea92590cda6420b2069e2dee9a5173b61089bc32257ec1ab22158eaa39ad2fa8
6
+ metadata.gz: 5745df2cf4664fff7b8a507fb82662cd1e448a51dba7a0a0ac30485d624ac1bb3624e85b6086a6bd511a9485636b0d5a9804c561e9476106679a7458572fcf62
7
+ data.tar.gz: 637d5150a3b0d192b1c68288c83c4e0ad13827d4d60ac9deb4a974397ab9b0c2ab86dd9281f33bc11dc5e1fd7ba06b22daa4c8d0f80c8927c108946e4c8ffe46
data/exe/exa-ai-search CHANGED
@@ -15,7 +15,8 @@ def print_help
15
15
 
16
16
  Options:
17
17
  --num-results N Number of results to return (default: 10)
18
- --type TYPE Search type: fast, deep, keyword, or auto (default: fast)
18
+ --type TYPE Search type: auto, neural, fast, deep, deep-reasoning,
19
+ or instant (default: auto)
19
20
  --category CAT Focus on specific data category
20
21
  Options: "company", "research paper", "news", "pdf",
21
22
  "github", "tweet", "personal site", "financial report",
@@ -42,6 +43,19 @@ def print_help
42
43
  --subpage-target PHRASE Subpage target phrases (repeatable)
43
44
  --links N Number of links to extract per result
44
45
  --image-links N Number of image links to extract
46
+ --highlights Include text highlights in results
47
+ --highlights-max-characters N Max characters per highlight
48
+ --highlights-num-sentences N Number of sentences per highlight
49
+ --highlights-per-url N Number of highlights per URL
50
+ --highlights-query QUERY Custom query for highlight extraction
51
+ --livecrawl MODE Livecrawl mode: always, fallback, never, auto, or preferred
52
+ --livecrawl-timeout N Livecrawl timeout in milliseconds
53
+ --max-age-hours N Maximum age of results in hours
54
+
55
+ Search Options:
56
+ --additional-queries QUERY Additional search queries (repeatable)
57
+ --output-schema JSON JSON schema for output structure (@file syntax)
58
+ --user-location CODE User location (ISO country code)
45
59
 
46
60
  General Options:
47
61
  --api-key KEY Exa API key (or set EXA_API_KEY env var)
@@ -105,6 +119,25 @@ def build_contents(args)
105
119
  contents[:extras][:image_links] = args[:image_links] if args[:image_links]
106
120
  end
107
121
 
122
+ # Highlights options
123
+ if args[:highlights]
124
+ highlight_opts = %i[highlights_max_characters highlights_num_sentences highlights_per_url highlights_query]
125
+ if highlight_opts.any? { |k| args[k] }
126
+ contents[:highlights] = {}
127
+ contents[:highlights][:max_characters] = args[:highlights_max_characters] if args[:highlights_max_characters]
128
+ contents[:highlights][:num_sentences] = args[:highlights_num_sentences] if args[:highlights_num_sentences]
129
+ contents[:highlights][:highlights_per_url] = args[:highlights_per_url] if args[:highlights_per_url]
130
+ contents[:highlights][:query] = args[:highlights_query] if args[:highlights_query]
131
+ else
132
+ contents[:highlights] = true
133
+ end
134
+ end
135
+
136
+ # Livecrawl options
137
+ contents[:livecrawl] = args[:livecrawl] if args[:livecrawl]
138
+ contents[:livecrawl_timeout] = args[:livecrawl_timeout] if args[:livecrawl_timeout]
139
+ contents[:max_age_hours] = args[:max_age_hours] if args[:max_age_hours]
140
+
108
141
  contents.empty? ? nil : contents
109
142
  end
110
143
 
@@ -130,17 +163,20 @@ begin
130
163
 
131
164
  # Prepare search parameters
132
165
  search_params = {}
133
- search_params[:numResults] = args[:num_results] if args[:num_results]
166
+ search_params[:num_results] = args[:num_results] if args[:num_results]
134
167
  search_params[:type] = args[:type] if args[:type]
135
168
  search_params[:category] = args[:category] if args[:category]
136
- search_params[:includeDomains] = args[:include_domains] if args[:include_domains]
137
- search_params[:excludeDomains] = args[:exclude_domains] if args[:exclude_domains]
169
+ search_params[:include_domains] = args[:include_domains] if args[:include_domains]
170
+ search_params[:exclude_domains] = args[:exclude_domains] if args[:exclude_domains]
138
171
  search_params[:start_published_date] = args[:start_published_date] if args[:start_published_date]
139
172
  search_params[:end_published_date] = args[:end_published_date] if args[:end_published_date]
140
173
  search_params[:start_crawl_date] = args[:start_crawl_date] if args[:start_crawl_date]
141
174
  search_params[:end_crawl_date] = args[:end_crawl_date] if args[:end_crawl_date]
142
175
  search_params[:include_text] = args[:include_text] if args[:include_text]
143
176
  search_params[:exclude_text] = args[:exclude_text] if args[:exclude_text]
177
+ search_params[:additional_queries] = args[:additional_queries] if args[:additional_queries]
178
+ search_params[:output_schema] = args[:output_schema] if args[:output_schema]
179
+ search_params[:user_location] = args[:user_location] if args[:user_location]
144
180
  contents = build_contents(args)
145
181
  search_params.merge!(contents) if contents
146
182
 
@@ -3,7 +3,8 @@
3
3
  module Exa
4
4
  module CLI
5
5
  class SearchParser
6
- VALID_SEARCH_TYPES = ["fast", "deep", "keyword", "auto"].freeze
6
+ VALID_SEARCH_TYPES = ["auto", "neural", "fast", "deep", "deep-reasoning", "instant"].freeze
7
+ VALID_LIVECRAWL_MODES = ["always", "fallback", "never", "auto", "preferred"].freeze
7
8
  VALID_CATEGORIES = [
8
9
  "company", "research paper", "news", "pdf", "github",
9
10
  "tweet", "personal site", "financial report", "people"
@@ -123,6 +124,47 @@ module Exa
123
124
  when "--image-links"
124
125
  @args[:image_links] = @argv[i + 1].to_i
125
126
  i += 2
127
+ when "--highlights"
128
+ @args[:highlights] = true
129
+ i += 1
130
+ when "--highlights-max-characters"
131
+ @args[:highlights_max_characters] = @argv[i + 1].to_i
132
+ i += 2
133
+ when "--highlights-num-sentences"
134
+ @args[:highlights_num_sentences] = @argv[i + 1].to_i
135
+ i += 2
136
+ when "--highlights-per-url"
137
+ @args[:highlights_per_url] = @argv[i + 1].to_i
138
+ i += 2
139
+ when "--highlights-query"
140
+ @args[:highlights_query] = @argv[i + 1]
141
+ i += 2
142
+ when "--livecrawl"
143
+ livecrawl = @argv[i + 1]
144
+ validate_livecrawl(livecrawl)
145
+ @args[:livecrawl] = livecrawl
146
+ i += 2
147
+ when "--livecrawl-timeout"
148
+ @args[:livecrawl_timeout] = @argv[i + 1].to_i
149
+ i += 2
150
+ when "--max-age-hours"
151
+ @args[:max_age_hours] = @argv[i + 1].to_i
152
+ i += 2
153
+ when "--additional-queries"
154
+ @args[:additional_queries] ||= []
155
+ @args[:additional_queries] << @argv[i + 1]
156
+ i += 2
157
+ when "--output-schema"
158
+ schema_arg = @argv[i + 1]
159
+ @args[:output_schema] = if schema_arg.start_with?("@")
160
+ JSON.parse(File.read(schema_arg[1..]))
161
+ else
162
+ JSON.parse(schema_arg)
163
+ end
164
+ i += 2
165
+ when "--user-location"
166
+ @args[:user_location] = @argv[i + 1]
167
+ i += 2
126
168
  else
127
169
  query_parts << arg
128
170
  i += 1
@@ -142,6 +184,12 @@ module Exa
142
184
  raise ArgumentError, "Search type must be one of: #{VALID_SEARCH_TYPES.join(', ')}"
143
185
  end
144
186
 
187
+ def validate_livecrawl(mode)
188
+ return if VALID_LIVECRAWL_MODES.include?(mode)
189
+
190
+ raise ArgumentError, "Livecrawl mode must be one of: #{VALID_LIVECRAWL_MODES.join(', ')}"
191
+ end
192
+
145
193
  def validate_category(category)
146
194
  return if VALID_CATEGORIES.include?(category)
147
195
 
@@ -11,9 +11,10 @@ module Exa
11
11
  :search_type,
12
12
  :context,
13
13
  :cost_dollars,
14
+ :output,
14
15
  keyword_init: true
15
16
  )
16
- def initialize(results:, request_id: nil, resolved_search_type: nil, search_type: nil, context: nil, cost_dollars: nil)
17
+ def initialize(results:, request_id: nil, resolved_search_type: nil, search_type: nil, context: nil, cost_dollars: nil, output: nil)
17
18
  super
18
19
  freeze
19
20
  end
@@ -36,18 +36,26 @@ module Exa
36
36
  when :include_text then :includeText
37
37
  when :exclude_text then :excludeText
38
38
  when :external_id then :externalId
39
+ when :additional_queries then :additionalQueries
40
+ when :output_schema then :outputSchema
41
+ when :user_location then :userLocation
42
+ when :num_results then :numResults
43
+ when :include_domains then :includeDomains
44
+ when :exclude_domains then :excludeDomains
39
45
  else
40
46
  key
41
47
  end
42
48
  end
43
49
 
44
50
  def content_key?(key)
45
- %i[text summary context subpages subpage_target extras].include?(key)
51
+ %i[text summary context subpages subpage_target extras highlights livecrawl livecrawl_timeout max_age_hours].include?(key)
46
52
  end
47
53
 
48
54
  def convert_content_key(key)
49
55
  case key
50
56
  when :subpage_target then :subpageTarget
57
+ when :livecrawl_timeout then :livecrawlTimeout
58
+ when :max_age_hours then :maxAgeHours
51
59
  else
52
60
  key
53
61
  end
@@ -79,6 +87,12 @@ module Exa
79
87
  else
80
88
  value
81
89
  end
90
+ when :highlights
91
+ if value.is_a?(Hash)
92
+ convert_hash_value(value, highlights_hash_mappings)
93
+ else
94
+ value
95
+ end
82
96
  else
83
97
  value
84
98
  end
@@ -96,7 +110,9 @@ module Exa
96
110
  def text_hash_mappings
97
111
  {
98
112
  max_characters: :maxCharacters,
99
- include_html_tags: :includeHtmlTags
113
+ include_html_tags: :includeHtmlTags,
114
+ include_sections: :includeSections,
115
+ exclude_sections: :excludeSections
100
116
  }
101
117
  end
102
118
 
@@ -118,6 +134,15 @@ module Exa
118
134
  image_links: :imageLinks
119
135
  }
120
136
  end
137
+
138
+ def highlights_hash_mappings
139
+ {
140
+ max_characters: :maxCharacters,
141
+ num_sentences: :numSentences,
142
+ highlights_per_url: :highlightsPerUrl,
143
+ query: :query
144
+ }
145
+ end
121
146
  end
122
147
  end
123
148
  end
@@ -5,7 +5,7 @@ require_relative "parameter_converter"
5
5
  module Exa
6
6
  module Services
7
7
  class Search
8
- VALID_SEARCH_TYPES = ["fast", "deep", "keyword", "auto"].freeze
8
+ VALID_SEARCH_TYPES = ["auto", "neural", "fast", "deep", "deep-reasoning", "instant"].freeze
9
9
  DEFAULT_SEARCH_TYPE = "auto"
10
10
 
11
11
  def initialize(connection, **params)
@@ -24,7 +24,8 @@ module Exa
24
24
  resolved_search_type: body["resolvedSearchType"],
25
25
  search_type: body["searchType"],
26
26
  context: body["context"],
27
- cost_dollars: body["costDollars"]
27
+ cost_dollars: body["costDollars"],
28
+ output: body["output"]
28
29
  )
29
30
  end
30
31
 
data/lib/exa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exa
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exa-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Jackson