refactor ai serving modules and crates

This commit is contained in:
fawney19
2026-05-02 13:23:54 +08:00
parent 4fc7cecf30
commit c130d0e2c9
309 changed files with 21549 additions and 14265 deletions
@@ -0,0 +1,44 @@
use axum::body::Body;
use axum::http::Response;
use serde_json::Value;
use crate::ai_serving::GatewayControlDecision;
use crate::{usage::GatewaySyncReportRequest, GatewayError};
#[path = "stream_rewrite.rs"]
pub(crate) mod stream;
#[path = "sync_finalize.rs"]
pub(crate) mod sync;
#[path = "sync_to_stream.rs"]
pub(crate) mod sync_to_stream;
pub(crate) use stream::LocalStreamRewriter;
pub(crate) use sync::LocalCoreSyncFinalizeOutcome;
pub(crate) use sync_to_stream::{
maybe_bridge_standard_sync_json_to_stream, SyncToStreamBridgeOutcome,
};
pub(crate) fn maybe_build_sync_finalize_outcome(
trace_id: &str,
decision: &GatewayControlDecision,
payload: &GatewaySyncReportRequest,
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
sync::maybe_build_local_core_sync_finalize_response(trace_id, decision, payload)
}
pub(crate) fn maybe_compile_sync_finalize_response(
trace_id: &str,
decision: &GatewayControlDecision,
payload: &GatewaySyncReportRequest,
) -> Result<Option<Response<Body>>, GatewayError> {
Ok(
maybe_build_sync_finalize_outcome(trace_id, decision, payload)?
.map(|outcome| outcome.response),
)
}
pub(crate) fn maybe_build_stream_response_rewriter(
report_context: Option<&Value>,
) -> Option<LocalStreamRewriter<'_>> {
stream::maybe_build_local_stream_rewriter(report_context)
}
@@ -0,0 +1,35 @@
use serde_json::Value;
use crate::ai_serving::{
maybe_build_ai_surface_stream_rewriter, AiSurfaceFinalizeError, AiSurfaceStreamRewriter,
};
use crate::GatewayError;
pub(crate) struct LocalStreamRewriter<'a> {
inner: AiSurfaceStreamRewriter<'a>,
}
pub(crate) fn maybe_build_local_stream_rewriter<'a>(
report_context: Option<&'a Value>,
) -> Option<LocalStreamRewriter<'a>> {
maybe_build_ai_surface_stream_rewriter(report_context)
.map(|inner| LocalStreamRewriter { inner })
}
impl LocalStreamRewriter<'_> {
pub(crate) fn push_chunk(&mut self, chunk: &[u8]) -> Result<Vec<u8>, GatewayError> {
self.inner.push_chunk(chunk).map_err(map_surface_error)
}
pub(crate) fn finish(&mut self) -> Result<Vec<u8>, GatewayError> {
self.inner.finish().map_err(map_surface_error)
}
}
fn map_surface_error(error: AiSurfaceFinalizeError) -> GatewayError {
error.into()
}
#[cfg(test)]
#[path = "../tests_stream.rs"]
mod tests;
@@ -0,0 +1,113 @@
use crate::ai_serving::GatewayControlDecision;
use crate::ai_serving::{build_generated_tool_call_id, canonicalize_tool_arguments};
use crate::{usage::GatewaySyncReportRequest, GatewayError};
pub(crate) use crate::ai_serving::finalize::common::{
build_local_success_outcome, build_local_success_outcome_with_conversion_report,
local_finalize_allows_envelope, unwrap_local_finalize_response_value,
LocalCoreSyncFinalizeOutcome,
};
pub(crate) use crate::ai_serving::finalize::standard::{
maybe_build_standard_sync_finalize_product_from_normalized_payload,
StandardSyncFinalizeNormalizedProduct,
};
pub(crate) use crate::ai_serving::{
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
aggregate_openai_chat_stream_sync_response, aggregate_openai_responses_stream_sync_response,
maybe_build_openai_image_sync_finalize_product,
};
pub(crate) use crate::ai_serving::{
convert_claude_chat_response_to_openai_chat, convert_claude_response_to_openai_responses,
convert_gemini_chat_response_to_openai_chat, convert_gemini_response_to_openai_responses,
};
pub(crate) fn maybe_build_local_core_sync_finalize_response(
trace_id: &str,
decision: &GatewayControlDecision,
payload: &GatewaySyncReportRequest,
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
if let Some(outcome) =
maybe_build_local_openai_image_sync_finalize_response(trace_id, decision, payload)?
{
return Ok(Some(outcome));
}
let Some(normalized_payload) =
crate::ai_serving::adaptation::private_envelope::maybe_normalize_provider_private_sync_report_payload(payload)?
else {
return Ok(None);
};
let payload = &normalized_payload;
let Some(report_context) = payload.report_context.as_ref() else {
return Ok(None);
};
if !local_finalize_allows_envelope(report_context) {
return Ok(None);
}
let Some(product) = maybe_build_standard_sync_finalize_product_from_normalized_payload(
payload.report_kind.as_str(),
payload.status_code,
Some(report_context),
payload.body_json.as_ref(),
payload.body_base64.as_deref(),
)
.map_err(GatewayError::from)?
else {
return Ok(None);
};
match product {
StandardSyncFinalizeNormalizedProduct::SuccessBody(body_json) => {
let Some(body_json) = unwrap_local_finalize_response_value(body_json, report_context)
else {
return Ok(None);
};
Ok(Some(build_local_success_outcome(
trace_id, decision, payload, body_json,
)?))
}
StandardSyncFinalizeNormalizedProduct::CrossFormat(product) => {
let Some(provider_body_json) =
unwrap_local_finalize_response_value(product.provider_body_json, report_context)
else {
return Ok(None);
};
Ok(Some(build_local_success_outcome_with_conversion_report(
trace_id,
decision,
payload,
product.client_body_json,
provider_body_json,
)?))
}
}
}
fn maybe_build_local_openai_image_sync_finalize_response(
trace_id: &str,
decision: &GatewayControlDecision,
payload: &GatewaySyncReportRequest,
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
let Some(product) = maybe_build_openai_image_sync_finalize_product(
payload.report_kind.as_str(),
payload.status_code,
payload.report_context.as_ref(),
payload.body_base64.as_deref(),
)
.map_err(GatewayError::from)?
else {
return Ok(None);
};
Ok(Some(build_local_success_outcome_with_conversion_report(
trace_id,
decision,
payload,
product.client_body_json,
product.provider_body_json,
)?))
}
#[cfg(test)]
#[path = "../tests_sync.rs"]
mod tests;
@@ -0,0 +1,20 @@
use serde_json::Value;
use crate::GatewayError;
pub(crate) use crate::ai_serving::pure::SyncToStreamBridgeOutcome;
pub(crate) fn maybe_bridge_standard_sync_json_to_stream(
provider_body_json: &Value,
provider_api_format: &str,
client_api_format: &str,
report_context: Option<&Value>,
) -> Result<Option<SyncToStreamBridgeOutcome>, GatewayError> {
crate::ai_serving::pure::maybe_bridge_standard_sync_json_to_stream(
provider_body_json,
provider_api_format,
client_api_format,
report_context,
)
.map_err(GatewayError::from)
}