feat(codex-image): 封装 GPT Image 2 图片接口并收紧错误处理

- 新增 openai:image 路由、planner 与 finalize,内部通过 Codex responses image_generation tool 执行生图

- 补充 Codex OAuth/header 兼容、图片 success report 本地处理与相关前后端/集成测试

- 禁止 chat/completions 使用 gpt-image-2,图片接口限制 n=1,并移除 Provider 模型页的图片能力开关
This commit is contained in:
Entropy.Xu
2026-04-22 21:09:29 +08:00
committed by fawney19
parent 4374f53315
commit f55f22d2e8
55 changed files with 2676 additions and 52 deletions

View File

@@ -92,7 +92,6 @@ pub(crate) async fn maybe_build_local_admin_provider_writes_response(
};
}
}
return Ok(Some(attach_admin_audit_response(
Json(json!({
"id": created_provider.id,

View File

@@ -243,6 +243,8 @@ pub(crate) struct AdminProviderModelCreateRequest {
#[serde(default)]
pub(crate) supports_extended_thinking: Option<bool>,
#[serde(default)]
pub(crate) supports_image_generation: Option<bool>,
#[serde(default)]
pub(crate) is_active: Option<bool>,
#[serde(default)]
pub(crate) config: Option<serde_json::Value>,
@@ -272,6 +274,8 @@ pub(crate) struct AdminProviderModelUpdateRequest {
#[serde(default)]
pub(crate) supports_extended_thinking: Option<bool>,
#[serde(default)]
pub(crate) supports_image_generation: Option<bool>,
#[serde(default)]
pub(crate) is_active: Option<bool>,
#[serde(default)]
pub(crate) is_available: Option<bool>,

View File

@@ -7,6 +7,7 @@ use crate::handlers::admin::provider::write::normalize::normalize_provider_type_
use crate::handlers::admin::request::AdminAppState;
use crate::handlers::admin::shared::normalize_json_object;
use aether_data_contracts::repository::provider_catalog::StoredProviderCatalogProvider;
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;

View File

@@ -20,12 +20,13 @@ pub(crate) fn build_admin_fixed_provider_endpoint_record(
Some(provider.provider_type.as_str()),
)
.and_then(|(_, rules)| (!rules.is_empty()).then_some(serde_json::Value::Array(rules)));
let endpoint_config =
if provider.provider_type == "codex" && normalized_api_format == "openai:cli" {
Some(json!({ "upstream_stream_policy": "force_stream" }))
} else {
None
};
let endpoint_config = if provider.provider_type == "codex"
&& matches!(normalized_api_format, "openai:cli" | "openai:image")
{
Some(json!({ "upstream_stream_policy": "force_stream" }))
} else {
None
};
let now_unix_secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.ok()

View File

@@ -7,6 +7,7 @@ use crate::handlers::admin::provider::write::normalize::normalize_provider_type_
use crate::handlers::admin::request::AdminAppState;
use crate::handlers::admin::shared::normalize_json_object;
use aether_data_contracts::repository::provider_catalog::StoredProviderCatalogProvider;
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
pub(crate) async fn build_admin_update_provider_record(

View File

@@ -120,6 +120,7 @@ impl<'a> AdminAppState<'a> {
payload.supports_function_calling,
payload.supports_streaming,
payload.supports_extended_thinking,
payload.supports_image_generation,
payload.is_active,
config,
)
@@ -226,6 +227,11 @@ impl<'a> AdminAppState<'a> {
} else {
existing.supports_extended_thinking
},
if fields.contains("supports_image_generation") {
payload.supports_image_generation
} else {
existing.supports_image_generation
},
payload.is_active.unwrap_or(existing.is_active),
payload.is_available.unwrap_or(existing.is_available),
config,