exa-ai 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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +562 -0
- data/exe/exa-ai +95 -0
- data/exe/exa-ai-answer +131 -0
- data/exe/exa-ai-context +104 -0
- data/exe/exa-ai-get-contents +114 -0
- data/exe/exa-ai-research-get +110 -0
- data/exe/exa-ai-research-list +95 -0
- data/exe/exa-ai-research-start +175 -0
- data/exe/exa-ai-search +134 -0
- data/lib/exa/cli/base.rb +51 -0
- data/lib/exa/cli/error_handler.rb +98 -0
- data/lib/exa/cli/formatters/answer_formatter.rb +63 -0
- data/lib/exa/cli/formatters/contents_formatter.rb +50 -0
- data/lib/exa/cli/formatters/context_formatter.rb +58 -0
- data/lib/exa/cli/formatters/research_formatter.rb +120 -0
- data/lib/exa/cli/formatters/search_formatter.rb +44 -0
- data/lib/exa/cli/polling.rb +46 -0
- data/lib/exa/client.rb +132 -0
- data/lib/exa/connection.rb +32 -0
- data/lib/exa/error.rb +31 -0
- data/lib/exa/middleware/raise_error.rb +55 -0
- data/lib/exa/resources/answer.rb +20 -0
- data/lib/exa/resources/contents_result.rb +29 -0
- data/lib/exa/resources/context_result.rb +37 -0
- data/lib/exa/resources/find_similar_result.rb +28 -0
- data/lib/exa/resources/research_list.rb +18 -0
- data/lib/exa/resources/research_task.rb +39 -0
- data/lib/exa/resources/search_result.rb +30 -0
- data/lib/exa/services/answer.rb +23 -0
- data/lib/exa/services/context.rb +27 -0
- data/lib/exa/services/find_similar.rb +26 -0
- data/lib/exa/services/get_contents.rb +25 -0
- data/lib/exa/services/research_get.rb +30 -0
- data/lib/exa/services/research_list.rb +37 -0
- data/lib/exa/services/research_start.rb +26 -0
- data/lib/exa/services/search.rb +26 -0
- data/lib/exa/version.rb +5 -0
- data/lib/exa.rb +54 -0
- metadata +174 -0
data/exe/exa-ai-answer
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Set up load paths
|
5
|
+
require "bundler/setup"
|
6
|
+
require "exa"
|
7
|
+
require "exa/cli/base"
|
8
|
+
require "exa/cli/formatters/answer_formatter"
|
9
|
+
|
10
|
+
# Parse command-line arguments
|
11
|
+
def parse_args(argv)
|
12
|
+
args = {
|
13
|
+
output_format: "json",
|
14
|
+
api_key: nil,
|
15
|
+
text: false
|
16
|
+
}
|
17
|
+
|
18
|
+
# Extract query (first non-flag argument)
|
19
|
+
query_parts = []
|
20
|
+
i = 0
|
21
|
+
while i < argv.length
|
22
|
+
arg = argv[i]
|
23
|
+
case arg
|
24
|
+
when "--text"
|
25
|
+
args[:text] = true
|
26
|
+
i += 1
|
27
|
+
when "--output-schema"
|
28
|
+
args[:output_schema] = argv[i + 1]
|
29
|
+
i += 2
|
30
|
+
when "--api-key"
|
31
|
+
args[:api_key] = argv[i + 1]
|
32
|
+
i += 2
|
33
|
+
when "--output-format"
|
34
|
+
args[:output_format] = argv[i + 1]
|
35
|
+
i += 2
|
36
|
+
when "--help", "-h"
|
37
|
+
puts <<~HELP
|
38
|
+
Usage: exa-api answer QUERY [OPTIONS]
|
39
|
+
|
40
|
+
Generate an answer to a question using Exa AI
|
41
|
+
|
42
|
+
Arguments:
|
43
|
+
QUERY Question or query to answer (required)
|
44
|
+
|
45
|
+
Options:
|
46
|
+
--text Include full text content from sources
|
47
|
+
--output-schema JSON JSON schema for structured output
|
48
|
+
--api-key KEY Exa API key (or set EXA_API_KEY env var)
|
49
|
+
--output-format FMT Output format: json, pretty, or text (default: json)
|
50
|
+
--help, -h Show this help message
|
51
|
+
|
52
|
+
Examples:
|
53
|
+
exa-api answer "What is the capital of France?"
|
54
|
+
exa-api answer "Latest AI breakthroughs" --text
|
55
|
+
exa-api answer "Ruby best practices" --output-format pretty
|
56
|
+
exa-api answer "What is the capital of France?" --output-schema '{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"}}}'
|
57
|
+
HELP
|
58
|
+
exit 0
|
59
|
+
else
|
60
|
+
query_parts << arg
|
61
|
+
i += 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
args[:query] = query_parts.join(" ")
|
66
|
+
args
|
67
|
+
end
|
68
|
+
|
69
|
+
# Main execution
|
70
|
+
begin
|
71
|
+
args = parse_args(ARGV)
|
72
|
+
|
73
|
+
# Validate query
|
74
|
+
if args[:query].nil? || args[:query].empty?
|
75
|
+
$stderr.puts "Error: Query is required"
|
76
|
+
$stderr.puts "Run 'exa-api answer --help' for usage information"
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
|
80
|
+
# Resolve API key
|
81
|
+
api_key = Exa::CLI::Base.resolve_api_key(args[:api_key])
|
82
|
+
|
83
|
+
# Resolve output format
|
84
|
+
output_format = Exa::CLI::Base.resolve_output_format(args[:output_format])
|
85
|
+
|
86
|
+
# Build client
|
87
|
+
client = Exa::CLI::Base.build_client(api_key)
|
88
|
+
|
89
|
+
# Prepare answer parameters
|
90
|
+
answer_params = {}
|
91
|
+
answer_params[:text] = args[:text] if args[:text]
|
92
|
+
|
93
|
+
# Parse output_schema as JSON if provided
|
94
|
+
if args[:output_schema]
|
95
|
+
begin
|
96
|
+
answer_params[:output_schema] = JSON.parse(args[:output_schema])
|
97
|
+
rescue JSON::ParserError => e
|
98
|
+
$stderr.puts "Error: Invalid JSON in --output-schema: #{e.message}"
|
99
|
+
exit 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Execute answer
|
104
|
+
result = client.answer(args[:query], **answer_params)
|
105
|
+
|
106
|
+
# Format and output result
|
107
|
+
output = Exa::CLI::Formatters::AnswerFormatter.format(result, output_format)
|
108
|
+
puts output
|
109
|
+
|
110
|
+
rescue Exa::ConfigurationError => e
|
111
|
+
$stderr.puts "Configuration error: #{e.message}"
|
112
|
+
exit 1
|
113
|
+
rescue Exa::Unauthorized => e
|
114
|
+
$stderr.puts "Authentication error: #{e.message}"
|
115
|
+
$stderr.puts "Check your API key (set EXA_API_KEY or use --api-key)"
|
116
|
+
exit 1
|
117
|
+
rescue Exa::ClientError => e
|
118
|
+
$stderr.puts "Client error: #{e.message}"
|
119
|
+
exit 1
|
120
|
+
rescue Exa::ServerError => e
|
121
|
+
$stderr.puts "Server error: #{e.message}"
|
122
|
+
$stderr.puts "The Exa API may be experiencing issues. Please try again later."
|
123
|
+
exit 1
|
124
|
+
rescue Exa::Error => e
|
125
|
+
$stderr.puts "Error: #{e.message}"
|
126
|
+
exit 1
|
127
|
+
rescue StandardError => e
|
128
|
+
$stderr.puts "Unexpected error: #{e.message}"
|
129
|
+
$stderr.puts e.backtrace.first(5) if ENV["DEBUG"]
|
130
|
+
exit 1
|
131
|
+
end
|
data/exe/exa-ai-context
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "exa"
|
6
|
+
require "exa/cli/base"
|
7
|
+
require "exa/cli/formatters/context_formatter"
|
8
|
+
|
9
|
+
# Parse command line arguments
|
10
|
+
def parse_args(args)
|
11
|
+
query = nil
|
12
|
+
api_key = nil
|
13
|
+
tokens_num = "dynamic"
|
14
|
+
output_format = nil
|
15
|
+
|
16
|
+
i = 0
|
17
|
+
while i < args.length
|
18
|
+
arg = args[i]
|
19
|
+
|
20
|
+
case arg
|
21
|
+
when "--api-key"
|
22
|
+
i += 1
|
23
|
+
api_key = args[i]
|
24
|
+
when "--tokens-num"
|
25
|
+
i += 1
|
26
|
+
tokens_num = args[i]
|
27
|
+
# Convert to integer if it's not "dynamic"
|
28
|
+
tokens_num = tokens_num.to_i unless tokens_num.downcase == "dynamic"
|
29
|
+
when "--output-format"
|
30
|
+
i += 1
|
31
|
+
output_format = args[i]
|
32
|
+
when "--help", "-h"
|
33
|
+
print_help
|
34
|
+
exit 0
|
35
|
+
else
|
36
|
+
# First non-flag argument is the query
|
37
|
+
query = arg if query.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
i += 1
|
41
|
+
end
|
42
|
+
|
43
|
+
{ query: query, api_key: api_key, tokens_num: tokens_num, output_format: output_format }
|
44
|
+
end
|
45
|
+
|
46
|
+
def print_help
|
47
|
+
puts "Exa Context - Get code context from repositories"
|
48
|
+
puts ""
|
49
|
+
puts "Usage: exa-api context <query> [options]"
|
50
|
+
puts ""
|
51
|
+
puts "Arguments:"
|
52
|
+
puts " query Search query for code context (required)"
|
53
|
+
puts ""
|
54
|
+
puts "Options:"
|
55
|
+
puts " --tokens-num NUM Number of tokens for response (or 'dynamic', default: dynamic)"
|
56
|
+
puts " --api-key KEY Exa API key (or set EXA_API_KEY env var)"
|
57
|
+
puts " --output-format FMT Output format: json, pretty, or text (default: json)"
|
58
|
+
puts " --help, -h Show this help message"
|
59
|
+
puts ""
|
60
|
+
puts "Examples:"
|
61
|
+
puts " exa-api context 'React hooks'"
|
62
|
+
puts " exa-api context 'authentication with JWT in Ruby' --tokens-num 5000"
|
63
|
+
puts " exa-api context 'React hooks' --output-format text"
|
64
|
+
end
|
65
|
+
|
66
|
+
begin
|
67
|
+
# Parse arguments
|
68
|
+
options = parse_args(ARGV)
|
69
|
+
|
70
|
+
# Validate query
|
71
|
+
unless options[:query]
|
72
|
+
puts "Error: Query argument required"
|
73
|
+
puts ""
|
74
|
+
puts "Run 'exa-api context --help' for usage information."
|
75
|
+
exit 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# Resolve API key
|
79
|
+
api_key = Exa::CLI::Base.resolve_api_key(options[:api_key])
|
80
|
+
|
81
|
+
# Resolve output format
|
82
|
+
output_format = Exa::CLI::Base.resolve_output_format(options[:output_format])
|
83
|
+
|
84
|
+
# Build client
|
85
|
+
client = Exa::CLI::Base.build_client(api_key)
|
86
|
+
|
87
|
+
# Build request parameters
|
88
|
+
params = {}
|
89
|
+
params[:tokens_num] = options[:tokens_num]
|
90
|
+
|
91
|
+
# Call API
|
92
|
+
result = client.context(options[:query], **params)
|
93
|
+
|
94
|
+
# Format and output
|
95
|
+
output = Exa::CLI::Formatters::ContextFormatter.format(result, output_format)
|
96
|
+
puts output
|
97
|
+
rescue Exa::Error => e
|
98
|
+
puts "Error: #{e.message}"
|
99
|
+
exit 1
|
100
|
+
rescue StandardError => e
|
101
|
+
puts "Unexpected error: #{e.message}"
|
102
|
+
puts e.backtrace.first(5) if ENV["DEBUG"]
|
103
|
+
exit 1
|
104
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "exa"
|
6
|
+
require "exa/cli/base"
|
7
|
+
require "exa/cli/formatters/contents_formatter"
|
8
|
+
|
9
|
+
# Parse command line arguments
|
10
|
+
def parse_args(args)
|
11
|
+
ids = []
|
12
|
+
api_key = nil
|
13
|
+
text = false
|
14
|
+
highlights = false
|
15
|
+
summary = false
|
16
|
+
output_format = nil
|
17
|
+
|
18
|
+
i = 0
|
19
|
+
while i < args.length
|
20
|
+
arg = args[i]
|
21
|
+
|
22
|
+
case arg
|
23
|
+
when "--api-key"
|
24
|
+
i += 1
|
25
|
+
api_key = args[i]
|
26
|
+
when "--text"
|
27
|
+
text = true
|
28
|
+
when "--highlights"
|
29
|
+
highlights = true
|
30
|
+
when "--summary"
|
31
|
+
summary = true
|
32
|
+
when "--output-format"
|
33
|
+
i += 1
|
34
|
+
output_format = args[i]
|
35
|
+
when "--help", "-h"
|
36
|
+
print_help
|
37
|
+
exit 0
|
38
|
+
else
|
39
|
+
# First non-flag argument is the IDs (comma-separated or single)
|
40
|
+
if ids.empty?
|
41
|
+
ids_arg = arg
|
42
|
+
ids = ids_arg.include?(",") ? ids_arg.split(",").map(&:strip) : [ids_arg]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
i += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
{ ids: ids, api_key: api_key, text: text, highlights: highlights, summary: summary, output_format: output_format }
|
50
|
+
end
|
51
|
+
|
52
|
+
def print_help
|
53
|
+
puts "Exa Get-Contents - Retrieve page contents"
|
54
|
+
puts ""
|
55
|
+
puts "Usage: exa-api get-contents <ids> [options]"
|
56
|
+
puts ""
|
57
|
+
puts "Arguments:"
|
58
|
+
puts " ids Comma-separated list of IDs or URLs (required)"
|
59
|
+
puts ""
|
60
|
+
puts "Options:"
|
61
|
+
puts " --text Include page text in response"
|
62
|
+
puts " --highlights Include highlights in response"
|
63
|
+
puts " --summary Include summary in response"
|
64
|
+
puts " --api-key KEY Exa API key (or set EXA_API_KEY env var)"
|
65
|
+
puts " --output-format FMT Output format: json, pretty, or text (default: json)"
|
66
|
+
puts " --help, -h Show this help message"
|
67
|
+
puts ""
|
68
|
+
puts "Examples:"
|
69
|
+
puts " exa-api get-contents 'https://example.com'"
|
70
|
+
puts " exa-api get-contents 'id1,id2,id3' --text"
|
71
|
+
puts " exa-api get-contents 'https://example.com' --highlights --output-format pretty"
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
# Parse arguments
|
76
|
+
options = parse_args(ARGV)
|
77
|
+
|
78
|
+
# Validate IDs
|
79
|
+
if options[:ids].empty?
|
80
|
+
puts "Error: IDs argument required"
|
81
|
+
puts ""
|
82
|
+
puts "Run 'exa-api get-contents --help' for usage information."
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
|
86
|
+
# Resolve API key
|
87
|
+
api_key = Exa::CLI::Base.resolve_api_key(options[:api_key])
|
88
|
+
|
89
|
+
# Resolve output format
|
90
|
+
output_format = Exa::CLI::Base.resolve_output_format(options[:output_format])
|
91
|
+
|
92
|
+
# Build client
|
93
|
+
client = Exa::CLI::Base.build_client(api_key)
|
94
|
+
|
95
|
+
# Build request parameters
|
96
|
+
params = {}
|
97
|
+
params[:text] = true if options[:text]
|
98
|
+
params[:highlights] = true if options[:highlights]
|
99
|
+
params[:summary] = true if options[:summary]
|
100
|
+
|
101
|
+
# Call API
|
102
|
+
result = client.get_contents(options[:ids], **params)
|
103
|
+
|
104
|
+
# Format and output
|
105
|
+
output = Exa::CLI::Formatters::ContentsFormatter.format(result, output_format)
|
106
|
+
puts output
|
107
|
+
rescue Exa::Error => e
|
108
|
+
puts "Error: #{e.message}"
|
109
|
+
exit 1
|
110
|
+
rescue StandardError => e
|
111
|
+
puts "Unexpected error: #{e.message}"
|
112
|
+
puts e.backtrace.first(5) if ENV["DEBUG"]
|
113
|
+
exit 1
|
114
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "exa"
|
6
|
+
|
7
|
+
# Parse command-line arguments
|
8
|
+
api_key = nil
|
9
|
+
research_id = nil
|
10
|
+
events = false
|
11
|
+
stream = false
|
12
|
+
output_format = "json"
|
13
|
+
|
14
|
+
args = ARGV.dup
|
15
|
+
while args.any?
|
16
|
+
arg = args.shift
|
17
|
+
case arg
|
18
|
+
when "--api-key"
|
19
|
+
api_key = args.shift
|
20
|
+
when "--events"
|
21
|
+
events = true
|
22
|
+
when "--stream"
|
23
|
+
stream = true
|
24
|
+
when "--output-format"
|
25
|
+
output_format = args.shift
|
26
|
+
when "--help", "-h"
|
27
|
+
puts <<~HELP
|
28
|
+
Usage: exa-api research-get <research_id> [options]
|
29
|
+
|
30
|
+
Get the status and results of a research task.
|
31
|
+
|
32
|
+
Arguments:
|
33
|
+
research_id ID of the research task to retrieve
|
34
|
+
|
35
|
+
Options:
|
36
|
+
--api-key KEY Exa API key (or use EXA_API_KEY env var)
|
37
|
+
--events Include task execution events in response
|
38
|
+
--stream Stream the response (for real-time updates)
|
39
|
+
--output-format FORMAT Output format: json, pretty, or text (default: json)
|
40
|
+
--help, -h Show this help message
|
41
|
+
|
42
|
+
Examples:
|
43
|
+
exa-api research-get research_123
|
44
|
+
exa-api research-get research_123 --events
|
45
|
+
exa-api research-get research_123 --stream
|
46
|
+
exa-api research-get research_123 --output-format pretty
|
47
|
+
HELP
|
48
|
+
exit 0
|
49
|
+
else
|
50
|
+
# First positional argument is the research_id
|
51
|
+
if research_id.nil?
|
52
|
+
research_id = arg
|
53
|
+
else
|
54
|
+
warn "Unknown option: #{arg}"
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Validate required arguments
|
61
|
+
if research_id.nil?
|
62
|
+
warn "Error: Research ID argument required"
|
63
|
+
warn "Usage: exa-api research-get <research_id> [options]"
|
64
|
+
warn "Try 'exa-api research-get --help' for more information"
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
begin
|
69
|
+
# Resolve API key
|
70
|
+
api_key = Exa::CLI::Base.resolve_api_key(api_key)
|
71
|
+
|
72
|
+
# Build client
|
73
|
+
client = Exa::CLI::Base.build_client(api_key)
|
74
|
+
|
75
|
+
# Build parameters
|
76
|
+
params = {}
|
77
|
+
params[:events] = events if events
|
78
|
+
params[:stream] = stream if stream
|
79
|
+
|
80
|
+
# Call API
|
81
|
+
result = client.research_get(research_id, **params)
|
82
|
+
|
83
|
+
# Format output
|
84
|
+
formatted = Exa::CLI::Formatters::ResearchFormatter.format_task(
|
85
|
+
result,
|
86
|
+
output_format,
|
87
|
+
show_events: events
|
88
|
+
)
|
89
|
+
puts formatted
|
90
|
+
|
91
|
+
rescue Exa::NotFound => e
|
92
|
+
warn "Research task not found: #{e.message}"
|
93
|
+
exit 1
|
94
|
+
rescue Exa::Unauthorized => e
|
95
|
+
warn "Authentication failed: #{e.message}"
|
96
|
+
warn "Please provide a valid API key via --api-key or EXA_API_KEY environment variable"
|
97
|
+
exit 1
|
98
|
+
rescue Exa::ClientError => e
|
99
|
+
warn "Client error: #{e.message}"
|
100
|
+
exit 1
|
101
|
+
rescue Exa::ServerError => e
|
102
|
+
warn "Server error: #{e.message}"
|
103
|
+
exit 1
|
104
|
+
rescue Exa::Error => e
|
105
|
+
warn "Error: #{e.message}"
|
106
|
+
exit 1
|
107
|
+
rescue StandardError => e
|
108
|
+
warn "Unexpected error: #{e.message}"
|
109
|
+
exit 1
|
110
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "exa"
|
6
|
+
|
7
|
+
# Parse command-line arguments
|
8
|
+
api_key = nil
|
9
|
+
cursor = nil
|
10
|
+
limit = 10
|
11
|
+
output_format = "json"
|
12
|
+
|
13
|
+
args = ARGV.dup
|
14
|
+
while args.any?
|
15
|
+
arg = args.shift
|
16
|
+
case arg
|
17
|
+
when "--api-key"
|
18
|
+
api_key = args.shift
|
19
|
+
when "--cursor"
|
20
|
+
cursor = args.shift
|
21
|
+
when "--limit"
|
22
|
+
limit = args.shift.to_i
|
23
|
+
when "--output-format"
|
24
|
+
output_format = args.shift
|
25
|
+
when "--help", "-h"
|
26
|
+
puts <<~HELP
|
27
|
+
Usage: exa-api research-list [options]
|
28
|
+
|
29
|
+
List research tasks with cursor-based pagination.
|
30
|
+
|
31
|
+
Options:
|
32
|
+
--api-key KEY Exa API key (or use EXA_API_KEY env var)
|
33
|
+
--cursor CURSOR Pagination cursor for next page
|
34
|
+
--limit LIMIT Number of results per page (default: 10)
|
35
|
+
--output-format FORMAT Output format: json, pretty, or text (default: json)
|
36
|
+
--help, -h Show this help message
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
exa-api research-list
|
40
|
+
exa-api research-list --limit 20
|
41
|
+
exa-api research-list --cursor next_page_cursor
|
42
|
+
exa-api research-list --output-format pretty
|
43
|
+
HELP
|
44
|
+
exit 0
|
45
|
+
else
|
46
|
+
warn "Unknown option: #{arg}"
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
# Resolve API key
|
53
|
+
api_key = Exa::CLI::Base.resolve_api_key(api_key)
|
54
|
+
|
55
|
+
# Build client
|
56
|
+
client = Exa::CLI::Base.build_client(api_key)
|
57
|
+
|
58
|
+
# Build parameters
|
59
|
+
params = {limit: limit}
|
60
|
+
params[:cursor] = cursor if cursor
|
61
|
+
|
62
|
+
# Call API
|
63
|
+
result = client.research_list(**params)
|
64
|
+
|
65
|
+
# Format output
|
66
|
+
formatted = Exa::CLI::Formatters::ResearchFormatter.format_list(result, output_format)
|
67
|
+
puts formatted
|
68
|
+
|
69
|
+
# Show pagination info if there are more results
|
70
|
+
if result.has_more && result.next_cursor
|
71
|
+
if output_format == "pretty"
|
72
|
+
puts "\n" + "=" * 80
|
73
|
+
puts "More results available. Use --cursor #{result.next_cursor} to get next page."
|
74
|
+
else
|
75
|
+
warn "More results available. Use --cursor #{result.next_cursor} to get next page."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
rescue Exa::Unauthorized => e
|
80
|
+
warn "Authentication failed: #{e.message}"
|
81
|
+
warn "Please provide a valid API key via --api-key or EXA_API_KEY environment variable"
|
82
|
+
exit 1
|
83
|
+
rescue Exa::ClientError => e
|
84
|
+
warn "Client error: #{e.message}"
|
85
|
+
exit 1
|
86
|
+
rescue Exa::ServerError => e
|
87
|
+
warn "Server error: #{e.message}"
|
88
|
+
exit 1
|
89
|
+
rescue Exa::Error => e
|
90
|
+
warn "Error: #{e.message}"
|
91
|
+
exit 1
|
92
|
+
rescue StandardError => e
|
93
|
+
warn "Unexpected error: #{e.message}"
|
94
|
+
exit 1
|
95
|
+
end
|