Skip to content

Honor proxy env for runtime undici dispatcher#42320

Closed
wuxudongxd wants to merge 5 commits intoopenclaw:mainfrom
wuxudongxd:codex/runtime-proxy-env
Closed

Honor proxy env for runtime undici dispatcher#42320
wuxudongxd wants to merge 5 commits intoopenclaw:mainfrom
wuxudongxd:codex/runtime-proxy-env

Conversation

@wuxudongxd
Copy link
Copy Markdown

Summary

This PR makes the runtime undici dispatcher honor proxy env in the common Agent case.

In proxy-only environments, openai-codex runtime requests could fail even after OAuth succeeded, because the runtime dispatcher path stayed on a plain Agent instead of switching to env-proxy mode.

With this change, when proxy env vars are present and the current global dispatcher is the default Agent, OpenClaw upgrades it to EnvHttpProxyAgent before applying stream timeout tuning.

This keeps the existing behavior for:

  • already-proxied EnvHttpProxyAgent dispatchers
  • unsupported custom dispatcher types such as explicit ProxyAgent

Related:

What changed

  • import hasProxyEnvConfigured() into src/infra/net/undici-global-dispatcher.ts
  • when the current dispatcher is Agent and proxy env is configured, treat the effective mode as env-proxy
  • add a unit test covering Agent -> EnvHttpProxyAgent upgrade

Why this is minimal

This PR intentionally does not:

  • set NODE_USE_ENV_PROXY=1 globally
  • modify OpenAI Codex request headers
  • change behavior for custom proxy dispatchers

It only makes the runtime dispatcher reuse OpenClaw's existing env-proxy capability when proxy env vars are already configured.

Validation

Ran:

corepack pnpm -C /home/dong/openclaw exec vitest run src/infra/net/undici-global-dispatcher.test.ts

Result:

  • 1 test file passed
  • 6 tests passed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 10, 2026

Greptile Summary

This PR makes the undici global dispatcher honor proxy environment variables when the current dispatcher is a plain Agent. When hasProxyEnvConfigured() returns true, the function now treats the effective dispatcher kind as "env-proxy" and replaces the Agent with an EnvHttpProxyAgent (including stream-timeout and autoSelectFamily options), fixing runtime request failures in proxy-only environments. Existing EnvHttpProxyAgent and unsupported ProxyAgent dispatchers are unaffected.

Key changes:

  • undici-global-dispatcher.ts: adds a one-line promotion — currentKind === "agent" && hasProxyEnvConfigured() → "env-proxy" — before the dispatcher is rebuilt, routing through the existing EnvHttpProxyAgent construction path.
  • undici-global-dispatcher.test.ts: mocks ./proxy-env.js, resets the mock to false in beforeEach, and adds a test that validates the Agent → EnvHttpProxyAgent upgrade including timeout and connect options.

Minor behavioural note: once the dispatcher has been upgraded to EnvHttpProxyAgent, removing proxy env vars at runtime will not trigger a downgrade because resolveDispatcherKind returns "env-proxy" for the live instance and the upgrade condition only fires for "agent". This is acceptable given that proxy env vars are expected to be static, but it is worth keeping in mind if the application ever needs to support dynamic proxy reconfiguration.

Confidence Score: 4/5

  • This PR is safe to merge. The change is minimal, well-tested, and intentionally scoped to the Agent→EnvHttpProxyAgent upgrade path.
  • The logic is correct and idempotent: after the first upgrade the live dispatcher is EnvHttpProxyAgent, so resolveDispatcherKind returns "env-proxy" on subsequent calls and the caching key matches — no repeated re-creation. The new test covers the happy path thoroughly (type check, timeout options, connect options). The only deduction is for the runtime proxy-removal edge case: once upgraded, the dispatcher won't downgrade if proxy env vars are later unset, because the promotion condition only fires for "agent" instances. This is an acceptable limitation given static proxy env conventions, but it leaves a small gap in reversibility.
  • No files require special attention.

Last reviewed commit: 71bdebe

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: 71bdebe58d

ℹ️ 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".

