Skip to content

fix(tools): route web_search requests through HTTP proxy env vars#16897

Open
battman21 wants to merge 3 commits intoopenclaw:mainfrom
battman21:fix/8534-web-search-proxy
Open

fix(tools): route web_search requests through HTTP proxy env vars#16897
battman21 wants to merge 3 commits intoopenclaw:mainfrom
battman21:fix/8534-web-search-proxy

Conversation

@battman21
Copy link
Contributor

@battman21 battman21 commented Feb 15, 2026

Summary

Fixes #8534
Related: #15869

The web_search tool uses bare fetch() which doesn't respect HTTP proxy environment variables (HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy). This causes "fetch failed" errors in environments behind a proxy (WSL2, corporate networks, China).

Node.js 22's built-in fetch() doesn't automatically pick up proxy env vars — it needs an explicit dispatcher from undici's ProxyAgent.

Fix: When proxy env vars are set, create an undici ProxyAgent and pass it as the dispatcher to all fetch() calls (Brave Search, Perplexity, and Grok/xAI).

Test plan

  • pnpm lint passes
  • pnpm build succeeds (type-check + bundle)
  • All 3 fetch call sites updated: Brave, Perplexity, Grok
  • When no proxy env vars set, behavior unchanged (dispatcher is undefined, not passed)
  • Follows same pattern as proxy support in other tools (SSRF guard, Discord provider)

🤖 Generated with Claude Code

Greptile Summary

Adds HTTP proxy support to the web_search tool by reading HTTPS_PROXY/HTTP_PROXY environment variables and passing an undici ProxyAgent as dispatcher to all three fetch call sites (Brave Search, Perplexity, Grok/xAI). Includes a lazy-cached singleton pattern so the ProxyAgent is reused across requests.

  • All three fetch call sites (runPerplexitySearch, runGrokSearch, runWebSearch) are updated consistently with the same dispatcher pattern
  • The ProxyAgent is cached at module level and only recreated if the proxy URL changes, avoiding per-request connection pool allocation
  • When no proxy env vars are set, the behavior is unchanged (dispatcher is undefined and not spread into the options)
  • Follows the same proxy patterns used elsewhere in the codebase (src/telegram/proxy.ts, extensions/zalo/src/proxy.ts)

Confidence Score: 4/5

  • This PR is safe to merge — it adds proxy support with minimal risk and no behavioral change when proxy env vars are absent.
  • The change is narrowly scoped to a single file, follows established patterns from other proxy implementations in the codebase (Telegram, Zalo), correctly caches the ProxyAgent, and has no effect when proxy env vars are unset. The as RequestInit cast is the standard approach for passing dispatcher to Node 22's fetch. No logic or security issues found.
  • No files require special attention.

Last reviewed commit: 49b915d

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +46 to +52
function resolveSearchDispatcher(): ProxyAgent | undefined {
const proxyUrl = resolveSearchProxyUrl();
if (!proxyUrl) {
return undefined;
}
return new ProxyAgent(proxyUrl);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

New ProxyAgent allocated on every search request

resolveSearchDispatcher() is called at each of the three fetch sites, and each call creates a new ProxyAgent(proxyUrl) — meaning every search request spins up a fresh connection pool. The Zalo proxy (extensions/zalo/src/proxy.ts) avoids this by caching the agent per URL. Consider caching the agent at module level (lazy singleton) so the same connection pool is reused across requests:

Suggested change
function resolveSearchDispatcher(): ProxyAgent | undefined {
const proxyUrl = resolveSearchProxyUrl();
if (!proxyUrl) {
return undefined;
}
return new ProxyAgent(proxyUrl);
}
let _cachedDispatcher: ProxyAgent | undefined;
let _cachedProxyUrl: string | undefined;
function resolveSearchDispatcher(): ProxyAgent | undefined {
const proxyUrl = resolveSearchProxyUrl();
if (!proxyUrl) {
return undefined;
}
if (_cachedDispatcher && _cachedProxyUrl === proxyUrl) {
return _cachedDispatcher;
}
_cachedDispatcher = new ProxyAgent(proxyUrl);
_cachedProxyUrl = proxyUrl;
return _cachedDispatcher;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/web-search.ts
Line: 46:52

Comment:
**New `ProxyAgent` allocated on every search request**

`resolveSearchDispatcher()` is called at each of the three fetch sites, and each call creates a `new ProxyAgent(proxyUrl)` — meaning every search request spins up a fresh connection pool. The Zalo proxy (`extensions/zalo/src/proxy.ts`) avoids this by caching the agent per URL. Consider caching the agent at module level (lazy singleton) so the same connection pool is reused across requests:

```suggestion
let _cachedDispatcher: ProxyAgent | undefined;
let _cachedProxyUrl: string | undefined;

function resolveSearchDispatcher(): ProxyAgent | undefined {
  const proxyUrl = resolveSearchProxyUrl();
  if (!proxyUrl) {
    return undefined;
  }
  if (_cachedDispatcher && _cachedProxyUrl === proxyUrl) {
    return _cachedDispatcher;
  }
  _cachedDispatcher = new ProxyAgent(proxyUrl);
  _cachedProxyUrl = proxyUrl;
  return _cachedDispatcher;
}
```

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

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: XS labels Feb 15, 2026
@battman21 battman21 force-pushed the fix/8534-web-search-proxy branch 2 times, most recently from 8ddf591 to 49b915d Compare February 15, 2026 07:36
@steipete steipete closed this Feb 16, 2026
@steipete steipete reopened this Feb 17, 2026
@battman21 battman21 force-pushed the fix/8534-web-search-proxy branch 2 times, most recently from 49e7721 to 45d1c65 Compare February 17, 2026 03:04
@battman21 battman21 force-pushed the fix/8534-web-search-proxy branch from 45d1c65 to e7c86db Compare February 17, 2026 07:51
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: S and removed size: XS labels Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

web_search ignores proxy env vars, fails with fetch failed behind proxy

2 participants