Merge remote-tracking branch 'origin/aether-rust-pioneer' into payment-billing-plans

# Conflicts:
#	crates/aether-data/src/lifecycle/bootstrap/postgres.rs
#	crates/aether-data/src/lifecycle/migrate/tests.rs
This commit is contained in:
Entropy.Xu
2026-05-13 01:29:18 +08:00
185 changed files with 14980 additions and 3638 deletions

View File

@@ -1,6 +1,7 @@
import apiClient from './client'
import { cachedRequest, buildCacheKey } from '@/utils/cache'
import type { BillingSummary } from './auth'
import type { ApiKeyInstallSession, InstallSessionTargetSystem, InstallTargetCli } from './me'
// LDAP 配置导出结构
export interface LDAPConfigExport {
@@ -678,6 +679,18 @@ export const adminApi = {
return response.data
},
// 创建独立余额 Key 的 CLI 安装会话
async createApiKeyInstallSession(
keyId: string,
data: { target_cli: InstallTargetCli; target_system: InstallSessionTargetSystem }
): Promise<ApiKeyInstallSession> {
const response = await apiClient.post<ApiKeyInstallSession>(
`/api/admin/api-keys/${keyId}/install-sessions`,
data
)
return response.data
},
// 系统配置相关
// 获取所有系统配置
async getAllSystemConfigs(): Promise<Array<{ key: string; value: unknown; description?: string }>> {

View File

@@ -132,6 +132,7 @@ export interface PoolKeyDetail {
quota_updated_at?: number | null
health_score?: number
circuit_breaker_open?: boolean
pool_score?: PoolKeyScoreDetail | null
api_formats?: string[]
rate_multipliers?: Record<string, number> | null
internal_priority?: number
@@ -192,6 +193,69 @@ export interface PoolKeysPageResponse {
keys: PoolKeyDetail[]
}
export interface PoolKeyScoreDetail {
id: string
capability: string
scope_kind: string
scope_id: string | null
score: number
hard_state: PoolScoreHardState
score_version: number
score_reason: Record<string, unknown> | null
last_ranked_at: number | null
last_scheduled_at: number | null
last_success_at: number | null
last_failure_at: number | null
failure_count: number
last_probe_attempt_at: number | null
last_probe_success_at: number | null
last_probe_failure_at: number | null
probe_failure_count: number
probe_status: PoolScoreProbeStatus
updated_at: number
}
export type PoolScoreHardState =
| 'available'
| 'unknown'
| 'cooldown'
| 'quota_exhausted'
| 'auth_invalid'
| 'banned'
| 'inactive'
export type PoolScoreProbeStatus = 'never' | 'ok' | 'failed' | 'stale' | 'in_progress'
export interface PoolScoreKeySummary {
id: string
name: string
auth_type: string
is_active: boolean
internal_priority: number
last_used_at: number | null
}
export interface PoolMemberScoreItem extends PoolKeyScoreDetail {
pool_kind: string
pool_id: string
member_kind: string
member_id: string
key?: PoolScoreKeySummary | null
}
export interface PoolScoresResponse {
provider_id: string
page: number
page_size: number
filters: {
api_format?: string | null
model_id?: string | null
hard_state?: string | null
probe_status?: string | null
}
items: PoolMemberScoreItem[]
}
export interface PoolKeysQuery {
page?: number
page_size?: number
@@ -203,6 +267,15 @@ export interface PoolKeysQuery {
sort_order?: 'asc' | 'desc'
}
export interface PoolScoresQuery {
page?: number
page_size?: number
api_format?: string
model_id?: string
hard_state?: string
probe_status?: string
}
export interface PoolKeySelectionRequest {
search?: string
quick_selectors?: string[]
@@ -293,6 +366,29 @@ export async function listPoolKeys(
)
}
export async function listPoolScores(
providerId: string,
params: PoolScoresQuery = {},
options: PoolReadOptions = {},
): Promise<PoolScoresResponse> {
const normalizedParams = { ...params }
const cacheKey = buildCacheKey(
`pool:scores:${providerId}`,
normalizedParams as Record<string, unknown>,
)
return cachedRequest(
cacheKey,
async () => {
const response = await client.get<PoolScoresResponse>(
`/api/admin/pool/${providerId}/scores`,
{ params: normalizedParams },
)
return response.data
},
options.cacheTtlMs ?? 0,
)
}
export async function resolvePoolKeySelection(
providerId: string,
body: PoolKeySelectionRequest,

View File

@@ -521,6 +521,24 @@ export interface SchedulingPresetItem {
mode?: string | null
}
export interface PoolScoreWeights {
manual_priority?: number | null
health?: number | null
probe_freshness?: number | null
quota_remaining?: number | null
latency?: number | null
cost_lru?: number | null
}
export interface PoolScoreRules {
weights?: PoolScoreWeights | null
probe_freshness_ttl_seconds?: number | null
unschedulable_score_cap?: number | null
probe_failure_penalty?: number | null
request_failure_penalty?: number | null
probe_failure_cooldown_threshold?: number | null
}
export interface PoolAdvancedConfig {
global_priority?: number | null
sticky_session_ttl_seconds?: number | null
@@ -548,6 +566,10 @@ export interface PoolAdvancedConfig {
health_policy_enabled?: boolean
unschedulable_rules?: Array<Record<string, unknown>> | null
batch_concurrency?: number | null
probe_concurrency?: number | null
score_top_n?: number | null
score_fallback_scan_limit?: number | null
score_rules?: PoolScoreRules | null
probing_enabled?: boolean
probing_interval_minutes?: number | null
auto_remove_banned_keys?: boolean

View File

@@ -173,6 +173,7 @@ export interface ApiKey {
export type InstallTargetCli = 'claude_code' | 'codex_cli' | 'gemini_cli'
export type InstallTargetSystem = 'macos' | 'linux' | 'windows' | 'auto'
export type InstallSessionTargetSystem = Exclude<InstallTargetSystem, 'auto'>
export interface ApiKeyInstallSession {
install_code: string
@@ -287,7 +288,7 @@ export const meApi = {
async createApiKeyInstallSession(
keyId: string,
data: { target_cli: InstallTargetCli; target_system: InstallTargetSystem }
data: { target_cli: InstallTargetCli; target_system: InstallSessionTargetSystem }
): Promise<ApiKeyInstallSession> {
const response = await apiClient.post<ApiKeyInstallSession>(
`/api/users/me/api-keys/${keyId}/install-sessions`,