Comment on lines +78 to +79
const kind =
currentKind === "agent" && hasProxyEnvConfigured() ? ("env-proxy" as const) : currentKind;
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 Fall back to Agent when env proxy upgrade fails

When hasProxyEnvConfigured() is true, this forces the dispatcher mode to env-proxy even if the proxy env value is malformed or unsupported; in that case new EnvHttpProxyAgent(...) can throw, the catch block swallows it, and no tuned Agent is applied. This is a regression from the previous behavior, where the default Agent path still set stream timeouts, so users with bad proxy env values can silently lose the timeout hardening and hit premature request timeouts.

Useful? React with 👍 / 👎.

@wuxudongxd
Copy link
Copy Markdown
Author

Addressed the fallback issue in e45225c.\n\nIf env-proxy upgrade throws (for example due to malformed/unsupported proxy env values), we now fall back to a hardened Agent so body/header timeouts are still preserved. Also added a regression test covering that fallback path.

@RickyTong1 RickyTong1 mentioned this pull request Mar 12, 2026
20 tasks
@rushwing
Copy link
Copy Markdown

We need this for auto proxy, please help to resolve the conflicts and merge this PR.

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: b821aee74c

ℹ️ 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".

@@ -1,11 +1,13 @@
import * as net from "node:net";
import { Agent, EnvHttpProxyAgent, getGlobalDispatcher, setGlobalDispatcher } from "undici";
import { hasProxyEnvConfigured, hasEnvHttpProxyConfigured } from "./proxy-env.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove unresolved hasEnvHttpProxyConfigured import

src/infra/net/undici-global-dispatcher.ts now imports hasEnvHttpProxyConfigured from src/infra/net/proxy-env.ts, but proxy-env.ts only exports hasProxyEnvConfigured. In ESM this is a load-time failure (Export named ... not found), so any path that imports the dispatcher module (including the embedded runner before requests are sent) will crash before timeout/proxy hardening executes.

Useful? React with 👍 / 👎.

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: c69480f250

ℹ️ 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".

Comment on lines +119 to +123
const envProxyKey = envProxyRequested
? resolveDispatcherKey({ kind: "env-proxy", timeoutMs, autoSelectFamily })
: null;
const appliedKey = envProxyKey ?? agentKey;
if (lastAppliedTimeoutKey === appliedKey) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reapply env-proxy when dispatcher reverts to Agent

When hasEnvHttpProxyConfigured("https") is true, appliedKey is forced to the env-proxy key even if the current dispatcher is now a plain Agent, so a later call can hit the lastAppliedTimeoutKey === appliedKey fast path and return without reinstalling EnvHttpProxyAgent. This means if any code resets Undici's global dispatcher after an earlier successful hardening pass, subsequent runtime attempts can silently stay on an unproxied Agent in proxy-only environments and fail outbound requests.

Useful? React with 👍 / 👎.

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: a585ce16b3

ℹ️ 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".

@@ -1,11 +1,13 @@
import * as net from "node:net";
import { Agent, EnvHttpProxyAgent, getGlobalDispatcher, setGlobalDispatcher } from "undici";
import { hasEnvHttpProxyConfigured } from "./proxy-env.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Import the exported proxy-env helper

undici-global-dispatcher.ts now imports hasEnvHttpProxyConfigured, but src/infra/net/proxy-env.ts only exports hasProxyEnvConfigured. In ESM this throws at module load (does not provide an export named ...), so any runtime path that imports this dispatcher (including embedded attempt startup) can fail before request timeout/proxy hardening is applied.

Useful? React with 👍 / 👎.

@steipete
Copy link
Copy Markdown
Contributor

Closing this as implemented after Codex review.

Current main already implements this proxy-env runtime dispatcher behavior, and the shipped v2026.4.22 release tag contains the same functionality, so the open PR is redundant.

What I checked:

So I’m closing this as already implemented rather than keeping a duplicate issue open.

Review notes: reviewed against 7d9172d5e093; fix evidence: release v2026.4.22, commit 00bd2cf7a376.

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.

openai-codex runtime requests can ignore proxy env unless NODE_USE_ENV_PROXY=1; backend-api requests also need browser-like headers in some proxy setups

3 participants