chatgpt/src/chatgpt_client.rs
72 lines
use codex_core::config::Config;use codex_login::AuthManager;use codex_login::default_client::create_client;use anyhow::Context;use serde::de::DeserializeOwned;use std::time::Duration;const OAI_PRODUCT_SKU_HEADER: &str = "OAI-Product-Sku";const CODEX_PRODUCT_SKU: &str = "codex";/// Make a GET request to the ChatGPT backend API.pub(crate) async fn chatgpt_get_request<T: DeserializeOwned>( config: &Config, path: String,) -> anyhow::Result<T> { chatgpt_get_request_with_timeout(config, path, /*timeout*/ None).await}pub(crate) async fn chatgpt_get_request_with_timeout<T: DeserializeOwned>( config: &Config, path: String, timeout: Option<Duration>,) -> anyhow::Result<T> { let chatgpt_base_url = &config.chatgpt_base_url; let auth_manager = AuthManager::shared_from_config(config, /*enable_codex_api_key_env*/ false).await; let auth = auth_manager .auth() .await .ok_or_else(|| anyhow::anyhow!("ChatGPT auth not available"))?; anyhow::ensure!( auth.uses_codex_backend(), "ChatGPT backend requests require Codex backend auth" ); anyhow::ensure!( auth.get_account_id().is_some(), "ChatGPT account ID not available, please re-run `codex login`" ); // Make direct HTTP request to ChatGPT backend API with the token let client = create_client(); let url = format!( "{}/{}", chatgpt_base_url.trim_end_matches('/'), path.trim_start_matches('/') ); let mut request = client .get(&url) .headers(codex_model_provider::auth_provider_from_auth(&auth).to_auth_headers()) .header(OAI_PRODUCT_SKU_HEADER, CODEX_PRODUCT_SKU) .header("Content-Type", "application/json"); if let Some(timeout) = timeout { request = request.timeout(timeout); } let response = request.send().await.context("Failed to send request")?; if response.status().is_success() { let result: T = response .json() .await .context("Failed to parse JSON response")?; Ok(result) } else { let status = response.status(); let body = response.text().await.unwrap_or_default(); anyhow::bail!("Request failed with status {status}: {body}") }}