codex-helper-core 0.15.0

Core library for codex-helper.
Documentation
use std::time::Instant;

use axum::body::Body;
use axum::http::{Request, Response, StatusCode};
use tracing::instrument;

use super::ProxyService;
use super::provider_execution::{
    ExecuteProviderChainParams, ProviderExecutionOutcome,
    execute_provider_chain_with_route_executor, log_retry_options,
};
use super::request_context::prepare_proxy_request;
use super::request_failures::finish_failed_proxy_request;
use super::retry::retry_info_for_failed_attempts;

#[instrument(skip_all, fields(service = %proxy.service_name))]
pub async fn handle_proxy(
    proxy: ProxyService,
    req: Request<Body>,
) -> Result<Response<Body>, (StatusCode, String)> {
    let start = Instant::now();
    let started_at_ms = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_millis() as u64)
        .unwrap_or(0);

    let prepared = prepare_proxy_request(&proxy, req, &start, started_at_ms).await?;
    log_retry_options(proxy.service_name, prepared.request_id, &prepared.plan);
    let provider_chain_params = ExecuteProviderChainParams {
        proxy: &proxy,
        route_selection: &prepared.route_selection,
        method: &prepared.method,
        uri: &prepared.uri,
        client_headers: &prepared.client_headers,
        client_headers_entries_cache: &prepared.client_headers_entries_cache,
        client_uri: prepared.client_uri.as_str(),
        start: &start,
        started_at_ms,
        request_id: prepared.request_id,
        request_body_len: prepared.request_body_len,
        body_for_upstream: &prepared.body_for_upstream,
        request_model: prepared.request_model.as_deref(),
        session_binding: prepared.session_binding.as_ref(),
        session_override_config: prepared.session_override_config.as_deref(),
        global_station_override: prepared.global_station_override.as_deref(),
        override_model: prepared.override_model.as_deref(),
        override_effort: prepared.override_effort.as_deref(),
        override_service_tier: prepared.override_service_tier.as_deref(),
        effective_effort: prepared.effective_effort.as_deref(),
        effective_service_tier: prepared.effective_service_tier.as_deref(),
        base_service_tier: &prepared.base_service_tier,
        session_id: prepared.session_id.as_deref(),
        cwd: prepared.cwd.as_deref(),
        request_flavor: &prepared.request_flavor,
        request_body_previews: prepared.request_body_previews,
        debug_max: prepared.debug_max,
        warn_max: prepared.warn_max,
        client_body_debug: prepared.client_body_debug.as_ref(),
        client_body_warn: prepared.client_body_warn.as_ref(),
        plan: &prepared.plan,
        cooldown_backoff: prepared.cooldown_backoff,
    };
    let provider_execution =
        execute_provider_chain_with_route_executor(provider_chain_params).await;
    let (upstream_chain, route_attempts, last_err) = match provider_execution {
        ProviderExecutionOutcome::Return(response) => return Ok(response),
        ProviderExecutionOutcome::Exhausted(state) => {
            (state.upstream_chain, state.route_attempts, state.last_err)
        }
    };

    let dur = start.elapsed().as_millis() as u64;
    let retry = retry_info_for_failed_attempts(&upstream_chain, &route_attempts);
    let (status, msg) = last_err.unwrap_or_else(|| {
        (
            StatusCode::BAD_GATEWAY,
            "no upstreams available".to_string(),
        )
    });

    Err(
        finish_failed_proxy_request(super::request_failures::FailedProxyRequestParams {
            proxy: &proxy,
            method: &prepared.method,
            path: prepared.uri.path(),
            request_id: prepared.request_id,
            status,
            message: msg,
            duration_ms: dur,
            started_at_ms,
            session_id: prepared.session_id.clone(),
            cwd: prepared.cwd.clone(),
            effective_effort: prepared.effective_effort.clone(),
            service_tier: prepared.base_service_tier.clone(),
            retry,
            failure_route_attempts: route_attempts,
        })
        .await,
    )
}