mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 09:57:47 +08:00
99 lines
5.1 KiB
TypeScript
99 lines
5.1 KiB
TypeScript
/**
|
|||
|
|
* 候选"被跳过"原因的中文标签。
|
||
|
|
*
|
||
|
|
* 这些字符串来自后端 `StoredRequestCandidate.skip_reason`,取值受
|
||
|
|
* `crates/aether-data/contracts/src/repository/candidates/types.rs` 里的
|
||
|
|
* `REQUEST_CANDIDATE_SKIP_REASONS` 白名单约束(未知原因会被后端统一清洗成
|
||
|
|
* `unclassified_candidate_skip_reason`)。
|
||
|
|
*
|
||
|
|
* 维护约定:后端新增白名单项时,这里补一条中文说明;缺失时前端会原样显示英文,
|
||
|
|
* 不会丢信息,所以可以安全地"先上线原因、后补翻译"。
|
||
|
|
*/
|
||
|
|
export const CANDIDATE_SKIP_REASON_LABELS: Record<string, string> = {
|
||
|
|
// —— 调度期运行时可选择性(不满足条件,从未真正发起请求)——
|
||
|
|
account_quota_exhausted: '账号额度已耗尽',
|
||
|
|
oauth_invalid: 'OAuth 凭证已失效',
|
||
|
|
provider_quota_blocked: '上游提供商额度已用尽',
|
||
|
|
provider_concurrency_limit_reached: '上游提供商并发已达上限',
|
||
|
|
provider_key_concurrency_limit_reached: '上游账号并发已达上限',
|
||
|
|
provider_inactive: '提供商已停用',
|
||
|
|
key_inactive: '密钥已停用',
|
||
|
|
key_circuit_open: '密钥熔断中(连续失败后暂停)',
|
||
|
|
key_health_score_zero: '密钥健康分为 0',
|
||
|
|
key_rpm_exhausted: '密钥本分钟请求数已达上限',
|
||
|
|
key_model_disabled: '该密钥已停用此模型',
|
||
|
|
key_model_not_allowed: '该密钥不允许使用此模型',
|
||
|
|
key_api_format_disabled: '该密钥已停用此 API 格式',
|
||
|
|
api_key_concurrency_limit_reached: '调用方 API Key 并发已达上限',
|
||
|
|
auth_api_key_concurrency_limit_reached: '调用方 API Key 并发已达上限',
|
||
|
|
|
||
|
|
// —— 传输与路由策略门(在真正发请求前就被拦下)——
|
||
|
|
auth_channel_mismatch: '鉴权通道不匹配',
|
||
|
|
auth_snapshot_missing: '缺少该密钥的鉴权快照',
|
||
|
|
endpoint_api_format_changed: '端点 API 格式已变更',
|
||
|
|
endpoint_inactive: '端点已停用',
|
||
|
|
format_conversion_disabled: '该提供商未开启格式转换',
|
||
|
|
mapped_model_missing: '缺少映射后的上游模型',
|
||
|
|
routing_profile_disallowed_key: '路由策略未允许该密钥',
|
||
|
|
routing_profile_disallowed_provider: '路由策略未允许该提供商',
|
||
|
|
upstream_url_missing: '缺少上游地址',
|
||
|
|
gemini_file_mapping_mismatch: 'Gemini 文件映射不匹配',
|
||
|
|
provider_request_body_build_failed: '上游请求体转换失败',
|
||
|
|
provider_request_body_missing: '无法构建上游请求体',
|
||
|
|
|
||
|
|
// —— transport_* 系列:该提供商/端点不支持当前这种转发方式 ——
|
||
|
|
transport_unsupported: '该传输方式不受支持',
|
||
|
|
transport_api_format_mismatch: 'API 格式与端点不匹配',
|
||
|
|
transport_api_format_unsupported: '不支持该 API 格式',
|
||
|
|
transport_auth_unavailable: '无法获取可用鉴权',
|
||
|
|
transport_body_rules_apply_failed: '请求体改写规则执行失败',
|
||
|
|
transport_body_rules_unsupported: '不支持请求体改写规则',
|
||
|
|
transport_body_rules_unsupported_for_binary_upload: '二进制上传不支持请求体改写规则',
|
||
|
|
transport_custom_path_unsupported: '不支持自定义路径',
|
||
|
|
transport_endpoint_kind_unsupported: '不支持该端点类型',
|
||
|
|
transport_header_rules_apply_failed: '请求头改写规则执行失败',
|
||
|
|
transport_header_rules_unsupported: '不支持请求头改写规则',
|
||
|
|
transport_oauth_resolution_unsupported: '不支持该 OAuth 解析方式',
|
||
|
|
transport_operation_unsupported: '不支持该操作类型',
|
||
|
|
transport_profile_unsupported: '不支持该传输配置',
|
||
|
|
transport_provider_type_unsupported: '不支持该提供商类型',
|
||
|
|
transport_proxy_or_profile_unsupported: '不支持代理或传输配置',
|
||
|
|
transport_proxy_unsupported: '不支持该代理',
|
||
|
|
transport_snapshot_missing: '缺少传输快照',
|
||
|
|
|
||
|
|
// —— 号池(pool)相关 ——
|
||
|
|
pool_group_exhausted: '号池已无可用账号',
|
||
|
|
pool_account_blocked: '号池账号已被封禁',
|
||
|
|
pool_account_exhausted: '号池账号额度已耗尽',
|
||
|
|
pool_active_probe_sealed: '号池探测中,暂不分配',
|
||
|
|
pool_cooldown: '号池账号冷却中',
|
||
|
|
pool_cost_limit_reached: '号池费用已达上限',
|
||
|
|
pool_key_lease_busy: '池内账号正被其他请求占用',
|
||
|
|
pool_score_member_missing: '号池评分成员缺失',
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 后端无法归类时使用的占位原因。 */
|
||
|
|
export const UNCLASSIFIED_CANDIDATE_SKIP_REASON = 'unclassified_candidate_skip_reason'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 把候选跳过原因转成中文展示文案。
|
||
|
|
*
|
||
|
|
* 命中已知标签时返回中文;否则原样返回后端字符串(便于排查新原因),
|
||
|
|
* 空值返回空字符串,调用方据此判断是否展示。
|
||
|
|
*/
|
||
|
|
export function formatCandidateSkipReason(reason?: string | null): string {
|
||
|
|
const normalized = typeof reason === 'string' ? reason.trim() : ''
|
||
|
|
if (!normalized) return ''
|
||
|
|
return CANDIDATE_SKIP_REASON_LABELS[normalized] ?? normalized
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 是否为"根本没有向上游发起请求"的跳过状态。 */
|
||
|
|
export function isSkippedCandidateStatus(status?: string | null): boolean {
|
||
|
|
return status === 'skipped'
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 是否为"被枚举出来但从未尝试"的候选状态(含跳过与未使用)。 */
|
||
|
|
export function isNonAttemptedCandidateStatus(status?: string | null): boolean {
|
||
|
|
return status === 'skipped' || status === 'available' || status === 'unused'
|
||
|
|
}
|