exaonruby 1.0.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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +614 -0
- data/exaonruby.gemspec +37 -0
- data/exe/exa +7 -0
- data/lib/exa/cli.rb +458 -0
- data/lib/exa/client.rb +210 -0
- data/lib/exa/configuration.rb +81 -0
- data/lib/exa/endpoints/answer.rb +109 -0
- data/lib/exa/endpoints/contents.rb +141 -0
- data/lib/exa/endpoints/events.rb +71 -0
- data/lib/exa/endpoints/find_similar.rb +154 -0
- data/lib/exa/endpoints/imports.rb +145 -0
- data/lib/exa/endpoints/monitors.rb +193 -0
- data/lib/exa/endpoints/research.rb +158 -0
- data/lib/exa/endpoints/search.rb +195 -0
- data/lib/exa/endpoints/webhooks.rb +161 -0
- data/lib/exa/endpoints/webset_enrichments.rb +162 -0
- data/lib/exa/endpoints/webset_items.rb +90 -0
- data/lib/exa/endpoints/webset_searches.rb +137 -0
- data/lib/exa/endpoints/websets.rb +214 -0
- data/lib/exa/errors.rb +180 -0
- data/lib/exa/resources/answer_response.rb +101 -0
- data/lib/exa/resources/base.rb +56 -0
- data/lib/exa/resources/contents_response.rb +123 -0
- data/lib/exa/resources/event.rb +84 -0
- data/lib/exa/resources/import.rb +137 -0
- data/lib/exa/resources/monitor.rb +205 -0
- data/lib/exa/resources/paginated_response.rb +87 -0
- data/lib/exa/resources/research_task.rb +165 -0
- data/lib/exa/resources/search_response.rb +111 -0
- data/lib/exa/resources/search_result.rb +95 -0
- data/lib/exa/resources/webhook.rb +152 -0
- data/lib/exa/resources/webset.rb +491 -0
- data/lib/exa/resources/webset_item.rb +256 -0
- data/lib/exa/utils/parameter_converter.rb +159 -0
- data/lib/exa/utils/webhook_handler.rb +239 -0
- data/lib/exa/version.rb +7 -0
- data/lib/exa.rb +130 -0
- metadata +146 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# typed: strict
|
|
4
|
+
|
|
5
|
+
module Exa
|
|
6
|
+
module Resources
|
|
7
|
+
class SearchResponse < Base
|
|
8
|
+
# @return [String] Unique request identifier
|
|
9
|
+
def request_id
|
|
10
|
+
get(:request_id)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [String, nil] The search type that was resolved/used
|
|
14
|
+
def resolved_search_type
|
|
15
|
+
get(:resolved_search_type)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [String, nil] The search type (for auto searches)
|
|
19
|
+
def search_type
|
|
20
|
+
get(:search_type)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Array<SearchResult>] Search results
|
|
24
|
+
def results
|
|
25
|
+
@results ||= (get(:results, []) || []).map { |data| SearchResult.new(data) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [String, nil] Combined context string for LLM consumption
|
|
29
|
+
def context
|
|
30
|
+
get(:context)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [CostInfo, nil] Cost information for the request
|
|
34
|
+
def cost
|
|
35
|
+
cost_data = get(:cost_dollars)
|
|
36
|
+
return nil unless cost_data
|
|
37
|
+
|
|
38
|
+
CostInfo.new(cost_data)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Float] Total cost in dollars
|
|
42
|
+
def total_cost
|
|
43
|
+
cost&.total || 0.0
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [Integer] Number of results
|
|
47
|
+
def count
|
|
48
|
+
results.length
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [Boolean] Whether results are empty
|
|
52
|
+
def empty?
|
|
53
|
+
results.empty?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Iterates over each result
|
|
57
|
+
# @yield [SearchResult] Each result
|
|
58
|
+
# @return [Enumerator, self]
|
|
59
|
+
def each(&block)
|
|
60
|
+
return results.each unless block
|
|
61
|
+
|
|
62
|
+
results.each(&block)
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @param index [Integer] Index of result
|
|
67
|
+
# @return [SearchResult, nil] Result at index
|
|
68
|
+
def [](index)
|
|
69
|
+
results[index]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [SearchResult, nil] First result
|
|
73
|
+
def first
|
|
74
|
+
results.first
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @return [SearchResult, nil] Last result
|
|
78
|
+
def last
|
|
79
|
+
results.last
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def inspectable_attributes
|
|
85
|
+
{ request_id: request_id, count: count }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class CostInfo < Base
|
|
90
|
+
# @return [Float] Total cost in dollars
|
|
91
|
+
def total
|
|
92
|
+
get(:total, 0.0)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [Array<Hash>] Breakdown of costs
|
|
96
|
+
def breakdown
|
|
97
|
+
get(:break_down, [])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @return [Hash] Per-request price information
|
|
101
|
+
def per_request_prices
|
|
102
|
+
get(:per_request_prices, {})
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @return [Hash] Per-page price information
|
|
106
|
+
def per_page_prices
|
|
107
|
+
get(:per_page_prices, {})
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# typed: strict
|
|
4
|
+
|
|
5
|
+
module Exa
|
|
6
|
+
module Resources
|
|
7
|
+
class SearchResult < Base
|
|
8
|
+
# @return [String] Unique identifier for the result
|
|
9
|
+
def id
|
|
10
|
+
get(:id)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [String] Title of the page
|
|
14
|
+
def title
|
|
15
|
+
get(:title)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [String] URL of the page
|
|
19
|
+
def url
|
|
20
|
+
get(:url)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Time, nil] Published date of the content
|
|
24
|
+
def published_date
|
|
25
|
+
date_str = get(:published_date)
|
|
26
|
+
return nil unless date_str
|
|
27
|
+
|
|
28
|
+
Time.parse(date_str)
|
|
29
|
+
rescue ArgumentError
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [String, nil] Author of the content
|
|
34
|
+
def author
|
|
35
|
+
get(:author)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [String, nil] URL of the page image
|
|
39
|
+
def image
|
|
40
|
+
get(:image)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [String, nil] URL of the page favicon
|
|
44
|
+
def favicon
|
|
45
|
+
get(:favicon)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Float, nil] Relevance score
|
|
49
|
+
def score
|
|
50
|
+
get(:score)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [String, nil] Full text content of the page
|
|
54
|
+
def text
|
|
55
|
+
get(:text)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Array<String>] Highlighted text snippets
|
|
59
|
+
def highlights
|
|
60
|
+
get(:highlights, [])
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Array<Float>] Scores for each highlight
|
|
64
|
+
def highlight_scores
|
|
65
|
+
get(:highlight_scores, [])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @return [String, nil] AI-generated summary
|
|
69
|
+
def summary
|
|
70
|
+
get(:summary)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @return [Array<SearchResult>] Related subpages
|
|
74
|
+
def subpages
|
|
75
|
+
(get(:subpages, []) || []).map { |data| SearchResult.new(data) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [Hash] Extra metadata
|
|
79
|
+
def extras
|
|
80
|
+
get(:extras, {})
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @return [Array<String>] Links found on the page
|
|
84
|
+
def links
|
|
85
|
+
dig(:extras, :links) || []
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def inspectable_attributes
|
|
91
|
+
{ id: id, title: title, url: url }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# typed: strict
|
|
4
|
+
|
|
5
|
+
module Exa
|
|
6
|
+
module Resources
|
|
7
|
+
class Webhook < Base
|
|
8
|
+
# @return [String] Unique identifier
|
|
9
|
+
def id
|
|
10
|
+
get(:id)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [String] Object type
|
|
14
|
+
def object
|
|
15
|
+
get(:object)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [String] Status: active, inactive
|
|
19
|
+
def status
|
|
20
|
+
get(:status)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Array<String>] Subscribed event types
|
|
24
|
+
def events
|
|
25
|
+
get(:events, [])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [String] Webhook URL
|
|
29
|
+
def url
|
|
30
|
+
get(:url)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [String, nil] Secret for signature verification (only on creation)
|
|
34
|
+
def secret
|
|
35
|
+
get(:secret)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Hash] Custom metadata
|
|
39
|
+
def metadata
|
|
40
|
+
get(:metadata, {})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Time, nil] Creation timestamp
|
|
44
|
+
def created_at
|
|
45
|
+
parse_time(get(:created_at))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Time, nil] Last update timestamp
|
|
49
|
+
def updated_at
|
|
50
|
+
parse_time(get(:updated_at))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Boolean] Whether webhook is active
|
|
54
|
+
def active?
|
|
55
|
+
status == "active"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Boolean] Whether webhook is inactive
|
|
59
|
+
def inactive?
|
|
60
|
+
status == "inactive"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def parse_time(value)
|
|
66
|
+
return nil unless value
|
|
67
|
+
|
|
68
|
+
Time.parse(value)
|
|
69
|
+
rescue ArgumentError
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def inspectable_attributes
|
|
74
|
+
{ id: id, status: status, url: url }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class WebhookAttempt < Base
|
|
79
|
+
# @return [String] Unique identifier
|
|
80
|
+
def id
|
|
81
|
+
get(:id)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @return [String] Object type
|
|
85
|
+
def object
|
|
86
|
+
get(:object)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @return [String] Webhook ID
|
|
90
|
+
def webhook_id
|
|
91
|
+
get(:webhook_id)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [String] Event ID
|
|
95
|
+
def event_id
|
|
96
|
+
get(:event_id)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @return [String] Event type
|
|
100
|
+
def event_type
|
|
101
|
+
get(:event_type)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [Integer, nil] HTTP response status code
|
|
105
|
+
def response_status
|
|
106
|
+
get(:response_status)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @return [String, nil] Response body
|
|
110
|
+
def response_body
|
|
111
|
+
get(:response_body)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @return [Boolean] Whether delivery succeeded
|
|
115
|
+
def success?
|
|
116
|
+
response_status && response_status >= 200 && response_status < 300
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @return [Time, nil] Attempt timestamp
|
|
120
|
+
def attempted_at
|
|
121
|
+
parse_time(get(:attempted_at))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @return [Time, nil] Creation timestamp
|
|
125
|
+
def created_at
|
|
126
|
+
parse_time(get(:created_at))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def parse_time(value)
|
|
132
|
+
return nil unless value
|
|
133
|
+
|
|
134
|
+
Time.parse(value)
|
|
135
|
+
rescue ArgumentError
|
|
136
|
+
nil
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class WebhookListResponse < PaginatedResponse
|
|
141
|
+
def data
|
|
142
|
+
@data ||= (get(:data, []) || []).map { |item| Webhook.new(item) }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class WebhookAttemptListResponse < PaginatedResponse
|
|
147
|
+
def data
|
|
148
|
+
@data ||= (get(:data, []) || []).map { |item| WebhookAttempt.new(item) }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|