Releases: vicentereig/exa-ruby
Releases · vicentereig/exa-ruby
Release 1.3.0
What's New
Instrumentation & Cost Tracking
This release adds a built-in instrumentation system for tracking API usage and costs. Events are emitted around every API request, enabling logging, monitoring, and cost management.
Features
- EventRegistry - Thread-safe event registry with wildcard pattern subscriptions (
exa.request.*) - CostTracker - Built-in subscriber for tracking API costs with summary and reporting
- BaseSubscriber - Base class for building custom event subscribers
- Typed Events -
RequestStart,RequestComplete,RequestErrorstructs with full Sorbet types - Endpoint Enum -
T::Enumfor typed endpoint identification
Typed Cost Structs
- Unified
CostDollarstypes into sharedlib/exa/responses/cost.rb - All response types now use fully-typed
CostDollarsstruct with detailed breakdown fields - Supports
total,break_down,per_request_prices, andper_page_prices
Usage Example
require "exa"
client = Exa::Client.new(api_key: ENV.fetch("EXA_API_KEY"))
tracker = Exa::Instrumentation::CostTracker.new
tracker.subscribe
response = client.search.search(query: "AI papers", num_results: 10)
puts response.cost_dollars&.total # => 0.005
puts tracker.total_cost # => 0.005
puts tracker.request_count # => 1
puts tracker.report # => Formatted cost reportSee the README for complete documentation.
Full Changelog: v1.2.0...v1.3.0
v1.2.2 - Fix text extraction in search results
Bug Fix
BUGFIX: Fix text/highlights/summary/context extraction in search results.
The Exa API requires these options to be wrapped in a contents object. Previously, passing text: true or text: {max_characters: 1000} would silently return no text content.
What Changed
SearchRequest#to_payloadnow automatically wraps content options (text,highlights,summary,context) in the requiredcontentsstructure- Text extraction now works as documented
Example
# This now works correctly!
results = client.search.search(
query: "latest AI papers",
num_results: 5,
text: { max_characters: 1000 }
)
results.results.each do |r|
puts r.text # Now contains the actual text content
endUpgrade
gem update exa-ai-rubyOr update your Gemfile:
gem "exa-ai-ruby", "~> 1.2.2"v1.2.1
Bug Fixes
- Fix subpages type mismatch in
ResultWithContent- subpages are now correctly typed asResultWithContentobjects (notResult), allowing access to content fields liketext,highlights, andsummary
Tests
- Add test coverage for subpages parsing
exa-ai-ruby v1.2.0
Highlights
- Add
Exa::Internal::Transport::AsyncRequesterfor fiber-scheduler-friendly HTTP viaasync/async-http. - Document optional async setup in the README and keep the synchronous defaults untouched.
- Cover the new transport with integration-style tests and wire optional development/test dependencies.
Async requester example
require "async"
require "exa/internal/transport/async_requester"
require "exa"
Async do
requester = Exa::Internal::Transport::AsyncRequester.new
client = Exa::Client.new(api_key: ENV.fetch("EXA_API_KEY"), requester: requester)
search_task = Async { client.search.search(query: "climate tech", num_results: 3) }
research_task = Async { client.research.create(instructions: "Map top autonomous robotics labs") }
puts "Top result: #{search_task.wait.results.first.title}"
puts "Research ID: #{research_task.wait.id}"
ensure
requester.close
endv1.1.3
What's Changed
- Extend compatibility down to Ruby 3.0.x by lowering the minimum required Ruby version.
- Require dspy-schema >= 1.0.1 for bugfix updates.
Published Gem
- exa-ai-ruby 1.1.3
exa-ai-ruby 1.1.2
What's Changed
- Broaden runtime support to Ruby 3.1+ by lowering the minimum required version.
Checks
- ✅ RBENV_VERSION=3.4.5 ~/.rbenv/shims/bundle exec rake test
v1.1.1
Highlights
- Introduce JSONL + Markdown output modes for the
exaCLI (--format jsonl|markdown) so you can pipe results to logs or share-ready docs. - Document copy-paste ready CLI and Ruby API workflows in the README to help humans & LLMs ramp instantly.
API snippet
client = Exa::Client.new(api_key: ENV.fetch("EXA_API_KEY"))
resp = client.search.search(query: "latest reasoning LLM papers", num_results: 5)
resp.results.each { |r| puts "#{r.title} - #{r.url}" }CLI snippet
exa accounts:add prod --api-key $EXA_API_KEY --base-url https://api.exa.ai
exa search:run "latest reasoning LLM papers" --num-results 5 --format jsonl
exa websets:list --format markdownv1.1.0
Highlights
- Ship the new
exaCLI with multi-account config management plus JSON-friendly output defaults. - Cover the entire Exa API surface (search, research, websets/items/enrichments/monitors, imports, events, webhooks) from the CLI with shared streaming + payload helpers.
- Harden the HTTP transport to avoid duplicate requests and handle
costDollarshashes, so live CLI/API calls succeed reliably.
API snippet
client = Exa::Client.new(api_key: ENV.fetch("EXA_API_KEY"))
resp = client.search.search(query: "latest reasoning LLM papers", num_results: 5)
resp.results.each { |r| puts "#{r.title} - #{r.url}" }CLI snippet
exa accounts:add prod --api-key $EXA_API_KEY --base-url https://api.exa.ai
exa search:run "latest reasoning LLM papers" --num-results 5 --jsonv1.0.0
Highlights
- First stable release of typed Exa API client.
- Covers search, research, websets, monitors, imports, events, and webhooks.
- Includes Sorbet request/response structs, schema-aware structured output, retries, and streaming helpers.
- Ships connection pooling, pagination utilities, and exhaustive README guidance.