Skip to content

Releases: vicentereig/exa-ruby

Release 1.3.0

23 Dec 12:36

Choose a tag to compare

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, RequestError structs with full Sorbet types
  • Endpoint Enum - T::Enum for typed endpoint identification

Typed Cost Structs

  • Unified CostDollars types into shared lib/exa/responses/cost.rb
  • All response types now use fully-typed CostDollars struct with detailed breakdown fields
  • Supports total, break_down, per_request_prices, and per_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 report

See the README for complete documentation.

Full Changelog: v1.2.0...v1.3.0

v1.2.2 - Fix text extraction in search results

22 Dec 15:20

Choose a tag to compare

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_payload now automatically wraps content options (text, highlights, summary, context) in the required contents structure
  • 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
end

Upgrade

gem update exa-ai-ruby

Or update your Gemfile:

gem "exa-ai-ruby", "~> 1.2.2"

v1.2.1

21 Dec 22:37

Choose a tag to compare

Bug Fixes

  • Fix subpages type mismatch in ResultWithContent - subpages are now correctly typed as ResultWithContent objects (not Result), allowing access to content fields like text, highlights, and summary

Tests

  • Add test coverage for subpages parsing

exa-ai-ruby v1.2.0

31 Oct 12:17

Choose a tag to compare

Highlights

  • Add Exa::Internal::Transport::AsyncRequester for fiber-scheduler-friendly HTTP via async/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
end

v1.1.3

30 Oct 09:25

Choose a tag to compare

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

27 Oct 18:37

Choose a tag to compare

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

26 Oct 14:09

Choose a tag to compare

Highlights

  • Introduce JSONL + Markdown output modes for the exa CLI (--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 markdown

v1.1.0

26 Oct 13:58

Choose a tag to compare

Highlights

  • Ship the new exa CLI 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 costDollars hashes, 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 --json

v1.0.0

26 Oct 11:25

Choose a tag to compare

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.