feat(parallel): add Parallel as a bundled web_search provider#85158
Conversation
Dependency Changes DetectedThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
|
Codex review: needs real behavior proof before merge. Reviewed June 3, 2026, 2:58 AM ET / 06:58 UTC. Summary PR surface: Source +626, Tests +674, Docs +141, Config +35, Other +6. Total +1482 across 27 files. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model gpt-5.5, reasoning high; reviewed against 2c9297339817. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +626, Tests +674, Docs +141, Config +35, Other +6. Total +1482 across 27 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
b89f346 to
628cf23
Compare
628cf23 to
aa5fded
Compare
|
ClawSweeper PR egg 🔥 Warming up: real-behavior proof passed; findings, security review, or rank-up moves are still in progress. Hatch commandComment Hatchability rules:
What is this egg doing here?
|
aa5fded to
1ef1300
Compare
1ef1300 to
085953c
Compare
Dependency GuardThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
Dependency graph changes are blockedOpenClaw does not accept dependency graph changes through PRs unless a repository admin or security explicitly authorizes the current head SHA. Dependency updates are generated internally by maintainers so external PRs cannot change the resolved graph. Detected dependency graph changes:
Auto-scrub was not attempted because this PR changes package manifest dependency graph fields:
Dependency graph changes must be reviewed by security or handled by maintainers internally. Please remove lockfile changes manually if they are not needed. To remove lockfile changes, restore them from the target branch: git fetch origin
git checkout 'origin/main' -- 'pnpm-lock.yaml'
git commit -m 'chore: remove dependency lockfile change'
git pushIf this PR intentionally needs a dependency graph change, ask a repository admin or member of The action will approve the current head SHA ( |
085953c to
225e302
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
225e302 to
db84391
Compare
- New extensions/parallel package modeled on extensions/exa
- Wires Parallel's POST /v1/search through the generic web_search contract,
exposing Parallel's recommended {objective, search_queries} shape (plus
optional count, session_id, client_model) so the model can supply both the
natural-language goal and 2-3 short keyword queries as Parallel docs advise
- client_model lets the model report its own slug so Parallel can tailor
optimizations for the consuming model's capabilities; partitions the cache
by client_model so different models do not silently share ranked excerpts
- Honors top-level tools.web.search.{maxResults,timeoutSeconds,cacheTtlMinutes}
via the shared SDK helpers (mergeScopedSearchConfig, withTrustedWebSearchEndpoint,
buildSearchCacheKey, read/writeCachedSearchPayload)
- Auto-detect order 75; auth via PARALLEL_API_KEY or
plugins.entries.parallel.config.webSearch.apiKey
- Optional baseUrl override for proxies (e.g. Cloudflare AI Gateway)
- Threads caller-supplied session_id through follow-up calls; strips
auto-generated session_id from the shared cache to avoid cross-task leaks
- Always sends advanced_settings.max_results so result volume matches the
OpenClaw web_search default (5) instead of Parallel's default (10)
- Identifies the plugin via User-Agent header built from package version
- Runtime accepts the generic `query` arg as a fallback so the operator
CLI (openclaw capability web.search) keeps working when Parallel is the
active provider: it is promoted into the lone `search_queries` entry.
`objective` stays optional and is never synthesized from a keyword
query (Parallel documents it as natural-language intent). Agent callers
using the native objective+search_queries shape take precedence; the
schema still advertises only the native keys
- Updates the agent tool-display extractor (src/agents/tool-display-common.ts)
to recognize Parallel's objective+search_queries shape so calls render with
query context in CLI progress and Codex activity metadata
- Adds /tools/parallel-search docs page, web.md provider listing, docs nav,
labeler entry, per-plugin registration contract test, and minimal core
touch-points (legacy migrate, registration cases, providers contract list,
runtime bundled list, vitest extension paths)
db84391 to
12a2b69
Compare
…aw#85158) - New extensions/parallel package modeled on extensions/exa - Wires Parallel's POST /v1/search through the generic web_search contract, exposing Parallel's recommended {objective, search_queries} shape (plus optional count, session_id, client_model) so the model can supply both the natural-language goal and 2-3 short keyword queries as Parallel docs advise - client_model lets the model report its own slug so Parallel can tailor optimizations for the consuming model's capabilities; partitions the cache by client_model so different models do not silently share ranked excerpts - Honors top-level tools.web.search.{maxResults,timeoutSeconds,cacheTtlMinutes} via the shared SDK helpers (mergeScopedSearchConfig, withTrustedWebSearchEndpoint, buildSearchCacheKey, read/writeCachedSearchPayload) - Auto-detect order 75; auth via PARALLEL_API_KEY or plugins.entries.parallel.config.webSearch.apiKey - Optional baseUrl override for proxies (e.g. Cloudflare AI Gateway) - Threads caller-supplied session_id through follow-up calls; strips auto-generated session_id from the shared cache to avoid cross-task leaks - Always sends advanced_settings.max_results so result volume matches the OpenClaw web_search default (5) instead of Parallel's default (10) - Identifies the plugin via User-Agent header built from package version - Runtime accepts the generic `query` arg as a fallback so the operator CLI (openclaw capability web.search) keeps working when Parallel is the active provider: it is promoted into the lone `search_queries` entry. `objective` stays optional and is never synthesized from a keyword query (Parallel documents it as natural-language intent). Agent callers using the native objective+search_queries shape take precedence; the schema still advertises only the native keys - Updates the agent tool-display extractor (src/agents/tool-display-common.ts) to recognize Parallel's objective+search_queries shape so calls render with query context in CLI progress and Codex activity metadata - Adds /tools/parallel-search docs page, web.md provider listing, docs nav, labeler entry, per-plugin registration contract test, and minimal core touch-points (legacy migrate, registration cases, providers contract list, runtime bundled list, vitest extension paths)
…aw#85158) - New extensions/parallel package modeled on extensions/exa - Wires Parallel's POST /v1/search through the generic web_search contract, exposing Parallel's recommended {objective, search_queries} shape (plus optional count, session_id, client_model) so the model can supply both the natural-language goal and 2-3 short keyword queries as Parallel docs advise - client_model lets the model report its own slug so Parallel can tailor optimizations for the consuming model's capabilities; partitions the cache by client_model so different models do not silently share ranked excerpts - Honors top-level tools.web.search.{maxResults,timeoutSeconds,cacheTtlMinutes} via the shared SDK helpers (mergeScopedSearchConfig, withTrustedWebSearchEndpoint, buildSearchCacheKey, read/writeCachedSearchPayload) - Auto-detect order 75; auth via PARALLEL_API_KEY or plugins.entries.parallel.config.webSearch.apiKey - Optional baseUrl override for proxies (e.g. Cloudflare AI Gateway) - Threads caller-supplied session_id through follow-up calls; strips auto-generated session_id from the shared cache to avoid cross-task leaks - Always sends advanced_settings.max_results so result volume matches the OpenClaw web_search default (5) instead of Parallel's default (10) - Identifies the plugin via User-Agent header built from package version - Runtime accepts the generic `query` arg as a fallback so the operator CLI (openclaw capability web.search) keeps working when Parallel is the active provider: it is promoted into the lone `search_queries` entry. `objective` stays optional and is never synthesized from a keyword query (Parallel documents it as natural-language intent). Agent callers using the native objective+search_queries shape take precedence; the schema still advertises only the native keys - Updates the agent tool-display extractor (src/agents/tool-display-common.ts) to recognize Parallel's objective+search_queries shape so calls render with query context in CLI progress and Codex activity metadata - Adds /tools/parallel-search docs page, web.md provider listing, docs nav, labeler entry, per-plugin registration contract test, and minimal core touch-points (legacy migrate, registration cases, providers contract list, runtime bundled list, vitest extension paths)
Summary
Note
AI-assisted PR. Prepared with the help of Claude (Opus 4.7). Implementation, audits, and iterative review were driven by Claude with
codex review --base origin/mainrun four times and two general-purpose subagents (repo-conventions audit + Parallel API best-practices audit against Parallel's docs, two rounds each). All findings addressed; final Codex pass returned "no actionable bugs found." The author personally reviewed every change, ran the live integration end-to-end (see Real behavior proof + Evidence), and understands the code being merged.extensions/parallel/as a new bundledweb_searchprovider modeled onextensions/exa/. Authenticates viaPARALLEL_API_KEY(orplugins.entries.parallel.config.webSearch.apiKey), hitsPOST https://api.parallel.ai/v1/search, and surfaces ranked excerpts through the genericweb_searchcontract.withTrustedWebSearchEndpoint,mergeScopedSearchConfig,buildSearchCacheKey,readCachedSearchPayload/writeCachedSearchPayload,wrapWebContent,resolveSearchTimeoutSeconds,resolveSearchCacheTtlMs,DEFAULT_SEARCH_COUNT); minimal core touch-points for legacy-config migrate, registration contract cases, runtime test allowlists, doctor migration, vitest paths, labeler, and docs nav.CHANGELOG.mdleft to maintainers perCONTRIBUTING.md. No standalone Parallel-only tool (kept scope to the genericweb_searchprovider tool to stay aligned with the Exa pattern and "keep it simple").Motivation
Parallel is purpose-built for agentic web search: it returns compressed, LLM-optimized excerpts ranked by reasoning utility, not human click-through. That fits OpenClaw's
web_searchcontract well and gives users a high-accuracy provider option alongside Brave/Exa/Firecrawl/Tavily/Perplexity. Parallel best practices (docs.parallel.ai/search/best-practices) were checked against the implementation; see Verification.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Real behavior proof (required for external PRs)
web_searchprovider in OpenClaw.pnpm openclaw onboard --flow quickstart --accept-risk --auth-choice skip --skip-channels --skip-skills --skip-daemon --skip-ui --skip-health, gateway viapnpm openclaw gateway run --port 18789 --bind loopback --force, TUI viapnpm openclaw tui, model via a real Anthropic key, search pinned toparallelviapnpm openclaw config set tools.web.search.provider parallel.From the repo root:
In another window:
OPENCLAW_LIVE_TEST=1 node scripts/run-vitest.mjs run extensions/parallel/parallel.live.test.tsapi.parallel.ai/v1/searchreturned real ranked results with asessionIdechoed back. TUI agent successfully usedweb_searchagainst Parallel and surfaced results to the model.searchId/sessionId. Confirmed identifyingUser-Agent: openclaw-parallel/<version> (<platform>)on outbound requests.baseUrloverride).cacheTtlMinutes-driven TTL expiry not exercised live (relies on the shared SDK helper).Root Cause (if applicable)
N/A.
Regression Test Plan (if applicable)
N/A — this is a feature, not a regression fix. Coverage added:
extensions/parallel/src/parallel-web-search-provider.test.ts(20 tests covering schema metadata, credential resolution, base URL normalization, count clamping, response normalization, session-id normalization, long-query → objective adaptation, cache-key partitioning by endpoint/count/session, missing-key payload, top-level web search settings honored end-to-end via mocked SDK fetch helper, session-id cache-leak protection).src/plugins/contracts/plugin-registration.parallel.contract.test.ts.src/plugins/web-search-providers.runtime.test.ts.src/plugins/contracts/providers.contract.test.ts.src/plugin-sdk/test-helpers/plugin-registration-contract-cases.ts.extensions/parallel/parallel.live.test.ts(gated onOPENCLAW_LIVE_TEST=1+PARALLEL_API_KEY).User-visible / Behavior Changes
web_searchprovider option:parallel. Configurable viaPARALLEL_API_KEYenv var orplugins.entries.parallel.config.webSearch.apiKeyconfig.plugins.entries.parallel.config.webSearch.baseUrloverrides the Parallel endpoint (e.g., for Cloudflare AI Gateway proxying). OpenClaw appends/v1/searchwhen the URL doesn't already end there.PARALLEL_API_KEYis the only configured key.https://docs.openclaw.ai/tools/parallel-search.pnpm openclaw onboardsearch-provider picker automatically (dynamic discovery; no static list to update).Diagram (if applicable)
Security Impact (required)
readConfiguredSecretString,readProviderEnvValue). API key flows through the standardwebSearch.apiKeyplugin config path (SecretRef-capable like all other web search providers).api.parallel.ai(or a user-configured base URL). All calls go through the SDK's guardedwithTrustedWebSearchEndpointhelper, which applies the existing OpenClaw network safety policy.withTrustedWebSearchEndpointguard; SSRF/loopback rules unchanged; response excerpts are wrapped viawrapWebContentso they're tagged untrusted before reaching the model.Repro + Verification
Environment
{ "tools": { "web": { "search": { "provider": "parallel", "enabled": true } } }, "plugins": { "entries": { "parallel": { "enabled": true } } } }Steps
pnpm buildexport PARALLEL_API_KEY=par-...pnpm openclaw onboard --flow quickstart --accept-risk --auth-choice skip --skip-channels --skip-skills --skip-daemon --skip-ui --skip-healthpnpm openclaw config set tools.web.search.provider parallel && pnpm openclaw config set plugins.entries.parallel.enabled truepnpm openclaw gateway run --port 18789 --bind loopback --force(window 1)pnpm openclaw tui(window 2), ask the agent to perform a web searchExpected
web_searchroutes to Parallel; response includesprovider: "parallel", ranked results with title/url/excerpts, and asessionId.Actual
Evidence
./scripts/clawlog.sh | grep parallelshows outboundapi.parallel.ai/v1/searchPOSTsHuman Verification (required)
web_searchcall via the TUI hits Parallel and surfaces real results to the model; live test (parallel.live.test.ts) hits the realapi.parallel.ai/v1/searchendpoint and asserts shape; onboard flow shows Parallel automatically in the search-provider picker; base URL override path validated via unit tests; missing-key path validated via unit tests; long-query →objectiveadaptation validated via unit tests; session-id cache-leak protection validated via unit tests.missing_parallel_api_keypayload); invalid base URL (invalid_base_urlpayload); query length > 200 chars (truncated to 200 insearch_queries[0], full text routed asobjective);countclamped to 1-40; caller-supplied vs auto-generatedsession_id(cache key partitioned; only caller-supplied id is preserved across cache hits).Review Conversations
Pre-PR review evidence (all green after iteration):
codex review --base origin/mainrun four times; final pass: "no actionable bugs found." All earlier P2/P3 findings addressed: top-level web-search settings now honored viamergeScopedSearchConfig; missing-key/invalid-base-url payloads point at the real config paths and the new docs page; defaultmax_resultsmatches OpenClaw'sDEFAULT_SEARCH_COUNT(5) instead of Parallel's default (10) so switching providers doesn't silently change result volume; long-query →objectiveadaptation handles Parallel's 200-charsearch_querieslimit; auto-generatedsessionIdstripped before caching to prevent cross-task contamination on cache hits.https://docs.parallel.ai/search/best-practicesandhttps://docs.parallel.ai/api-reference/search/search): two rounds, all PASS, no blocking findings.Compatibility / Migration
PARALLEL_API_KEYenv var orplugins.entries.parallel.config.webSearch.apiKeyconfig. Both auto-detected if present; ignored if absent.tools.web.search.parallel.*path, so it's listed inNON_MIGRATED_LEGACY_WEB_SEARCH_PROVIDER_IDSalongside Tavily (no doctor rewrite rule needed).Risks and Mitigations
api.parallel.ai).withTrustedWebSearchEndpointSDK guard. Same network policy as Exa/Brave/Firecrawl/Tavily. No new SSRF surface.advanced_settings.max_results = DEFAULT_SEARCH_COUNT(5) so result volume is consistent across providers. Locked by a unit test.session_idgetting cached and leaking across unrelated tasks.