Skip to main content

codex_helper_core/proxy/
entrypoint.rs

1use std::time::Instant;
2
3use axum::body::Body;
4use axum::http::{Request, Response, StatusCode};
5use tracing::instrument;
6
7use super::ProxyService;
8use super::provider_execution::{
9    ExecuteProviderChainParams, ProviderExecutionOutcome,
10    execute_provider_chain_with_route_executor, log_retry_options,
11};
12use super::request_context::prepare_proxy_request;
13use super::request_failures::finish_failed_proxy_request;
14use super::retry::retry_info_for_failed_attempts;
15use super::route_unavailability::route_unavailable_response_for_request;
16
17#[instrument(skip_all, fields(service = %proxy.service_name))]
18pub async fn handle_proxy(
19    proxy: ProxyService,
20    req: Request<Body>,
21) -> Result<Response<Body>, (StatusCode, String)> {
22    let start = Instant::now();
23    let started_at_ms = std::time::SystemTime::now()
24        .duration_since(std::time::UNIX_EPOCH)
25        .map(|d| d.as_millis() as u64)
26        .unwrap_or(0);
27
28    let prepared = prepare_proxy_request(&proxy, req, &start, started_at_ms).await?;
29    log_retry_options(proxy.service_name, prepared.request_id, &prepared.plan);
30    let provider_chain_params = ExecuteProviderChainParams {
31        proxy: &proxy,
32        route_selection: &prepared.route_selection,
33        method: &prepared.method,
34        uri: &prepared.uri,
35        client_headers: &prepared.client_headers,
36        client_headers_entries_cache: &prepared.client_headers_entries_cache,
37        client_uri: prepared.client_uri.as_str(),
38        start: &start,
39        started_at_ms,
40        request_id: prepared.request_id,
41        request_body_len: prepared.request_body_len,
42        body_for_upstream: &prepared.body_for_upstream,
43        request_model: prepared.request_model.as_deref(),
44        session_binding: prepared.session_binding.as_ref(),
45        session_override_config: prepared.session_override_config.as_deref(),
46        global_station_override: prepared.global_station_override.as_deref(),
47        override_model: prepared.override_model.as_deref(),
48        override_effort: prepared.override_effort.as_deref(),
49        override_service_tier: prepared.override_service_tier.as_deref(),
50        effective_effort: prepared.effective_effort.as_deref(),
51        effective_service_tier: prepared.effective_service_tier.as_deref(),
52        base_service_tier: &prepared.base_service_tier,
53        session_id: prepared.session_id.as_deref(),
54        session_identity_source: prepared.session_identity_source,
55        cwd: prepared.cwd.as_deref(),
56        request_flavor: &prepared.request_flavor,
57        request_body_previews: prepared.request_body_previews,
58        response_semantic_contract: prepared.response_semantic_contract,
59        debug_max: prepared.debug_max,
60        warn_max: prepared.warn_max,
61        client_body_debug: prepared.client_body_debug.as_ref(),
62        client_body_warn: prepared.client_body_warn.as_ref(),
63        plan: &prepared.plan,
64        cooldown_backoff: prepared.cooldown_backoff,
65    };
66    let provider_execution =
67        execute_provider_chain_with_route_executor(provider_chain_params).await;
68    let (upstream_chain, route_attempts, last_err) = match provider_execution {
69        ProviderExecutionOutcome::Return(response) => return Ok(response),
70        ProviderExecutionOutcome::Exhausted(state) => {
71            (state.upstream_chain, state.route_attempts, state.last_err)
72        }
73    };
74
75    let dur = start.elapsed().as_millis() as u64;
76    let retry = retry_info_for_failed_attempts(&upstream_chain, &route_attempts);
77    let (status, msg) = last_err.unwrap_or_else(|| {
78        (
79            StatusCode::BAD_GATEWAY,
80            "no upstreams available".to_string(),
81        )
82    });
83
84    let failure = finish_failed_proxy_request(super::request_failures::FailedProxyRequestParams {
85        proxy: &proxy,
86        method: &prepared.method,
87        path: prepared.uri.path(),
88        request_id: prepared.request_id,
89        status,
90        message: msg,
91        duration_ms: dur,
92        started_at_ms,
93        session_id: prepared.session_id.clone(),
94        session_identity_source: prepared.session_identity_source,
95        cwd: prepared.cwd.clone(),
96        effective_effort: prepared.effective_effort.clone(),
97        service_tier: prepared.base_service_tier.clone(),
98        codex_bridge: prepared.request_flavor.codex_bridge_log.clone(),
99        retry,
100        failure_route_attempts: route_attempts.clone(),
101    })
102    .await;
103
104    if let Some(response) = route_unavailable_response_for_request(
105        &prepared.request_flavor,
106        failure.1.as_str(),
107        &route_attempts,
108    ) {
109        return Ok(response);
110    }
111
112    Err(failure)
113}