Expose local scheduling failures in usage UI

This commit is contained in:
MMEXA
2026-05-18 16:28:37 +00:00
parent d51b44d642
commit 4317ff78b1
15 changed files with 620 additions and 24 deletions
@@ -73,6 +73,43 @@ describe('request failure notice', () => {
})
})
it('includes scheduling failure provider and endpoint hints in metadata', () => {
const notice = resolveRequestFailureNotice(buildRequestDetail({
failure_summary: {
status_code: 503,
message: '没有可用提供商支持模型 gemma-4-31b-it 的同步请求',
},
scheduling_failure: {
source: 'local_execution_runtime_miss',
reason: 'all_candidates_skipped',
reason_label: '所有候选均被跳过',
title: '本地调度失败:所有候选均被跳过',
message: '没有可用提供商支持模型 gemma-4-31b-it 的同步请求',
status_code: 503,
no_upstream_attempt: true,
requested_model: 'gemma-4-31b-it',
provider_hint: {
id: 'provider-google-api',
name: 'Google API',
},
endpoint_hint: {
id: 'endpoint-gemini',
api_format: 'gemini:generate_content',
},
} as NonNullable<RequestDetail['scheduling_failure']>,
}))
expect(notice?.meta).toEqual([
'Google API',
'gemini:generate_content',
'gemma-4-31b-it',
'所有候选均被跳过',
'all_candidates_skipped',
'HTTP 503',
'未进入上游执行',
])
})
it('falls back to the failure summary for upstream failures', () => {
const notice = resolveRequestFailureNotice(buildRequestDetail({
failure_summary: {
@@ -25,6 +25,11 @@ function uniqueMeta(values: Array<string | null | undefined>): string[] {
return Array.from(new Set(values.map(value => value?.trim()).filter((value): value is string => Boolean(value))))
}
function isUnknownProviderHint(value: string | null): boolean {
const normalized = value?.trim().toLowerCase()
return !normalized || ['unknown', 'unknow', 'pending'].includes(normalized)
}
function schedulingFailureMessage(
failure: RequestSchedulingFailure,
fallbackDomain: RequestErrorDomain | null,
@@ -37,6 +42,21 @@ function schedulingFailureMessage(
?? nonEmptyString(failure.reason)
}
function schedulingFailureProviderHint(failure: RequestSchedulingFailure): string | null {
const name = nonEmptyString(failure.provider_hint?.name)
if (name && !isUnknownProviderHint(name)) return name
const id = nonEmptyString(failure.provider_hint?.id)
if (id && !isUnknownProviderHint(id)) return id
return null
}
function schedulingFailureEndpointHint(failure: RequestSchedulingFailure): string | null {
return nonEmptyString(failure.endpoint_hint?.api_format)
?? nonEmptyString(failure.endpoint_hint?.id)
}
export function resolveRequestFailureNotice(detail: RequestDetail | null | undefined): RequestFailureNotice | null {
if (!detail) return null
@@ -55,6 +75,9 @@ export function resolveRequestFailureNotice(detail: RequestDetail | null | undef
message,
isSchedulingFailure: true,
meta: uniqueMeta([
schedulingFailureProviderHint(schedulingFailure),
schedulingFailureEndpointHint(schedulingFailure),
nonEmptyString(schedulingFailure.requested_model),
nonEmptyString(schedulingFailure.reason_summary),
nonEmptyString(schedulingFailure.reason_label),
nonEmptyString(schedulingFailure.reason),