Skip to Content

Exa (tracing)

Exa  provides search, contents, grounded-answer, tool, and Agent APIs. Respan’s native Exa instrumentations turn those SDK calls into connected OpenTelemetry spans with provider-neutral names and canonical Respan metadata.

Set up Respan

Create an account at platform.respan.ai  and grab an API key .

Package source and example projects

The first release of the Python respan-instrumentation-exa package is pending and is not currently available from PyPI. The Python installation steps below use a Respan source checkout. The JavaScript @respan/instrumentation-exa package is available from npm.

This is an SDK tracing integration, not a Respan Gateway provider route. Respan Gateway does not currently route Exa search, contents, answer, Agent, or Research APIs. EXA_API_KEY is used directly by the official Exa SDK; RESPAN_BASE_URL configures trace export only.

The Python package requires Python >=3.11,<3.14, supports exa-py>=2.20.0,<3.0.0, and is tested with exa-py==2.20.0. The JavaScript package requires Node.js 18 or newer, supports exa-js>=2.19.0 <3.0.0, and is tested with the npm-stable exa-js@2.19.0.

Paste this into your coding agent:

Help me set up Respan tracing with the Exa integration. Follow https://www.respan.ai/docs/integrations/exa.md

Setup

Install packages

Terminal
pip install respan-ai respan-instrumentation-exa "exa-py>=2.20,<3"

Set environment variables

Terminal
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY" export EXA_API_KEY="YOUR_EXA_API_KEY" # Optional: override the Respan API base URL. export RESPAN_BASE_URL="https://api.respan.ai/api"

Initialize Respan and call Exa

Initialize the explicit instrumentor before making Exa SDK calls, and shut Respan down when the application exits so pending spans are flushed.

Python
import os from exa_py import Exa from respan import Respan from respan_instrumentation_exa import ExaInstrumentor respan = Respan( api_key=os.environ["RESPAN_API_KEY"], base_url=os.getenv("RESPAN_BASE_URL", "https://api.respan.ai/api"), app_name="exa-tracing", instrumentations=[ExaInstrumentor()], ) exa = Exa(api_key=os.environ["EXA_API_KEY"]) try: result = exa.search( "recent advances in retrieval", type="auto", num_results=3, contents={"highlights": True}, ) print(result.results) finally: respan.shutdown()

View your trace

Open the Traces page  and inspect the tool.search span, its input and output, status, timing, and Exa metadata.

Captured SDK surfaces

The integration is explicit-only: pass ExaInstrumentor in instrumentations as shown above. Exa can execute OpenAI or Anthropic tool adapters internally, so it is not enabled as direct-LLM auto-instrumentation.

SurfacePythonJavaScriptRespan shape
Searchsearch(), search_and_contents(), find_similar(), find_similar_and_contents()search(), searchAndContents(), findSimilar(), findSimilarAndContents()Provider-neutral tool spans such as tool.search and tool.find_similar
Contentsget_contents()getContents()tool.get_contents with URLs/options as input and retrieved content as output
Grounded answersanswer(), stream_answer()answer(), streamAnswer()Chat spans; the model is recorded only when the SDK request or response supplies one
Search streamingstream_search()streamSearch()One span whose output aggregates the consumed chunks and citations
Agent runsSync and async agent.runs create, stream, get, list, cancel, stop, delete, poll, wait, and event-list operationsagent.runs and beta Agent run create, stream, get, list, cancel, stop, delete, poll, wait, and event-list operationsagent.run plus lifecycle task spans
Tool helperstools.web_search(), Python 2.20 tools.get_contents(), and the OpenAI Chat/Responses and Anthropic helper adapterstools.webSearch() plus the OpenAI Chat/Responses and Anthropic helper adaptersThe helper’s underlying core Exa call is traced once, without a duplicate wrapper span
Legacy ResearchSync and async research.create(), get(), list(), and poll_until_finished()research.create(), get(), list(), and pollUntilFinished()agent.research plus lifecycle task spans, marked as legacy metadata

Native SDK operation names, language, stream state, result counts, request IDs, resolved search type, cost, citations, and legacy Research markers are stored in the canonical respan.metadata JSON attribute. Successful and failed calls also retain their real status and error information. API keys and authorization-like fields are always redacted.

Streaming lifecycle

Streaming spans end when the iterator is exhausted, iteration raises an error, or the iterator is explicitly closed. JavaScript early exit from a for await loop calls the wrapped iterator’s return() and closes the span. Python exposes the SDK’s close behavior through the wrapped iterator, including the synchronous close() method on exa-py 2.20 async stream response objects.

If an application abandons a stream without exhausting or closing it, the instrumentation cannot record an exact completion timestamp. Always exhaust the stream or close it explicitly.

Content and privacy controls

Request and response content is captured by default. Disable it per instrumentor:

Python
ExaInstrumentor(capture_content=False)

Or disable content capture for the process:

Terminal
export TRACELOOP_TRACE_CONTENT=false

With content capture disabled, query, result, prompt, completion, citation, and stream payloads are omitted. Operation, stream state, status, timing, and other non-content metadata remain available.

Limitations

  • Websets, Search Monitor CRUD, and beta Agent Monitor operations are not patched; they are long-lived control-plane APIs rather than in-process AI operations.
  • exa-js@2.19.0 supports core getContents(), but does not ship a tools.getContents() helper. The Python 2.20 SDK does ship tools.get_contents().
  • Legacy Research remains instrumented for compatibility, but Exa recommends deep search (type="deep-reasoning") for new research flows.
  • Helper calls are deduplicated against the core SDK methods they invoke; activating overlapping provider instrumentations may still add their own lower-level model spans.