What happened? / 问题描述
网络代理选择「系统」时,PI-Desktop 只有内置浏览器走 Windows 系统代理,插件市场 / 插件下载(host-core → curl)和 AI 服务请求(Node sidecar)全部直连。在必须走代理才能出网的环境里,这两条链直接失败。
| 链路 |
实现 |
「系统」模式下的实际行为 |
| 插件市场、插件包下载 |
host-core → curl |
完全直连(无代理参数,也无代理环境变量) |
| AI 服务请求 |
agent sidecar → Node fetch |
直连 |
| 内置浏览器 / 插件面板 |
Chromium session |
走系统代理 ✅ |
与本仓库 #1393 的 CERT_HAS_EXPIRED 不是同一问题:那边是用户本机链路上的中间设备给出了过期证书,与代理设置无关;这里的问题是代理设置本身在「系统」模式下不生效。
这条限制在 ADR 0177 里是写明的("System mode does not magically make Node follow the macOS/Windows system proxy; users who need model calls through Clash still choose Custom"),但设置界面只呈现「系统 / 直连 / 自定义」三个词,没有任何说明,而「系统」又是默认值,因此按字面理解它的用户会直接踩到。
Steps to reproduce / 复现步骤
- 打开 PI-Desktop 0.16.1(Windows)。
- 设置 → 常规 → 网络 → 代理,保持默认的「系统」。此时 Windows 的「Internet 选项」已配置系统代理(如
127.0.0.1:7897),浏览器可正常访问需要代理的站点。
- 打开插件市场,刷新目录或安装任一插件。
- 下载失败,日志出现
PLUGIN_NETWORK: curl failed ... curl: (35) Recv failure: Connection was reset。
- 换成 AI 对话(任一需要代理才能访问的服务商),请求同样失败。
- 设置 → 网络 → 代理改为「自定义」,URL 填与系统代理相同的地址(
http://127.0.0.1:7897),不重启应用,重试第 3 步 → 立即成功。
Expected behavior / 预期行为
选择「系统」时,应用自身所有出网流量(插件市场 / 下载、AI 请求)应与内置浏览器一致地走系统代理;或者,界面明确说明「系统」只作用于内置浏览器,并提示需要代理时请选择「自定义」。
Actual behavior / 实际行为
「系统」模式下只有内置浏览器走代理,其余出网全部直连。可核对的行为证据:
- Windows 注册表
HKCU\...\Internet Settings:ProxyEnable=0x1、ProxyServer=127.0.0.1:7897,即系统代理确实已开启。
- 同一台机器、同一时刻、同一 URL:
curl <url>(无代理参数,等效于 host-core 的行为)→ curl: (35) Recv failure: Connection was reset
curl --proxy http://127.0.0.1:7897 <url> → HTTP 200
- 代码位置(0.16.1):
crates/host-core/src/network_proxy.rs 的 curl_proxy_args():ProxyMode::System 返回空数组,即不给 curl 传任何代理参数。
packages/host-runtime/src/host-process.ts:启动 host-core 子进程时用 stripProxyEnv(process.env) 无条件清空代理环境变量,连 shell 里已有的 HTTPS_PROXY 也传不进去。
- curl 在 Windows 上不读注册表里的系统代理(只认环境变量),两条路都没有 → 直连。
packages/agent-runtime/src/node-proxy.ts 的 applyNodeNetworkProxy():mode !== "custom" 时清空代理环境变量并使用默认 dispatcher,即直连。
App version / 应用版本
0.16.1
Operating system / 操作系统
Windows
Extra environment / 其他环境信息
win32 x64 · protocol 11 · host 0.16.1 · Windows 11 (10.0.26200)
Logs / 日志
# 代理模式 = 系统;Windows 系统代理已开启;插件市场走 host-core curl
PLUGIN_NETWORK: curl failed for https://raw.githubusercontent.com/<owner>/<repo>/main/packages/<name>.piplug: curl: (35) Recv failure: Connection was reset
与 ADR 0177 的冲突与期望修复
ADR 0177 把 System 定义为「Chromium session.setProxy({ mode: "system" }),Node sidecar 保持直连」,即「系统」只覆盖 Chromium。冲突在于:
- 设置界面里「系统」是一个与「直连 / 自定义」并列的全局网络选项,用户会理解为「整个应用走系统代理」。
- 它是默认值,大量用户(尤其国内)实际处于该模式,随后遇到插件市场和 AI 请求的静默失败。
- 失败时的报错(
curl: (35)、ERR_PROXY_CONNECTION_FAILED 之类)不会提示「当前为系统模式,本次请求未走代理」,用户无法定位。
建议二选一,或两者都做:
- 让「系统」真正走系统代理:在 System 模式下解析 OS 代理(Windows 读
Internet Settings 的 ProxyEnable / ProxyServer / AutoConfigURL,macOS 用 scutil --proxy),拿到具体地址后按 Custom 的方式传给 host-core curl(--proxy)与 sidecar(dispatcher)。注意 AutoConfigURL(PAC)需要单独决策是否支持。
- 或至少改文案并加提示:把「系统」标注为「仅作用于内置浏览器」,并在系统模式下 host-core / sidecar 发生网络失败时,于错误信息中提示「当前代理模式为系统,本次请求未走代理,请在 设置 → 网络 中选择自定义」。
What happened? / 问题描述
网络代理选择「系统」时,PI-Desktop 只有内置浏览器走 Windows 系统代理,插件市场 / 插件下载(host-core →
curl)和 AI 服务请求(Node sidecar)全部直连。在必须走代理才能出网的环境里,这两条链直接失败。curlfetch与本仓库 #1393 的
CERT_HAS_EXPIRED不是同一问题:那边是用户本机链路上的中间设备给出了过期证书,与代理设置无关;这里的问题是代理设置本身在「系统」模式下不生效。这条限制在 ADR 0177 里是写明的("System mode does not magically make Node follow the macOS/Windows system proxy; users who need model calls through Clash still choose Custom"),但设置界面只呈现「系统 / 直连 / 自定义」三个词,没有任何说明,而「系统」又是默认值,因此按字面理解它的用户会直接踩到。
Steps to reproduce / 复现步骤
127.0.0.1:7897),浏览器可正常访问需要代理的站点。PLUGIN_NETWORK: curl failed ... curl: (35) Recv failure: Connection was reset。http://127.0.0.1:7897),不重启应用,重试第 3 步 → 立即成功。Expected behavior / 预期行为
选择「系统」时,应用自身所有出网流量(插件市场 / 下载、AI 请求)应与内置浏览器一致地走系统代理;或者,界面明确说明「系统」只作用于内置浏览器,并提示需要代理时请选择「自定义」。
Actual behavior / 实际行为
「系统」模式下只有内置浏览器走代理,其余出网全部直连。可核对的行为证据:
HKCU\...\Internet Settings:ProxyEnable=0x1、ProxyServer=127.0.0.1:7897,即系统代理确实已开启。curl <url>(无代理参数,等效于 host-core 的行为)→curl: (35) Recv failure: Connection was resetcurl --proxy http://127.0.0.1:7897 <url>→ HTTP 200crates/host-core/src/network_proxy.rs的curl_proxy_args():ProxyMode::System返回空数组,即不给 curl 传任何代理参数。packages/host-runtime/src/host-process.ts:启动 host-core 子进程时用stripProxyEnv(process.env)无条件清空代理环境变量,连 shell 里已有的HTTPS_PROXY也传不进去。packages/agent-runtime/src/node-proxy.ts的applyNodeNetworkProxy():mode !== "custom"时清空代理环境变量并使用默认 dispatcher,即直连。App version / 应用版本
0.16.1
Operating system / 操作系统
Windows
Extra environment / 其他环境信息
win32 x64 · protocol 11 · host 0.16.1 · Windows 11 (10.0.26200)
Logs / 日志
与 ADR 0177 的冲突与期望修复
ADR 0177 把 System 定义为「Chromium
session.setProxy({ mode: "system" }),Node sidecar 保持直连」,即「系统」只覆盖 Chromium。冲突在于:curl: (35)、ERR_PROXY_CONNECTION_FAILED之类)不会提示「当前为系统模式,本次请求未走代理」,用户无法定位。建议二选一,或两者都做:
Internet Settings的ProxyEnable/ProxyServer/AutoConfigURL,macOS 用scutil --proxy),拿到具体地址后按 Custom 的方式传给 host-core curl(--proxy)与 sidecar(dispatcher)。注意AutoConfigURL(PAC)需要单独决策是否支持。