fix(auto-setup): v3.0.4 Key 验证 + 默认模型 + 指纹 Win11 兼容
茶师兄 Win11 机器真实报障驱动 4 Bug 闭环:
B1: 移除 change-key.js 优先验证分支 (硬编码 haiku → sonnet-only 套餐必 403)
统一走 Test-ApiKey (多模型 fallback + 三值错误分类).
B2: 默认 ANTHROPIC_MODEL 兜底 opus-4-7 → sonnet-4-6 (基础套餐覆盖面最广).
Test-ApiKey 成功时记录 $script:LastValidatedModel → Phase 4 末尾覆盖为真·可用模型.
B4: stderr 不再 2>&1 | Out-Null. PASS/AUTH_FAIL/NETWORK_ACCEPT 三态记录到
$env:TEMP\bw-phase4-validate.log 并附失败模型列表便于报障.
B3 在 bookworm-portable-config.git c46f0b6 解决 (fingerprint.js wmic→CIM).
Test-ApiKey 候选顺序: sonnet-4-6 > opus-4-7 > opus-4-6 > thinking 变体.
401/403 不再立即 return false, 改累积到 $authFailModels, 全候选失败才判 false.
This commit is contained in:
parent
235839a880
commit
85f2bcd52f
@ -20,7 +20,7 @@ param(
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
||||
$BWVersion = "3.0.3" # +PS7 MSI 直链兜底 (Win10 无 winget 仍能装 pwsh, 避免跌落到 PS 5.1)
|
||||
$BWVersion = "3.0.4" # fix: Key 验证模型兜底 + 默认模型反推 + Win11 指纹 wmic→CIM 三级 fallback
|
||||
|
||||
# DryRun 模式日志标记
|
||||
if ($DryRun) { $global:BWDryRun = $DryRun } else { $global:BWDryRun = $null }
|
||||
@ -488,23 +488,24 @@ function Show-LicenseKeyDialog($attempt = 1, $maxAttempts = 3) {
|
||||
|
||||
# 向中转站发一个最小请求验证 key 是否可用
|
||||
function Test-ApiKey([string]$apiKey, [string]$baseUrl = "https://bww.letcareme.com") {
|
||||
$script:LastValidatedModel = $null
|
||||
$script:LastAuthFailCodes = @()
|
||||
if (-not $apiKey -or $apiKey.Length -lt 10) { return $false }
|
||||
# 中转站/官方的模型命名差异大, 依次试候选列表, 任一 2xx/4xx(非认证) 即认 Key 有效
|
||||
# 顺序: 当前主流 (4-6/4-7) → 老版兼容 (4-5/3-5)
|
||||
# 中转站 (bww.letcareme.com) 目前限定这 5 个模型, 严格匹配防 503 误判
|
||||
# 默认主模型: claude-opus-4-7
|
||||
# v3.0.4: 模型候选按中转站兼容性+套餐覆盖面排序
|
||||
# sonnet-4-6 放首位 - 中转站基础套餐都有, opus-4-7 可能被低档套餐 403
|
||||
# 去掉 haiku (多数中转站已移除), 新增 sonnet-4-5 兼容老套餐
|
||||
$modelCandidates = @(
|
||||
"claude-sonnet-4-6",
|
||||
"claude-opus-4-7",
|
||||
"claude-opus-4-6",
|
||||
"claude-opus-4-6-thinking",
|
||||
"claude-sonnet-4-6",
|
||||
"claude-sonnet-4-6-thinking"
|
||||
)
|
||||
# v3.0.1 错误分类 (red-team-logic P0):
|
||||
# $true = 认证通过 (200/400)
|
||||
# $false = 认证失败 (401/403) 明确 Key 无效
|
||||
# 错误分类:
|
||||
# $true = 认证通过 (200/400) — $script:LastValidatedModel 记录通过的 model
|
||||
# $false = 认证失败 (全部候选都返 401/403) 明确 Key 无效或权限不足
|
||||
# $null = 网络/中转站故障 (5xx/404/timeout), 非 Key 问题, 外层应放行
|
||||
$lastStatus = 0
|
||||
$authFailModels = @()
|
||||
$hadNetworkError = $false
|
||||
foreach ($model in $modelCandidates) {
|
||||
try {
|
||||
@ -521,21 +522,27 @@ function Test-ApiKey([string]$apiKey, [string]$baseUrl = "https://bww.letcareme.
|
||||
$req.ContentLength = $bytes.Length
|
||||
$stream = $req.GetRequestStream(); $stream.Write($bytes, 0, $bytes.Length); $stream.Close()
|
||||
$resp = $req.GetResponse(); $resp.Close()
|
||||
$script:LastValidatedModel = $model
|
||||
return $true # 200 = Key 有效
|
||||
} catch [System.Net.WebException] {
|
||||
$lastStatus = 0
|
||||
try { $lastStatus = [int]$_.Exception.Response.StatusCode } catch {}
|
||||
# 401/403 = 明确认证失败, 立即返回 false
|
||||
if ($lastStatus -eq 401 -or $lastStatus -eq 403) { return $false }
|
||||
# 401/403 = 这个 model 维度的认证/权限失败, 继续试其他 model (v3.0.4 核心改动)
|
||||
# 只有全部候选都 401/403 才认 Key 无效; 任一 200/400 就算 Key 有效
|
||||
if ($lastStatus -eq 401 -or $lastStatus -eq 403) {
|
||||
$authFailModels += "$model=$lastStatus"
|
||||
continue
|
||||
}
|
||||
# 400 = 请求体问题 (模型名等), Key 本身通过
|
||||
if ($lastStatus -eq 400) { return $true }
|
||||
if ($lastStatus -eq 400) { $script:LastValidatedModel = $model; return $true }
|
||||
# 5xx/404/0 = 网络或中转站故障, 不能归咎 Key
|
||||
$hadNetworkError = $true
|
||||
continue
|
||||
} catch { $hadNetworkError = $true; continue }
|
||||
}
|
||||
$script:LastAuthFailCodes = $authFailModels
|
||||
# 全部候选都遇网络故障 → 返回 $null (外层应: 接受 Key, 首次真实请求时再判)
|
||||
if ($hadNetworkError) { return $null }
|
||||
if ($hadNetworkError -and $authFailModels.Count -eq 0) { return $null }
|
||||
return $false
|
||||
}
|
||||
|
||||
@ -1299,17 +1306,18 @@ if (-not $secretsDecrypted -and (Get-CachedSecrets)) {
|
||||
$secretsDecrypted = $true
|
||||
}
|
||||
|
||||
# v3.0.1: 强制设默认模型 = claude-opus-4-7 (中转站支持, Claude Code 2.0.1 默认 4-5 会 503)
|
||||
# 顺序: 已显式设置 > Worker /config 拉取 > fallback 硬编码
|
||||
# v3.0.4: 默认模型优先级重排(修复: opus-4-7 硬编码导致 sonnet-only 套餐用户启动后全 403)
|
||||
# 顺序: 已显式设置 > Test-ApiKey 实际通过的 model (延后设) > Worker /config > 兜底 sonnet-4-6
|
||||
# 注: 实际验证通过后会在 Phase 4 末尾用 $script:LastValidatedModel 覆盖为"真·可用模型"
|
||||
if (-not $env:ANTHROPIC_MODEL) {
|
||||
$defaultModel = "claude-opus-4-7"
|
||||
$defaultModel = "claude-sonnet-4-6" # v3.0.4: 兜底改 sonnet-4-6 (基础套餐都有, opus 常被低档 403)
|
||||
try {
|
||||
$cfg = Invoke-RestMethod "https://bookworm-router.bookworm-api.workers.dev/config" -TimeoutSec 8 -ErrorAction Stop
|
||||
if ($cfg.default_model) { $defaultModel = $cfg.default_model }
|
||||
} catch {}
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_MODEL", $defaultModel, "User")
|
||||
$env:ANTHROPIC_MODEL = $defaultModel
|
||||
Log-OK "ANTHROPIC_MODEL=$defaultModel (中转站兼容)"
|
||||
Log-OK "ANTHROPIC_MODEL=$defaultModel (暂设, Phase 4 验证通过后会根据实际可用 model 覆盖)"
|
||||
}
|
||||
# 优先级 3: 直接输入中转站 API Key (v2.3 新增)
|
||||
if (-not $secretsDecrypted) {
|
||||
@ -1330,30 +1338,40 @@ if (-not $secretsDecrypted) {
|
||||
continue
|
||||
}
|
||||
Log-Info "正在验证..."
|
||||
# P1-2: 统一调用 change-key.js (stdin 管道, 无 argv 泄露)
|
||||
$injectJs = Join-Path $ClaudeDir "change-key.js"
|
||||
# v3.0.4: 统一走 Test-ApiKey (移除 change-key.js 优先分支)
|
||||
# 删除原因: change-key.js 硬编码 claude-3-haiku-20240307 做验证,
|
||||
# sonnet-only 套餐用户的 Key 在 haiku 必返 403 → 误判 Key 无效,
|
||||
# 而 Test-ApiKey 本来就支持多模型 fallback + 三值错误分类, 覆盖更广.
|
||||
# 同步修复: stderr 不再 2>&1 | Out-Null, 改为记录到 phase4-validate.log 便于用户报障
|
||||
# 残留清理: 如 .claude/change-key.js 存在, 保留但不再调用 (未来版本会彻底移除)
|
||||
$ckOk = $false
|
||||
if ((Test-Path $injectJs) -and (Test-Cmd "node")) {
|
||||
try {
|
||||
$apiKey | & node $injectJs 2>&1 | Out-Null
|
||||
$ckOk = ($LASTEXITCODE -eq 0)
|
||||
} catch { $ckOk = $false }
|
||||
$checkResult = Test-ApiKey $apiKey
|
||||
$phase4Log = Join-Path $env:TEMP "bw-phase4-validate.log"
|
||||
if ($checkResult -eq $true) {
|
||||
$ckOk = $true
|
||||
$validatedModel = if ($script:LastValidatedModel) { $script:LastValidatedModel } else { "(unknown)" }
|
||||
Log-OK "Key 在线验证通过 (model=$validatedModel)"
|
||||
try { "[$([DateTime]::Now.ToString('s'))] PASS model=$validatedModel" | Out-File -FilePath $phase4Log -Append -Encoding UTF8 } catch {}
|
||||
} elseif ($null -eq $checkResult) {
|
||||
# 全部候选网络故障, 不能归咎 Key, 先接受 (首次真实请求时再判)
|
||||
$ckOk = $true
|
||||
Log-Warn "中转站暂不可达, 暂接受此 Key (首次使用时若失败请重装换 Key)"
|
||||
try { "[$([DateTime]::Now.ToString('s'))] NETWORK_ACCEPT baseUrl=https://bww.letcareme.com" | Out-File -FilePath $phase4Log -Append -Encoding UTF8 } catch {}
|
||||
} else {
|
||||
# v3.0.1: Test-ApiKey 三值返回 (true=有效, false=认证失败, null=网络故障放行)
|
||||
$checkResult = Test-ApiKey $apiKey
|
||||
if ($checkResult -eq $true) {
|
||||
$ckOk = $true
|
||||
Log-OK "Key 在线验证通过"
|
||||
} elseif ($null -eq $checkResult) {
|
||||
# 网络故障, 不能归咎 Key, 先接受 (首次真实请求时再判)
|
||||
$ckOk = $true
|
||||
Log-Warn "中转站暂不可达, 暂接受此 Key (首次使用时若失败请重装换 Key)"
|
||||
} else {
|
||||
$ckOk = $false # 明确认证失败
|
||||
}
|
||||
if ($ckOk) {
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "User")
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://bww.letcareme.com", "User")
|
||||
# 全部候选都 401/403 = 明确认证失败
|
||||
$ckOk = $false
|
||||
$failDetail = if ($script:LastAuthFailCodes) { $script:LastAuthFailCodes -join ',' } else { 'all_models_auth_fail' }
|
||||
Log-Warn "Key 被拒绝 ($failDetail)"
|
||||
try { "[$([DateTime]::Now.ToString('s'))] AUTH_FAIL $failDetail" | Out-File -FilePath $phase4Log -Append -Encoding UTF8 } catch {}
|
||||
}
|
||||
if ($ckOk) {
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "User")
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://bww.letcareme.com", "User")
|
||||
# v3.0.4: 如果 Test-ApiKey 返回了真实通过的模型, 用它覆盖先前设的兜底默认
|
||||
if ($script:LastValidatedModel) {
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_MODEL", $script:LastValidatedModel, "User")
|
||||
$env:ANTHROPIC_MODEL = $script:LastValidatedModel
|
||||
Log-OK "ANTHROPIC_MODEL 锁定为实际可用: $($script:LastValidatedModel)"
|
||||
}
|
||||
}
|
||||
if ($ckOk) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user