mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
refactor(health-check): remove per-provider test config
This commit is contained in:
@@ -24,6 +24,7 @@ Development since v3.16.4 reworks the Codex native-Responses path — restoring
|
||||
|
||||
### Changed
|
||||
|
||||
- **Provider Connectivity Configuration Simplified**: Removed the obsolete per-provider `testConfig` override (timeout, retry count, and degraded-latency threshold) from provider forms, frontend/backend provider metadata, and reachability-check merging. The lightweight `base_url` probe now always uses the single global connectivity-check configuration, while automatic failover remains driven exclusively by its separate proxy timeout and circuit-breaker settings. Also renamed the remaining settings UI and API modules from model-test terminology to connectivity-check terminology, removed the retired first-use confirmation flag, and deleted stale model/prompt/error copy across all four locales.
|
||||
- **Decoupled Codex Model Mapping From the Local-Routing Toggle**: Aligns the Codex provider form with Claude Code — the model-mapping catalog is now independent of route takeover, since native Responses providers (MiMo, Doubao, MiniMax) need it for proxy-less direct connect while Chat providers use the proxy regardless of any per-provider flag. The "Needs Local Routing" toggle is removed: it had no backend field and only gated catalog/reasoning persistence, which is equivalent to whether the mapping is filled. Model mapping is now always shown for non-official providers and persisted whenever the list is non-empty (the backend already keys off `modelCatalog.models`), while reasoning visibility/persistence is gated on the Chat format instead of the toggle. The Chat upstream-format option is marked "routing required" with a refreshed advanced-section hint across all four locales (zh/en/ja/zh-TW), dead `localRouting*` keys are dropped, and the model-mapping block moves above the custom User-Agent block. Also fixes `useCodexConfigState` dropping `supportsParallelToolCalls`/`inputModalities`/`baseInstructions` when loading a saved provider — which silently lost parallel tools, image input, and the official base instructions on edit — by preserving them on load (camelCase and snake_case) and comparing them in the row sync.
|
||||
- **Auto-Sync Claude Common Config From Live settings.json on Switch**: When switching away from a Claude provider that has `common_config_enabled`, the service now re-extracts the shareable portion of its live `settings.json` and replaces the stored common-config snippet, instead of only writing the snippet one way. This captures config the user added directly in the running app (`enabledPlugins`, `hooks`, `env`, `theme`, shared prefs) so it isn't silently lost on the next switch, and it propagates deletions so a removed key isn't re-injected later. The sync in `services/provider/mod.rs` is scoped strictly to Claude providers with `common_config_enabled`, is skipped when the snippet was explicitly cleared, and all failures are non-fatal (warn-only) and never block the switch. Four integration tests cover capture / delete-sync / opt-out / cleared.
|
||||
- **Default Sonnet Tier Now Pins to Claude Sonnet 5**: Bumped every default Sonnet pin from `claude-sonnet-4-6`/`claude-sonnet-4.6` to `claude-sonnet-5` across all provider presets (`claudeProviderPresets`, `claudeDesktopProviderPresets`, `hermesProviderPresets`, `openclawProviderPresets`, `opencodeProviderPresets`, and universal `NEWAPI_DEFAULT_MODELS`), covering the `ANTHROPIC_MODEL` / `ANTHROPIC_DEFAULT_SONNET_MODEL` / `ANTHROPIC_DEFAULT_OPUS_MODEL` env keys and prefixed variants like `anthropic/claude-sonnet-5` and `global.anthropic.claude-sonnet-5`. The Claude Desktop `DEFAULT_PROXY_ROUTES` sonnet `route_id` in `claude_desktop_config.rs` also moves to `claude-sonnet-5` (`supports_1m` preserved), and the route-derivation test expectations were updated to match. Non-Anthropic pins (gpt/gemini/glm/sonnet-4-5) were left untouched.
|
||||
|
||||
@@ -303,26 +303,6 @@ pub struct UsageResult {
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
/// 供应商单独的连通检测配置
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ProviderTestConfig {
|
||||
/// 是否启用单独配置(false 时使用全局配置)
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
/// 超时时间(秒)
|
||||
#[serde(rename = "timeoutSecs", skip_serializing_if = "Option::is_none")]
|
||||
pub timeout_secs: Option<u64>,
|
||||
/// 降级阈值(毫秒)
|
||||
#[serde(
|
||||
rename = "degradedThresholdMs",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub degraded_threshold_ms: Option<u64>,
|
||||
/// 最大重试次数
|
||||
#[serde(rename = "maxRetries", skip_serializing_if = "Option::is_none")]
|
||||
pub max_retries: Option<u32>,
|
||||
}
|
||||
|
||||
/// 认证绑定来源
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@@ -454,9 +434,6 @@ pub struct ProviderMeta {
|
||||
/// 每月消费限额(USD)
|
||||
#[serde(rename = "limitMonthlyUsd", skip_serializing_if = "Option::is_none")]
|
||||
pub limit_monthly_usd: Option<String>,
|
||||
/// 供应商单独的模型测试配置
|
||||
#[serde(rename = "testConfig", skip_serializing_if = "Option::is_none")]
|
||||
pub test_config: Option<ProviderTestConfig>,
|
||||
/// Claude API 格式(仅 Claude 供应商使用)
|
||||
/// - "anthropic": 原生 Anthropic Messages API,直接透传
|
||||
/// - "openai_chat": OpenAI Chat Completions 格式,需要转换
|
||||
|
||||
@@ -92,19 +92,12 @@ impl StreamCheckService {
|
||||
config: &StreamCheckConfig,
|
||||
base_url_override: Option<String>,
|
||||
) -> Result<StreamCheckResult, AppError> {
|
||||
let effective = Self::merge_provider_config(provider, config);
|
||||
|
||||
let mut last_result: Option<StreamCheckResult> = None;
|
||||
for attempt in 0..=effective.max_retries {
|
||||
for attempt in 0..=config.max_retries {
|
||||
let start = Instant::now();
|
||||
let result = Self::check_once(
|
||||
app_type,
|
||||
provider,
|
||||
&effective,
|
||||
base_url_override.clone(),
|
||||
start,
|
||||
)
|
||||
.await?;
|
||||
let result =
|
||||
Self::check_once(app_type, provider, config, base_url_override.clone(), start)
|
||||
.await?;
|
||||
|
||||
if result.success {
|
||||
return Ok(StreamCheckResult {
|
||||
@@ -114,7 +107,7 @@ impl StreamCheckService {
|
||||
}
|
||||
|
||||
// 仅超时 / abort 类网络抖动值得重试;连接被拒、DNS 失败等立即返回。
|
||||
if Self::should_retry(&result.message) && attempt < effective.max_retries {
|
||||
if Self::should_retry(&result.message) && attempt < config.max_retries {
|
||||
last_result = Some(result);
|
||||
continue;
|
||||
}
|
||||
@@ -132,31 +125,11 @@ impl StreamCheckService {
|
||||
http_status: None,
|
||||
model_used: String::new(),
|
||||
tested_at: chrono::Utc::now().timestamp(),
|
||||
retry_count: effective.max_retries,
|
||||
retry_count: config.max_retries,
|
||||
error_category: None,
|
||||
}))
|
||||
}
|
||||
|
||||
/// 合并供应商单独配置(`meta.testConfig`,仅当 `enabled`)与全局配置。
|
||||
fn merge_provider_config(provider: &Provider, global: &StreamCheckConfig) -> StreamCheckConfig {
|
||||
let tc = provider
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|m| m.test_config.as_ref())
|
||||
.filter(|tc| tc.enabled);
|
||||
|
||||
match tc {
|
||||
Some(tc) => StreamCheckConfig {
|
||||
timeout_secs: tc.timeout_secs.unwrap_or(global.timeout_secs),
|
||||
max_retries: tc.max_retries.unwrap_or(global.max_retries),
|
||||
degraded_threshold_ms: tc
|
||||
.degraded_threshold_ms
|
||||
.unwrap_or(global.degraded_threshold_ms),
|
||||
},
|
||||
None => global.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 单次连通性探测。
|
||||
async fn check_once(
|
||||
app_type: &AppType,
|
||||
@@ -474,48 +447,6 @@ mod tests {
|
||||
assert_eq!(r.status, HealthStatus::Degraded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_provider_config_override_and_default() {
|
||||
use crate::provider::{ProviderMeta, ProviderTestConfig};
|
||||
|
||||
let global = StreamCheckConfig::default();
|
||||
|
||||
// 无 testConfig → 用全局
|
||||
let p = make_provider(serde_json::json!({}));
|
||||
let merged = StreamCheckService::merge_provider_config(&p, &global);
|
||||
assert_eq!(merged.timeout_secs, global.timeout_secs);
|
||||
|
||||
// testConfig 启用并覆盖部分字段
|
||||
let mut p2 = make_provider(serde_json::json!({}));
|
||||
p2.meta = Some(ProviderMeta {
|
||||
test_config: Some(ProviderTestConfig {
|
||||
enabled: true,
|
||||
timeout_secs: Some(20),
|
||||
degraded_threshold_ms: Some(3000),
|
||||
max_retries: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
let merged2 = StreamCheckService::merge_provider_config(&p2, &global);
|
||||
assert_eq!(merged2.timeout_secs, 20);
|
||||
assert_eq!(merged2.degraded_threshold_ms, 3000);
|
||||
assert_eq!(merged2.max_retries, global.max_retries); // 未覆盖 → 全局
|
||||
|
||||
// testConfig 存在但未启用 → 忽略,用全局
|
||||
let mut p3 = make_provider(serde_json::json!({}));
|
||||
p3.meta = Some(ProviderMeta {
|
||||
test_config: Some(ProviderTestConfig {
|
||||
enabled: false,
|
||||
timeout_secs: Some(99),
|
||||
degraded_threshold_ms: None,
|
||||
max_retries: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
let merged3 = StreamCheckService::merge_provider_config(&p3, &global);
|
||||
assert_eq!(merged3.timeout_secs, global.timeout_secs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_opencode_base_url_explicit_wins() {
|
||||
let p = make_provider(serde_json::json!({
|
||||
|
||||
@@ -368,9 +368,6 @@ pub struct AppSettings {
|
||||
pub usage_confirmed: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub usage_dashboard_refresh_interval_ms: Option<u32>,
|
||||
/// User has confirmed the stream check first-run notice
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub stream_check_confirmed: Option<bool>,
|
||||
/// Whether to show the failover toggle independently on the main page
|
||||
#[serde(default)]
|
||||
pub enable_failover_toggle: bool,
|
||||
@@ -511,7 +508,6 @@ impl Default for AppSettings {
|
||||
proxy_confirmed: None,
|
||||
usage_confirmed: None,
|
||||
usage_dashboard_refresh_interval_ms: None,
|
||||
stream_check_confirmed: None,
|
||||
enable_failover_toggle: false,
|
||||
show_profile_switcher: true,
|
||||
preserve_codex_official_auth_on_switch: false,
|
||||
|
||||
@@ -20,7 +20,7 @@ export function FirstRunNoticeDialog() {
|
||||
const { data: settings } = useSettingsQuery();
|
||||
|
||||
// 后端启动时已经决定好要不要弹:条件不满足的话字段会立即被写成 true,
|
||||
// 所以前端这里只需要判空即可——完全对齐 streamCheckConfirmed 等既有 flag 的模式。
|
||||
// 所以前端这里只需要判空即可——与其他既有确认标记的模式一致。
|
||||
const isOpen = settings != null && settings.firstRunNoticeConfirmed !== true;
|
||||
|
||||
const handleAcknowledge = async () => {
|
||||
|
||||
@@ -174,7 +174,7 @@ export function EditProviderDialog({
|
||||
}, [
|
||||
open, // 修复:编辑保存后再次打开显示旧数据,依赖 open 确保每次打开时重新读取最新 provider 数据
|
||||
provider?.id, // 只依赖 ID,provider 对象更新不会触发重新计算
|
||||
provider?.meta, // 需要依赖 meta 以便正确初始化 testConfig
|
||||
provider?.meta, // 供应商元数据变化时重新初始化表单
|
||||
initialSettingsConfig,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { HealthStatus } from "@/lib/api/model-test";
|
||||
import type { HealthStatus } from "@/lib/api/connectivity-check";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface HealthStatusIndicatorProps {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState, useEffect } from "react";
|
||||
import { ChevronDown, ChevronRight, FlaskConical, Coins } from "lucide-react";
|
||||
import { ChevronDown, ChevronRight, Coins } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { ProviderTestConfig } from "@/types";
|
||||
|
||||
export type PricingModelSourceOption = "inherit" | "request" | "response";
|
||||
|
||||
interface ProviderPricingConfig {
|
||||
@@ -23,170 +21,25 @@ interface ProviderPricingConfig {
|
||||
}
|
||||
|
||||
interface ProviderAdvancedConfigProps {
|
||||
testConfig: ProviderTestConfig;
|
||||
pricingConfig: ProviderPricingConfig;
|
||||
onTestConfigChange: (config: ProviderTestConfig) => void;
|
||||
onPricingConfigChange: (config: ProviderPricingConfig) => void;
|
||||
}
|
||||
|
||||
export function ProviderAdvancedConfig({
|
||||
testConfig,
|
||||
pricingConfig,
|
||||
onTestConfigChange,
|
||||
onPricingConfigChange,
|
||||
}: ProviderAdvancedConfigProps) {
|
||||
const { t } = useTranslation();
|
||||
const [isTestConfigOpen, setIsTestConfigOpen] = useState(testConfig.enabled);
|
||||
const [isPricingConfigOpen, setIsPricingConfigOpen] = useState(
|
||||
pricingConfig.enabled,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsTestConfigOpen(testConfig.enabled);
|
||||
}, [testConfig.enabled]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsPricingConfigOpen(pricingConfig.enabled);
|
||||
}, [pricingConfig.enabled]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-lg border border-border/50 bg-muted/20">
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between p-4 hover:bg-muted/30 transition-colors"
|
||||
onClick={() => setIsTestConfigOpen(!isTestConfigOpen)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<FlaskConical className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">
|
||||
{t("providerAdvanced.testConfig", {
|
||||
defaultValue: "连通检测配置",
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className="flex items-center gap-2"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Label
|
||||
htmlFor="test-config-enabled"
|
||||
className="text-sm text-muted-foreground"
|
||||
>
|
||||
{t("providerAdvanced.useCustomConfig", {
|
||||
defaultValue: "使用单独配置",
|
||||
})}
|
||||
</Label>
|
||||
<Switch
|
||||
id="test-config-enabled"
|
||||
checked={testConfig.enabled}
|
||||
onCheckedChange={(checked) => {
|
||||
onTestConfigChange({ ...testConfig, enabled: checked });
|
||||
if (checked) setIsTestConfigOpen(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{isTestConfigOpen ? (
|
||||
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-hidden transition-all duration-200",
|
||||
isTestConfigOpen
|
||||
? "max-h-[500px] opacity-100"
|
||||
: "max-h-0 opacity-0",
|
||||
)}
|
||||
>
|
||||
<div className="border-t border-border/50 p-4 space-y-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("providerAdvanced.testConfigDesc", {
|
||||
defaultValue:
|
||||
"为此供应商配置单独的连通检测参数(超时/阈值/重试),不启用时使用全局配置。",
|
||||
})}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="test-timeout">
|
||||
{t("providerAdvanced.timeoutSecs", {
|
||||
defaultValue: "超时时间(秒)",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="test-timeout"
|
||||
type="number"
|
||||
min={1}
|
||||
max={60}
|
||||
value={testConfig.timeoutSecs || ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
timeoutSecs: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="8"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="degraded-threshold">
|
||||
{t("providerAdvanced.degradedThreshold", {
|
||||
defaultValue: "降级阈值(毫秒)",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="degraded-threshold"
|
||||
type="number"
|
||||
min={100}
|
||||
max={60000}
|
||||
value={testConfig.degradedThresholdMs || ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
degradedThresholdMs: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="6000"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="max-retries">
|
||||
{t("providerAdvanced.maxRetries", {
|
||||
defaultValue: "最大重试次数",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="max-retries"
|
||||
type="number"
|
||||
min={0}
|
||||
max={5}
|
||||
value={testConfig.maxRetries ?? ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
maxRetries: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="1"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 计费配置 */}
|
||||
<div className="rounded-lg border border-border/50 bg-muted/20">
|
||||
<button
|
||||
|
||||
@@ -17,7 +17,6 @@ import { useDarkMode } from "@/hooks/useDarkMode";
|
||||
import type {
|
||||
ProviderCategory,
|
||||
ProviderMeta,
|
||||
ProviderTestConfig,
|
||||
ClaudeApiFormat,
|
||||
CodexApiFormat,
|
||||
CodexCatalogModel,
|
||||
@@ -313,9 +312,6 @@ function ProviderFormFull({
|
||||
return initialData?.meta?.isFullUrl ?? false;
|
||||
});
|
||||
|
||||
const [testConfig, setTestConfig] = useState<ProviderTestConfig>(
|
||||
() => initialData?.meta?.testConfig ?? { enabled: false },
|
||||
);
|
||||
const [pricingConfig, setPricingConfig] = useState<{
|
||||
enabled: boolean;
|
||||
costMultiplier?: string;
|
||||
@@ -351,7 +347,6 @@ function ProviderFormFull({
|
||||
setLocalIsFullUrl(
|
||||
supportsFullUrl ? (initialData?.meta?.isFullUrl ?? false) : false,
|
||||
);
|
||||
setTestConfig(initialData?.meta?.testConfig ?? { enabled: false });
|
||||
setPricingConfig({
|
||||
enabled:
|
||||
initialData?.meta?.costMultiplier !== undefined ||
|
||||
@@ -1497,7 +1492,6 @@ function ProviderFormFull({
|
||||
localProxyRequestOverrides: shouldApplyLocalProxyRequestOverrides
|
||||
? overridesResult.overrides
|
||||
: undefined,
|
||||
testConfig: testConfig.enabled ? testConfig : undefined,
|
||||
costMultiplier: pricingConfig.enabled
|
||||
? pricingConfig.costMultiplier
|
||||
: undefined,
|
||||
@@ -2469,9 +2463,7 @@ function ProviderFormFull({
|
||||
appId !== "openclaw" &&
|
||||
appId !== "hermes" && (
|
||||
<ProviderAdvancedConfig
|
||||
testConfig={testConfig}
|
||||
pricingConfig={pricingConfig}
|
||||
onTestConfigChange={setTestConfig}
|
||||
onPricingConfigChange={setPricingConfig}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -47,7 +47,7 @@ import { BackupListSection } from "@/components/settings/BackupListSection";
|
||||
import { WebdavSyncSection } from "@/components/settings/WebdavSyncSection";
|
||||
import { AboutSection } from "@/components/settings/AboutSection";
|
||||
import { ProxyTabContent } from "@/components/settings/ProxyTabContent";
|
||||
import { ModelTestConfigPanel } from "@/components/usage/ModelTestConfigPanel";
|
||||
import { ConnectivityCheckConfigPanel } from "@/components/usage/ConnectivityCheckConfigPanel";
|
||||
import { UsageDashboard } from "@/components/usage/UsageDashboard";
|
||||
import { LogConfigPanel } from "@/components/settings/LogConfigPanel";
|
||||
import { AuthCenterPanel } from "@/components/settings/AuthCenterPanel";
|
||||
@@ -455,7 +455,7 @@ export function SettingsPage({
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem
|
||||
value="test"
|
||||
value="connectivityCheck"
|
||||
className="rounded-xl glass-card overflow-hidden"
|
||||
>
|
||||
<AccordionTrigger className="px-6 py-4 hover:no-underline hover:bg-muted/50 data-[state=open]:bg-muted/50">
|
||||
@@ -463,16 +463,18 @@ export function SettingsPage({
|
||||
<FlaskConical className="h-5 w-5 text-emerald-500" />
|
||||
<div className="text-left">
|
||||
<h3 className="text-base font-semibold">
|
||||
{t("settings.advanced.modelTest.title")}
|
||||
{t("settings.advanced.connectivityCheck.title")}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground font-normal">
|
||||
{t("settings.advanced.modelTest.description")}
|
||||
{t(
|
||||
"settings.advanced.connectivityCheck.description",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-6 pb-6 pt-4 border-t border-border/50">
|
||||
<ModelTestConfigPanel />
|
||||
<ConnectivityCheckConfigPanel />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@ import {
|
||||
getStreamCheckConfig,
|
||||
saveStreamCheckConfig,
|
||||
type StreamCheckConfig,
|
||||
} from "@/lib/api/model-test";
|
||||
} from "@/lib/api/connectivity-check";
|
||||
|
||||
export function ModelTestConfigPanel() {
|
||||
export function ConnectivityCheckConfigPanel() {
|
||||
const { t } = useTranslation();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
streamCheckProvider,
|
||||
type StreamCheckResult,
|
||||
} from "@/lib/api/model-test";
|
||||
} from "@/lib/api/connectivity-check";
|
||||
import type { AppId } from "@/lib/api";
|
||||
|
||||
/**
|
||||
|
||||
@@ -299,11 +299,6 @@
|
||||
"message": "Usage query requires a custom script or API parameters. Please make sure you have obtained the necessary information from your provider.\n\nIf unsure how to configure, please consult your provider's documentation first.",
|
||||
"confirm": "I understand, configure"
|
||||
},
|
||||
"streamCheck": {
|
||||
"title": "Model Health Check",
|
||||
"message": "Health check tests provider connectivity by sending a direct API request. The following may cause check failures:\n\n• Official providers (uses OAuth login, no standalone API Key)\n• Some relay services (verify requests come from Claude Code CLI)\n• AWS Bedrock (uses IAM signature authentication)\n\nA failed check does not mean the provider is unusable — it only means it cannot be verified via a standalone request. Please refer to actual behavior within the application.",
|
||||
"confirm": "I understand, proceed"
|
||||
},
|
||||
"autoSync": {
|
||||
"title": "Enable Auto Sync",
|
||||
"message": "When auto sync is enabled, every database change will be automatically uploaded to the WebDAV server.\n\nThis may result in significant network traffic. Please ensure your network and WebDAV service can handle frequent data transfers.",
|
||||
@@ -344,9 +339,9 @@
|
||||
"running": "Running",
|
||||
"stopped": "Stopped"
|
||||
},
|
||||
"modelTest": {
|
||||
"title": "Model Test Config",
|
||||
"description": "Configure default models and prompts for model testing"
|
||||
"connectivityCheck": {
|
||||
"title": "Connectivity Check Settings",
|
||||
"description": "Configure timeout, retries, and the slow-response threshold for provider reachability checks"
|
||||
},
|
||||
"failover": {
|
||||
"title": "Auto Failover",
|
||||
@@ -1240,15 +1235,6 @@
|
||||
"empty": "No endpoints"
|
||||
},
|
||||
"providerAdvanced": {
|
||||
"testConfig": "Model Test Config",
|
||||
"useCustomConfig": "Use separate config",
|
||||
"testConfigDesc": "Configure separate model testing parameters for this provider. Uses global settings when disabled.",
|
||||
"testModel": "Test Model",
|
||||
"testModelPlaceholder": "Leave empty to use global config",
|
||||
"timeoutSecs": "Timeout (seconds)",
|
||||
"testPrompt": "Test Prompt",
|
||||
"degradedThreshold": "Degraded Threshold (ms)",
|
||||
"maxRetries": "Max Retries",
|
||||
"pricingConfig": "Pricing Config",
|
||||
"useCustomPricing": "Use separate config",
|
||||
"pricingConfigDesc": "Configure separate pricing parameters for this provider. Uses global defaults when disabled.",
|
||||
@@ -2450,9 +2436,6 @@
|
||||
"agents": {
|
||||
"title": "Agents"
|
||||
},
|
||||
"modelTest": {
|
||||
"testProvider": "Test model"
|
||||
},
|
||||
"health": {
|
||||
"operational": "Operational",
|
||||
"degraded": "Degraded",
|
||||
@@ -2660,35 +2643,13 @@
|
||||
"unreachable": "{{providerName}} unreachable: {{message}}",
|
||||
"unreachableHint": "Could not establish a connection (DNS / connect / TLS / timeout). Check the base_url and your network.",
|
||||
"connectivityNote": "Connectivity check only probes whether the provider address is reachable; it does not send a real model request. Any response counts as \"reachable\" — which does not guarantee that auth or model settings are correct.",
|
||||
"configSaved": "Health check config saved",
|
||||
"configSaved": "Connectivity check settings saved",
|
||||
"configSaveFailed": "Save failed",
|
||||
"testModels": "Test Models",
|
||||
"claudeModel": "Claude Model",
|
||||
"codexModel": "Codex Model",
|
||||
"geminiModel": "Gemini Model",
|
||||
"checkParams": "Check Parameters",
|
||||
"timeout": "Timeout (seconds)",
|
||||
"maxRetries": "Max Retries",
|
||||
"degradedThreshold": "Degraded Threshold (ms)",
|
||||
"testPrompt": "Test Prompt",
|
||||
"operational": "{{providerName}} is operational ({{responseTimeMs}}ms)",
|
||||
"degraded": "{{providerName}} is slow ({{responseTimeMs}}ms)",
|
||||
"failed": "{{providerName}} check failed: {{message}}",
|
||||
"rejected": "{{providerName}} check rejected: {{message}}",
|
||||
"error": "{{providerName}} check error: {{error}}",
|
||||
"modelNotFound": "{{providerName}} test model {{model}} does not exist or has been deprecated",
|
||||
"modelNotFoundHint": "This model may have been retired by the provider. Update the default test model in \"Model Test Config\".",
|
||||
"quotaExceeded": "{{providerName}} Coding Plan quota has been exceeded",
|
||||
"quotaExceededHint": "Baidu Qianfan returned a Coding Plan quota-limit error. Wait for the 5-hour, weekly, or monthly quota refresh, or adjust the plan in the Qianfan console.",
|
||||
"httpHint": {
|
||||
"400": "Provider rejected request format. Health check probe may differ from actual usage.",
|
||||
"401": "API key may be invalid, or provider uses OAuth auth. Check failure doesn't mean it's unusable.",
|
||||
"402": "Account quota or billing issue.",
|
||||
"403": "Provider blocked this request. Some verify client identity; may work fine in actual use.",
|
||||
"404": "Endpoint not found. Check base URL and API path.",
|
||||
"429": "Too many requests. Try again later.",
|
||||
"5xx": "Provider internal error. Likely temporary."
|
||||
}
|
||||
"degradedThreshold": "Slow-response threshold (ms)",
|
||||
"error": "{{providerName}} check error: {{error}}"
|
||||
},
|
||||
"proxyConfig": {
|
||||
"proxyEnabled": "Routing Master Switch",
|
||||
|
||||
@@ -299,11 +299,6 @@
|
||||
"message": "使用量クエリにはカスタムスクリプトまたは API パラメータが必要です。プロバイダーから必要な情報を取得していることをご確認ください。\n\n設定方法が不明な場合は、プロバイダーのドキュメントを先にご確認ください。",
|
||||
"confirm": "理解しました、設定する"
|
||||
},
|
||||
"streamCheck": {
|
||||
"title": "モデルヘルスチェック",
|
||||
"message": "ヘルスチェックは API リクエストを直接送信してプロバイダーの接続性をテストします。以下の場合、チェックが失敗する可能性があります:\n\n• 公式プロバイダー(OAuth ログイン使用、独立した API キーなし)\n• 一部の中継サービス(リクエストが Claude Code CLI からのものか検証)\n• AWS Bedrock(IAM 署名認証を使用)\n\nチェック失敗はプロバイダーが使用不能であることを意味しません。独立したリクエストでの検証ができないことを示すだけです。アプリ内の実際の動作を基準にしてください。",
|
||||
"confirm": "理解しました、続行する"
|
||||
},
|
||||
"autoSync": {
|
||||
"title": "自動同期を有効にする",
|
||||
"message": "自動同期を有効にすると、データベースの変更ごとに WebDAV サーバーへ自動アップロードされます。\n\nネットワークトラフィックが大幅に増加する可能性があります。ネットワーク環境と WebDAV サービスが頻繁なデータ転送に対応できることをご確認ください。",
|
||||
@@ -344,9 +339,9 @@
|
||||
"running": "実行中",
|
||||
"stopped": "停止中"
|
||||
},
|
||||
"modelTest": {
|
||||
"title": "モデルテスト設定",
|
||||
"description": "モデルテストで使用するデフォルトモデルとプロンプトを設定"
|
||||
"connectivityCheck": {
|
||||
"title": "接続チェック設定",
|
||||
"description": "プロバイダー接続チェックのタイムアウト、リトライ、低速判定しきい値を設定"
|
||||
},
|
||||
"failover": {
|
||||
"title": "自動フェイルオーバー",
|
||||
@@ -1240,15 +1235,6 @@
|
||||
"empty": "エンドポイントがありません"
|
||||
},
|
||||
"providerAdvanced": {
|
||||
"testConfig": "モデルテスト設定",
|
||||
"useCustomConfig": "個別設定を使用",
|
||||
"testConfigDesc": "このプロバイダーに個別のモデルテストパラメータを設定します。無効の場合はグローバル設定を使用します。",
|
||||
"testModel": "テストモデル",
|
||||
"testModelPlaceholder": "空白の場合はグローバル設定を使用",
|
||||
"timeoutSecs": "タイムアウト(秒)",
|
||||
"testPrompt": "テストプロンプト",
|
||||
"degradedThreshold": "低下閾値(ミリ秒)",
|
||||
"maxRetries": "最大リトライ回数",
|
||||
"pricingConfig": "課金設定",
|
||||
"useCustomPricing": "個別設定を使用",
|
||||
"pricingConfigDesc": "このプロバイダーに個別の課金パラメータを設定します。無効の場合はグローバル設定を使用します。",
|
||||
@@ -2450,9 +2436,6 @@
|
||||
"agents": {
|
||||
"title": "エージェント"
|
||||
},
|
||||
"modelTest": {
|
||||
"testProvider": "モデルテスト"
|
||||
},
|
||||
"health": {
|
||||
"operational": "正常",
|
||||
"degraded": "低下",
|
||||
@@ -2660,35 +2643,13 @@
|
||||
"unreachable": "{{providerName}} に接続できません: {{message}}",
|
||||
"unreachableHint": "接続を確立できませんでした(DNS / 接続 / TLS / タイムアウト)。base_url とネットワークを確認してください。",
|
||||
"connectivityNote": "接続チェックはプロバイダーのアドレスに到達できるかを確認するだけで、実際のモデルリクエストは送信しません。何らかの応答があれば「到達可能」とみなされますが、認証やモデル設定が正しいことを保証するものではありません。",
|
||||
"configSaved": "ヘルスチェック設定を保存しました",
|
||||
"configSaved": "接続チェック設定を保存しました",
|
||||
"configSaveFailed": "保存に失敗しました",
|
||||
"testModels": "テストモデル",
|
||||
"claudeModel": "Claude モデル",
|
||||
"codexModel": "Codex モデル",
|
||||
"geminiModel": "Gemini モデル",
|
||||
"checkParams": "チェックパラメーター",
|
||||
"timeout": "タイムアウト(秒)",
|
||||
"maxRetries": "最大リトライ回数",
|
||||
"degradedThreshold": "劣化しきい値(ミリ秒)",
|
||||
"testPrompt": "テストプロンプト",
|
||||
"operational": "{{providerName}} は正常に動作しています ({{responseTimeMs}}ms)",
|
||||
"degraded": "{{providerName}} の応答が遅いです ({{responseTimeMs}}ms)",
|
||||
"failed": "{{providerName}} のチェックに失敗しました: {{message}}",
|
||||
"rejected": "{{providerName}} のチェックが拒否されました: {{message}}",
|
||||
"error": "{{providerName}} のチェックでエラーが発生しました: {{error}}",
|
||||
"modelNotFound": "{{providerName}} のテストモデル {{model}} は存在しないか廃止されています",
|
||||
"modelNotFoundHint": "このモデルはプロバイダーにより廃止された可能性があります。「モデルテスト設定」でデフォルトのテストモデルを更新してください。",
|
||||
"quotaExceeded": "{{providerName}} の Coding Plan 利用枠を超過しました",
|
||||
"quotaExceededHint": "Baidu Qianfan が Coding Plan の利用枠超過エラーを返しました。5時間・週次・月次の利用枠更新を待つか、Qianfan コンソールでプランを確認してください。",
|
||||
"httpHint": {
|
||||
"400": "リクエスト形式が拒否されました。ヘルスチェックの形式は実際の使用と異なる場合があります。",
|
||||
"401": "APIキーが無効か、OAuthなどの認証方式を使用しています。チェック失敗は実際に使えないことを意味しません。",
|
||||
"402": "アカウントの利用枠または請求の問題です。",
|
||||
"403": "プロバイダーがリクエストを拒否しました。実際の使用では正常に動作する場合があります。",
|
||||
"404": "エンドポイントが見つかりません。Base URLとAPIパスを確認してください。",
|
||||
"429": "リクエストが多すぎます。しばらくしてからお試しください。",
|
||||
"5xx": "プロバイダーの内部エラーです。一時的な問題の可能性が高いです。"
|
||||
}
|
||||
"degradedThreshold": "低速判定しきい値(ミリ秒)",
|
||||
"error": "{{providerName}} のチェックでエラーが発生しました: {{error}}"
|
||||
},
|
||||
"proxyConfig": {
|
||||
"proxyEnabled": "ルーティング総スイッチ",
|
||||
|
||||
@@ -299,11 +299,6 @@
|
||||
"message": "用量查詢需要設定專用的查詢腳本或 API 參數,請確保您已從供應商處取得相關資訊。\n\n如不確定如何設定,請先查閱供應商文件。",
|
||||
"confirm": "我已了解,繼續設定"
|
||||
},
|
||||
"streamCheck": {
|
||||
"title": "模型健康檢測",
|
||||
"message": "健康檢測透過直接發送 API 請求來測試供應商連線能力,以下情況可能導致檢測失敗:\n\n• 官方供應商(使用 OAuth 登入,無獨立 API Key)\n• 部分中繼服務(會驗證請求是否來自 Claude Code CLI)\n• AWS Bedrock(使用 IAM 簽章驗證)\n\n檢測失敗不代表供應商不可用,僅表示無法透過獨立請求驗證。請以應用程式內的實際情況為準。",
|
||||
"confirm": "我已了解,繼續檢測"
|
||||
},
|
||||
"autoSync": {
|
||||
"title": "開啟自動同步",
|
||||
"message": "開啟自動同步後,每次資料庫變更都會自動上傳至 WebDAV 伺服器。\n\n這可能會產生較高的網路流量消耗,請確保您的網路環境和 WebDAV 服務支援頻繁的資料傳輸。",
|
||||
@@ -344,9 +339,9 @@
|
||||
"running": "執行中",
|
||||
"stopped": "已停止"
|
||||
},
|
||||
"modelTest": {
|
||||
"title": "模型測試設定",
|
||||
"description": "設定模型測試使用的預設模型和提示詞"
|
||||
"connectivityCheck": {
|
||||
"title": "連通檢測設定",
|
||||
"description": "設定供應商位址探測的逾時、重試與緩慢閾值"
|
||||
},
|
||||
"failover": {
|
||||
"title": "自動故障轉移",
|
||||
@@ -1212,15 +1207,6 @@
|
||||
"empty": "暫無端點"
|
||||
},
|
||||
"providerAdvanced": {
|
||||
"testConfig": "模型測試設定",
|
||||
"useCustomConfig": "使用獨立設定",
|
||||
"testConfigDesc": "為此供應商設定獨立的模型測試參數,不啟用時使用全域設定。",
|
||||
"testModel": "測試模型",
|
||||
"testModelPlaceholder": "留空使用全域設定",
|
||||
"timeoutSecs": "逾時時間(秒)",
|
||||
"testPrompt": "測試提示詞",
|
||||
"degradedThreshold": "降級閾值(毫秒)",
|
||||
"maxRetries": "最大重試次數",
|
||||
"pricingConfig": "計費設定",
|
||||
"useCustomPricing": "使用獨立設定",
|
||||
"pricingConfigDesc": "為此供應商設定獨立的計費參數,不啟用時使用全域預設設定。",
|
||||
@@ -2422,9 +2408,6 @@
|
||||
"agents": {
|
||||
"title": "Agent"
|
||||
},
|
||||
"modelTest": {
|
||||
"testProvider": "測試模型"
|
||||
},
|
||||
"health": {
|
||||
"operational": "正常",
|
||||
"degraded": "降級",
|
||||
@@ -2632,35 +2615,13 @@
|
||||
"unreachable": "{{providerName}} 無法連通: {{message}}",
|
||||
"unreachableHint": "無法建立連線(DNS / 連線 / TLS / 逾時)。請檢查 base_url 與網路。",
|
||||
"connectivityNote": "連通檢測僅探測供應商位址是否可達,不發送真實模型請求。收到任意回應即視為「可達」——這不代表驗證或模型設定一定正確。",
|
||||
"configSaved": "健康檢測設定已儲存",
|
||||
"configSaved": "連通檢測設定已儲存",
|
||||
"configSaveFailed": "儲存失敗",
|
||||
"testModels": "測試模型",
|
||||
"claudeModel": "Claude 模型",
|
||||
"codexModel": "Codex 模型",
|
||||
"geminiModel": "Gemini 模型",
|
||||
"checkParams": "檢查參數",
|
||||
"timeout": "逾時時間(秒)",
|
||||
"maxRetries": "最大重試次數",
|
||||
"degradedThreshold": "降級閾值(毫秒)",
|
||||
"testPrompt": "檢查提示詞",
|
||||
"operational": "{{providerName}} 執行正常 ({{responseTimeMs}}ms)",
|
||||
"degraded": "{{providerName}} 回應較慢 ({{responseTimeMs}}ms)",
|
||||
"failed": "{{providerName}} 檢查失敗:{{message}}",
|
||||
"rejected": "{{providerName}} 檢查被拒:{{message}}",
|
||||
"error": "{{providerName}} 檢查出錯:{{error}}",
|
||||
"modelNotFound": "{{providerName}} 測試模型 {{model}} 不存在或已下架",
|
||||
"modelNotFoundHint": "該模型可能已被供應商棄用。請在「模型測試設定」中更新預設測試模型。",
|
||||
"quotaExceeded": "{{providerName}} Coding Plan 額度已用盡",
|
||||
"quotaExceededHint": "百度千帆回傳了 Coding Plan 超額錯誤。請等待 5 小時 / 每週 / 每月額度重新整理,或在千帆控制台切換方案。",
|
||||
"httpHint": {
|
||||
"400": "供應商拒絕了請求格式。健康檢測的探測格式可能與實際使用不同。",
|
||||
"401": "API Key 可能無效,或供應商使用 OAuth 等驗證方式。檢查失敗不代表實際不可用。",
|
||||
"402": "帳號配額或計費問題。",
|
||||
"403": "供應商拒絕了此請求。部分供應商會驗證用戶端身分,檢查失敗但實際使用可能正常。",
|
||||
"404": "API 位址不存在,請檢查 Base URL 和 API 路徑。",
|
||||
"429": "請求頻率過高,請稍後重試。",
|
||||
"5xx": "供應商內部錯誤,通常是臨時問題。"
|
||||
}
|
||||
"degradedThreshold": "緩慢閾值(毫秒)",
|
||||
"error": "{{providerName}} 檢查出錯:{{error}}"
|
||||
},
|
||||
"proxyConfig": {
|
||||
"proxyEnabled": "路由總開關",
|
||||
|
||||
@@ -299,11 +299,6 @@
|
||||
"message": "用量查询需要配置专用的查询脚本或 API 参数,请确保您已从供应商处获取相关信息。\n\n如不确定如何配置,请先查阅供应商文档。",
|
||||
"confirm": "我已了解,继续配置"
|
||||
},
|
||||
"streamCheck": {
|
||||
"title": "模型健康检测",
|
||||
"message": "健康检测通过直接发送 API 请求来测试供应商连通性,以下情况可能导致检测失败:\n\n• 官方供应商(使用 OAuth 登录,无独立 API Key)\n• 部分中转服务(会校验请求是否来自 Claude Code CLI)\n• AWS Bedrock(使用 IAM 签名认证)\n\n检测失败不代表供应商不可用,仅表示无法通过独立请求验证。请以应用内的实际情况为准。",
|
||||
"confirm": "我已了解,继续检测"
|
||||
},
|
||||
"autoSync": {
|
||||
"title": "开启自动同步",
|
||||
"message": "开启自动同步后,每次数据库变更都会自动上传到 WebDAV 服务器。\n\n这可能会产生较高的网络流量消耗,请确保您的网络环境和 WebDAV 服务支持频繁的数据传输。",
|
||||
@@ -344,9 +339,9 @@
|
||||
"running": "运行中",
|
||||
"stopped": "已停止"
|
||||
},
|
||||
"modelTest": {
|
||||
"title": "模型测试配置",
|
||||
"description": "配置模型测试使用的默认模型和提示词"
|
||||
"connectivityCheck": {
|
||||
"title": "连通检测配置",
|
||||
"description": "配置供应商地址探测的超时、重试和较慢阈值"
|
||||
},
|
||||
"failover": {
|
||||
"title": "自动故障转移",
|
||||
@@ -1240,15 +1235,6 @@
|
||||
"empty": "暂无端点"
|
||||
},
|
||||
"providerAdvanced": {
|
||||
"testConfig": "模型测试配置",
|
||||
"useCustomConfig": "使用单独配置",
|
||||
"testConfigDesc": "为此供应商配置单独的模型测试参数,不启用时使用全局配置。",
|
||||
"testModel": "测试模型",
|
||||
"testModelPlaceholder": "留空使用全局配置",
|
||||
"timeoutSecs": "超时时间(秒)",
|
||||
"testPrompt": "测试提示词",
|
||||
"degradedThreshold": "降级阈值(毫秒)",
|
||||
"maxRetries": "最大重试次数",
|
||||
"pricingConfig": "计费配置",
|
||||
"useCustomPricing": "使用单独配置",
|
||||
"pricingConfigDesc": "为此供应商配置单独的计费参数,不启用时使用全局默认配置。",
|
||||
@@ -2450,9 +2436,6 @@
|
||||
"agents": {
|
||||
"title": "智能体"
|
||||
},
|
||||
"modelTest": {
|
||||
"testProvider": "测试模型"
|
||||
},
|
||||
"health": {
|
||||
"operational": "正常",
|
||||
"degraded": "降级",
|
||||
@@ -2660,35 +2643,13 @@
|
||||
"unreachable": "{{providerName}} 无法连通: {{message}}",
|
||||
"unreachableHint": "无法建立连接(DNS / 连接 / TLS / 超时)。请检查 base_url 与网络。",
|
||||
"connectivityNote": "连通检测仅探测供应商地址是否可达,不发送真实模型请求。收到任意响应即视为“可达”——这不代表鉴权或模型配置一定正确。",
|
||||
"configSaved": "健康检查配置已保存",
|
||||
"configSaved": "连通检测配置已保存",
|
||||
"configSaveFailed": "保存失败",
|
||||
"testModels": "测试模型",
|
||||
"claudeModel": "Claude 模型",
|
||||
"codexModel": "Codex 模型",
|
||||
"geminiModel": "Gemini 模型",
|
||||
"checkParams": "检查参数",
|
||||
"timeout": "超时时间(秒)",
|
||||
"maxRetries": "最大重试次数",
|
||||
"degradedThreshold": "降级阈值(毫秒)",
|
||||
"testPrompt": "检查提示词",
|
||||
"operational": "{{providerName}} 运行正常 ({{responseTimeMs}}ms)",
|
||||
"degraded": "{{providerName}} 响应较慢 ({{responseTimeMs}}ms)",
|
||||
"failed": "{{providerName}} 检查失败: {{message}}",
|
||||
"rejected": "{{providerName}} 检查被拒: {{message}}",
|
||||
"error": "{{providerName}} 检查出错: {{error}}",
|
||||
"modelNotFound": "{{providerName}} 测试模型 {{model}} 不存在或已下架",
|
||||
"modelNotFoundHint": "该模型可能已被供应商弃用。请在\"模型测试配置\"中更新默认测试模型。",
|
||||
"quotaExceeded": "{{providerName}} Coding Plan 额度已用尽",
|
||||
"quotaExceededHint": "百度千帆返回了 Coding Plan 超额错误。请等待 5 小时/每周/每月额度刷新,或在千帆控制台切换套餐。",
|
||||
"httpHint": {
|
||||
"400": "供应商拒绝了请求格式。健康检查的探测格式可能与实际使用不同。",
|
||||
"401": "API Key 可能无效,或供应商使用 OAuth 等认证方式。检查失败不代表实际不可用。",
|
||||
"402": "账户配额或计费问题。",
|
||||
"403": "供应商拒绝了此请求。部分供应商会校验客户端身份,检查失败但实际使用可能正常。",
|
||||
"404": "接口地址不存在,请检查 Base URL 和 API 路径。",
|
||||
"429": "请求频率过高,请稍后重试。",
|
||||
"5xx": "供应商内部错误,通常是临时问题。"
|
||||
}
|
||||
"degradedThreshold": "较慢阈值(毫秒)",
|
||||
"error": "{{providerName}} 检查出错: {{error}}"
|
||||
},
|
||||
"proxyConfig": {
|
||||
"proxyEnabled": "路由总开关",
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function streamCheckProvider(
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量流式健康检查
|
||||
* 批量连通性检查
|
||||
*/
|
||||
export async function streamCheckAllProviders(
|
||||
appType: AppId,
|
||||
@@ -48,14 +48,14 @@ export async function streamCheckAllProviders(
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流式检查配置
|
||||
* 获取连通性检查配置
|
||||
*/
|
||||
export async function getStreamCheckConfig(): Promise<StreamCheckConfig> {
|
||||
return invoke("get_stream_check_config");
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存流式检查配置
|
||||
* 保存连通性检查配置
|
||||
*/
|
||||
export async function saveStreamCheckConfig(
|
||||
config: StreamCheckConfig,
|
||||
@@ -111,18 +111,6 @@ export interface UsageResult {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// 供应商单独的连通检测配置(覆盖全局配置)
|
||||
export interface ProviderTestConfig {
|
||||
// 是否启用单独配置(false 时使用全局配置)
|
||||
enabled: boolean;
|
||||
// 超时时间(秒)
|
||||
timeoutSecs?: number;
|
||||
// 降级阈值(毫秒)
|
||||
degradedThresholdMs?: number;
|
||||
// 最大重试次数
|
||||
maxRetries?: number;
|
||||
}
|
||||
|
||||
export type AuthBindingSource = "provider_config" | "managed_account";
|
||||
|
||||
export interface AuthBinding {
|
||||
@@ -196,8 +184,6 @@ export interface ProviderMeta {
|
||||
isPartner?: boolean;
|
||||
// 合作伙伴促销 key(用于后端识别 PackyCode 等)
|
||||
partnerPromotionKey?: string;
|
||||
// 供应商单独的模型测试配置
|
||||
testConfig?: ProviderTestConfig;
|
||||
// 供应商成本倍率
|
||||
costMultiplier?: string;
|
||||
// 供应商计费模式来源
|
||||
@@ -371,8 +357,6 @@ export interface Settings {
|
||||
// User has confirmed the usage query first-run notice
|
||||
usageConfirmed?: boolean;
|
||||
usageDashboardRefreshIntervalMs?: number;
|
||||
// User has confirmed the stream check first-run notice
|
||||
streamCheckConfirmed?: boolean;
|
||||
// Whether to show the failover toggle independently on the main page
|
||||
enableFailoverToggle?: boolean;
|
||||
// Whether to show the project profile switcher on the main page header
|
||||
|
||||
Reference in New Issue
Block a user