Skip to content

Add Exa search connector - #14245

Open
kesku wants to merge 1 commit into
microsoft:mainfrom
kesku:kesku/add-exa-support
Open

Add Exa search connector#14245
kesku wants to merge 1 commit into
microsoft:mainfrom
kesku:kesku/add-exa-support

Conversation

@kesku

@kesku kesku commented Jul 30, 2026

Copy link
Copy Markdown

Motivation and Context

Semantic Kernel already ships Python TextSearch connectors for Brave and Google. This PR adds Exa as another web search option for the same plugin/function calling scenarios, so agents can use Exa's semantic search API!

Description

Adds a ExaSearch TextSearch connector that calls POST https://api.exa.ai/search (type: "auto", highlights under contents).

  • New connector + settings/response models in python/semantic_kernel/connectors/exa.py
  • Lazy exports wired into search.py / search.pyi
  • Sample showing it as a plugin
  • .env.example entry for EXA_API_KEY
  • Unit tests alongside the other search connector tests

Set EXA_API_KEY and you're good to go!

Contribution Checklist

Copilot AI review requested due to automatic review settings July 30, 2026 22:50
@kesku
kesku requested a review from a team as a code owner July 30, 2026 22:50
@kesku

kesku commented Jul 30, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new Python TextSearch connector (ExaSearch) to Semantic Kernel, enabling agent/plugin scenarios to query Exa’s semantic search API alongside existing Brave and Google connectors.

Changes:

  • Added ExaSearch connector implementation and result/settings models.
  • Wired Exa connector into the lazy connector exports (search.py / search.pyi).
  • Added sample usage, environment variable template entry, and unit tests for the connector.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
python/semantic_kernel/connectors/exa.py Implements the Exa /search connector, settings, and response/result models.
python/semantic_kernel/connectors/search.py Adds lazy export mapping for Exa connector symbols.
python/semantic_kernel/connectors/search.pyi Exposes Exa connector symbols in type stubs.
python/tests/unit/connectors/search/test_exa_search.py Adds unit tests for ExaSearch behaviors and payload construction.
python/tests/unit/connectors/conftest.py Adds exa_unit_test_env fixture to provide EXA_API_KEY during tests.
python/samples/concepts/search/exa_text_search_as_plugin.py Adds a sample demonstrating ExaSearch as a Kernel plugin.
python/samples/concepts/README.md Links the new Exa sample in the concepts README.
python/.env.example Adds EXA_API_KEY to the example environment file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread python/semantic_kernel/connectors/exa.py Outdated
Comment thread python/tests/unit/connectors/search/test_exa_search.py

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 5 | Confidence: 70%

✓ Correctness

The new Exa search connector is well-structured and follows the existing patterns (Brave connector). One correctness issue found: the HTTP header for user agent uses an underscore (user_agent) instead of a hyphen (User-Agent), which means the user-agent string won't be recognized by servers or proxies. The skip parameter is accepted but silently ignored (Exa API has no offset), which matches other SK connectors. Tests are comprehensive and cover all major code paths.

✓ Security Reliability

The Exa search connector is well-structured from a security standpoint: it uses ast.parse (not eval) for filter lambda parsing, stores the API key as SecretStr, sets an HTTP timeout, and has comprehensive error handling. The only notable issue is the HTTP header name 'user_agent' (underscore) which should likely be 'User-Agent' (hyphen) to be recognized as the standard User-Agent header by servers and proxies. No injection risks, secret leaks, or resource leak concerns were identified.

✓ Test Coverage

The test suite covers the main happy paths and error handling well (init, three output types, HTTP/request/generic errors, validation, filters). However, there are a few notable coverage gaps: no test for empty search results, the skip parameter is accepted but silently ignored without any test verifying the behavior, include_total_count=False is never explicitly asserted to yield total_count=None, and the _get_options fallback path (returning default SearchOptions() on ValidationError) is untested. The api_key constructor parameter path is also untested (only env-var path is covered).

✓ Failure Modes

The Exa connector has a few silent failure modes: the skip parameter is accepted but silently ignored (callers get duplicate results instead of paginated ones), the User-Agent header uses an underscore instead of a hyphen so it won't be recognized by HTTP infrastructure, and _get_options silently swallows validation errors returning defaults. The error handling for HTTP failures is solid and well-tested.

✓ Design Approach

I found one design-level correctness issue: the new connector advertises paginated search via skip, but the implementation never sends any offset/cursor information to Exa or rejects unsupported paging, so nonzero skip silently returns the first page again.


Automated review by kesku's agents

Comment thread python/semantic_kernel/connectors/exa.py
@kesku
kesku force-pushed the kesku/add-exa-support branch from 360adc3 to 242c7b5 Compare July 30, 2026 23:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

python/samples/concepts/search/exa_text_search_as_plugin.py:19

  • Minor grammar issues in the sample docstring: “obtained by login to” should be “obtained by logging in to”, and “After that store it” should include a comma (“After that, …”).
To use Exa Search, you need an API key, which can be obtained by login to
https://dashboard.exa.ai/api-keys and creating a key.
After that store it under the name `EXA_API_KEY` in a .env file or your environment variables.

python/samples/concepts/search/exa_text_search_as_plugin.py:117

  • The print call uses backslash-continued string literals with indentation. In Python, the indentation spaces become part of the string, so the output will include unexpected whitespace. Prefer normal string concatenation with explicit \n.
    print(
        "Welcome to the chat bot!\
        \n  Type 'exit' to exit.\
        \n  Try to find out more about the inner workings of Semantic Kernel."
    )

python/semantic_kernel/connectors/exa.py:221

  • The request header key user_agent is not a standard HTTP header name; if the intent is to send a User-Agent, it should be User-Agent (or semantic_kernel.const.USER_AGENT). Using the wrong header name means the User-Agent may not be transmitted/recognized by Exa or proxies.
            "user_agent": SEMANTIC_KERNEL_USER_AGENT,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants