Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions controller/channel-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,9 @@ func selectChannelsForAutomaticTest(channels []*model.Channel, mode string) []*m
if channel.Status == common.ChannelStatusManuallyDisabled {
continue
}
if mode == operation_setting.ChannelTestModeAutoBanOnly && !channel.GetAutoBan() {
continue
}
if mode == operation_setting.ChannelTestModePassiveRecovery && channel.Status != common.ChannelStatusAutoDisabled {
continue
}
Expand Down
18 changes: 18 additions & 0 deletions controller/channel_test_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,24 @@ func TestSelectChannelsForAutomaticTestScheduledSkipsManualDisabled(t *testing.T
require.Equal(t, 2, selected[1].Id)
}

func TestSelectChannelsForAutomaticTestAutoBanOnlyUsesEligibleChannels(t *testing.T) {
autoBanEnabled := 1
autoBanDisabled := 0
channels := []*model.Channel{
{Id: 1, Status: common.ChannelStatusEnabled, AutoBan: &autoBanEnabled},
{Id: 2, Status: common.ChannelStatusEnabled, AutoBan: &autoBanDisabled},
{Id: 3, Status: common.ChannelStatusAutoDisabled, AutoBan: &autoBanEnabled},
{Id: 4, Status: common.ChannelStatusManuallyDisabled, AutoBan: &autoBanEnabled},
{Id: 5, Status: common.ChannelStatusEnabled},
}

selected := selectChannelsForAutomaticTest(channels, operation_setting.ChannelTestModeAutoBanOnly)

require.Len(t, selected, 2)
require.Equal(t, 1, selected[0].Id)
require.Equal(t, 3, selected[1].Id)
}

