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