Skip to content

Adding Exa as a web search plugin#50281

Closed
louiswalsh wants to merge 5 commits intoopenclaw:mainfrom
exa-labs:feat/exa-web-search-plugin
Closed

Adding Exa as a web search plugin#50281
louiswalsh wants to merge 5 commits intoopenclaw:mainfrom
exa-labs:feat/exa-web-search-plugin

Conversation

@louiswalsh
Copy link
Copy Markdown

Summary

  • Problem: OpenClaw has no native Exa web search provider — users must rely on a community plugin for Exa integration.
  • Why it matters: Exa is a neural search engine optimized for AI applications; bundling it makes it a zero-config option for OpenClaw users with an Exa API key.
  • What changed: Added extensions/exa/ as a new bundled web search provider plugin (4 new files), registered it in BUNDLED_WEB_SEARCH_PLUGIN_IDS, and updated the contract registry + test expectations.
  • What did NOT change (scope boundary): No modifications to core config types, Zod schemas, existing providers, or the plugin SDK. Only additive changes to shared registration files (+9 lines across 5 existing files).

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • New exa web search provider available when EXA_API_KEY is set or configured via openclaw configure --section web.
  • Exa appears last in auto-detect order (65, after Firecrawl at 60) — it will only auto-select if no other provider keys are configured.
  • New config path: plugins.entries.exa.config.webSearch.apiKey.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No — follows existing readConfiguredSecretString / readProviderEnvValue pattern
  • New/changed network calls? Yes — POST to https://api.exa.ai/search with x-api-key header
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: Network call is gated behind API key presence. Request goes through withTrustedWebSearchEndpoint (same as all other providers). No secrets are logged or exposed. The x-exa-integration: "openclaw" header is sent for usage tracking only.

Repro + Verification

Environment

  • OS: Linux (Ubuntu)
  • Runtime/container: Node.js >=22.16.0
  • Model/provider: N/A (web search provider, not model provider)
  • Integration/channel (if any): Exa Search API
  • Relevant config (redacted): EXA_API_KEY=exa-***

Steps

  1. Set EXA_API_KEY environment variable
  2. Run openclaw configure --section web and select Exa, or let auto-detect pick it up
  3. Use web_search tool — should route through Exa

Expected

  • Search returns titles, URLs, and highlighted snippets from Exa's neural search

Actual

  • (Verified via unit test suite — all 599 plugin tests pass)

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

All 599 plugin tests pass (pnpm vitest run src/plugins/). Lint clean (oxlint --type-aware: 0 warnings, 0 errors).

Human Verification (required)

  • Verified scenarios: Full plugin test suite (599 tests), lint, registration in bundled IDs, contract registry assertions, auto-detect ordering.
  • Edge cases checked: Missing API key returns descriptive error with docs link. Empty/malformed results handled via fallback defaults.
  • What you did not verify: Live API call to Exa (no API key available in test environment). UI rendering of Exa in provider selection dropdown.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? Yes — new optional EXA_API_KEY env var recognized
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Remove "exa" from BUNDLED_WEB_SEARCH_PLUGIN_IDS in src/plugins/bundled-web-search.ts, or set plugins.entries.exa.enabled: false in config.
  • Files/config to restore: src/plugins/bundled-web-search.ts (remove "exa" from array)
  • Known bad symptoms reviewers should watch for: Provider selection failing when EXA_API_KEY is set but Exa API is unreachable.

Risks and Mitigations

  • Risk: Exa API endpoint becomes unavailable or changes response format.
    • Mitigation: Provider is last in auto-detect order (65); users with other keys configured are unaffected. Response parsing handles missing fields with safe defaults.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 19, 2026

Greptile Summary

This PR adds Exa as a new bundled web search provider, following the exact same patterns established by Brave, Firecrawl, and other existing bundled providers — additive changes only, no modifications to core types or schemas.

Changes:

  • New extensions/exa/ plugin (4 files): provider implementation, plugin entry point, manifest, and package.json.
  • "exa" registered in BUNDLED_WEB_SEARCH_PLUGIN_IDS (alphabetical order) and in the contract registry with a test credential.
  • autoDetectOrder: 65 places Exa last in auto-detect priority — users with any other provider key configured are unaffected.
  • Test expectations updated across 3 test files to reflect the new provider.

Implementation quality: The provider correctly uses withTrustedWebSearchEndpoint, readConfiguredSecretString/readProviderEnvValue for secret resolution, the standard cache key/payload pattern, and the same createTool/pluginConfig merge logic as Brave. The API error body is surfaced in the thrown error message, and missing-key errors return a structured object with a docs link rather than throwing.

One nit found: published: entry.publishedDate ?? undefined on line 90 is redundant — since publishedDate is already string | undefined, the ?? undefined fallback is a no-op and can be removed.

Confidence Score: 5/5

  • This PR is safe to merge — purely additive changes with no modifications to existing code paths.
  • All changes are additive: a new plugin directory, a one-line addition to the bundled ID list, a one-import + one-entry addition to the contract registry, and updated test expectations. The implementation faithfully follows existing provider patterns (withTrustedWebSearchEndpoint, secret resolution, caching, payload structure). The only finding is a trivial redundant expression (?? undefined) with no runtime impact. The live API has not been verified but that is disclosed in the PR and is outside the unit-test scope.
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/exa/src/exa-web-search-provider.ts
Line: 90

Comment:
**Redundant `?? undefined` fallback**

`entry.publishedDate` is already typed as `string | undefined`, so appending `?? undefined` is a no-op — if the value is already `undefined`, the nullish coalescing just returns `undefined` again. The field can simply be assigned directly, matching how other result fields like `siteName` handle the same pattern via `|| undefined` (which additionally coerces empty string to `undefined`).

```suggestion
          published: entry.publishedDate,
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "refactor: move exa t..."

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a3720f976

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82afdc5bcf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

signupUrl: "https://exa.ai/",
docsUrl: "https://docs.exa.ai/",
autoDetectOrder: 65,
credentialPath: "plugins.entries.exa.config.webSearch.apiKey",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Register Exa's credential path with secret tooling

This provider advertises plugins.entries.exa.config.webSearch.apiKey, but the static secret registry was not updated for that path (src/secrets/target-registry-data.ts still only lists the existing Brave/Google/xAI/Moonshot/Perplexity/Firecrawl web-search entries). Because discoverConfigSecretTargets() drives both openclaw secrets configure (src/secrets/configure-plan.ts:88) and openclaw secrets audit (src/secrets/audit.ts:215), an Exa key stored at the new plugin path is invisible to those workflows: operators cannot manage it through the configure flow, manual plans using that target type fail validation, and audits miss plaintext Exa keys entirely.

Useful? React with 👍 / 👎.

@V-Gutierrez
Copy link
Copy Markdown

Hey @louiswalsh 👋 — I implemented the same Exa integration as a plugin extension in #49319 (following the firecrawl/moonshot pattern). Happy to help review, test, or merge efforts if it makes sense to consolidate. Let me know!

@vincentkoc
Copy link
Copy Markdown
Member

Thanks for pushing this.

I'm closing this as a duplicate of #52617. This was targeting the same bundled Exa plugin outcome, and the merged PR now covers that path on top of current main.

If you think there is still a gap in the landed version, point me to it and I can reopen review right away.

@vincentkoc vincentkoc closed this Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add Exa as a native web_search provider

3 participants