feat(gateway): add Codex Live and OpenAI Realtime

Implement preflighted Live/Realtime WebSocket transports, protocol-aware authentication, usage auditing, UI filtering, and legacy Codex permission migration.
This commit is contained in:
ZheFox
2026-08-21 04:27:34 +08:00
parent fe38dcd294
commit 2c89202001
105 changed files with 7553 additions and 947 deletions
@@ -1,9 +1,9 @@
mod types;
pub use types::{
MinimalCandidateSelectionReadRepository, MinimalCandidateSelectionRepository,
StoredApiFormatCandidateRowsQuery, StoredMinimalCandidateSelectionRow,
StoredPoolKeyCandidateOrder, StoredPoolKeyCandidateRowsByKeyIdsQuery,
StoredPoolKeyCandidateRowsQuery, StoredProviderModelMapping,
StoredRequestedModelCandidateRowsQuery,
provider_model_mapping_api_format_covers, MinimalCandidateSelectionReadRepository,
MinimalCandidateSelectionRepository, StoredApiFormatCandidateRowsQuery,
StoredMinimalCandidateSelectionRow, StoredPoolKeyCandidateOrder,
StoredPoolKeyCandidateRowsByKeyIdsQuery, StoredPoolKeyCandidateRowsQuery,
StoredProviderModelMapping, StoredRequestedModelCandidateRowsQuery,
};
@@ -113,6 +113,27 @@ impl StoredMinimalCandidateSelectionRow {
}
}
/// Evaluates the API-format scope on a provider-model mapping.
///
/// Codex Live was introduced after existing Codex model associations had
/// already stored their source-model scope as `openai:responses`. Preserve
/// those associations for the same Codex provider without treating the two
/// formats as globally interchangeable. Endpoint and key permissions remain
/// independently scoped to `codex:live`.
pub fn provider_model_mapping_api_format_covers(
provider_type: &str,
mapping_api_format: &str,
requested_api_format: &str,
) -> bool {
if aether_ai_formats::api_format_permission_covers(mapping_api_format, requested_api_format) {
return true;
}
provider_type.trim().eq_ignore_ascii_case("codex")
&& aether_ai_formats::normalize_api_format_alias(requested_api_format) == "codex:live"
&& aether_ai_formats::normalize_api_format_alias(mapping_api_format) == "openai:responses"
}
fn api_format_permission_covers(allowed: &str, requested: &str) -> bool {
aether_ai_formats::api_format_permission_covers(allowed, requested)
}
@@ -176,3 +197,37 @@ impl<T> MinimalCandidateSelectionRepository for T where
T: MinimalCandidateSelectionReadRepository + Send + Sync
{
}
#[cfg(test)]
mod tests {
use super::provider_model_mapping_api_format_covers;
#[test]
fn legacy_responses_mapping_is_only_compatible_with_codex_live() {
assert!(provider_model_mapping_api_format_covers(
"codex",
"openai:responses",
"codex:live"
));
assert!(provider_model_mapping_api_format_covers(
" CoDeX ",
"/v1/responses",
"codex:live"
));
for provider_type in ["openai", "custom", "chatgpt_web"] {
assert!(!provider_model_mapping_api_format_covers(
provider_type,
"openai:responses",
"codex:live"
));
}
for requested_api_format in ["openai:chat", "claude:messages", "openai:image"] {
assert!(!provider_model_mapping_api_format_covers(
"codex",
"openai:responses",
requested_api_format
));
}
}
}