exa-ai 0.4.1 → 0.6.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -0
  3. data/exe/exa-ai +61 -7
  4. data/exe/exa-ai-answer +9 -8
  5. data/exe/exa-ai-context +6 -5
  6. data/exe/exa-ai-enrichment-cancel +1 -0
  7. data/exe/exa-ai-enrichment-create +1 -0
  8. data/exe/exa-ai-enrichment-delete +1 -0
  9. data/exe/exa-ai-enrichment-get +1 -0
  10. data/exe/exa-ai-enrichment-list +1 -0
  11. data/exe/exa-ai-enrichment-update +1 -0
  12. data/exe/exa-ai-find-similar +1 -0
  13. data/exe/exa-ai-get-contents +9 -8
  14. data/exe/exa-ai-import-create +235 -0
  15. data/exe/exa-ai-import-delete +92 -0
  16. data/exe/exa-ai-import-get +92 -0
  17. data/exe/exa-ai-import-list +72 -0
  18. data/exe/exa-ai-import-update +164 -0
  19. data/exe/exa-ai-monitor-create +223 -0
  20. data/exe/exa-ai-monitor-delete +101 -0
  21. data/exe/exa-ai-monitor-get +92 -0
  22. data/exe/exa-ai-monitor-list +90 -0
  23. data/exe/exa-ai-monitor-runs-get +103 -0
  24. data/exe/exa-ai-monitor-runs-list +110 -0
  25. data/exe/exa-ai-monitor-update +207 -0
  26. data/exe/exa-ai-research-get +7 -7
  27. data/exe/exa-ai-research-list +5 -5
  28. data/exe/exa-ai-research-start +8 -7
  29. data/exe/exa-ai-search +20 -13
  30. data/exe/exa-ai-webset-cancel +1 -0
  31. data/exe/exa-ai-webset-create +44 -6
  32. data/exe/exa-ai-webset-delete +1 -0
  33. data/exe/exa-ai-webset-get +1 -0
  34. data/exe/exa-ai-webset-item-get +1 -0
  35. data/exe/exa-ai-webset-item-list +1 -0
  36. data/exe/exa-ai-webset-list +1 -0
  37. data/exe/exa-ai-webset-search-cancel +1 -0
  38. data/exe/exa-ai-webset-search-create +1 -0
  39. data/exe/exa-ai-webset-search-get +1 -0
  40. data/exe/exa-ai-webset-update +1 -0
  41. data/lib/exa/cli/base.rb +8 -2
  42. data/lib/exa/cli/formatters/answer_formatter.rb +2 -0
  43. data/lib/exa/cli/formatters/contents_formatter.rb +2 -0
  44. data/lib/exa/cli/formatters/context_formatter.rb +2 -0
  45. data/lib/exa/cli/formatters/enrichment_formatter.rb +4 -0
  46. data/lib/exa/cli/formatters/import_formatter.rb +85 -0
  47. data/lib/exa/cli/formatters/monitor_formatter.rb +81 -0
  48. data/lib/exa/cli/formatters/monitor_run_formatter.rb +75 -0
  49. data/lib/exa/cli/formatters/research_formatter.rb +4 -0
  50. data/lib/exa/cli/formatters/search_formatter.rb +2 -0
  51. data/lib/exa/cli/formatters/webset_formatter.rb +4 -0
  52. data/lib/exa/cli/formatters/webset_item_formatter.rb +4 -0
  53. data/lib/exa/client.rb +137 -0
  54. data/lib/exa/constants/websets.rb +19 -0
  55. data/lib/exa/middleware/raise_error.rb +5 -0
  56. data/lib/exa/resources/import.rb +86 -0
  57. data/lib/exa/resources/import_collection.rb +33 -0
  58. data/lib/exa/resources/monitor.rb +48 -0
  59. data/lib/exa/resources/monitor_collection.rb +30 -0
  60. data/lib/exa/resources/monitor_run.rb +52 -0
  61. data/lib/exa/resources/monitor_run_collection.rb +30 -0
  62. data/lib/exa/services/search.rb +21 -1
  63. data/lib/exa/services/websets/create_validator.rb +5 -3
  64. data/lib/exa/services/websets/import_create.rb +40 -0
  65. data/lib/exa/services/websets/import_delete.rb +37 -0
  66. data/lib/exa/services/websets/import_get.rb +37 -0
  67. data/lib/exa/services/websets/import_list.rb +25 -0
  68. data/lib/exa/services/websets/import_update.rb +38 -0
  69. data/lib/exa/services/websets/import_upload.rb +58 -0
  70. data/lib/exa/services/websets/monitors/create.rb +42 -0
  71. data/lib/exa/services/websets/monitors/delete.rb +32 -0
  72. data/lib/exa/services/websets/monitors/get.rb +33 -0
  73. data/lib/exa/services/websets/monitors/list.rb +27 -0
  74. data/lib/exa/services/websets/monitors/runs/get.rb +37 -0
  75. data/lib/exa/services/websets/monitors/runs/list.rb +30 -0
  76. data/lib/exa/services/websets/monitors/update.rb +33 -0
  77. data/lib/exa/version.rb +1 -1
  78. data/lib/exa.rb +23 -0
  79. metadata +50 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 636e2bd945c3fc5f9d73e7f350a229dc804703d1f42fff0bc5f596f187de79a3
