修复 Gemini 空输出按候选重试处理

This commit is contained in:
MMEXA
2026-07-09 23:10:30 +08:00
parent 7bc7d0f8d8
commit d2ea437c1c
5 changed files with 385 additions and 30 deletions
@@ -305,6 +305,9 @@ pub(super) fn admin_usage_terminal_candidate_state_override(
candidates: &[StoredRequestCandidate],
) -> Option<serde_json::Value> {
let candidate = admin_usage_current_candidate(candidates)?;
if admin_usage_candidate_failure_is_retryable_transition(candidate) {
return None;
}
let status = match candidate.status {
RequestCandidateStatus::Success => "completed",
@@ -343,6 +346,30 @@ pub(super) fn admin_usage_terminal_candidate_state_override(
Some(payload)
}
fn admin_usage_candidate_failure_is_retryable_transition(
candidate: &StoredRequestCandidate,
) -> bool {
if candidate.status != RequestCandidateStatus::Failed {
return false;
}
let Some(error_flow) = candidate
.extra_data
.as_ref()
.and_then(|value| value.get("error_flow"))
else {
return false;
};
let retryable = error_flow
.get("retryable")
.and_then(serde_json::Value::as_bool)
.unwrap_or(false);
let retry_next_candidate = error_flow
.get("decision")
.and_then(serde_json::Value::as_str)
.is_some_and(|value| value == "retry_next_candidate");
retryable && retry_next_candidate
}
pub(super) fn apply_admin_usage_state_override(
item: &mut StoredRequestUsageAudit,
override_payload: &serde_json::Value,
@@ -998,6 +1025,7 @@ mod tests {
use aether_data_contracts::repository::candidates::{
RequestCandidateStatus, StoredRequestCandidate,
};
use serde_json::json;
use super::admin_usage_terminal_candidate_state_override;
@@ -1076,4 +1104,27 @@ mod tests {
assert!(payload.is_none());
}
#[test]
fn admin_usage_active_override_ignores_retryable_candidate_failure() {
let mut failed = sample_candidate(
0,
RequestCandidateStatus::Failed,
Some(502),
Some(1_000),
Some("provider returned HTTP 200 without visible model output"),
);
failed.extra_data = Some(json!({
"error_flow": {
"decision": "retry_next_candidate",
"retryable": true,
"propagation": "suppressed",
"classification": "retry_upstream_failure"
}
}));
let payload = admin_usage_terminal_candidate_state_override(&[failed]);
assert!(payload.is_none());
}
}