codex_helper_core/proxy/
entrypoint.rs1use 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}