4
- data.tar.gz: 11cfbf774f057c79f2bfdef85a0d8e034c255dd557d154be8620bf1a24a19d66
3
+ metadata.gz: 4458cc74fb6924d5e7e57300ba28ae1db399d0d89bf68495b1203f5fe29d73d2
4
+ data.tar.gz: 00b7f59be62aad198438660acdec2e1a2e3c86539bd1a462c4ea03f45c08a87b
5
5
  SHA512:
6
- metadata.gz: dd922b361f4f05ea025205d2c00c454547f58633242abfd4b7b8dd35279295978df494142f9e3d59d82a51e5a65b92bb627fb4063c17e8445f5a9b27579bbf8b
7
- data.tar.gz: 0a27904cbd4a126dd375763b2c3c65edd068fc6f3c619ac91585b37083e64dba4cc5564c40e6e924cee1e2828b7b3e16edc230f07c261d1c26b0da7dafbb08c7
6
+ metadata.gz: b45e4d6a35d33910e9ce4b154b1b432efba13732b9c237ab94da5962944fae65bf3562a426dc9fa9c18af8c820e8db5d1a4ae3417605d171a136de2d01f149db
7
+ data.tar.gz: 98f082e62eeef3cf7851abcda1cdd61ee5edd548c2cd0d5a65b7645510248ebd0a2274b743e83b7ff354e1ebb4016a92ab83e8a4f93300c255d298fdb9a2683b
data/README.md CHANGED
@@ -128,6 +128,15 @@ exa-ai enrichment-get WEBSET_ID ENRICHMENT_ID
128
128
  exa-ai enrichment-update WEBSET_ID ENRICHMENT_ID --description "Updated description"
129
129
  exa-ai enrichment-delete WEBSET_ID ENRICHMENT_ID --force
130
130
  exa-ai enrichment-cancel WEBSET_ID ENRICHMENT_ID
