mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 14:00:35 +00:00
* fix(channels): keep Gateway calls off the environment proxy * fix(channels): keep the aio_sandbox policy import lazy Importing deerflow.community.aio_sandbox.backend at module scope executes the package __init__, which eagerly imports AioSandbox, AioSandboxProvider and both backends. That makes every ChannelManager import load the entire sandbox provider stack even when a different sandbox is configured. Mirror app/gateway/health.py::_make_provisioner_client: move the import into a small _make_gateway_client helper and route both Gateway call sites through it, so the URL policy stays lazy. * fix(channels): keep the run client off the environment proxy langgraph_sdk.get_client() builds httpx.AsyncHTTPTransport(retries=5) on an httpx.AsyncClient that leaves trust_env at its default True and exposes no transport/trust_env override, so ChannelManager._get_client() still sent runs.wait submissions to a loopback Gateway through HTTP_PROXY. That is the hop #7876 reports: the control-plane calls are fixed, the run submission is not. Route the SDK client through _make_langgraph_client: loopback and private Gateways get an explicit trust_env=False httpx.AsyncClient carrying the SDK's own retries, timeout and User-Agent and handed to LangGraphClient, while external Gateways keep the stock get_client() path. Also move the URL policy out of the aio_sandbox package into deerflow.utils.http_policy (control_plane_trust_env). Keeping the import lazy did not help on its own: aio_sandbox/__init__ eagerly imports the provider stack, so importing aio_sandbox.backend still loaded all of it. The neutral module has no httpx or sandbox dependency, so manager.py and gateway/health.py import it at module scope, and aio_sandbox.backend re-exports it as sandbox_http_trust_env for the existing sandbox call sites. * fix(channels): keep AGENTS.md under budget and align legacy CSRF test with new client * style(sandbox): remove unused urlparse import --------- Co-authored-by: jack12178 <jack12178@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
41 lines
1.5 KiB
Python
41 lines
1.5 KiB
Python
"""Proxy policy shared by every control-plane HTTP client.
|
|
|
|
DeerFlow reaches its own Gateway, provisioner and sandboxes over the deployment
|
|
network, not the public internet. When operators export ``HTTP_PROXY`` for
|
|
outbound model/tool traffic, those hops must not be sent through the proxy: the
|
|
proxy answers with its own 502/504 while the target is perfectly healthy
|
|
(#3441, #7876).
|
|
|
|
This module is deliberately dependency-free (no ``httpx``, no sandbox imports)
|
|
so that ``app.channels.manager``, ``app.gateway.health`` and the sandbox
|
|
backends can all import the policy without dragging in the sandbox provider
|
|
stack.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ipaddress
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
def control_plane_trust_env(url: str) -> bool:
|
|
"""Whether HTTP clients for *url* should inherit environment proxy settings.
|
|
|
|
Local Docker, DooD, Kubernetes and co-located Gateway endpoints are
|
|
control-plane connections, not internet traffic. External fully-qualified
|
|
hosts retain normal environment proxy behavior.
|
|
"""
|
|
try:
|
|
hostname = (urlparse(url).hostname or "").rstrip(".").lower()
|
|
except ValueError:
|
|
return True
|
|
if not hostname:
|
|
return True
|
|
if hostname == "localhost" or hostname.endswith(".localhost") or hostname.endswith(".docker.internal") or hostname.endswith(".containers.internal"):
|
|
return False
|
|
try:
|
|
address = ipaddress.ip_address(hostname)
|
|
except ValueError:
|
|
return "." in hostname
|
|
return not (address.is_loopback or address.is_private or address.is_link_local)
|