-
Notifications
You must be signed in to change notification settings - Fork 695
fix(codex): harden Windows CLI and HF downloads #1097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
8475ecc
d0ecdb5
cff6dd9
796f487
af2989f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -155,17 +155,44 @@ function Test-SourceMode { | |
| # "corp-proxy reaches Tsinghua even though it can't reach pypi" case: | ||
| # Sync-SystemProxy no longer gates the candidate on a single pypi probe, | ||
| # so per-source decisions in Assert-Network always see the candidate. | ||
| param([string]$Url, [int]$TimeoutSec = 5, [string]$CandidateProxy = $null) | ||
| param( | ||
| [string]$Url, | ||
| [int]$TimeoutSec = 5, | ||
| [string]$CandidateProxy = $null, | ||
| [ValidateSet("HEAD", "GET")][string]$Method = "HEAD" | ||
| ) | ||
|
|
||
| $probe = { | ||
| param($Proxy) | ||
| $resp = $null | ||
| $stream = $null | ||
| try { | ||
| $req = [System.Net.HttpWebRequest]::Create($Url) | ||
| $req.Proxy = $Proxy | ||
| $req.Method = $Method | ||
| $req.Timeout = $TimeoutSec * 1000 | ||
| $req.ReadWriteTimeout = $TimeoutSec * 1000 | ||
| $req.AllowAutoRedirect = $true | ||
| $req.UserAgent = "cat-cafe-prereq-check" | ||
| $resp = $req.GetResponse() | ||
| if ($Method -eq "GET") { | ||
| $stream = $resp.GetResponseStream() | ||
| $buffer = New-Object byte[] 8192 | ||
| while ($stream -and $stream.Read($buffer, 0, $buffer.Length) -gt 0) {} | ||
| } | ||
| return $true | ||
| } catch { | ||
| return $false | ||
| } finally { | ||
| if ($stream) { $stream.Dispose() } | ||
| if ($resp) { $resp.Close() } | ||
| } | ||
| } | ||
|
|
||
| # 1. Try without any proxy at all. | ||
| try { | ||
| $req = [System.Net.HttpWebRequest]::Create($Url) | ||
| $req.Proxy = $null | ||
| $req.Method = 'HEAD' | ||
| $req.Timeout = $TimeoutSec * 1000 | ||
| $resp = $req.GetResponse() | ||
| $resp.Close() | ||
| if (& $probe $null) { | ||
| return 'direct' | ||
| } catch {} | ||
| } | ||
| # 2. Try via candidate proxy (anonymous -- DON'T let .NET auto-fill the | ||
| # SSPI token, that would mask auth-required corp proxies as reachable). | ||
| $proxyUrl = $CandidateProxy | ||
|
|
@@ -175,18 +202,12 @@ function Test-SourceMode { | |
| if (-not $proxyUrl) { $proxyUrl = $env:HTTP_PROXY } | ||
| } | ||
| if ($proxyUrl) { | ||
| try { | ||
| $webProxy = New-Object System.Net.WebProxy($proxyUrl) | ||
| $webProxy.UseDefaultCredentials = $false | ||
| $webProxy.Credentials = $null | ||
| $req = [System.Net.HttpWebRequest]::Create($Url) | ||
| $req.Proxy = $webProxy | ||
| $req.Method = 'HEAD' | ||
| $req.Timeout = $TimeoutSec * 1000 | ||
| $resp = $req.GetResponse() | ||
| $resp.Close() | ||
| $webProxy = New-Object System.Net.WebProxy($proxyUrl) | ||
| $webProxy.UseDefaultCredentials = $false | ||
| $webProxy.Credentials = $null | ||
| if (& $probe $webProxy) { | ||
| return 'proxy' | ||
| } catch {} | ||
| } | ||
| } | ||
| return 'unreachable' | ||
| } | ||
|
|
@@ -242,6 +263,11 @@ function Invoke-ModelDownloadWithRetry { | |
| [string]$Loader = "snapshot" | ||
| ) | ||
|
|
||
| if ($env:OS -eq "Windows_NT") { | ||
| $env:HF_HUB_DISABLE_SYMLINKS = if ($env:HF_HUB_DISABLE_SYMLINKS) { $env:HF_HUB_DISABLE_SYMLINKS } else { "1" } | ||
| $env:HF_HUB_DISABLE_SYMLINKS_WARNING = if ($env:HF_HUB_DISABLE_SYMLINKS_WARNING) { $env:HF_HUB_DISABLE_SYMLINKS_WARNING } else { "1" } | ||
| } | ||
|
|
||
| $script = switch ($Loader) { | ||
| "snapshot" { @" | ||
| import sys, time, os | ||
|
|
@@ -455,26 +481,31 @@ function Assert-Network { | |
| Write-Host " Auto-set PIP_INDEX_URL = Tsinghua mirror (primary)" | ||
| } | ||
|
|
||
| # Same two-mode probe for HuggingFace. | ||
| $hfMode = Test-SourceMode -Url "https://huggingface.co" -TimeoutSec 5 -CandidateProxy $candidate | ||
| # Same two-mode probe for HuggingFace. Probe a real model artifact rather | ||
| # than the homepage: some networks allow API/root requests but break TLS on | ||
| # /resolve artifact downloads, which is the path snapshot_download needs. | ||
| $hfProbeUrl = "https://huggingface.co/BAAI/bge-small-zh-v1.5/resolve/main/config.json" | ||
| $hfMode = Test-SourceMode -Url $hfProbeUrl -TimeoutSec 10 -CandidateProxy $candidate -Method "GET" | ||
| if ($hfMode -eq 'direct') { | ||
| Write-Host " HuggingFace connectivity [OK] (direct)" | ||
| Add-NoProxyHost "huggingface.co" | ||
| Write-Host " HuggingFace artifact download [OK] (direct)" | ||
| # Do not add huggingface.co to NO_PROXY. The actual download happens in | ||
| # Python/huggingface_hub, whose TLS/proxy behavior can differ from this | ||
| # .NET probe; preserving the user's proxy avoids false direct bypasses. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the HuggingFace artifact probe returns Useful? React with 👍 / 👎. |
||
| } elseif ($hfMode -eq 'proxy') { | ||
| Write-Host " HuggingFace connectivity [OK] (via proxy: $candidate)" | ||
| Write-Host " HuggingFace artifact download [OK] (via proxy: $candidate)" | ||
| $needProxyInjection = $true | ||
| } else { | ||
| $hfMirrorMode = Test-SourceMode -Url "https://hf-mirror.com" -TimeoutSec 5 -CandidateProxy $candidate | ||
| $hfMirrorProbeUrl = "https://hf-mirror.com/BAAI/bge-small-zh-v1.5/resolve/main/config.json" | ||
| $hfMirrorMode = Test-SourceMode -Url $hfMirrorProbeUrl -TimeoutSec 10 -CandidateProxy $candidate -Method "GET" | ||
| if ($hfMirrorMode -eq 'direct') { | ||
| Write-Host " HuggingFace unreachable, switching to hf-mirror.com (direct)" | ||
| Write-Host " HuggingFace artifact download unreachable, switching to hf-mirror.com (direct)" | ||
| $env:HF_ENDPOINT = "https://hf-mirror.com" | ||
| Add-NoProxyHost "hf-mirror.com" | ||
| } elseif ($hfMirrorMode -eq 'proxy') { | ||
| Write-Host " HuggingFace unreachable, switching to hf-mirror.com (via proxy: $candidate)" | ||
| Write-Host " HuggingFace artifact download unreachable, switching to hf-mirror.com (via proxy: $candidate)" | ||
| $env:HF_ENDPOINT = "https://hf-mirror.com" | ||
| $needProxyInjection = $true | ||
| } else { | ||
| Write-ProxyGuidance -Context "huggingface.co and hf-mirror.com are unreachable in both direct and via-proxy modes; model download will definitely fail." | ||
| Write-ProxyGuidance -Context "huggingface.co and hf-mirror.com artifact downloads are unreachable in both direct and via-proxy modes; model download will definitely fail." | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -152,7 +152,7 @@ _test_source_mode() { | |
| # in a way that matches pip's runtime path. | ||
| local url="$1" | ||
| local timeout="${2:-5}" | ||
| if curl -sf --max-time "$timeout" --noproxy '*' "$url" >/dev/null 2>&1; then | ||
| if curl -fsL --max-time "$timeout" --noproxy '*' "$url" >/dev/null 2>&1; then | ||
| echo "direct" | ||
| return | ||
| fi | ||
|
|
@@ -173,7 +173,7 @@ _test_source_mode() { | |
| candidate=$(_get_system_proxy_candidate 2>/dev/null || echo "") | ||
| fi | ||
| if [ -n "$candidate" ]; then | ||
| if curl -sf --max-time "$timeout" -x "$candidate" "$url" >/dev/null 2>&1; then | ||
| if curl -fsL --max-time "$timeout" -x "$candidate" "$url" >/dev/null 2>&1; then | ||
| echo "proxy" | ||
| return | ||
| fi | ||
|
|
@@ -320,36 +320,39 @@ check_network() { | |
| echo " Auto-enabled Tsinghua pip mirror as primary source: $PIP_INDEX_URL" | ||
| fi | ||
|
|
||
| local hf_probe_url="https://huggingface.co/BAAI/bge-small-zh-v1.5/resolve/main/config.json" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This gate now declares HuggingFace artifact downloads OK after fetching only Useful? React with 👍 / 👎. |
||
| local hf_mode | ||
| hf_mode=$(_test_source_mode "https://huggingface.co" "$timeout") | ||
| hf_mode=$(_test_source_mode "$hf_probe_url" "$timeout") | ||
| case "$hf_mode" in | ||
| direct) | ||
| echo " HuggingFace connectivity [OK] (direct)" | ||
| _add_no_proxy_host "huggingface.co" | ||
| echo " HuggingFace artifact download [OK] (direct)" | ||
| # Do not add huggingface.co to NO_PROXY. Python/huggingface_hub can | ||
| # behave differently from curl against model CDN/CAS artifact paths, so | ||
| # keep any user proxy available for the actual download. | ||
|
Comment on lines
327
to
+331
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| ;; | ||
| proxy) | ||
| echo " HuggingFace connectivity [OK] (via env proxy)" | ||
| echo " HuggingFace artifact download [OK] (via env proxy)" | ||
| ;; | ||
| unreachable) | ||
| echo "WARNING: HuggingFace unreachable (https://huggingface.co); model downloads may fail" | ||
| echo "WARNING: HuggingFace artifact download unreachable ($hf_probe_url); model downloads may fail" | ||
| local hf_mirror_probe_url="https://hf-mirror.com/BAAI/bge-small-zh-v1.5/resolve/main/config.json" | ||
| local hf_mirror_mode | ||
| hf_mirror_mode=$(_test_source_mode "https://hf-mirror.com" "$timeout") | ||
| hf_mirror_mode=$(_test_source_mode "$hf_mirror_probe_url" "$timeout") | ||
| case "$hf_mirror_mode" in | ||
| direct) | ||
| if [ -z "${HF_ENDPOINT:-}" ]; then | ||
| export HF_ENDPOINT="https://hf-mirror.com" | ||
| echo " Auto-enabled HF mirror (direct): $HF_ENDPOINT" | ||
| echo " Auto-enabled HF mirror for artifact downloads (direct): $HF_ENDPOINT" | ||
| fi | ||
| _add_no_proxy_host "hf-mirror.com" | ||
| ;; | ||
| proxy) | ||
| if [ -z "${HF_ENDPOINT:-}" ]; then | ||
| export HF_ENDPOINT="https://hf-mirror.com" | ||
| echo " Auto-enabled HF mirror (via env proxy): $HF_ENDPOINT" | ||
| echo " Auto-enabled HF mirror for artifact downloads (via env proxy): $HF_ENDPOINT" | ||
| fi | ||
| ;; | ||
| unreachable) | ||
| _print_proxy_guidance "huggingface.co and hf-mirror.com are unreachable in both direct and via-proxy modes." | ||
| _print_proxy_guidance "huggingface.co and hf-mirror.com artifact downloads are unreachable in both direct and via-proxy modes." | ||
| ;; | ||
| esac | ||
| ;; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
HTTPS_PROXY/HTTP_PROXYor the registry-derived candidate is malformed,New-Object System.Net.WebProxy($proxyUrl)can throw before the$probecatch block runs; Windows proxy settings commonly use per-scheme strings likehttp=host:port;https=host:port, whichGet-SystemProxyCandidatecurrently turns into a non-URI. Before this refactor the constructor was inside the try/catch and the source was classified as unreachable, but now one bad proxy value aborts the whole prerequisite check instead of falling back/giving guidance.Useful? React with 👍 / 👎.