func TestTestAllChannelsRejectsExistingActiveTask(t *testing.T) {
db := setupModelListControllerTestDB(t)
require.NoError(t, db.AutoMigrate(&model.SystemTask{}, &model.SystemTaskLock{}))
Expand Down
5 changes: 4 additions & 1 deletion setting/operation_setting/monitor_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type MonitorSetting struct {

const (
ChannelTestModeScheduledAll = "scheduled_all"
ChannelTestModeAutoBanOnly = "auto_ban_only"
ChannelTestModePassiveRecovery = "passive_recovery"
)

Expand Down Expand Up @@ -45,7 +46,9 @@ func GetMonitorSetting() *MonitorSetting {
monitorSetting.AutoTestChannelEnabled = parsed
}
}
if monitorSetting.ChannelTestMode != ChannelTestModePassiveRecovery {
switch monitorSetting.ChannelTestMode {
case ChannelTestModeAutoBanOnly, ChannelTestModePassiveRecovery:
default:
monitorSetting.ChannelTestMode = ChannelTestModeScheduledAll
}
return &monitorSetting
Expand Down
14 changes: 14 additions & 0 deletions setting/operation_setting/monitor_setting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,17 @@ func TestGetMonitorSetting_ChannelTestEnabledEnvCanEnableDisabledConfig(t *testi
assert.True(t, setting.AutoTestChannelEnabled)
assert.Equal(t, float64(12), setting.AutoTestChannelMinutes)
}

func TestGetMonitorSettingPreservesAutoBanOnlyMode(t *testing.T) {
orig := monitorSetting
t.Cleanup(func() { monitorSetting = orig })

t.Setenv("CHANNEL_TEST_ENABLED", "")
t.Setenv("CHANNEL_TEST_FREQUENCY", "")
monitorSetting = MonitorSetting{ChannelTestMode: ChannelTestModeAutoBanOnly}

setting := GetMonitorSetting()

require.NotNil(t, setting)
assert.Equal(t, ChannelTestModeAutoBanOnly, setting.ChannelTestMode)
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ const numericString = z.string().refine((value) => {
return !Number.isNaN(Number(trimmed)) && Number(trimmed) >= 0
}, 'Enter a non-negative number or leave empty')

const channelTestModes = ['scheduled_all', 'passive_recovery'] as const
const channelTestModes = [
'scheduled_all',
'auto_ban_only',
'passive_recovery',
] as const
type ChannelTestMode = (typeof channelTestModes)[number]

const routingReliabilitySchema = z
Expand Down Expand Up @@ -148,7 +152,10 @@ type NormalizedRoutingReliabilityValues = {
}

function normalizeChannelTestMode(value?: string): ChannelTestMode {
return value === 'passive_recovery' ? 'passive_recovery' : 'scheduled_all'
if (value === 'auto_ban_only' || value === 'passive_recovery') {
return value
}
return 'scheduled_all'
}

const buildFormDefaults = (
Expand Down Expand Up @@ -250,6 +257,23 @@ export function RoutingReliabilitySection({
const autoDisableStatusCodes = form.watch('AutomaticDisableStatusCodes')
const autoRetryStatusCodes = form.watch('AutomaticRetryStatusCodes')
const channelTestMode = form.watch('monitor_setting.channel_test_mode')
let channelTestModeDescription: string
switch (channelTestMode) {
case 'auto_ban_only':
channelTestModeDescription = t(
'Periodically checks only channels with auto-disable enabled, excluding manually disabled channels.'
)
break
case 'passive_recovery':
channelTestModeDescription = t(
'Does not check healthy channels. It only rechecks auto-disabled channels and restores them after they recover.'
)
break
default:
channelTestModeDescription = t(
'Periodically checks all channels except manually disabled ones to detect failures and recover channels automatically.'
)
}
const autoDisableParsed = useMemo(
() => parseHttpStatusCodeRules(autoDisableStatusCodes),
[autoDisableStatusCodes]
Expand Down Expand Up @@ -391,11 +415,17 @@ export function RoutingReliabilitySection({
items={[
{
value: 'scheduled_all',
label: t('Scheduled full test'),
label: t('Actively check all channels'),
},
{
value: 'auto_ban_only',
label: t(
'Actively check auto-disable-enabled channels'
),
},
{
value: 'passive_recovery',
label: t('Passive recovery only'),
label: t('Check channels awaiting recovery only'),
},
]}
value={field.value}
Expand All @@ -409,18 +439,19 @@ export function RoutingReliabilitySection({
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='scheduled_all'>
{t('Scheduled full test')}
{t('Actively check all channels')}
</SelectItem>
<SelectItem value='auto_ban_only'>
{t('Actively check auto-disable-enabled channels')}
</SelectItem>
<SelectItem value='passive_recovery'>
{t('Passive recovery only')}
{t('Check channels awaiting recovery only')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
{t(
'Scheduled full test probes non-manually-disabled channels; passive recovery only checks auto-disabled channels after real request failures.'
)}
{channelTestModeDescription}
</FormDescription>
<FormMessage />
</FormItem>
Expand Down
5 changes: 4 additions & 1 deletion web/src/features/system-settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,10 @@ export type ModelSettings = {
AutomaticRetryStatusCodes: string
'monitor_setting.auto_test_channel_enabled': boolean
'monitor_setting.auto_test_channel_minutes': number
'monitor_setting.channel_test_mode': 'scheduled_all' | 'passive_recovery'
'monitor_setting.channel_test_mode':
| 'scheduled_all'
| 'auto_ban_only'
| 'passive_recovery'
'channel_affinity_setting.enabled': boolean
'channel_affinity_setting.switch_on_success': boolean
'channel_affinity_setting.keep_on_channel_disabled': boolean
Expand Down
9 changes: 9 additions & 0 deletions web/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
"Active models": "Active models",
"Active Tasks": "Active Tasks",
"active users": "active users",
"Actively check all channels": "Actively check all channels",
"Actively check auto-disable-enabled channels": "Actively check auto-disable-enabled channels",
"Actual Amount": "Actual Amount",
"Actual Model": "Actual Model",
"Actual Model:": "Actual Model:",
Expand Down Expand Up @@ -512,6 +514,8 @@
"Auto Sync Upstream Models": "Auto Sync Upstream Models",
"Auto-disable rules": "Auto-disable rules",
"Auto-disable status codes": "Auto-disable status codes",
"Auto-disable-enabled channels only": "Auto-disable-enabled channels only",
"Auto-disable-enabled mode probes non-manually-disabled channels with auto-disable enabled.": "Auto-disable-enabled mode probes non-manually-disabled channels with auto-disable enabled.",
"Auto-discover": "Auto-discover",
"Auto-discovers endpoints from the provider": "Auto-discovers endpoints from the provider",
"Auto-fill when one field exists and another is missing": "Auto-fill when one field exists and another is missing",
Expand Down Expand Up @@ -783,6 +787,7 @@
"Chat session management": "Chat session management",
"ChatCompletions -> Responses Compatibility": "ChatCompletions -> Responses Compatibility",
"ChatGPT Subscription (Codex)": "ChatGPT Subscription (Codex)",
"Check channels awaiting recovery only": "Check channels awaiting recovery only",
"Check for updates": "Check for updates",
"Check in daily to receive random quota rewards": "Check in daily to receive random quota rewards",
"Check in now": "Check in now",
Expand Down Expand Up @@ -1437,6 +1442,7 @@
"Docs": "Docs",
"Documentation Link": "Documentation Link",
"Documentation or external knowledge base.": "Documentation or external knowledge base.",
"Does not check healthy channels. It only rechecks auto-disabled channels and restores them after they recover.": "Does not check healthy channels. It only rechecks auto-disabled channels and restores them after they recover.",
"does not exist or might have been removed.": "does not exist or might have been removed.",
"Domain": "Domain",
"Domain Filter Mode": "Domain Filter Mode",
Expand Down Expand Up @@ -3358,6 +3364,8 @@
"Performed {{action}} on user {{username}} (ID: {{id}})": "Performed {{action}} on user {{username}} (ID: {{id}})",
"Period": "Period",
"Periodically check for upstream model changes": "Periodically check for upstream model changes",
"Periodically checks all channels except manually disabled ones to detect failures and recover channels automatically.": "Periodically checks all channels except manually disabled ones to detect failures and recover channels automatically.",
"Periodically checks only channels with auto-disable enabled, excluding manually disabled channels.": "Periodically checks only channels with auto-disable enabled, excluding manually disabled channels.",
"Periodically send ping frames to keep streaming connections active.": "Periodically send ping frames to keep streaming connections active.",
"Permanently delete your account and all data": "Permanently delete your account and all data",
"Permit Passkey registration on non-HTTPS origins (only recommended for development)": "Permit Passkey registration on non-HTTPS origins (only recommended for development)",
Expand Down Expand Up @@ -3673,6 +3681,7 @@
"Recommended to keep this high to avoid upstream throttling.": "Recommended to keep this high to avoid upstream throttling.",
"Record IP Address": "Record IP Address",
"Record quota usage": "Record quota usage",
"Recover auto-disabled channels only": "Recover auto-disabled channels only",
"Recursion Strategy": "Recursion Strategy",
"Recursive": "Recursive",
"Redeem": "Redeem",
Expand Down
9 changes: 9 additions & 0 deletions web/src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
"Active models": "Modèles actifs",
"Active Tasks": "Tâches actives",
"active users": "utilisateurs actifs",
"Actively check all channels": "Vérifier activement tous les canaux",
"Actively check auto-disable-enabled channels": "Vérifier activement les canaux avec désactivation automatique",
"Actual Amount": "Montant réel",
"Actual Model": "Modèle réel",
"Actual Model:": "Modèle réel :",
Expand Down Expand Up @@ -512,6 +514,8 @@
"Auto Sync Upstream Models": "Synchronisation automatique des modèles en amont",
"Auto-disable rules": "Règles de désactivation automatique",
"Auto-disable status codes": "Codes de statut de désactivation auto",
"Auto-disable-enabled channels only": "Canaux avec désactivation automatique uniquement",
"Auto-disable-enabled mode probes non-manually-disabled channels with auto-disable enabled.": "Ce mode sonde uniquement les canaux dont la désactivation automatique est activée et qui ne sont pas désactivés manuellement.",
"Auto-discover": "Découverte automatique",
"Auto-discovers endpoints from the provider": "Découvre automatiquement les points de terminaison du fournisseur",
"Auto-fill when one field exists and another is missing": "Remplissage automatique si un champ existe et l'autre est manquant",
Expand Down Expand Up @@ -783,6 +787,7 @@
"Chat session management": "Gestion des sessions de chat",
"ChatCompletions -> Responses Compatibility": "Compatibilité ChatCompletions -> Réponses",
"ChatGPT Subscription (Codex)": "ChatGPT Subscription (Codex)",
"Check channels awaiting recovery only": "Vérifier uniquement les canaux en attente de rétablissement",
"Check for updates": "Vérifier les mises à jour",
"Check in daily to receive random quota rewards": "Connectez-vous quotidiennement pour recevoir des récompenses de quota aléatoires",
"Check in now": "Se connecter maintenant",
Expand Down Expand Up @@ -1437,6 +1442,7 @@
"Docs": "Documents",
"Documentation Link": "Lien de la documentation",
"Documentation or external knowledge base.": "Documentation ou base de connaissances externe.",
"Does not check healthy channels. It only rechecks auto-disabled channels and restores them after they recover.": "Ne vérifie pas les canaux opérationnels. Revérifie uniquement les canaux désactivés automatiquement et les réactive après leur rétablissement.",
"does not exist or might have been removed.": "n'existe pas ou a peut-être été supprimé.",
"Domain": "Domaine",
"Domain Filter Mode": "Mode de filtre de domaine",
Expand Down Expand Up @@ -3358,6 +3364,8 @@
"Performed {{action}} on user {{username}} (ID: {{id}})": "Action {{action}} effectuée sur l'utilisateur {{username}} (ID : {{id}})",
"Period": "Période",
"Periodically check for upstream model changes": "Vérifier périodiquement les changements de modèles en amont",
"Periodically checks all channels except manually disabled ones to detect failures and recover channels automatically.": "Vérifie périodiquement tous les canaux sauf ceux désactivés manuellement afin de détecter les pannes et de rétablir automatiquement les canaux.",
"Periodically checks only channels with auto-disable enabled, excluding manually disabled channels.": "Vérifie périodiquement uniquement les canaux dont la désactivation automatique est activée, en excluant les canaux désactivés manuellement.",
"Periodically send ping frames to keep streaming connections active.": "Envoyer périodiquement des trames ping pour maintenir les connexions de streaming actives.",
"Permanently delete your account and all data": "Supprimer définitivement votre compte et toutes les données",
"Permit Passkey registration on non-HTTPS origins (only recommended for development)": "Autoriser l'enregistrement de Passkey sur des origines non-HTTPS (recommandé uniquement pour le développement)",
Expand Down Expand Up @@ -3673,6 +3681,7 @@
"Recommended to keep this high to avoid upstream throttling.": "Il est recommandé de maintenir cette valeur élevée pour éviter la limitation en amont.",
"Record IP Address": "Enregistrer l'adresse IP",
"Record quota usage": "Enregistrer l'utilisation du quota",
"Recover auto-disabled channels only": "Restaurer uniquement les canaux désactivés automatiquement",
"Recursion Strategy": "Stratégie de récursion",
"Recursive": "Récursif",
"Redeem": "Utiliser",
Expand Down
9 changes: 9 additions & 0 deletions web/src/i18n/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
"Active models": "アクティブなモデル",
"Active Tasks": "進行中のタスク",
"active users": "アクティブユーザー",
"Actively check all channels": "すべてのチャネルを定期チェック",
"Actively check auto-disable-enabled channels": "自動無効化が有効なチャネルを定期チェック",
Comment on lines +154 to +155

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the distinction between active and periodic checks.

The Japanese value 定期チェック means “periodically check,” not “actively check.” The same wording is already used for the separate periodic-check descriptions at Lines 3367-3368. Use wording such as 能動的にチェック so users can distinguish active probing from periodic scheduling.

Proposed fix
-    "Actively check all channels": "すべてのチャネルを定期チェック",
-    "Actively check auto-disable-enabled channels": "自動無効化が有効なチャネルを定期チェック",
+    "Actively check all channels": "すべてのチャネルを能動的にチェック",
+    "Actively check auto-disable-enabled channels": "自動無効化が有効なチャネルを能動的にチェック",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"Actively check all channels": "すべてのチャネルを定期チェック",
"Actively check auto-disable-enabled channels": "自動無効化が有効なチャネルを定期チェック",
"Actively check all channels": "すべてのチャネルを能動的にチェック",
"Actively check auto-disable-enabled channels": "自動無効化が有効なチャネルを能動的にチェック",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/i18n/locales/ja.json` around lines 154 - 155, Update the Japanese
translations for “Actively check all channels” and “Actively check
auto-disable-enabled channels” to use wording that conveys active probing, such
as 能動的にチェック, instead of 定期チェック. Leave the separate periodic-check descriptions
unchanged.

"Actual Amount": "実際の金額",
"Actual Model": "実際のモデル",
"Actual Model:": "実際のモデル:",
Expand Down Expand Up @@ -512,6 +514,8 @@
"Auto Sync Upstream Models": "アップストリームモデルの自動同期",
"Auto-disable rules": "自動無効化ルール",
"Auto-disable status codes": "自動無効化するステータスコード",
"Auto-disable-enabled channels only": "自動無効化が有効なチャネルのみ",
"Auto-disable-enabled mode probes non-manually-disabled channels with auto-disable enabled.": "このモードでは、自動無効化が有効で、手動で無効化されていないチャネルのみを検査します。",
"Auto-discover": "自動検出",
"Auto-discovers endpoints from the provider": "プロバイダーからエンドポイントを自動検出します",
"Auto-fill when one field exists and another is missing": "一方のフィールドがあり他方が欠けている場合に自動補完",
Expand Down Expand Up @@ -783,6 +787,7 @@
"Chat session management": "チャットセッション管理",
"ChatCompletions -> Responses Compatibility": "ChatCompletions → レスポンス互換",
"ChatGPT Subscription (Codex)": "ChatGPT Subscription (Codex)",
"Check channels awaiting recovery only": "復旧待ちのチャネルのみチェック",
"Check for updates": "更新を確認",
"Check in daily to receive random quota rewards": "毎日チェックインして、ランダムなノルマ報酬を受け取りましょう",
"Check in now": "今すぐチェックイン",
Expand Down Expand Up @@ -1437,6 +1442,7 @@
"Docs": "ドキュメント",
"Documentation Link": "ドキュメントリンク",
"Documentation or external knowledge base.": "ドキュメントまたは外部知識ベース。",
"Does not check healthy channels. It only rechecks auto-disabled channels and restores them after they recover.": "正常なチャネルはチェックしません。自動無効化されたチャネルのみを再チェックし、復旧後に再び有効化します。",
"does not exist or might have been removed.": "存在しないか、削除された可能性があります。",
"Domain": "ドメイン",
"Domain Filter Mode": "ドメインフィルターモード",
Expand Down Expand Up @@ -3358,6 +3364,8 @@
"Performed {{action}} on user {{username}} (ID: {{id}})": "ユーザー {{username}}(ID: {{id}})に対して {{action}} を実行しました",
"Period": "期間",
"Periodically check for upstream model changes": "アップストリームモデルの変更を定期的にチェック",
"Periodically checks all channels except manually disabled ones to detect failures and recover channels automatically.": "手動で無効化されたものを除くすべてのチャネルを定期チェックし、障害の検出と自動復旧を行います。",
"Periodically checks only channels with auto-disable enabled, excluding manually disabled channels.": "自動無効化が有効なチャネルのみを定期チェックします。手動で無効化されたチャネルは対象外です。",
"Periodically send ping frames to keep streaming connections active.": "ストリーミング接続をアクティブに保つために、定期的にpingフレームを送信します。",
"Permanently delete your account and all data": "アカウントとすべてのデータを永久に削除",
"Permit Passkey registration on non-HTTPS origins (only recommended for development)": "非HTTPSオリジンでのパスキー登録を許可する(開発でのみ推奨)",
Expand Down Expand Up @@ -3673,6 +3681,7 @@
"Recommended to keep this high to avoid upstream throttling.": "アップストリームのスロットリングを避けるため、これを高く保つことを推奨します。",
"Record IP Address": "IPアドレスを記録",
"Record quota usage": "クォータ使用量を記録",
"Recover auto-disabled channels only": "自動無効化されたチャネルの復旧のみ",
"Recursion Strategy": "再帰戦略",
"Recursive": "再帰",
"Redeem": "引き換え",
Expand Down
Loading
Loading