exa-ai 0.3.0 → 0.4.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 +4 -4
- data/README.md +94 -591
- data/exe/exa-ai +112 -9
- data/exe/exa-ai-answer +1 -5
- data/exe/exa-ai-context +1 -4
- data/exe/exa-ai-enrichment-cancel +107 -0
- data/exe/exa-ai-enrichment-create +235 -0
- data/exe/exa-ai-enrichment-delete +121 -0
- data/exe/exa-ai-enrichment-get +103 -0
- data/exe/exa-ai-enrichment-list +98 -0
- data/exe/exa-ai-enrichment-update +170 -0
- data/exe/exa-ai-find-similar +240 -0
- data/exe/exa-ai-get-contents +1 -4
- data/exe/exa-ai-research-get +1 -2
- data/exe/exa-ai-research-list +1 -2
- data/exe/exa-ai-research-start +1 -3
- data/exe/exa-ai-search +1 -3
- data/exe/exa-ai-webset-cancel +96 -0
- data/exe/exa-ai-webset-create +192 -0
- data/exe/exa-ai-webset-delete +110 -0
- data/exe/exa-ai-webset-get +92 -0
- data/exe/exa-ai-webset-item-delete +111 -0
- data/exe/exa-ai-webset-item-get +104 -0
- data/exe/exa-ai-webset-item-list +93 -0
- data/exe/exa-ai-webset-list +90 -0
- data/exe/exa-ai-webset-search-cancel +103 -0
- data/exe/exa-ai-webset-search-create +233 -0
- data/exe/exa-ai-webset-search-get +104 -0
- data/exe/exa-ai-webset-update +139 -0
- data/lib/exa/cli/base.rb +3 -3
- data/lib/exa/cli/formatters/enrichment_formatter.rb +69 -0
- data/lib/exa/cli/formatters/webset_formatter.rb +68 -0
- data/lib/exa/cli/formatters/webset_item_formatter.rb +69 -0
- data/lib/exa/client.rb +172 -0
- data/lib/exa/connection.rb +8 -1
- data/lib/exa/resources/webset.rb +74 -0
- data/lib/exa/resources/webset_collection.rb +33 -0
- data/lib/exa/resources/webset_enrichment.rb +71 -0
- data/lib/exa/resources/webset_enrichment_collection.rb +28 -0
- data/lib/exa/resources/webset_search.rb +112 -0
- data/lib/exa/services/parameter_converter.rb +1 -0
- data/lib/exa/services/websets/cancel.rb +36 -0
- data/lib/exa/services/websets/cancel_enrichment.rb +35 -0
- data/lib/exa/services/websets/cancel_search.rb +44 -0
- data/lib/exa/services/websets/create.rb +45 -0
- data/lib/exa/services/websets/create_enrichment.rb +35 -0
- data/lib/exa/services/websets/create_search.rb +48 -0
- data/lib/exa/services/websets/create_search_validator.rb +128 -0
- data/lib/exa/services/websets/create_validator.rb +189 -0
- data/lib/exa/services/websets/delete.rb +36 -0
- data/lib/exa/services/websets/delete_enrichment.rb +35 -0
- data/lib/exa/services/websets/delete_item.rb +20 -0
- data/lib/exa/services/websets/get_item.rb +20 -0
- data/lib/exa/services/websets/get_search.rb +43 -0
- data/lib/exa/services/websets/list.rb +25 -0
- data/lib/exa/services/websets/list_items.rb +20 -0
- data/lib/exa/services/websets/retrieve.rb +47 -0
- data/lib/exa/services/websets/retrieve_enrichment.rb +35 -0
- data/lib/exa/services/websets/update.rb +37 -0
- data/lib/exa/services/websets/update_enrichment.rb +36 -0
- data/lib/exa/services/websets_parameter_converter.rb +45 -0
- data/lib/exa/version.rb +1 -1
- data/lib/exa-ai.rb +5 -0
- data/lib/exa.rb +26 -0
- metadata +65 -3
data/exe/exa-ai
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "
|
|
5
|
-
require "exa"
|
|
6
|
-
require "exa/cli/base"
|
|
4
|
+
require "exa-ai"
|
|
7
5
|
|
|
8
6
|
# Global CLI interface for Exa API
|
|
9
7
|
|
|
10
8
|
module ExaCLI
|
|
11
9
|
AVAILABLE_COMMANDS = {
|
|
12
10
|
"search" => "Search the web",
|
|
11
|
+
"find-similar" => "Find content similar to a URL",
|
|
13
12
|
"answer" => "Generate an answer to a question",
|
|
14
13
|
"context" => "Get code context from repositories",
|
|
15
14
|
"get-contents" => "Retrieve page contents",
|
|
16
15
|
"research-start" => "Start a research task",
|
|
17
16
|
"research-get" => "Get research task status",
|
|
18
|
-
"research-list" => "List research tasks"
|
|
17
|
+
"research-list" => "List research tasks",
|
|
18
|
+
"webset-create" => "Create a new webset",
|
|
19
|
+
"webset-get" => "Get webset details",
|
|
20
|
+
"webset-list" => "List websets",
|
|
21
|
+
"webset-update" => "Update a webset",
|
|
22
|
+
"webset-delete" => "Delete a webset",
|
|
23
|
+
"webset-cancel" => "Cancel a webset",
|
|
24
|
+
"webset-search-create" => "Create a search in a webset",
|
|
25
|
+
"webset-search-get" => "Get webset search details",
|
|
26
|
+
"webset-search-cancel" => "Cancel a webset search",
|
|
27
|
+
"webset-item-list" => "List items in a webset",
|
|
28
|
+
"webset-item-get" => "Get webset item details",
|
|
29
|
+
"webset-item-delete" => "Delete a webset item",
|
|
30
|
+
"enrichment-create" => "Create an enrichment",
|
|
31
|
+
"enrichment-get" => "Get enrichment details",
|
|
32
|
+
"enrichment-list" => "List enrichments",
|
|
33
|
+
"enrichment-update" => "Update an enrichment",
|
|
34
|
+
"enrichment-delete" => "Delete an enrichment",
|
|
35
|
+
"enrichment-cancel" => "Cancel an enrichment"
|
|
19
36
|
}.freeze
|
|
20
37
|
|
|
21
38
|
def self.run
|
|
@@ -31,6 +48,8 @@ module ExaCLI
|
|
|
31
48
|
exit 1
|
|
32
49
|
when "search"
|
|
33
50
|
exec File.expand_path("../exa-ai-search", __FILE__), *ARGV[1..]
|
|
51
|
+
when "find-similar"
|
|
52
|
+
exec File.expand_path("../exa-ai-find-similar", __FILE__), *ARGV[1..]
|
|
34
53
|
when "answer"
|
|
35
54
|
exec File.expand_path("../exa-ai-answer", __FILE__), *ARGV[1..]
|
|
36
55
|
when "context"
|
|
@@ -43,6 +62,42 @@ module ExaCLI
|
|
|
43
62
|
exec File.expand_path("../exa-ai-research-get", __FILE__), *ARGV[1..]
|
|
44
63
|
when "research-list"
|
|
45
64
|
exec File.expand_path("../exa-ai-research-list", __FILE__), *ARGV[1..]
|
|
65
|
+
when "webset-create"
|
|
66
|
+
exec File.expand_path("../exa-ai-webset-create", __FILE__), *ARGV[1..]
|
|
67
|
+
when "webset-get"
|
|
68
|
+
exec File.expand_path("../exa-ai-webset-get", __FILE__), *ARGV[1..]
|
|
69
|
+
when "webset-list"
|
|
70
|
+
exec File.expand_path("../exa-ai-webset-list", __FILE__), *ARGV[1..]
|
|
71
|
+
when "webset-update"
|
|
72
|
+
exec File.expand_path("../exa-ai-webset-update", __FILE__), *ARGV[1..]
|
|
73
|
+
when "webset-delete"
|
|
74
|
+
exec File.expand_path("../exa-ai-webset-delete", __FILE__), *ARGV[1..]
|
|
75
|
+
when "webset-cancel"
|
|
76
|
+
exec File.expand_path("../exa-ai-webset-cancel", __FILE__), *ARGV[1..]
|
|
77
|
+
when "webset-search-create"
|
|
78
|
+
exec File.expand_path("../exa-ai-webset-search-create", __FILE__), *ARGV[1..]
|
|
79
|
+
when "webset-search-get"
|
|
80
|
+
exec File.expand_path("../exa-ai-webset-search-get", __FILE__), *ARGV[1..]
|
|
81
|
+
when "webset-search-cancel"
|
|
82
|
+
exec File.expand_path("../exa-ai-webset-search-cancel", __FILE__), *ARGV[1..]
|
|
83
|
+
when "webset-item-list"
|
|
84
|
+
exec File.expand_path("../exa-ai-webset-item-list", __FILE__), *ARGV[1..]
|
|
85
|
+
when "webset-item-get"
|
|
86
|
+
exec File.expand_path("../exa-ai-webset-item-get", __FILE__), *ARGV[1..]
|
|
87
|
+
when "webset-item-delete"
|
|
88
|
+
exec File.expand_path("../exa-ai-webset-item-delete", __FILE__), *ARGV[1..]
|
|
89
|
+
when "enrichment-create"
|
|
90
|
+
exec File.expand_path("../exa-ai-enrichment-create", __FILE__), *ARGV[1..]
|
|
91
|
+
when "enrichment-get"
|
|
92
|
+
exec File.expand_path("../exa-ai-enrichment-get", __FILE__), *ARGV[1..]
|
|
93
|
+
when "enrichment-list"
|
|
94
|
+
exec File.expand_path("../exa-ai-enrichment-list", __FILE__), *ARGV[1..]
|
|
95
|
+
when "enrichment-update"
|
|
96
|
+
exec File.expand_path("../exa-ai-enrichment-update", __FILE__), *ARGV[1..]
|
|
97
|
+
when "enrichment-delete"
|
|
98
|
+
exec File.expand_path("../exa-ai-enrichment-delete", __FILE__), *ARGV[1..]
|
|
99
|
+
when "enrichment-cancel"
|
|
100
|
+
exec File.expand_path("../exa-ai-enrichment-cancel", __FILE__), *ARGV[1..]
|
|
46
101
|
else
|
|
47
102
|
print_error_for_command(ARGV[0])
|
|
48
103
|
exit 1
|
|
@@ -54,11 +109,51 @@ module ExaCLI
|
|
|
54
109
|
puts ""
|
|
55
110
|
puts "Usage: exa-ai <command> [options]"
|
|
56
111
|
puts ""
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
112
|
+
|
|
113
|
+
print_command_section("Core Search", [
|
|
114
|
+
["search", "Search the web"],
|
|
115
|
+
["find-similar", "Find content similar to a URL"],
|
|
116
|
+
["answer", "Generate an answer to a question"],
|
|
117
|
+
["context", "Get code context from repositories"],
|
|
118
|
+
["get-contents", "Retrieve page contents"]
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
print_command_section("Research", [
|
|
122
|
+
["research-start", "Start a research task"],
|
|
123
|
+
["research-get", "Get research task status"],
|
|
124
|
+
["research-list", "List research tasks"]
|
|
125
|
+
])
|
|
126
|
+
|
|
127
|
+
print_command_section("Websets", [
|
|
128
|
+
["webset-create", "Create a new webset"],
|
|
129
|
+
["webset-get", "Get webset details"],
|
|
130
|
+
["webset-list", "List websets"],
|
|
131
|
+
["webset-update", "Update a webset"],
|
|
132
|
+
["webset-delete", "Delete a webset"],
|
|
133
|
+
["webset-cancel", "Cancel a webset"]
|
|
134
|
+
])
|
|
135
|
+
|
|
136
|
+
print_command_section("Webset Searches", [
|
|
137
|
+
["webset-search-create", "Create a search in a webset"],
|
|
138
|
+
["webset-search-get", "Get webset search details"],
|
|
139
|
+
["webset-search-cancel", "Cancel a webset search"]
|
|
140
|
+
])
|
|
141
|
+
|
|
142
|
+
print_command_section("Webset Items", [
|
|
143
|
+
["webset-item-list", "List items in a webset"],
|
|
144
|
+
["webset-item-get", "Get webset item details"],
|
|
145
|
+
["webset-item-delete", "Delete a webset item"]
|
|
146
|
+
])
|
|
147
|
+
|
|
148
|
+
print_command_section("Webset Enrichments", [
|
|
149
|
+
["enrichment-create", "Create an enrichment"],
|
|
150
|
+
["enrichment-get", "Get enrichment details"],
|
|
151
|
+
["enrichment-list", "List enrichments"],
|
|
152
|
+
["enrichment-update", "Update an enrichment"],
|
|
153
|
+
["enrichment-delete", "Delete an enrichment"],
|
|
154
|
+
["enrichment-cancel", "Cancel an enrichment"]
|
|
155
|
+
])
|
|
156
|
+
|
|
62
157
|
puts "Global Options:"
|
|
63
158
|
puts " --help, -h Show this help message"
|
|
64
159
|
puts " --version Show version number"
|
|
@@ -69,6 +164,14 @@ module ExaCLI
|
|
|
69
164
|
puts " exa-ai research-start --instructions 'Find AI papers'"
|
|
70
165
|
end
|
|
71
166
|
|
|
167
|
+
def self.print_command_section(title, commands)
|
|
168
|
+
puts "#{title}:"
|
|
169
|
+
commands.each do |cmd, desc|
|
|
170
|
+
puts " #{cmd.ljust(24)} #{desc}"
|
|
171
|
+
end
|
|
172
|
+
puts ""
|
|
173
|
+
end
|
|
174
|
+
|
|
72
175
|
def self.print_error_for_command(cmd)
|
|
73
176
|
return print_help if cmd.nil?
|
|
74
177
|
|
data/exe/exa-ai-answer
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
require "bundler/setup"
|
|
6
|
-
require "exa"
|
|
7
|
-
require "exa/cli/base"
|
|
8
|
-
require "exa/cli/formatters/answer_formatter"
|
|
4
|
+
require "exa-ai"
|
|
9
5
|
|
|
10
6
|
# Parse command-line arguments
|
|
11
7
|
def parse_args(argv)
|
data/exe/exa-ai-context
CHANGED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "exa-ai"
|
|
5
|
+
|
|
6
|
+
# Parse arguments
|
|
7
|
+
webset_id = nil
|
|
8
|
+
enrichment_id = nil
|
|
9
|
+
api_key = nil
|
|
10
|
+
output_format = "json"
|
|
11
|
+
|
|
12
|
+
args = ARGV.dup
|
|
13
|
+
while args.any?
|
|
14
|
+
arg = args.shift
|
|
15
|
+
case arg
|
|
16
|
+
when "--api-key"
|
|
17
|
+
api_key = args.shift
|
|
18
|
+
when "--output-format"
|
|
19
|
+
output_format = args.shift
|
|
20
|
+
when "--help", "-h"
|
|
21
|
+
puts <<~HELP
|
|
22
|
+
Usage: exa-ai enrichment-cancel <webset_id> <enrichment_id> [OPTIONS]
|
|
23
|
+
|
|
24
|
+
Cancel a running enrichment
|
|
25
|
+
|
|
26
|
+
Arguments:
|
|
27
|
+
webset_id ID of the webset (required)
|
|
28
|
+
enrichment_id ID of the enrichment to cancel (required)
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--api-key KEY Exa API key (or set EXA_API_KEY env var)
|
|
32
|
+
--output-format FMT Output format: json, pretty, or text (default: json)
|
|
33
|
+
--help, -h Show this help message
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
exa-ai enrichment-cancel ws_123 enr_456
|
|
37
|
+
exa-ai enrichment-cancel ws_123 enr_456 --output-format pretty
|
|
38
|
+
HELP
|
|
39
|
+
exit 0
|
|
40
|
+
else
|
|
41
|
+
# First positional argument is webset_id, second is enrichment_id
|
|
42
|
+
if webset_id.nil?
|
|
43
|
+
webset_id = arg
|
|
44
|
+
elsif enrichment_id.nil?
|
|
45
|
+
enrichment_id = arg
|
|
46
|
+
else
|
|
47
|
+
$stderr.puts "Unknown option: #{arg}"
|
|
48
|
+
exit 1
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Validate
|
|
54
|
+
if webset_id.nil?
|
|
55
|
+
$stderr.puts "Error: webset_id argument is required"
|
|
56
|
+
$stderr.puts "Usage: exa-ai enrichment-cancel <webset_id> <enrichment_id> [OPTIONS]"
|
|
57
|
+
$stderr.puts "Try 'exa-ai enrichment-cancel --help' for more information"
|
|
58
|
+
exit 1
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if enrichment_id.nil?
|
|
62
|
+
$stderr.puts "Error: enrichment_id argument is required"
|
|
63
|
+
$stderr.puts "Usage: exa-ai enrichment-cancel <webset_id> <enrichment_id> [OPTIONS]"
|
|
64
|
+
$stderr.puts "Try 'exa-ai enrichment-cancel --help' for more information"
|
|
65
|
+
exit 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
# Resolve API key and format
|
|
70
|
+
api_key = Exa::CLI::Base.resolve_api_key(api_key)
|
|
71
|
+
output_format = Exa::CLI::Base.resolve_output_format(output_format)
|
|
72
|
+
|
|
73
|
+
# Build client
|
|
74
|
+
client = Exa::CLI::Base.build_client(api_key)
|
|
75
|
+
|
|
76
|
+
# Cancel enrichment
|
|
77
|
+
enrichment = client.cancel_enrichment(webset_id: webset_id, id: enrichment_id)
|
|
78
|
+
|
|
79
|
+
# Format and output
|
|
80
|
+
output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
|
|
81
|
+
puts output
|
|
82
|
+
|
|
83
|
+
rescue Exa::NotFound => e
|
|
84
|
+
$stderr.puts "Enrichment not found: #{e.message}"
|
|
85
|
+
exit 1
|
|
86
|
+
rescue Exa::ConfigurationError => e
|
|
87
|
+
$stderr.puts "Configuration error: #{e.message}"
|
|
88
|
+
exit 1
|
|
89
|
+
rescue Exa::Unauthorized => e
|
|
90
|
+
$stderr.puts "Authentication error: #{e.message}"
|
|
91
|
+
$stderr.puts "Check your API key (set EXA_API_KEY or use --api-key)"
|
|
92
|
+
exit 1
|
|
93
|
+
rescue Exa::ClientError => e
|
|
94
|
+
$stderr.puts "Client error: #{e.message}"
|
|
95
|
+
exit 1
|
|
96
|
+
rescue Exa::ServerError => e
|
|
97
|
+
$stderr.puts "Server error: #{e.message}"
|
|
98
|
+
$stderr.puts "The Exa API may be experiencing issues. Please try again later."
|
|
99
|
+
exit 1
|
|
100
|
+
rescue Exa::Error => e
|
|
101
|
+
$stderr.puts "Error: #{e.message}"
|
|
102
|
+
exit 1
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
$stderr.puts "Unexpected error: #{e.message}"
|
|
105
|
+
$stderr.puts e.backtrace.first(5) if ENV["DEBUG"]
|
|
106
|
+
exit 1
|
|
107
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "exa-ai"
|
|
5
|
+
|
|
6
|
+
VALID_FORMATS = %w[text url options].freeze
|
|
7
|
+
|
|
8
|
+
# Recursively convert hash keys from strings to symbols
|
|
9
|
+
def deep_symbolize_keys(obj)
|
|
10
|
+
case obj
|
|
11
|
+
when Hash
|
|
12
|
+
obj.each_with_object({}) do |(key, value), result|
|
|
13
|
+
result[key.to_sym] = deep_symbolize_keys(value)
|
|
14
|
+
end
|
|
15
|
+
when Array
|
|
16
|
+
obj.map { |item| deep_symbolize_keys(item) }
|
|
17
|
+
else
|
|
18
|
+
obj
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Parse JSON string or load from file (supports @file.json syntax)
|
|
23
|
+
def parse_json_or_file(value)
|
|
24
|
+
json_data = if value.start_with?("@")
|
|
25
|
+
file_path = value[1..]
|
|
26
|
+
JSON.parse(File.read(file_path))
|
|
27
|
+
else
|
|
28
|
+
JSON.parse(value)
|
|
29
|
+
end
|
|
30
|
+
deep_symbolize_keys(json_data)
|
|
31
|
+
rescue JSON::ParserError => e
|
|
32
|
+
$stderr.puts "Error: Invalid JSON: #{e.message}"
|
|
33
|
+
exit 1
|
|
34
|
+
rescue Errno::ENOENT => e
|
|
35
|
+
$stderr.puts "Error: File not found: #{e.message}"
|
|
36
|
+
exit 1
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Parse command-line arguments
|
|
40
|
+
def parse_args(argv)
|
|
41
|
+
# Check for help first
|
|
42
|
+
if argv.include?("--help") || argv.include?("-h")
|
|
43
|
+
puts <<~HELP
|
|
44
|
+
Usage: exa-ai enrichment-create <webset_id> --description TEXT --format TYPE [OPTIONS]
|
|
45
|
+
|
|
46
|
+
Create a new enrichment for a webset
|
|
47
|
+
|
|
48
|
+
Required:
|
|
49
|
+
<webset_id> Webset ID
|
|
50
|
+
--description TEXT What to extract
|
|
51
|
+
--format TYPE One of: #{VALID_FORMATS.join(', ')}
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
--title TEXT Display title
|
|
55
|
+
--options JSON Array of {label: "..."} (required if format=options, supports @file.json)
|
|
56
|
+
--instructions TEXT Additional instructions
|
|
57
|
+
--metadata JSON Custom metadata (supports @file.json)
|
|
58
|
+
--wait Wait for enrichment to complete
|
|
59
|
+
--api-key KEY Exa API key (or set EXA_API_KEY env var)
|
|
60
|
+
--output-format FMT Output format: json, pretty, or text (default: json)
|
|
61
|
+
--help, -h Show this help message
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
exa-ai enrichment-create ws_123 --description "Company size" --format text
|
|
65
|
+
exa-ai enrichment-create ws_123 --description "Industry" --format options --options options.json
|
|
66
|
+
exa-ai enrichment-create ws_123 --description "Website URL" --format url --wait
|
|
67
|
+
HELP
|
|
68
|
+
exit 0
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
args = {
|
|
72
|
+
output_format: "json",
|
|
73
|
+
api_key: nil,
|
|
74
|
+
wait: false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# First, check for positional argument (webset_id)
|
|
78
|
+
if argv.empty? || argv[0].start_with?("--")
|
|
79
|
+
return args
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
args[:webset_id] = argv[0]
|
|
83
|
+
i = 1
|
|
84
|
+
|
|
85
|
+
while i < argv.length
|
|
86
|
+
arg = argv[i]
|
|
87
|
+
case arg
|
|
88
|
+
when "--description"
|
|
89
|
+
args[:description] = argv[i + 1]
|
|
90
|
+
i += 2
|
|
91
|
+
when "--format"
|
|
92
|
+
args[:format] = argv[i + 1]
|
|
93
|
+
i += 2
|
|
94
|
+
when "--title"
|
|
95
|
+
args[:title] = argv[i + 1]
|
|
96
|
+
i += 2
|
|
97
|
+
when "--options"
|
|
98
|
+
args[:options] = parse_json_or_file(argv[i + 1])
|
|
99
|
+
i += 2
|
|
100
|
+
when "--instructions"
|
|
101
|
+
args[:instructions] = argv[i + 1]
|
|
102
|
+
i += 2
|
|
103
|
+
when "--metadata"
|
|
104
|
+
args[:metadata] = parse_json_or_file(argv[i + 1])
|
|
105
|
+
i += 2
|
|
106
|
+
when "--wait"
|
|
107
|
+
args[:wait] = true
|
|
108
|
+
i += 1
|
|
109
|
+
when "--api-key"
|
|
110
|
+
args[:api_key] = argv[i + 1]
|
|
111
|
+
i += 2
|
|
112
|
+
when "--output-format"
|
|
113
|
+
args[:output_format] = argv[i + 1]
|
|
114
|
+
i += 2
|
|
115
|
+
else
|
|
116
|
+
$stderr.puts "Unknown option: #{arg}"
|
|
117
|
+
exit 1
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
args
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Main execution
|
|
125
|
+
begin
|
|
126
|
+
args = parse_args(ARGV)
|
|
127
|
+
|
|
128
|
+
# Validate required parameters
|
|
129
|
+
unless args[:webset_id]
|
|
130
|
+
$stderr.puts "Error: <webset_id> is required"
|
|
131
|
+
$stderr.puts "Run 'exa-ai enrichment-create --help' for usage information"
|
|
132
|
+
exit 1
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
unless args[:description]
|
|
136
|
+
$stderr.puts "Error: --description is required"
|
|
137
|
+
$stderr.puts "Run 'exa-ai enrichment-create --help' for usage information"
|
|
138
|
+
exit 1
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
unless args[:format]
|
|
142
|
+
$stderr.puts "Error: --format is required"
|
|
143
|
+
$stderr.puts "Run 'exa-ai enrichment-create --help' for usage information"
|
|
144
|
+
exit 1
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Validate format
|
|
148
|
+
unless VALID_FORMATS.include?(args[:format])
|
|
149
|
+
$stderr.puts "Error: format must be one of: #{VALID_FORMATS.join(', ')}"
|
|
150
|
+
exit 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Validate options requirement for 'options' format
|
|
154
|
+
if args[:format] == "options" && !args[:options]
|
|
155
|
+
$stderr.puts "Error: --options is required when format is 'options'"
|
|
156
|
+
exit 1
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Resolve API key
|
|
160
|
+
api_key = Exa::CLI::Base.resolve_api_key(args[:api_key])
|
|
161
|
+
|
|
162
|
+
# Resolve output format
|
|
163
|
+
output_format = Exa::CLI::Base.resolve_output_format(args[:output_format])
|
|
164
|
+
|
|
165
|
+
# Build client
|
|
166
|
+
client = Exa::CLI::Base.build_client(api_key)
|
|
167
|
+
|
|
168
|
+
# Prepare enrichment parameters
|
|
169
|
+
enrichment_params = {
|
|
170
|
+
description: args[:description],
|
|
171
|
+
format: args[:format]
|
|
172
|
+
}
|
|
173
|
+
enrichment_params[:title] = args[:title] if args[:title]
|
|
174
|
+
enrichment_params[:options] = args[:options] if args[:options]
|
|
175
|
+
enrichment_params[:instructions] = args[:instructions] if args[:instructions]
|
|
176
|
+
enrichment_params[:metadata] = args[:metadata] if args[:metadata]
|
|
177
|
+
|
|
178
|
+
# Create enrichment
|
|
179
|
+
enrichment = client.create_enrichment(webset_id: args[:webset_id], **enrichment_params)
|
|
180
|
+
|
|
181
|
+
# If --wait flag is set, poll until enrichment is complete
|
|
182
|
+
if args[:wait]
|
|
183
|
+
$stderr.print "Creating enrichment... "
|
|
184
|
+
|
|
185
|
+
begin
|
|
186
|
+
final_enrichment = Exa::CLI::Polling.poll(max_duration: 300, initial_delay: 2, max_delay: 10) do
|
|
187
|
+
current = client.get_enrichment(webset_id: args[:webset_id], id: enrichment.id)
|
|
188
|
+
|
|
189
|
+
case current.status
|
|
190
|
+
when "pending"
|
|
191
|
+
$stderr.print "⏳"
|
|
192
|
+
when "running"
|
|
193
|
+
$stderr.print "⚙️"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
done = current.completed?
|
|
197
|
+
{ done: done, result: current, status: current.status }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
$stderr.puts " COMPLETED"
|
|
201
|
+
enrichment = final_enrichment
|
|
202
|
+
|
|
203
|
+
rescue Exa::CLI::Polling::TimeoutError
|
|
204
|
+
$stderr.puts "\nWarning: Enrichment did not complete within timeout"
|
|
205
|
+
$stderr.puts "Enrichment ID: #{enrichment.id}"
|
|
206
|
+
$stderr.puts "Check status with: exa-ai enrichment-get #{args[:webset_id]} #{enrichment.id}"
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Format and output result
|
|
211
|
+
output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
|
|
212
|
+
puts output
|
|
213
|
+
|
|
214
|
+
rescue Exa::ConfigurationError => e
|
|
215
|
+
$stderr.puts "Configuration error: #{e.message}"
|
|
216
|
+
exit 1
|
|
217
|
+
rescue Exa::Unauthorized => e
|
|
218
|
+
$stderr.puts "Authentication error: #{e.message}"
|
|
219
|
+
$stderr.puts "Check your API key (set EXA_API_KEY or use --api-key)"
|
|
220
|
+
exit 1
|
|
221
|
+
rescue Exa::ClientError => e
|
|
222
|
+
$stderr.puts "Client error: #{e.message}"
|
|
223
|
+
exit 1
|
|
224
|
+
rescue Exa::ServerError => e
|
|
225
|
+
$stderr.puts "Server error: #{e.message}"
|
|
226
|
+
$stderr.puts "The Exa API may be experiencing issues. Please try again later."
|
|
227
|
+
exit 1
|
|
228
|
+
rescue Exa::Error => e
|
|
229
|
+
$stderr.puts "Error: #{e.message}"
|
|
230
|
+
exit 1
|
|
231
|
+
rescue StandardError => e
|
|
232
|
+
$stderr.puts "Unexpected error: #{e.message}"
|
|
233
|
+
$stderr.puts e.backtrace.first(5) if ENV["DEBUG"]
|
|
234
|
+
exit 1
|
|
235
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "exa-ai"
|
|
5
|
+
|
|
6
|
+
# Parse arguments
|
|
7
|
+
webset_id = nil
|
|
8
|
+
enrichment_id = nil
|
|
9
|
+
force = false
|
|
10
|
+
api_key = nil
|
|
11
|
+
output_format = "json"
|
|
12
|
+
|
|
13
|
+
args = ARGV.dup
|
|
14
|
+
while args.any?
|
|
15
|
+
arg = args.shift
|
|
16
|
+
case arg
|
|
17
|
+
when "--force"
|
|
18
|
+
force = true
|
|
19
|
+
when "--api-key"
|
|
20
|
+
api_key = args.shift
|
|
21
|
+
when "--output-format"
|
|
22
|
+
output_format = args.shift
|
|
23
|
+
when "--help", "-h"
|
|
24
|
+
puts <<~HELP
|
|
25
|
+
Usage: exa-ai enrichment-delete <webset_id> <enrichment_id> [OPTIONS]
|
|
26
|
+
|
|
27
|
+
Delete an enrichment
|
|
28
|
+
|
|
29
|
+
Arguments:
|
|
30
|
+
webset_id ID of the webset (required)
|
|
31
|
+
enrichment_id ID of the enrichment to delete (required)
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--force Skip confirmation prompt
|
|
35
|
+
--api-key KEY Exa API key (or set EXA_API_KEY env var)
|
|
36
|
+
--output-format FMT Output format: json, pretty, or text (default: json)
|
|
37
|
+
--help, -h Show this help message
|
|
38
|
+
|
|
39
|
+
Examples:
|
|
40
|
+
exa-ai enrichment-delete ws_123 enr_456
|
|
41
|
+
exa-ai enrichment-delete ws_123 enr_456 --force
|
|
42
|
+
HELP
|
|
43
|
+
exit 0
|
|
44
|
+
else
|
|
45
|
+
# First positional argument is webset_id, second is enrichment_id
|
|
46
|
+
if webset_id.nil?
|
|
47
|
+
webset_id = arg
|
|
48
|
+
elsif enrichment_id.nil?
|
|
49
|
+
enrichment_id = arg
|
|
50
|
+
else
|
|
51
|
+
$stderr.puts "Unknown option: #{arg}"
|
|
52
|
+
exit 1
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Validate
|
|
58
|
+
if webset_id.nil?
|
|
59
|
+
$stderr.puts "Error: webset_id argument is required"
|
|
60
|
+
$stderr.puts "Usage: exa-ai enrichment-delete <webset_id> <enrichment_id> [OPTIONS]"
|
|
61
|
+
$stderr.puts "Try 'exa-ai enrichment-delete --help' for more information"
|
|
62
|
+
exit 1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if enrichment_id.nil?
|
|
66
|
+
$stderr.puts "Error: enrichment_id argument is required"
|
|
67
|
+
$stderr.puts "Usage: exa-ai enrichment-delete <webset_id> <enrichment_id> [OPTIONS]"
|
|
68
|
+
$stderr.puts "Try 'exa-ai enrichment-delete --help' for more information"
|
|
69
|
+
exit 1
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
begin
|
|
73
|
+
# Resolve API key and format
|
|
74
|
+
api_key = Exa::CLI::Base.resolve_api_key(api_key)
|
|
75
|
+
output_format = Exa::CLI::Base.resolve_output_format(output_format)
|
|
76
|
+
|
|
77
|
+
# Confirm deletion unless --force is used
|
|
78
|
+
unless force
|
|
79
|
+
$stderr.print "Delete enrichment #{enrichment_id} from webset #{webset_id}? (y/N): "
|
|
80
|
+
response = $stdin.gets.chomp.downcase
|
|
81
|
+
unless response == "y" || response == "yes"
|
|
82
|
+
$stderr.puts "Cancelled"
|
|
83
|
+
exit 0
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Build client
|
|
88
|
+
client = Exa::CLI::Base.build_client(api_key)
|
|
89
|
+
|
|
90
|
+
# Delete enrichment
|
|
91
|
+
result = client.delete_enrichment(webset_id: webset_id, id: enrichment_id)
|
|
92
|
+
|
|
93
|
+
# Format and output
|
|
94
|
+
output = Exa::CLI::Formatters::EnrichmentFormatter.format(result, output_format)
|
|
95
|
+
puts output
|
|
96
|
+
|
|
97
|
+
rescue Exa::NotFound => e
|
|
98
|
+
$stderr.puts "Enrichment not found: #{e.message}"
|
|
99
|
+
exit 1
|
|
100
|
+
rescue Exa::ConfigurationError => e
|
|
101
|
+
$stderr.puts "Configuration error: #{e.message}"
|
|
102
|
+
exit 1
|
|
103
|
+
rescue Exa::Unauthorized => e
|
|
104
|
+
$stderr.puts "Authentication error: #{e.message}"
|
|
105
|
+
$stderr.puts "Check your API key (set EXA_API_KEY or use --api-key)"
|
|
106
|
+
exit 1
|
|
107
|
+
rescue Exa::ClientError => e
|
|
108
|
+
$stderr.puts "Client error: #{e.message}"
|
|
109
|
+
exit 1
|
|
110
|
+
rescue Exa::ServerError => e
|
|
111
|
+
$stderr.puts "Server error: #{e.message}"
|
|
112
|
+
$stderr.puts "The Exa API may be experiencing issues. Please try again later."
|
|
113
|
+
exit 1
|
|
114
|
+
rescue Exa::Error => e
|
|
115
|
+
$stderr.puts "Error: #{e.message}"
|
|
116
|
+
exit 1
|
|
117
|
+
rescue StandardError => e
|
|
118
|
+
$stderr.puts "Unexpected error: #{e.message}"
|
|
119
|
+
$stderr.puts e.backtrace.first(5) if ENV["DEBUG"]
|
|
120
|
+
exit 1
|
|
121
|
+
end
|