131
+
132
+ # Webset Imports
133
+ exa-ai webset-import-create companies.csv --count 100 --title "My Companies" --format csv --entity-type company
134
+ exa-ai webset-import-create data.csv --count 50 --title "Tech Startups" --format csv --entity-type company --csv-identifier 0
135
+ exa-ai webset-import-create import.csv --count 100 --title "Import" --format csv --entity-type company --metadata '{"source":"crm"}' --quiet
136
+ exa-ai webset-import-list
137
+ exa-ai webset-import-get IMPORT_ID
138
+ exa-ai webset-import-update IMPORT_ID --title "Updated Title"
139
+ exa-ai webset-import-delete IMPORT_ID
131
140
  ```
132
141
 
133
142
  ## Features
@@ -150,6 +159,7 @@ The gem provides complete access to Exa's API endpoints:
150
159
  - **Webset Searches** — Run searches within websets and manage search tasks
151
160
  - **Webset Items** — List, retrieve, and manage individual items in websets
152
161
  - **Enrichments** — Create and manage AI-powered data enrichment tasks on websets
162
+ - **Imports** — Upload CSV files to import external data into websets
153
163
 
154
164
  ## Error Handling
155
165
 
data/exe/exa-ai CHANGED
@@ -32,7 +32,19 @@ module ExaCLI
32
32
  "enrichment-list" => "List enrichments",
33
33
  "enrichment-update" => "Update an enrichment",
34
34
  "enrichment-delete" => "Delete an enrichment",
35
- "enrichment-cancel" => "Cancel an enrichment"
35
+ "enrichment-cancel" => "Cancel an enrichment",
36
+ "import-create" => "Create a new import",
37
+ "import-list" => "List imports",
38
+ "import-get" => "Get import details",
39
+ "import-update" => "Update an import",
40
+ "import-delete" => "Delete an import",
41
+ "monitor-create" => "Create a webset monitor",
42
+ "monitor-get" => "Get monitor details",
43
+ "monitor-list" => "List monitors",
44
+ "monitor-update" => "Update a monitor",
45
+ "monitor-delete" => "Delete a monitor",
46
+ "monitor-runs-list" => "List monitor runs",
47
+ "monitor-runs-get" => "Get monitor run details"
36
48
  }.freeze
37
49
 
38
50
  def self.run
@@ -44,7 +56,7 @@ module ExaCLI
44
56
  print_help
45
57
  exit 0
46
58
  when "--api-key"
47
- puts "Use --api-key flag with specific commands"
59
+ $stderr.puts "Error: Use --api-key flag with specific commands"
48
60
  exit 1
49
61
  when "search"
50
62
  exec File.expand_path("../exa-ai-search", __FILE__), *ARGV[1..]
@@ -98,6 +110,30 @@ module ExaCLI
98
110
  exec File.expand_path("../exa-ai-enrichment-delete", __FILE__), *ARGV[1..]
99
111
  when "enrichment-cancel"
100
112
  exec File.expand_path("../exa-ai-enrichment-cancel", __FILE__), *ARGV[1..]
113
+ when "import-create"
114
+ exec File.expand_path("../exa-ai-import-create", __FILE__), *ARGV[1..]
115
+ when "import-list"
116
+ exec File.expand_path("../exa-ai-import-list", __FILE__), *ARGV[1..]
117
+ when "import-get"
118
+ exec File.expand_path("../exa-ai-import-get", __FILE__), *ARGV[1..]
119
+ when "import-update"
120
+ exec File.expand_path("../exa-ai-import-update", __FILE__), *ARGV[1..]
121
+ when "import-delete"
122
+ exec File.expand_path("../exa-ai-import-delete", __FILE__), *ARGV[1..]
123
+ when "monitor-create"
124
+ exec File.expand_path("../exa-ai-monitor-create", __FILE__), *ARGV[1..]
125
+ when "monitor-get"
126
+ exec File.expand_path("../exa-ai-monitor-get", __FILE__), *ARGV[1..]
127
+ when "monitor-list"
128
+ exec File.expand_path("../exa-ai-monitor-list", __FILE__), *ARGV[1..]
129
+ when "monitor-update"
130
+ exec File.expand_path("../exa-ai-monitor-update", __FILE__), *ARGV[1..]
131
+ when "monitor-delete"
132
+ exec File.expand_path("../exa-ai-monitor-delete", __FILE__), *ARGV[1..]
133
+ when "monitor-runs-list"
134
+ exec File.expand_path("../exa-ai-monitor-runs-list", __FILE__), *ARGV[1..]
135
+ when "monitor-runs-get"
136
+ exec File.expand_path("../exa-ai-monitor-runs-get", __FILE__), *ARGV[1..]
101
137
  else
102
138
  print_error_for_command(ARGV[0])
103
139
  exit 1
@@ -154,6 +190,24 @@ module ExaCLI
154
190
  ["enrichment-cancel", "Cancel an enrichment"]
155
191
  ])
156
192
 
193
+ print_command_section("Imports", [
194
+ ["import-create", "Create a new import"],
195
+ ["import-list", "List imports"],
196
+ ["import-get", "Get import details"],
197
+ ["import-update", "Update an import"],
198
+ ["import-delete", "Delete an import"]
199
+ ])
200
+
201
+ print_command_section("Webset Monitors", [
202
+ ["monitor-create", "Create a webset monitor"],
203
+ ["monitor-get", "Get monitor details"],
204
+ ["monitor-list", "List monitors"],
205
+ ["monitor-update", "Update a monitor"],
206
+ ["monitor-delete", "Delete a monitor"],
207
+ ["monitor-runs-list", "List monitor runs"],
208
+ ["monitor-runs-get", "Get monitor run details"]
209
+ ])
210
+
157
211
  puts "Global Options:"
158
212
  puts " --help, -h Show this help message"
159
213
  puts " --version Show version number"
@@ -175,15 +229,15 @@ module ExaCLI
175
229
  def self.print_error_for_command(cmd)
176
230
  return print_help if cmd.nil?
177
231
 
178
- puts "Error: Unknown command '#{cmd}'"
179
- puts ""
232
+ $stderr.puts "Error: Unknown command '#{cmd}'"
233
+ $stderr.puts ""
180
234
 
181
235
  # Try to suggest similar commands
182
236
  suggestion = suggest_command(cmd)
183
- puts "Did you mean: #{suggestion}?" if suggestion
237
+ $stderr.puts "Did you mean: #{suggestion}?" if suggestion
184
238
 
185
- puts ""
186
- puts "Run 'exa-ai --help' for usage information."
239
+ $stderr.puts ""
240
+ $stderr.puts "Run 'exa-ai --help' for usage information."
187
241
  end
188
242
 
189
243
  def self.suggest_command(input)
data/exe/exa-ai-answer CHANGED
@@ -38,7 +38,7 @@ def parse_args(argv)
38
38
  i += 2
39
39
  when "--help", "-h"
40
40
  puts <<~HELP
41
- Usage: exa-api answer QUERY [OPTIONS]
41
+ Usage: exa-ai answer QUERY [OPTIONS]
42
42
 
43
43
  Generate an answer to a question using Exa AI
44
44
 
@@ -55,12 +55,12 @@ def parse_args(argv)
55
55
  --help, -h Show this help message
56
56
 
57
57
  Examples:
58
- exa-api answer "What is the capital of France?"
59
- exa-api answer "Latest AI breakthroughs" --stream
60
- exa-api answer "Latest AI breakthroughs" --text
61
- exa-api answer "Ruby best practices" --output-format pretty
62
- exa-api answer "What is the capital of France?" --output-schema '{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"}}}'
63
- exa-api answer "What is Paris?" --system-prompt "Respond in the voice of a pirate"
58
+ exa-ai answer "What is the capital of France?"
59
+ exa-ai answer "Latest AI breakthroughs" --stream
60
+ exa-ai answer "Latest AI breakthroughs" --text
61
+ exa-ai answer "Ruby best practices" --output-format pretty
62
+ exa-ai answer "What is the capital of France?" --output-schema '{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"}}}'
63
+ exa-ai answer "What is Paris?" --system-prompt "Respond in the voice of a pirate"
64
64
  HELP
65
65
  exit 0
66
66
  else
@@ -80,7 +80,7 @@ begin
80
80
  # Validate query
81
81
  if args[:query].nil? || args[:query].empty?
82
82
  $stderr.puts "Error: Query is required"
83
- $stderr.puts "Run 'exa-api answer --help' for usage information"
83
+ $stderr.puts "Run 'exa-ai answer --help' for usage information"
84
84
  exit 1
85
85
  end
86
86
 
@@ -125,6 +125,7 @@ begin
125
125
  result = client.answer(args[:query], **answer_params)
126
126
  output = Exa::CLI::Formatters::AnswerFormatter.format(result, output_format)
127
127
  puts output
128
+ $stdout.flush
128
129
  end
129
130
 
130
131
  rescue Exa::ConfigurationError => e
data/exe/exa-ai-context CHANGED
@@ -43,7 +43,7 @@ end
43
43
  def print_help
44
44
  puts "Exa Context - Get code context from repositories"
45
45
  puts ""
46
- puts "Usage: exa-api context <query> [options]"
46
+ puts "Usage: exa-ai context <query> [options]"
47
47
  puts ""
48
48
  puts "Arguments:"
49
49
  puts " query Search query for code context (required)"
@@ -55,9 +55,9 @@ def print_help
55
55
  puts " --help, -h Show this help message"
56
56
  puts ""
57
57
  puts "Examples:"
58
- puts " exa-api context 'React hooks'"
59
- puts " exa-api context 'authentication with JWT in Ruby' --tokens-num 5000"
60
- puts " exa-api context 'React hooks' --output-format text"
58
+ puts " exa-ai context 'React hooks'"
59
+ puts " exa-ai context 'authentication with JWT in Ruby' --tokens-num 5000"
60
+ puts " exa-ai context 'React hooks' --output-format text"
61
61
  end
62
62
 
63
63
  begin
@@ -68,7 +68,7 @@ begin
68
68
  unless options[:query]
69
69
  puts "Error: Query argument required"
70
70
  puts ""
71
- puts "Run 'exa-api context --help' for usage information."
71
+ puts "Run 'exa-ai context --help' for usage information."
72
72
  exit 1
73
73
  end
74
74
 
@@ -91,6 +91,7 @@ begin
91
91
  # Format and output
92
92
  output = Exa::CLI::Formatters::ContextFormatter.format(result, output_format)
93
93
  puts output
94
+ $stdout.flush
94
95
  rescue Exa::Error => e
95
96
  puts "Error: #{e.message}"
96
97
  exit 1
@@ -79,6 +79,7 @@ begin
79
79
  # Format and output
80
80
  output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
81
81
  puts output
82
+ $stdout.flush
82
83
 
83
84
  rescue Exa::NotFound => e
84
85
  $stderr.puts "Enrichment not found: #{e.message}"
@@ -210,6 +210,7 @@ begin
210
210
  # Format and output result
211
211
  output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
212
212
  puts output
213
+ $stdout.flush
213
214
 
214
215
  rescue Exa::ConfigurationError => e
215
216
  $stderr.puts "Configuration error: #{e.message}"
@@ -93,6 +93,7 @@ begin
93
93
  # Format and output
94
94
  output = Exa::CLI::Formatters::EnrichmentFormatter.format(result, output_format)
95
95
  puts output
96
+ $stdout.flush
96
97
 
97
98
  rescue Exa::NotFound => e
98
99
  $stderr.puts "Enrichment not found: #{e.message}"
@@ -79,6 +79,7 @@ begin
79
79
  # Format and output
80
80
  output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
81
81
  puts output
82
+ $stdout.flush
82
83
 
83
84
  rescue Exa::NotFound => e
84
85
  $stderr.puts "Enrichment not found: #{e.message}"
@@ -74,6 +74,7 @@ begin
74
74
  # Format and output
75
75
  output = Exa::CLI::Formatters::EnrichmentFormatter.format_collection(collection, output_format)
76
76
  puts output
77
+ $stdout.flush
77
78
 
78
79
  rescue Exa::NotFound => e
79
80
  $stderr.puts "Webset not found: #{e.message}"
@@ -142,6 +142,7 @@ begin
142
142
  # Format and output
143
143
  output = Exa::CLI::Formatters::EnrichmentFormatter.format(enrichment, output_format)
144
144
  puts output
145
+ $stdout.flush
145
146
 
146
147
  rescue Exa::NotFound => e
147
148
  $stderr.puts "Enrichment not found: #{e.message}"
@@ -215,6 +215,7 @@ begin
215
215
  # Format and output result
216
216
  output = Exa::CLI::Formatters::SearchFormatter.format(result, output_format)
217
217
  puts output
218
+ $stdout.flush
218
219
 
219
220
  rescue Exa::ConfigurationError => e
220
221
  $stderr.puts "Configuration error: #{e.message}"
@@ -164,7 +164,7 @@ end
164
164
 
165
165
  def print_help
166
166
  puts <<~HELP
167
- Usage: exa-api get-contents <urls> [options]
167
+ Usage: exa-ai get-contents <urls> [options]
168
168
 
169
169
  Retrieve full page contents from URLs
170
170
 
@@ -203,12 +203,12 @@ def print_help
203
203
  --help, -h Show this help message
204
204
 
205
205
  Examples:
206
- exa-api get-contents 'https://example.com'
207
- exa-api get-contents 'https://example.com' --text
208
- exa-api get-contents 'https://example.com' --text --text-max-characters 3000 --include-html-tags
209
- exa-api get-contents 'url1,url2' --summary --summary-query "Be terse"
210
- exa-api get-contents 'https://example.com' --subpages 1 --subpage-target about
211
- exa-api get-contents 'https://example.com' --links 5 --image-links 10
206
+ exa-ai get-contents 'https://example.com'
207
+ exa-ai get-contents 'https://example.com' --text
208
+ exa-ai get-contents 'https://example.com' --text --text-max-characters 3000 --include-html-tags
209
+ exa-ai get-contents 'url1,url2' --summary --summary-query "Be terse"
210
+ exa-ai get-contents 'https://example.com' --subpages 1 --subpage-target about
211
+ exa-ai get-contents 'https://example.com' --links 5 --image-links 10
212
212
  HELP
213
213
  end
214
214
 
@@ -220,7 +220,7 @@ begin
220
220
  if options[:ids].empty?
221
221
  $stderr.puts "Error: URLs argument required"
222
222
  $stderr.puts ""
223
- $stderr.puts "Run 'exa-api get-contents --help' for usage information."
223
+ $stderr.puts "Run 'exa-ai get-contents --help' for usage information."
224
224
  exit 1
225
225
  end
226
226
 
@@ -243,6 +243,7 @@ begin
243
243
  # Format and output
244
244
  output = Exa::CLI::Formatters::ContentsFormatter.format(result, output_format)
245
245
  puts output
246
+ $stdout.flush
246
247
  rescue Exa::ConfigurationError => e
247
248
  $stderr.puts "Configuration error: #{e.message}"
248
249
  exit 1
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "exa-ai"
5
+
6
+ VALID_FORMATS = Exa::Constants::Websets::IMPORT_FORMATS
7
+ VALID_ENTITY_TYPES = Exa::Constants::Websets::ENTITY_TYPES
8
+
9
+ # Recursively convert hash keys from strings to symbols
10
+ def deep_symbolize_keys(obj)
11
+ case obj
12
+ when Hash
13
+ obj.each_with_object({}) do |(key, value), result|
14
+ result[key.to_sym] = deep_symbolize_keys(value)
15
+ end
16
+ when Array
17
+ obj.map { |item| deep_symbolize_keys(item) }
18
+ else
19
+ obj
20
+ end
21
+ end
22
+
23
+ # Parse JSON string or load from file (supports @file.json syntax)
24
+ def parse_json_or_file(value)
25
+ json_data = if value.start_with?("@")
26
+ file_path = value[1..]
27
+ JSON.parse(File.read(file_path))
28
+ else
29
+ JSON.parse(value)
30
+ end
31
+ deep_symbolize_keys(json_data)
32
+ rescue JSON::ParserError => e
33
+ $stderr.puts "Error: Invalid JSON: #{e.message}"
34
+ exit 1
35
+ rescue Errno::ENOENT => e
36
+ $stderr.puts "Error: File not found: #{e.message}"
37
+ exit 1
38
+ end
39
+
40
+ # Parse command-line arguments
41
+ def parse_args(argv)
42
+ # Check for help first
43
+ if argv.include?("--help") || argv.include?("-h")
44
+ puts <<~HELP
45
+ Usage: exa-ai import-create FILE [OPTIONS]
46
+
47
+ Create a new import and upload external data file
48
+
49
+ Arguments:
50
+ FILE Path to the CSV file to upload
51
+
52
+ Required:
53
+ --count N Number of entities in the import
54
+ --title TEXT Display title
55
+ --format TYPE Format type (default: csv, options: #{VALID_FORMATS.join(', ')})
56
+ --entity-type TYPE Entity type (options: #{VALID_ENTITY_TYPES.join(', ')})
57
+
58
+ Options:
59
+ --csv-identifier N CSV column identifier (0-indexed)
60
+ --metadata JSON Custom metadata (supports @file.json)
61
+ --quiet Suppress normal output (only show errors)
62
+ --api-key KEY Exa API key (or set EXA_API_KEY env var)
63
+ --output-format FMT Output format: json, pretty, or text (default: json)
64
+ --help, -h Show this help message
65
+
66
+ Examples:
67
+ exa-ai import-create data.csv --count 100 --title "My Companies" --format csv --entity-type company
68
+ exa-ai import-create companies.csv --count 50 --title "Tech Startups" --format csv --entity-type company --csv-identifier 0
69
+ exa-ai import-create import.csv --count 100 --title "Import" --format csv --entity-type company --metadata '{"source":"crm"}' --quiet
70
+ HELP
71
+ exit 0
72
+ end
73
+
74
+ # First argument should be the file path
75
+ if argv.empty? || argv[0].start_with?("--")
76
+ $stderr.puts "Error: FILE argument is required"
77
+ $stderr.puts "Run 'exa-ai import-create --help' for usage information"
78
+ exit 1
79
+ end
80
+
81
+ args = {
82
+ file_path: argv[0],
83
+ output_format: "json",
84
+ api_key: nil,
85
+ format: "csv",
86
+ quiet: false
87
+ }
88
+
89
+ i = 1 # Start after the file path
90
+ while i < argv.length
91
+ arg = argv[i]
92
+ case arg
93
+ when "--count"
94
+ args[:count] = argv[i + 1].to_i
95
+ i += 2
96
+ when "--title"
97
+ args[:title] = argv[i + 1]
98
+ i += 2
99
+ when "--format"
100
+ args[:format] = argv[i + 1]
101
+ i += 2
102
+ when "--entity-type"
103
+ args[:entity_type] = argv[i + 1]
104
+ i += 2
105
+ when "--csv-identifier"
106
+ args[:csv_identifier] = argv[i + 1].to_i
107
+ i += 2
108
+ when "--metadata"
109
+ args[:metadata] = parse_json_or_file(argv[i + 1])
110
+ i += 2
111
+ when "--quiet"
112
+ args[:quiet] = true
113
+ i += 1
114
+ when "--api-key"
115
+ args[:api_key] = argv[i + 1]
116
+ i += 2
117
+ when "--output-format"
118
+ args[:output_format] = argv[i + 1]
119
+ i += 2
120
+ else
121
+ $stderr.puts "Unknown option: #{arg}"
122
+ exit 1
123
+ end
124
+ end
125
+
126
+ args
127
+ end
128
+
129
+ # Main execution
130
+ begin
131
+ args = parse_args(ARGV)
132
+
133
+ # Validate required parameters
134
+ unless args[:count]
135
+ $stderr.puts "Error: --count is required"
136
+ $stderr.puts "Run 'exa-ai import-create --help' for usage information"
137
+ exit 1
138
+ end
139
+
140
+ unless args[:title]
141
+ $stderr.puts "Error: --title is required"
142
+ $stderr.puts "Run 'exa-ai import-create --help' for usage information"
143
+ exit 1
144
+ end
145
+
146
+ unless args[:entity_type]
147
+ $stderr.puts "Error: --entity-type is required"
148
+ $stderr.puts "Run 'exa-ai import-create --help' for usage information"
149
+ exit 1
150
+ end
151
+
152
+ # Validate format
153
+ unless VALID_FORMATS.include?(args[:format])
154
+ $stderr.puts "Error: format must be one of: #{VALID_FORMATS.join(', ')}"
155
+ exit 1
156
+ end
157
+
158
+ # Validate entity type
159
+ unless VALID_ENTITY_TYPES.include?(args[:entity_type])
160
+ $stderr.puts "Error: entity-type must be one of: #{VALID_ENTITY_TYPES.join(', ')}"
161
+ exit 1
162
+ end
163
+
164
+ # Validate file exists
165
+ unless File.exist?(args[:file_path])
166
+ $stderr.puts "Error: File not found: #{args[:file_path]}"
167
+ exit 1
168
+ end
169
+
170
+ # Resolve API key
171
+ api_key = Exa::CLI::Base.resolve_api_key(args[:api_key])
172
+
173
+ # Resolve output format
174
+ output_format = Exa::CLI::Base.resolve_output_format(args[:output_format])
175
+
176
+ # Build client
177
+ client = Exa::CLI::Base.build_client(api_key)
178
+
179
+ # Prepare import parameters
180
+ import_params = {
181
+ file_path: args[:file_path],
182
+ count: args[:count],
183
+ title: args[:title],
184
+ format: args[:format],
185
+ entity: { type: args[:entity_type] }
186
+ }
187
+ import_params[:metadata] = args[:metadata] if args[:metadata]
188
+
189
+ # Add CSV config if csv_identifier provided
190
+ if args[:csv_identifier]
191
+ import_params[:csv] = { identifier: args[:csv_identifier] }
192
+ end
193
+
194
+ # Show upload message unless quiet
195
+ unless args[:quiet]
196
+ file_size = File.size(args[:file_path])
197
+ $stderr.puts "Uploading #{args[:file_path]} (#{file_size} bytes)..."
198
+ end
199
+
200
+ # Upload import
201
+ import = client.upload_import(**import_params)
202
+
203
+ # Show success message unless quiet
204
+ unless args[:quiet]
205
+ $stderr.puts "Upload complete. Import ID: #{import.id}"
206
+ end
207
+
208
+ # Format and output result (unless quiet)
209
+ unless args[:quiet]
210
+ output = Exa::CLI::Formatters::ImportFormatter.format(import, output_format)
211
+ puts output
212
+ end
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,92 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "exa-ai"
5
+
6
+ # Parse arguments
7
+ import_id = nil
8
+ api_key = nil
9
+ output_format = "json"
10
+
11
+ args = ARGV.dup
12
+ while args.any?
13
+ arg = args.shift
14
+ case arg
15
+ when "--api-key"
16
+ api_key = args.shift
17
+ when "--output-format"
18
+ output_format = args.shift
19
+ when "--help", "-h"
20
+ puts <<~HELP
21
+ Usage: exa-ai import-delete <import_id> [OPTIONS]
22
+
23
+ Delete an import
24
+
25
+ Arguments:
26
+ import_id ID of the import to delete (required)
27
+
28
+ Options:
29
+ --api-key KEY Exa API key (or set EXA_API_KEY env var)
30
+ --output-format FMT Output format: json, pretty, or text (default: json)
31
+ --help, -h Show this help message
32
+
33
+ Examples:
34
+ exa-ai import-delete imp_123
35
+ exa-ai import-delete imp_123 --output-format text
36
+ HELP
37
+ exit 0
38
+ else
39
+ # First positional argument is import_id
40
+ if import_id.nil?
41
+ import_id = arg
42
+ else
43
+ $stderr.puts "Unknown option: #{arg}"
44
+ exit 1
45
+ end
46
+ end
47
+ end
48
+
49
+ # Validate
50
+ if import_id.nil?
51
+ $stderr.puts "Error: import_id argument is required"
52
+ $stderr.puts "Usage: exa-ai import-delete <import_id> [OPTIONS]"
53
+ $stderr.puts "Try 'exa-ai import-delete --help' for more information"
54
+ exit 1
55
+ end
56
+
57
+ begin
58
+ # Resolve API key and format
59
+ api_key = Exa::CLI::Base.resolve_api_key(api_key)
60
+ output_format = Exa::CLI::Base.resolve_output_format(output_format)
61
+
62
+ # Build client
63
+ client = Exa::CLI::Base.build_client(api_key)
64
+
65
+ # Delete import
66
+ import = client.delete_import(import_id)
67
+
68
+ # Format and output
69
+ output = Exa::CLI::Formatters::ImportFormatter.format(import, output_format)
70
+ puts output
71
+
72
+ rescue Exa::NotFound => e
73
+ $stderr.puts "Import not found: #{e.message}"
74
+ exit 1
75
+ rescue Exa::Unauthorized => e
76
+ $stderr.puts "Authentication error: #{e.message}"
77
+ $stderr.puts "Check your API key (set EXA_API_KEY or use --api-key)"
78
+ exit 1
79
+ rescue Exa::ClientError => e
80
+ $stderr.puts "Client error: #{e.message}"
81
+ exit 1
82
+ rescue Exa::ServerError => e
83
+ $stderr.puts "Server error: #{e.message}"
84
+ exit 1
85
+ rescue Exa::Error => e
86
+ $stderr.puts "Error: #{e.message}"
87
+ exit 1
88
+ rescue StandardError => e
89
+ $stderr.puts "Unexpected error: #{e.message}"
90
+ $stderr.puts e.backtrace.first(5) if ENV["DEBUG"]
91
+ exit 1
92
+ end