exa-ai-ruby 1.1.0 → 1.1.1
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/CHANGELOG.md +4 -0
- data/README.md +58 -8
- data/lib/exa/cli/formatters.rb +91 -0
- data/lib/exa/cli/root.rb +10 -18
- data/lib/exa/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cbb55f4b95516f779fda2e4f26d34d38778ce94186683001768348b8378e06ac
|
|
4
|
+
data.tar.gz: dc31ed93afbc2a1f7d96db620fe975d70c2aaa7647a11eaa7592ae973e9fe5cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8bcb3d9fa20d16ac14435ad04c327ab508afa1461fe0aa0f99528a5eb423fb32246bfdf5db732547c52bab9f89107dc5feae65f28879699948ef9d188570929f
|
|
7
|
+
data.tar.gz: 56019a774cb70ab4a1f73a9586c1e02735d3df867313c6c62d0012b19180f1067d6b0aa8774b5625a71d5b0b0f3ce924e490c86b8d99256444d66bf3da00b4c7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.1] - 2025-10-26
|
|
4
|
+
- Add CLI output formatters: `--format jsonl` emits one JSON object per line, and `--format markdown` prints share-ready bullet lists/tables.
|
|
5
|
+
- Document copy-paste ready CLI and Ruby API examples in the README so users/LLMs can get started instantly.
|
|
6
|
+
|
|
3
7
|
## [1.1.0] - 2025-10-26
|
|
4
8
|
- Add the `exa` CLI entrypoint (installed automatically with the gem) including multi-account credential management and JSON-friendly output helpers.
|
|
5
9
|
- Introduce a secure YAML config store (`~/.config/exa/config.yml`) and CLI commands for `accounts:list`, `accounts:add`, `accounts:use`, and `accounts:remove`.
|
data/README.md
CHANGED
|
@@ -125,17 +125,67 @@ Starting with v1.1.0 the gem ships an `exa` executable that mirrors the API surf
|
|
|
125
125
|
|
|
126
126
|
Every command accepts `--account`, `--api-key`, `--base-url`, `--config`, and `--format`. If omitted they fall back to the config file, environment variables (`EXA_ACCOUNT`, `EXA_API_KEY`, `EXA_BASE_URL`), or defaults.
|
|
127
127
|
|
|
128
|
-
3. **Call the API from any shell**
|
|
128
|
+
3. **Call the API from any shell**
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
```
|
|
131
|
+
# Run a typed search (pipe `--json` to jq or capture raw data)
|
|
132
|
+
$ exa search:run "latest reasoning LLM papers" --num-results 3 --json
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
# Fetch contents for explicit URLs
|
|
135
|
+
$ exa search:contents --urls https://exa.ai,https://exa.com --json
|
|
136
|
+
|
|
137
|
+
# Stream results as JSON lines (great for logging/piping)
|
|
138
|
+
$ exa search:run "ai funding" --num-results 2 --format jsonl
|
|
139
|
+
|
|
140
|
+
# Share-ready Markdown lists
|
|
141
|
+
$ exa websets:list --format markdown
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Omit `--json` for friendly summaries; include it when scripting so you get the Sorbet structs serialized as plain JSON.
|
|
145
|
+
|
|
146
|
+
Prefer `--format jsonl` for streaming-friendly logs or `--format markdown` when you want ready-to-share bullet lists/tables.
|
|
147
|
+
|
|
148
|
+
### Copy-paste CLI examples
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# 1) Configure credentials once (stored at ~/.config/exa/config.yml)
|
|
152
|
+
exa accounts:add prod --api-key $EXA_API_KEY --base-url https://api.exa.ai
|
|
153
|
+
|
|
154
|
+
# 2) Run searches with different outputs
|
|
155
|
+
exa search:run "latest reasoning LLM papers" --num-results 5
|
|
156
|
+
exa search:run "biotech funding" --format jsonl | tee results.jsonl
|
|
157
|
+
|
|
158
|
+
# 3) Inspect resources in Markdown form (perfect for PRs/notes)
|
|
159
|
+
exa websets:list --format markdown
|
|
160
|
+
exa webhooks:list --format markdown
|
|
161
|
+
|
|
162
|
+
# 4) Use a one-off API key without mutating config
|
|
163
|
+
exa search:contents --urls https://exa.ai --api-key $EXA_API_KEY --json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Copy-paste API client example
|
|
137
167
|
|
|
138
|
-
|
|
168
|
+
```ruby
|
|
169
|
+
require "exa"
|
|
170
|
+
|
|
171
|
+
client = Exa::Client.new(api_key: ENV.fetch("EXA_API_KEY"))
|
|
172
|
+
|
|
173
|
+
search = client.search.search(
|
|
174
|
+
query: "latest reasoning LLM papers",
|
|
175
|
+
num_results: 5,
|
|
176
|
+
text: true
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
search.results.each do |result|
|
|
180
|
+
puts "#{result.title} - #{result.url}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Websets + monitors
|
|
184
|
+
websets = client.websets.list(limit: 5)
|
|
185
|
+
websets.data.each_with_index do |webset, idx|
|
|
186
|
+
puts "#{idx + 1}. #{webset.title} (#{webset.id})"
|
|
187
|
+
end
|
|
188
|
+
```
|
|
139
189
|
|
|
140
190
|
Command families currently available:
|
|
141
191
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Exa
|
|
6
|
+
module CLI
|
|
7
|
+
module Formatters
|
|
8
|
+
def self.for(name)
|
|
9
|
+
case name&.to_s&.downcase
|
|
10
|
+
when "json"
|
|
11
|
+
JsonFormatter.new
|
|
12
|
+
when "jsonl"
|
|
13
|
+
JsonlFormatter.new
|
|
14
|
+
when "markdown"
|
|
15
|
+
MarkdownFormatter.new
|
|
16
|
+
else
|
|
17
|
+
TableFormatter.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class BaseFormatter
|
|
22
|
+
def render(cli:, payload:, collection:)
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def serialize(cli, object)
|
|
29
|
+
cli.send(:serializable, object)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class JsonFormatter < BaseFormatter
|
|
34
|
+
def render(cli:, payload:, collection:)
|
|
35
|
+
cli.say JSON.pretty_generate(serialize(cli, payload))
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class JsonlFormatter < BaseFormatter
|
|
40
|
+
def render(cli:, payload:, collection:)
|
|
41
|
+
items = collection && !collection.empty? ? collection : [payload]
|
|
42
|
+
items.each do |item|
|
|
43
|
+
cli.say JSON.generate(serialize(cli, item))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class MarkdownFormatter < BaseFormatter
|
|
49
|
+
def render(cli:, payload:, collection:)
|
|
50
|
+
if collection && !collection.empty?
|
|
51
|
+
collection.each do |item|
|
|
52
|
+
cli.say "- #{markdown_line(cli, item)}"
|
|
53
|
+
end
|
|
54
|
+
else
|
|
55
|
+
cli.say "```json"
|
|
56
|
+
cli.say JSON.pretty_generate(serialize(cli, payload))
|
|
57
|
+
cli.say "```"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def markdown_line(cli, item)
|
|
64
|
+
title = cli.send(:value_from, item, :title) || cli.send(:value_from, item, :name)
|
|
65
|
+
url = cli.send(:value_from, item, :url)
|
|
66
|
+
id = cli.send(:value_from, item, :id)
|
|
67
|
+
primary = title || id || cli.send(:serializable, item)
|
|
68
|
+
|
|
69
|
+
line = primary.is_a?(String) ? primary : primary.to_s
|
|
70
|
+
line = "[#{line}](#{url})" if url
|
|
71
|
+
line += " (#{id})" if id && (title || url)
|
|
72
|
+
line
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class TableFormatter < BaseFormatter
|
|
77
|
+
def render(cli:, payload:, collection:)
|
|
78
|
+
if collection && !collection.empty?
|
|
79
|
+
collection.each_with_index do |item, index|
|
|
80
|
+
cli.say cli.send(:format_collection_entry, item, index)
|
|
81
|
+
end
|
|
82
|
+
elsif collection
|
|
83
|
+
cli.say "No results."
|
|
84
|
+
else
|
|
85
|
+
cli.say cli.send(:format_single_entry, payload)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/exa/cli/root.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "json"
|
|
|
5
5
|
require "exa"
|
|
6
6
|
require_relative "config_store"
|
|
7
7
|
require_relative "account_resolver"
|
|
8
|
+
require_relative "formatters"
|
|
8
9
|
|
|
9
10
|
module Exa
|
|
10
11
|
module CLI
|
|
@@ -69,7 +70,7 @@ module Exa
|
|
|
69
70
|
class_option :api_key, type: :string, desc: "Override the API key for this invocation"
|
|
70
71
|
class_option :base_url, type: :string, desc: "Override the API base URL"
|
|
71
72
|
class_option :config, type: :string, desc: "Path to the exa CLI config file"
|
|
72
|
-
class_option :format, type: :string, default: "table", desc: "Output format: table, json, or
|
|
73
|
+
class_option :format, type: :string, default: "table", desc: "Output format: table, json, jsonl, or markdown"
|
|
73
74
|
|
|
74
75
|
# Version -----------------------------------------------------------------
|
|
75
76
|
|
|
@@ -631,24 +632,10 @@ module Exa
|
|
|
631
632
|
|
|
632
633
|
def render_response(response, json:, collection_accessor: nil)
|
|
633
634
|
payload = serializable(response)
|
|
634
|
-
if json
|
|
635
|
-
say JSON.pretty_generate(payload)
|
|
636
|
-
return
|
|
637
|
-
end
|
|
638
|
-
|
|
639
635
|
collection = extract_collection(response, payload, collection_accessor)
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
else
|
|
644
|
-
collection.each_with_index do |item, index|
|
|
645
|
-
say format_collection_entry(item, index)
|
|
646
|
-
end
|
|
647
|
-
end
|
|
648
|
-
return
|
|
649
|
-
end
|
|
650
|
-
|
|
651
|
-
say format_single_entry(payload)
|
|
636
|
+
formatter_name = determine_format(json)
|
|
637
|
+
formatter = Exa::CLI::Formatters.for(formatter_name)
|
|
638
|
+
formatter.render(cli: self, payload: payload, collection: collection)
|
|
652
639
|
end
|
|
653
640
|
|
|
654
641
|
def render_stream(stream, json:)
|
|
@@ -800,3 +787,8 @@ module Exa
|
|
|
800
787
|
end
|
|
801
788
|
end
|
|
802
789
|
end
|
|
790
|
+
def determine_format(json_requested)
|
|
791
|
+
return "json" if json_requested
|
|
792
|
+
value = options[:format]
|
|
793
|
+
value.nil? ? "table" : value.to_s.downcase
|
|
794
|
+
end
|
data/lib/exa/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: exa-ai-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vicente Reig Rincon de Arellano
|
|
@@ -193,6 +193,7 @@ files:
|
|
|
193
193
|
- lib/exa/cli.rb
|
|
194
194
|
- lib/exa/cli/account_resolver.rb
|
|
195
195
|
- lib/exa/cli/config_store.rb
|
|
196
|
+
- lib/exa/cli/formatters.rb
|
|
196
197
|
- lib/exa/cli/root.rb
|
|
197
198
|
- lib/exa/client.rb
|
|
198
199
|
- lib/exa/errors.rb
|