fix(routing): harden routed pool scheduling

This commit is contained in:
elky
2026-07-27 22:06:28 +08:00
parent 550cc36760
commit 4148ab1931
62 changed files with 5510 additions and 850 deletions
@@ -530,7 +530,8 @@ import { CircleHelp } from 'lucide-vue-next'
import { Dialog, Button, Input, Label, Switch, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui'
import { useToast } from '@/composables/useToast'
import { parseApiError } from '@/utils/errorParser'
import { updateProvider } from '@/api/endpoints'
import { getProvider, updateProvider } from '@/api/endpoints'
import { mergePoolAdvancedPatch } from '@/features/pool/utils/poolSchedulingDialog'
import {
buildPoolCooldownFieldLayout,
buildPoolHealthToggleCards,
@@ -557,6 +558,7 @@ const emit = defineEmits<{
const { success, error: showError } = useToast()
const loading = ref(false)
let dialogRevision = 0
const isClaudeCode = computed(() => {
return (props.providerType || '').trim().toLowerCase() === 'claude_code'
@@ -652,7 +654,9 @@ function updateHealthToggleValue(key: PoolHealthToggleKey, value: boolean): void
}
}
watch(() => props.modelValue, (open) => {
watch([() => props.modelValue, () => props.providerId], ([open]) => {
dialogRevision += 1
loading.value = false
if (!open) return
const cfg = props.currentConfig
@@ -698,12 +702,26 @@ watch(() => props.modelValue, (open) => {
})
async function handleSave() {
const providerId = props.providerId
const revision = dialogRevision
loading.value = true
try {
const latestProvider = await getProvider(providerId)
if (!props.modelValue || props.providerId !== providerId || dialogRevision !== revision) return
const latestAdvanced = (latestProvider as Record<string, unknown>).pool_advanced
const existingPoolAdvanced = mergePoolAdvancedPatch(latestAdvanced, {})
const latestScoreRules = typeof existingPoolAdvanced.score_rules === 'object'
&& existingPoolAdvanced.score_rules !== null
? existingPoolAdvanced.score_rules as Record<string, unknown>
: {}
const latestScoreWeights = typeof latestScoreRules.weights === 'object'
&& latestScoreRules.weights !== null
? latestScoreRules.weights as Record<string, unknown>
: {}
const scoreRules = {
...(props.currentConfig?.score_rules ?? {}),
...latestScoreRules,
weights: {
...(props.currentConfig?.score_rules?.weights ?? {}),
...latestScoreWeights,
manual_priority: form.value.score_weight_manual_priority ?? undefined,
health: form.value.score_weight_health ?? undefined,
probe_freshness: form.value.score_weight_probe_freshness ?? undefined,
@@ -717,31 +735,8 @@ async function handleSave() {
request_failure_penalty: form.value.request_failure_penalty ?? undefined,
probe_failure_cooldown_threshold: form.value.probe_failure_cooldown_threshold ?? undefined,
}
const existingPoolAdvanced: Record<string, unknown> = { ...(props.currentConfig ?? {}) }
for (const key of [
'probing_target_percent',
'probing_target_count',
'probing_active_target_percent',
'probing_active_target_count',
'active_probe_target_percent',
'active_probe_target_count',
'probing_interval_minutes',
'account_self_check_method',
'self_check_method',
'account_self_check_request',
'self_check_request',
'health_policy_enabled',
'sticky_session_ttl_seconds',
'global_priority',
'cost_window_seconds',
'cost_limit_per_key_tokens',
'cost_soft_threshold_percent',
]) {
delete existingPoolAdvanced[key]
}
// 合并已有配置(保留 scheduling_presets 等不在此对话框编辑的字段)
const poolAdvanced: Record<string, unknown> = {
...existingPoolAdvanced,
const poolAdvanced = mergePoolAdvancedPatch(existingPoolAdvanced, {
rate_limit_cooldown_seconds: form.value.rate_limit_cooldown_seconds ?? undefined,
overload_cooldown_seconds: form.value.overload_cooldown_seconds ?? undefined,
batch_concurrency: form.value.batch_concurrency ?? undefined,
@@ -760,7 +755,7 @@ async function handleSave() {
auto_remove_banned_keys: form.value.auto_remove_banned_keys,
auto_remove_quota_exhausted_keys: form.value.auto_remove_quota_exhausted_keys,
skip_exhausted_accounts: form.value.skip_exhausted_accounts,
}
})
const payload: Parameters<typeof updateProvider>[1] = {
pool_advanced: poolAdvanced as PoolAdvancedConfig,
@@ -776,14 +771,17 @@ async function handleSave() {
cli_only_enabled: cf.cli_only_enabled,
}
}
const updatedProvider = await updateProvider(props.providerId, payload)
const updatedProvider = await updateProvider(providerId, payload)
if (!props.modelValue || props.providerId !== providerId || dialogRevision !== revision) return
success('高级设置已保存')
emit('saved', updatedProvider)
emit('update:modelValue', false)
} catch (err) {
showError(parseApiError(err))
} finally {
loading.value = false
if (dialogRevision === revision) {
loading.value = false
}
}
}
</script>