feat: codex subscription support (#6600)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Michael Neale
2026-01-23 17:11:58 +11:00
committed by GitHub
parent e7bfdf8fa2
commit e78a1e7d4e
26 changed files with 1666 additions and 69 deletions
+1
View File
@@ -352,6 +352,7 @@ derive_utoipa!(Icon as IconSchema);
super::routes::config_management::remove_custom_provider,
super::routes::config_management::check_provider,
super::routes::config_management::set_config_provider,
super::routes::config_management::configure_provider_oauth,
super::routes::config_management::get_pricing,
super::routes::prompts::get_prompts,
super::routes::prompts::get_prompt,
@@ -210,6 +210,13 @@ fn mask_secret(secret: Value) -> String {
format!("{}{}", visible, mask)
}
fn is_valid_provider_name(provider_name: &str) -> bool {
!provider_name.is_empty()
&& provider_name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
}
#[utoipa::path(
post,
path = "/config/read",
@@ -823,6 +830,54 @@ pub async fn set_config_provider(
Ok(())
}
#[utoipa::path(
post,
path = "/config/providers/{name}/oauth",
params(
("name" = String, Path, description = "Provider name")
),
responses(
(status = 200, description = "OAuth configuration completed"),
(status = 400, description = "OAuth configuration failed")
)
)]
pub async fn configure_provider_oauth(
Path(provider_name): Path<String>,
) -> Result<Json<String>, (StatusCode, String)> {
use goose::model::ModelConfig;
use goose::providers::create;
if !is_valid_provider_name(&provider_name) {
return Err((StatusCode::BAD_REQUEST, "Invalid provider name".to_string()));
}
let temp_model =
ModelConfig::new("temp").map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;
let provider = create(&provider_name, temp_model).await.map_err(|e| {
(
StatusCode::BAD_REQUEST,
format!("Failed to create provider: {}", e),
)
})?;
provider.configure_oauth().await.map_err(|e| {
(
StatusCode::BAD_REQUEST,
format!("OAuth configuration failed: {}", e),
)
})?;
// Mark the provider as configured after successful OAuth
let configured_marker = format!("{}_configured", provider_name);
let config = goose::config::Config::global();
config
.set_param(&configured_marker, true)
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json("OAuth configuration completed".to_string()))
}
pub fn routes(state: Arc<AppState>) -> Router {
Router::new()
.route("/config", get(read_all_config))
@@ -851,6 +906,10 @@ pub fn routes(state: Arc<AppState>) -> Router {
.route("/config/custom-providers/{id}", get(get_custom_provider))
.route("/config/check_provider", post(check_provider))
.route("/config/set_provider", post(set_config_provider))
.route(
"/config/providers/{name}/oauth",
post(configure_provider_oauth),
)
.with_state(state)
}
+10
View File
@@ -101,6 +101,16 @@ pub fn check_provider_configured(metadata: &ProviderMetadata, provider_type: Pro
.is_ok();
}
}
// Special case: OAuth providers - check for configured marker
let has_oauth_key = metadata.config_keys.iter().any(|key| key.oauth_flow);
if has_oauth_key {
let configured_marker = format!("{}_configured", metadata.name);
if matches!(config.get_param::<bool>(&configured_marker), Ok(true)) {
return true;
}
}
// Special case: Zero-config providers (no config keys)
if metadata.config_keys.is_empty() {
// Check if the provider has been explicitly configured via the UI