fix(ai-formats): support cyber policy failover and custom tool/audio passthrough

This commit is contained in:
zhefox
2026-06-17 02:33:14 +08:00
parent f9d97ececb
commit 628a3a0d8d
17 changed files with 2255 additions and 159 deletions
@@ -937,6 +937,7 @@ mod tests {
continue_status_codes: [409, 429].into_iter().collect(),
success_failover_patterns: Vec::new(),
error_stop_patterns: Vec::new(),
stop_cyber_policy_errors: false,
}
);
}
@@ -1,5 +1,6 @@
use crate::handlers::admin::shared::unix_secs_to_rfc3339;
use crate::handlers::public::{request_candidate_event_unix_ms, request_candidate_status_label};
use crate::orchestration::codex_cyber_flag_passthrough_enabled;
use crate::provider_key_auth::provider_key_effective_api_formats;
use aether_data_contracts::repository::candidates::{
RequestCandidateStatus, StoredRequestCandidate,
@@ -204,6 +205,7 @@ pub(crate) fn build_admin_provider_summary_value(
"ops_configured": ops_configured,
"ops_architecture_id": ops_architecture_id,
"kiro_simulated_cache_enabled": kiro_simulated_cache_enabled,
"codex_cyber_flag_passthrough_enabled": codex_cyber_flag_passthrough_enabled(&provider.provider_type, provider.config.as_ref()),
"ops_quota_alert_enabled": ops_quota_alert_enabled,
"created_at": endpoint_timestamp_or_now(provider.created_at_unix_ms, now_unix_secs),
"updated_at": endpoint_timestamp_or_now(provider.updated_at_unix_secs, now_unix_secs),
@@ -33,6 +33,7 @@ pub(crate) enum LocalFailoverClassification {
StopStatusCode,
StopErrorPattern,
StopExecutionError,
StopCyberPolicy,
RetrySuccessPattern,
RetryStatusCode,
RetryUpstreamFailure,
@@ -45,6 +46,7 @@ impl LocalFailoverClassification {
Self::StopStatusCode => "stop_status_code",
Self::StopErrorPattern => "stop_error_pattern",
Self::StopExecutionError => "stop_execution_error",
Self::StopCyberPolicy => "stop_cyber_policy",
Self::RetrySuccessPattern => "retry_success_pattern",
Self::RetryStatusCode => "retry_status_code",
Self::RetryUpstreamFailure => "retry_upstream_failure",
@@ -60,6 +62,13 @@ pub(crate) fn classify_local_failover(
return LocalFailoverClassification::StopStatusCode;
}
if policy.stop_cyber_policy_errors
&& input.status_code >= 400
&& local_error_response_has_cyber_policy_code(input.response_text)
{
return LocalFailoverClassification::StopCyberPolicy;
}
if input.status_code >= 400
&& policy.error_stop_patterns.iter().any(|rule| {
local_failover_regex_rule_matches(rule, input.response_text, input.status_code)
@@ -104,6 +113,44 @@ fn should_failover_local_upstream_status(status_code: u16) -> bool {
status_code >= 400
}
fn local_error_response_has_cyber_policy_code(response_text: Option<&str>) -> bool {
let Some(response_text) = response_text else {
return false;
};
let Ok(value) = serde_json::from_str::<Value>(response_text) else {
return false;
};
json_value_has_cyber_policy_code(&value, 0)
}
fn json_value_has_cyber_policy_code(value: &Value, depth: usize) -> bool {
if depth > 16 {
return false;
}
match value {
Value::Object(object) => object.iter().any(|(key, value)| {
(key == "code"
&& value
.as_str()
.is_some_and(|code| code.eq_ignore_ascii_case("cyber_policy")))
|| json_value_has_cyber_policy_code(value, depth + 1)
}),
Value::Array(values) => values
.iter()
.any(|value| json_value_has_cyber_policy_code(value, depth + 1)),
Value::String(text) => {
let text = text.trim_start();
if !text.starts_with('{') && !text.starts_with('[') {
return false;
}
serde_json::from_str::<Value>(text)
.ok()
.is_some_and(|value| json_value_has_cyber_policy_code(&value, depth + 1))
}
_ => false,
}
}
fn parse_local_error_response(response_text: Option<&str>) -> ParsedLocalErrorResponse {
let raw = response_text
.map(str::trim)
@@ -310,6 +357,58 @@ mod tests {
);
}
#[test]
fn classifier_stops_cyber_policy_when_policy_enabled() {
let policy = LocalFailoverPolicy {
stop_cyber_policy_errors: true,
..LocalFailoverPolicy::default()
};
assert_eq!(
classify_local_failover(
&policy,
LocalFailoverInput::new(
400,
Some(
r#"{"type":"error","error":{"type":"invalid_request","code":"cyber_policy","message":"flagged"}}"#,
)
)
),
LocalFailoverClassification::StopCyberPolicy
);
assert_eq!(
classify_local_failover(
&policy,
LocalFailoverInput::new(
400,
Some(r#"{"outer":{"error":{"code":"cyber_policy"}}}"#)
)
),
LocalFailoverClassification::StopCyberPolicy
);
assert_eq!(
classify_local_failover(
&policy,
LocalFailoverInput::new(400, Some(r#"{"error":{"code":"other"}}"#))
),
LocalFailoverClassification::RetryUpstreamFailure
);
}
#[test]
fn classifier_retries_cyber_policy_when_policy_disabled() {
assert_eq!(
classify_local_failover(
&LocalFailoverPolicy::default(),
LocalFailoverInput::new(
400,
Some(r#"{"error":{"code":"cyber_policy","message":"flagged"}}"#)
)
),
LocalFailoverClassification::RetryUpstreamFailure
);
}
#[test]
fn classifier_detects_success_continue_status_code() {
let policy = LocalFailoverPolicy {
@@ -903,7 +903,8 @@ fn local_candidate_failure_should_invalidate_affinity(
status_code >= 500
}
LocalFailoverClassification::StopErrorPattern
| LocalFailoverClassification::StopExecutionError => false,
| LocalFailoverClassification::StopExecutionError
| LocalFailoverClassification::StopCyberPolicy => false,
}
}
@@ -332,7 +332,8 @@ fn local_candidate_failure_should_project_health(
status_code >= 500
}
LocalFailoverClassification::StopErrorPattern
| LocalFailoverClassification::StopExecutionError => false,
| LocalFailoverClassification::StopExecutionError
| LocalFailoverClassification::StopCyberPolicy => false,
}
}
+4 -3
View File
@@ -38,9 +38,9 @@ pub(crate) use self::health::{
project_local_key_circuit_failure, project_local_success_health,
};
pub(crate) use self::policy::{
append_local_failover_policy_to_value, local_failover_policy_from_report_context,
local_failover_policy_from_transport, resolve_local_failover_policy, LocalFailoverPolicy,
LocalFailoverRegexRule,
append_local_failover_policy_to_value, codex_cyber_flag_passthrough_enabled,
local_failover_policy_from_report_context, local_failover_policy_from_transport,
resolve_local_failover_policy, LocalFailoverPolicy, LocalFailoverRegexRule,
};
pub(crate) use self::recovery::{
analyze_local_failover, recover_local_failover_decision, LocalFailoverAnalysis,
@@ -95,6 +95,7 @@ pub(crate) fn build_local_error_flow_metadata(
LocalFailoverClassification::StopStatusCode
| LocalFailoverClassification::StopErrorPattern
| LocalFailoverClassification::StopExecutionError
| LocalFailoverClassification::StopCyberPolicy
);
let propagation = match analysis.decision {
LocalFailoverDecision::RetryNextCandidate => "suppressed",
@@ -14,6 +14,7 @@ pub(crate) struct LocalFailoverPolicy {
pub(crate) continue_status_codes: BTreeSet<u16>,
pub(crate) success_failover_patterns: Vec<LocalFailoverRegexRule>,
pub(crate) error_stop_patterns: Vec<LocalFailoverRegexRule>,
pub(crate) stop_cyber_policy_errors: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -80,6 +81,10 @@ pub(crate) fn local_failover_policy_from_transport(
LocalFailoverPolicy {
max_retries,
stop_cyber_policy_errors: codex_cyber_flag_passthrough_enabled(
&transport.provider.provider_type,
transport.provider.config.as_ref(),
),
stop_status_codes: rules
.map(|value| {
parse_status_code_set(
@@ -135,6 +140,10 @@ pub(crate) fn local_failover_policy_from_report_context(
.unwrap_or_default(),
success_failover_patterns: parse_regex_rules(object, "success_failover_patterns"),
error_stop_patterns: parse_regex_rules(object, "error_stop_patterns"),
stop_cyber_policy_errors: object
.get("stop_cyber_policy_errors")
.and_then(Value::as_bool)
.unwrap_or(false),
})
}
@@ -168,9 +177,29 @@ fn local_failover_policy_to_value(policy: &LocalFailoverPolicy) -> Value {
"continue_status_codes": policy.continue_status_codes.iter().copied().collect::<Vec<_>>(),
"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,
})
}
pub(crate) fn codex_cyber_flag_passthrough_enabled(
provider_type: &str,
provider_config: Option<&Value>,
) -> bool {
if !provider_type.trim().eq_ignore_ascii_case("codex") {
return false;
}
provider_config
.and_then(|config| config.get("codex"))
.and_then(Value::as_object)
.and_then(|codex| {
codex
.get("pass_through_cyber_flag_interrupt")
.or_else(|| codex.get("passthrough_cyber_flag_interrupt"))
.and_then(Value::as_bool)
})
.unwrap_or(true)
}
fn local_failover_regex_rule_to_value(rule: &LocalFailoverRegexRule) -> Value {
json!({
"pattern": rule.pattern,
@@ -345,7 +374,28 @@ mod tests {
pattern: "validation".to_string(),
status_codes: [422].into_iter().collect(),
}],
stop_cyber_policy_errors: false,
})
);
}
#[test]
fn codex_cyber_policy_passthrough_defaults_on_and_can_be_disabled() {
let mut transport = sample_transport(None, None, None);
transport.provider.provider_type = "codex".to_string();
assert!(local_failover_policy_from_transport(&transport).stop_cyber_policy_errors);
transport.provider.config = Some(json!({
"codex": {"pass_through_cyber_flag_interrupt": false}
}));
assert!(!local_failover_policy_from_transport(&transport).stop_cyber_policy_errors);
transport.provider.config = Some(json!({
"codex": {"passthrough_cyber_flag_interrupt": true}
}));
assert!(local_failover_policy_from_transport(&transport).stop_cyber_policy_errors);
transport.provider.provider_type = "llm".to_string();
assert!(!local_failover_policy_from_transport(&transport).stop_cyber_policy_errors);
}
}
@@ -58,9 +58,8 @@ const fn decision_from_classification(
LocalFailoverClassification::UseDefault => LocalFailoverDecision::UseDefault,
LocalFailoverClassification::StopStatusCode
| LocalFailoverClassification::StopErrorPattern
| LocalFailoverClassification::StopExecutionError => {
LocalFailoverDecision::StopLocalFailover
}
| LocalFailoverClassification::StopExecutionError
| LocalFailoverClassification::StopCyberPolicy => LocalFailoverDecision::StopLocalFailover,
LocalFailoverClassification::RetrySuccessPattern
| LocalFailoverClassification::RetryStatusCode
| LocalFailoverClassification::RetryUpstreamFailure => {
@@ -144,4 +143,22 @@ mod tests {
LocalFailoverClassification::RetryUpstreamFailure
);
}
#[test]
fn recovery_stops_cyber_policy_failover() {
let policy = LocalFailoverPolicy {
stop_cyber_policy_errors: true,
..LocalFailoverPolicy::default()
};
let analysis = analyze_local_failover(
&policy,
LocalFailoverInput::new(400, Some(r#"{"error":{"code":"cyber_policy"}}"#)),
);
assert_eq!(analysis.decision, LocalFailoverDecision::StopLocalFailover);
assert_eq!(
analysis.classification,
LocalFailoverClassification::StopCyberPolicy
);
}
}