mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 18:37:46 +08:00
feat(codex): align Search and execution protocol
This commit is contained in:
@@ -92,7 +92,10 @@ pub(crate) fn classify_local_failover(
|
||||
return LocalFailoverClassification::RetryStatusCode;
|
||||
}
|
||||
|
||||
if should_failover_local_upstream_status(input.status_code) {
|
||||
if should_failover_local_upstream_status(
|
||||
input.status_code,
|
||||
policy.retry_client_errors_by_default,
|
||||
) {
|
||||
return LocalFailoverClassification::RetryUpstreamFailure;
|
||||
}
|
||||
|
||||
@@ -109,8 +112,11 @@ pub(crate) fn local_failover_error_message(response_text: Option<&str>) -> Optio
|
||||
.filter(|value| !value.is_empty())
|
||||
}
|
||||
|
||||
fn should_failover_local_upstream_status(status_code: u16) -> bool {
|
||||
status_code >= 400
|
||||
fn should_failover_local_upstream_status(
|
||||
status_code: u16,
|
||||
retry_client_errors_by_default: bool,
|
||||
) -> bool {
|
||||
status_code >= 500 || status_code >= 400 && retry_client_errors_by_default
|
||||
}
|
||||
|
||||
fn local_error_response_has_cyber_policy_code(response_text: Option<&str>) -> bool {
|
||||
@@ -474,6 +480,39 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifier_passes_through_client_errors_when_protocol_default_disables_failover() {
|
||||
let policy = LocalFailoverPolicy {
|
||||
retry_client_errors_by_default: false,
|
||||
..LocalFailoverPolicy::default()
|
||||
};
|
||||
|
||||
for status_code in [400, 401, 429, 499] {
|
||||
assert_eq!(
|
||||
classify_local_failover(&policy, LocalFailoverInput::new(status_code, None)),
|
||||
LocalFailoverClassification::UseDefault
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
classify_local_failover(&policy, LocalFailoverInput::new(500, None)),
|
||||
LocalFailoverClassification::RetryUpstreamFailure
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifier_explicit_continue_rule_overrides_protocol_client_error_default() {
|
||||
let policy = LocalFailoverPolicy {
|
||||
continue_status_codes: [429].into_iter().collect(),
|
||||
retry_client_errors_by_default: false,
|
||||
..LocalFailoverPolicy::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
classify_local_failover(&policy, LocalFailoverInput::new(429, None)),
|
||||
LocalFailoverClassification::RetryStatusCode
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifier_keeps_embedded_rate_limit_error_in_success_response_on_default_path() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -243,7 +243,11 @@ fn local_client_session_affinity(report_context: Option<&Value>) -> Option<Clien
|
||||
.get("original_request_body")
|
||||
.filter(|value| !value.is_null());
|
||||
|
||||
crate::client_session_affinity::client_session_affinity_from_request(&headers, body_json)
|
||||
crate::client_session_affinity::client_session_affinity_from_api_request(
|
||||
report_context_string_field(Some(report_context), "client_api_format").unwrap_or_default(),
|
||||
&headers,
|
||||
body_json,
|
||||
)
|
||||
}
|
||||
|
||||
fn header_map_from_report_context(headers: Option<&Value>) -> http::HeaderMap {
|
||||
|
||||
@@ -7,7 +7,7 @@ use tracing::debug;
|
||||
use crate::provider_transport::GatewayProviderTransportSnapshot;
|
||||
use crate::AppState;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct LocalFailoverPolicy {
|
||||
pub(crate) max_retries: Option<u64>,
|
||||
pub(crate) stop_status_codes: BTreeSet<u16>,
|
||||
@@ -15,6 +15,21 @@ pub(crate) struct LocalFailoverPolicy {
|
||||
pub(crate) success_failover_patterns: Vec<LocalFailoverRegexRule>,
|
||||
pub(crate) error_stop_patterns: Vec<LocalFailoverRegexRule>,
|
||||
pub(crate) stop_cyber_policy_errors: bool,
|
||||
pub(crate) retry_client_errors_by_default: bool,
|
||||
}
|
||||
|
||||
impl Default for LocalFailoverPolicy {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_retries: None,
|
||||
stop_status_codes: BTreeSet::new(),
|
||||
continue_status_codes: BTreeSet::new(),
|
||||
success_failover_patterns: Vec::new(),
|
||||
error_stop_patterns: Vec::new(),
|
||||
stop_cyber_policy_errors: false,
|
||||
retry_client_errors_by_default: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -81,6 +96,10 @@ pub(crate) fn local_failover_policy_from_transport(
|
||||
|
||||
LocalFailoverPolicy {
|
||||
max_retries,
|
||||
retry_client_errors_by_default:
|
||||
aether_ai_formats::api_format_defaults_to_client_error_failover(
|
||||
&transport.endpoint.api_format,
|
||||
),
|
||||
stop_cyber_policy_errors: codex_cyber_flag_passthrough_enabled(
|
||||
&transport.provider.provider_type,
|
||||
transport.provider.config.as_ref(),
|
||||
@@ -144,6 +163,10 @@ pub(crate) fn local_failover_policy_from_report_context(
|
||||
.get("stop_cyber_policy_errors")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false),
|
||||
retry_client_errors_by_default: object
|
||||
.get("retry_client_errors_by_default")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(true),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -178,6 +201,7 @@ fn local_failover_policy_to_value(policy: &LocalFailoverPolicy) -> Value {
|
||||
"success_failover_patterns": policy.success_failover_patterns.iter().map(local_failover_regex_rule_to_value).collect::<Vec<_>>(),
|
||||
"error_stop_patterns": policy.error_stop_patterns.iter().map(local_failover_regex_rule_to_value).collect::<Vec<_>>(),
|
||||
"stop_cyber_policy_errors": policy.stop_cyber_policy_errors,
|
||||
"retry_client_errors_by_default": policy.retry_client_errors_by_default,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -375,10 +399,26 @@ mod tests {
|
||||
status_codes: [422].into_iter().collect(),
|
||||
}],
|
||||
stop_cyber_policy_errors: false,
|
||||
retry_client_errors_by_default: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_transport_disables_default_client_error_failover() {
|
||||
let mut transport = sample_transport(None, None, None);
|
||||
transport.endpoint.api_format = "openai:search".to_string();
|
||||
let policy = local_failover_policy_from_transport(&transport);
|
||||
|
||||
assert!(!policy.retry_client_errors_by_default);
|
||||
let report_context = append_local_failover_policy_to_value(json!({}), &transport);
|
||||
assert_eq!(
|
||||
local_failover_policy_from_report_context(Some(&report_context))
|
||||
.map(|policy| policy.retry_client_errors_by_default),
|
||||
Some(false)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codex_cyber_policy_passthrough_defaults_on_and_can_be_disabled() {
|
||||
let mut transport = sample_transport(None, None, None);
|
||||
|
||||
Reference in New Issue
Block a user