fix: preserve provider auth metadata

This commit is contained in:
elky
2026-06-20 22:11:42 +08:00
parent 1123095bb7
commit f1c30439ff
51 changed files with 2098 additions and 420 deletions
@@ -436,6 +436,38 @@ export function useUsageData(options: UseUsageDataOptions) {
return existingValue ?? nextValue
}
function mergeSparseRecordMetric(
existingValue: number | null | undefined,
nextValue: number | null | undefined
): number | null | undefined {
const existingIsPositive = typeof existingValue === 'number' && Number.isFinite(existingValue) && existingValue > 0
const nextIsPositive = typeof nextValue === 'number' && Number.isFinite(nextValue) && nextValue > 0
if (nextIsPositive) {
return nextValue
}
if (existingIsPositive) {
return existingValue
}
return existingValue ?? nextValue
}
function mergeBooleanTrueWins(
existingValue: boolean | null | undefined,
nextValue: boolean | null | undefined
): boolean | undefined {
if (existingValue === true || nextValue === true) {
return true
}
if (typeof nextValue === 'boolean') {
return nextValue
}
if (typeof existingValue === 'boolean') {
return existingValue
}
return undefined
}
function mergeRecordStatus(
current: UsageRecord[],
next: UsageRecord[]
@@ -466,104 +498,94 @@ export function useUsageData(options: UseUsageDataOptions) {
(nextRank === currentRank && existing.status === record.status)
)
const mergedStatus = statusProgressed ? record.status : existing.status
const protectStatus = mergedStatus !== record.status
// 确定是否需要保护 provider(避免 pending/unknown/unknow 覆盖已有的正确值)
const isPendingProvider = !isUsageProviderVisible(record.provider)
const hasValidExistingProvider = isUsageProviderVisible(existing.provider)
const protectProvider = isPendingProvider && hasValidExistingProvider
// 如果需要保护状态,说明本地数据比后端更新,应该保留本地的所有实时更新字段
if (protectStatus) {
const recordUpstreamIsStream = typeof record.upstream_is_stream === 'boolean'
? record.upstream_is_stream
: typeof record.is_stream === 'boolean'
? record.is_stream
: undefined
const existingUpstreamIsStream = typeof existing.upstream_is_stream === 'boolean'
? existing.upstream_is_stream
: typeof existing.is_stream === 'boolean'
? existing.is_stream
: undefined
const upstreamIsStream = recordUpstreamIsStream ?? existingUpstreamIsStream ?? false
const recordUpstreamIsStream = typeof record.upstream_is_stream === 'boolean'
? record.upstream_is_stream
: typeof record.is_stream === 'boolean'
? record.is_stream
: undefined
const existingUpstreamIsStream = typeof existing.upstream_is_stream === 'boolean'
? existing.upstream_is_stream
: typeof existing.is_stream === 'boolean'
? existing.is_stream
: undefined
const upstreamIsStream = mergeBooleanTrueWins(existingUpstreamIsStream, recordUpstreamIsStream) ?? false
const recordClientRequestedStream = typeof record.client_requested_stream === 'boolean'
? record.client_requested_stream
: typeof record.client_is_stream === 'boolean'
? record.client_is_stream
: undefined
const existingClientRequestedStream = typeof existing.client_requested_stream === 'boolean'
? existing.client_requested_stream
: typeof existing.client_is_stream === 'boolean'
? existing.client_is_stream
: undefined
const clientRequestedStream = recordClientRequestedStream ?? existingClientRequestedStream
const recordClientIsStream = typeof record.client_is_stream === 'boolean'
const recordClientRequestedStream = typeof record.client_requested_stream === 'boolean'
? record.client_requested_stream
: typeof record.client_is_stream === 'boolean'
? record.client_is_stream
: typeof record.client_requested_stream === 'boolean'
? record.client_requested_stream
: undefined
const existingClientIsStream = typeof existing.client_is_stream === 'boolean'
: undefined
const existingClientRequestedStream = typeof existing.client_requested_stream === 'boolean'
? existing.client_requested_stream
: typeof existing.client_is_stream === 'boolean'
? existing.client_is_stream
: typeof existing.client_requested_stream === 'boolean'
? existing.client_requested_stream
: undefined
const clientIsStream = recordClientIsStream ?? existingClientIsStream ?? clientRequestedStream
: undefined
const clientRequestedStream = mergeBooleanTrueWins(existingClientRequestedStream, recordClientRequestedStream)
return {
...record,
// 保留本地的状态和所有通过轮询更新的字段
status: mergedStatus,
provider: protectProvider ? existing.provider : (record.provider || existing.provider),
input_tokens: Number.isFinite(record.input_tokens)
? record.input_tokens
: existing.input_tokens,
effective_input_tokens: record.effective_input_tokens ?? existing.effective_input_tokens,
output_tokens: existing.output_tokens || record.output_tokens,
cache_creation_input_tokens: existing.cache_creation_input_tokens ?? record.cache_creation_input_tokens,
cache_creation_ephemeral_5m_input_tokens:
existing.cache_creation_ephemeral_5m_input_tokens
?? record.cache_creation_ephemeral_5m_input_tokens,
cache_creation_ephemeral_1h_input_tokens:
existing.cache_creation_ephemeral_1h_input_tokens
?? record.cache_creation_ephemeral_1h_input_tokens,
cache_read_input_tokens: existing.cache_read_input_tokens ?? record.cache_read_input_tokens,
cost: existing.cost || record.cost,
actual_cost: existing.actual_cost ?? record.actual_cost,
response_time_ms: mergePositiveDurationMs(existing.response_time_ms, record.response_time_ms),
first_byte_time_ms: mergePositiveDurationMs(existing.first_byte_time_ms, record.first_byte_time_ms),
updated_at: existing.updated_at ?? record.updated_at,
response_time_updated_at: existing.response_time_updated_at ?? record.response_time_updated_at,
status_code: existing.status_code ?? record.status_code,
error_message: existing.error_message ?? record.error_message,
image_progress: existing.image_progress ?? record.image_progress,
is_stream: upstreamIsStream,
upstream_is_stream: upstreamIsStream,
client_requested_stream: clientRequestedStream,
client_is_stream: clientIsStream,
api_format: existing.api_format || record.api_format,
endpoint_api_format: existing.endpoint_api_format || record.endpoint_api_format,
has_format_conversion: existing.has_format_conversion ?? record.has_format_conversion,
has_fallback: existing.has_fallback === true || record.has_fallback === true,
api_key_name: existing.api_key_name || record.api_key_name,
provider_key_name: existing.provider_key_name || record.provider_key_name,
rate_multiplier: existing.rate_multiplier ?? record.rate_multiplier,
target_model: existing.target_model || record.target_model,
reasoning_effort: existing.reasoning_effort || record.reasoning_effort,
service_tier: existing.service_tier || record.service_tier
}
const recordClientIsStream = typeof record.client_is_stream === 'boolean'
? record.client_is_stream
: typeof record.client_requested_stream === 'boolean'
? record.client_requested_stream
: undefined
const existingClientIsStream = typeof existing.client_is_stream === 'boolean'
? existing.client_is_stream
: typeof existing.client_requested_stream === 'boolean'
? existing.client_requested_stream
: undefined
const clientIsStream = mergeBooleanTrueWins(existingClientIsStream, recordClientIsStream) ?? clientRequestedStream
return {
...record,
// 保留详情抽屉/活跃轮询已经拿到的完整指标,避免列表刷新用 0 或空值回退。
status: mergedStatus,
provider: protectProvider ? existing.provider : (record.provider || existing.provider),
input_tokens: mergeSparseRecordMetric(existing.input_tokens, record.input_tokens) ?? record.input_tokens,
effective_input_tokens: mergeSparseRecordMetric(existing.effective_input_tokens, record.effective_input_tokens) ?? record.effective_input_tokens,
output_tokens: mergeSparseRecordMetric(existing.output_tokens, record.output_tokens) ?? record.output_tokens,
total_tokens: mergeSparseRecordMetric(existing.total_tokens, record.total_tokens) ?? record.total_tokens,
cache_creation_input_tokens: mergeSparseRecordMetric(existing.cache_creation_input_tokens, record.cache_creation_input_tokens) ?? record.cache_creation_input_tokens,
cache_creation_ephemeral_5m_input_tokens:
mergeSparseRecordMetric(
existing.cache_creation_ephemeral_5m_input_tokens,
record.cache_creation_ephemeral_5m_input_tokens
) ?? record.cache_creation_ephemeral_5m_input_tokens,
cache_creation_ephemeral_1h_input_tokens:
mergeSparseRecordMetric(
existing.cache_creation_ephemeral_1h_input_tokens,
record.cache_creation_ephemeral_1h_input_tokens
) ?? record.cache_creation_ephemeral_1h_input_tokens,
cache_read_input_tokens: mergeSparseRecordMetric(existing.cache_read_input_tokens, record.cache_read_input_tokens) ?? record.cache_read_input_tokens,
cost: mergeSparseRecordMetric(existing.cost, record.cost) ?? record.cost,
actual_cost: mergeSparseRecordMetric(existing.actual_cost, record.actual_cost) ?? record.actual_cost,
response_time_ms: mergePositiveDurationMs(existing.response_time_ms, record.response_time_ms),
first_byte_time_ms: mergePositiveDurationMs(existing.first_byte_time_ms, record.first_byte_time_ms),
updated_at: record.updated_at ?? existing.updated_at,
response_time_updated_at: record.response_time_updated_at ?? existing.response_time_updated_at,
status_code: record.status_code ?? existing.status_code,
error_message: record.error_message ?? existing.error_message,
image_progress: record.image_progress ?? existing.image_progress,
is_stream: upstreamIsStream,
upstream_is_stream: upstreamIsStream,
client_requested_stream: clientRequestedStream,
client_is_stream: clientIsStream,
api_format: record.api_format || existing.api_format,
endpoint_api_format: record.endpoint_api_format || existing.endpoint_api_format,
has_format_conversion: record.has_format_conversion ?? existing.has_format_conversion,
has_fallback: existing.has_fallback === true || record.has_fallback === true,
has_retry: existing.has_retry === true || record.has_retry === true,
api_key_name: record.api_key_name || existing.api_key_name,
provider_key_name: record.provider_key_name || existing.provider_key_name,
rate_multiplier: record.rate_multiplier ?? existing.rate_multiplier,
target_model: record.target_model ?? existing.target_model,
reasoning_effort: record.reasoning_effort ?? existing.reasoning_effort,
service_tier: record.service_tier ?? existing.service_tier
}
// 只需要保护 provider
if (protectProvider) {
return {
...record,
provider: existing.provider
}
}
return record
})
}