Files
Aether/frontend/src/api/requestTrace.ts
T

170 lines
5.2 KiB
TypeScript
Raw Normal View History

2025-12-10 20:52:44 +08:00
import apiClient from './client'
2026-04-27 17:16:30 +08:00
export interface CandidateRankingMetadata {
mode?: string
priority_mode?: string
index?: number
priority_slot?: number
promoted_by?: string
demoted_by?: string
}
2026-05-09 01:21:26 +08:00
export interface ImageProgress {
phase?: 'upstream_connecting' | 'upstream_streaming' | 'upstream_completed' | 'failed' | string
upstream_ttfb_ms?: number | null
upstream_sse_frame_count?: number | null
last_upstream_event?: string | null
last_upstream_frame_at_unix_ms?: number | null
partial_image_count?: number | null
last_client_visible_event?: string | null
downstream_heartbeat_count?: number | null
last_downstream_heartbeat_at_unix_ms?: number | null
downstream_heartbeat_interval_ms?: number | null
}
2026-05-09 10:46:04 +08:00
export interface CandidateResponseBoundary {
source?: string
status_code?: number | null
headers?: Record<string, unknown> | null
body?: unknown
body_ref?: string | null
body_state?: string | null
}
export interface CandidateProxyTiming {
body_read_ms?: number | null
decompress_ms?: number | null
wire_size?: number | null
body_size?: number | null
ttfb_ms?: number | null
upstream_ms?: number | null
response_wait_ms?: number | null
connection_acquire_ms?: number | null
upstream_processing_ms?: number | null
connect_ms?: number | null
tls_ms?: number | null
dns_ms?: number | null
total_ms?: number | null
connection_reused?: boolean | null
}
export interface CandidateProxy {
node_name?: string | null
node_id?: string | null
url?: string | null
source?: string | null
ttfb_ms?: number | null
timing?: CandidateProxyTiming | null
}
2025-12-10 20:52:44 +08:00
export interface CandidateRecord {
id: string
request_id: string
candidate_index: number
retry_index: number
provider_id?: string
provider_name?: string
provider_website?: string // Provider 官网
provider_priority?: number
provider_keep_priority_on_conversion?: boolean
provider_enable_format_conversion?: boolean
2025-12-10 20:52:44 +08:00
endpoint_id?: string
endpoint_name?: string // 端点显示名称(api_format)
endpoint_api_family?: string
endpoint_kind?: string
endpoint_format_acceptance_config?: Record<string, unknown> | null
2025-12-10 20:52:44 +08:00
key_id?: string
key_name?: string // 密钥名称
key_account_label?: string // 更适合展示的测试账号标签(优先 OAuth 邮箱)
key_preview?: string // 密钥脱敏预览(如 sk-***abc),OAuth 类型不返回
key_auth_type?: string // 密钥认证类型(api_key, service_account, oauth 等)
key_api_formats?: unknown
key_internal_priority?: number
key_global_priority_by_format?: Record<string, number> | null
key_oauth_plan_type?: string // OAuth 账号套餐类型(free/plus/team/enterprise)
2025-12-10 20:52:44 +08:00
key_capabilities?: Record<string, boolean> | null // Key 支持的能力
required_capabilities?: Record<string, boolean> | null // 请求实际需要的能力标签
status: 'pending' | 'streaming' | 'success' | 'failed' | 'skipped' | 'cancelled' | 'available' | 'unused' | 'stream_interrupted'
2025-12-10 20:52:44 +08:00
skip_reason?: string
is_cached: boolean
// 执行结果字段
status_code?: number
error_type?: string
error_message?: string
latency_ms?: number
concurrent_requests?: number
2026-04-27 17:16:30 +08:00
ranking?: CandidateRankingMetadata | null
2026-05-09 01:21:26 +08:00
image_progress?: ImageProgress | null
2026-05-09 10:46:04 +08:00
extra_data?: Record<string, unknown> & {
first_byte_time_ms?: number | null
needs_conversion?: boolean
provider_api_format?: string | null
proxy?: CandidateProxy | null
pool_selection?: {
reason: string
cost_soft_threshold?: number | boolean | null
cost_window_usage?: number | null
cost_limit?: number | null
} | null
pool_skip?: {
type: string
cooldown_reason?: string | null
cooldown_ttl?: number | null
cost_window_usage?: number | null
} | null
2026-05-09 10:46:04 +08:00
upstream_response?: CandidateResponseBoundary
image_progress?: ImageProgress | null
2026-05-09 10:46:04 +08:00
}
2025-12-10 20:52:44 +08:00
created_at: string
started_at?: string
finished_at?: string
}
export interface RequestTrace {
request_id: string
2026-05-09 10:46:04 +08:00
request_path?: string
request_query_string?: string
request_path_and_query?: string
2025-12-10 20:52:44 +08:00
total_candidates: number
final_status: 'success' | 'failed' | 'streaming' | 'pending' | 'cancelled'
2025-12-10 20:52:44 +08:00
total_latency_ms: number
candidates: CandidateRecord[]
}
export interface ProviderStats {
total_attempts: number
success_count: number
failed_count: number
cancelled_count: number
2025-12-10 20:52:44 +08:00
skipped_count: number
pending_count: number
available_count: number
failure_rate: number
}
export const requestTraceApi = {
/**
* 获取特定请求的完整追踪信息
*/
async getRequestTrace(
requestId: string,
options: { attemptedOnly?: boolean } = {},
): Promise<RequestTrace> {
const attemptedOnly = options.attemptedOnly ?? false
const response = await apiClient.get<RequestTrace>(`/api/admin/monitoring/trace/${requestId}`, {
params: { attempted_only: attemptedOnly },
})
2025-12-10 20:52:44 +08:00
return response.data
},
/**
* 获取某个 Provider 的失败率统计
*/
async getProviderStats(providerId: string, limit: number = 100): Promise<ProviderStats> {
const response = await apiClient.get<ProviderStats>(`/api/admin/monitoring/trace/stats/provider/${providerId}`, {
params: { limit }
})
return response.data
}
}