mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-06 17:37:47 +08:00
feat(openai): align GPT-5.6 and Codex request contracts
This commit is contained in:
@@ -559,7 +559,7 @@ async fn gateway_handles_admin_provider_query_models_falls_back_to_codex_preset_
|
||||
.expect("mutex should lock") += 1;
|
||||
assert_eq!(
|
||||
plan.url,
|
||||
"https://chatgpt.com/backend-api/codex/models?client_version=0.128.0-alpha.1"
|
||||
"https://chatgpt.com/backend-api/codex/models?client_version=0.144.1"
|
||||
);
|
||||
Json(json!({
|
||||
"request_id": "req-provider-query-codex-invalidated",
|
||||
@@ -625,6 +625,11 @@ async fn gateway_handles_admin_provider_query_models_falls_back_to_codex_preset_
|
||||
let payload: serde_json::Value = response.json().await.expect("json body should parse");
|
||||
assert_eq!(payload["success"], json!(true));
|
||||
assert_eq!(payload["data"]["error"], serde_json::Value::Null);
|
||||
let warning = payload["data"]["warning"]
|
||||
.as_str()
|
||||
.expect("Codex fallback warning should be present");
|
||||
assert!(warning.contains("Codex 动态模型目录不可用"));
|
||||
assert!(warning.contains("invalidated"));
|
||||
let model_ids = payload["data"]["models"]
|
||||
.as_array()
|
||||
.expect("models should be an array")
|
||||
@@ -634,11 +639,14 @@ async fn gateway_handles_admin_provider_query_models_falls_back_to_codex_preset_
|
||||
assert_eq!(
|
||||
model_ids,
|
||||
vec![
|
||||
"gpt-5.3-codex",
|
||||
"gpt-5.3-codex-spark",
|
||||
"codex-auto-review",
|
||||
"gpt-5.2",
|
||||
"gpt-5.4",
|
||||
"gpt-5.4-mini",
|
||||
"gpt-5.5",
|
||||
"gpt-5.6-luna",
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-terra",
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -3837,13 +3845,12 @@ async fn gateway_handles_openai_responses_test_model_locally_impl() {
|
||||
.and_then(|value| value.as_str()),
|
||||
Some(prompt)
|
||||
);
|
||||
assert_eq!(
|
||||
plan.body
|
||||
.json_body
|
||||
.as_ref()
|
||||
.and_then(|body| body.get("instructions")),
|
||||
Some(&json!(""))
|
||||
);
|
||||
assert!(plan
|
||||
.body
|
||||
.json_body
|
||||
.as_ref()
|
||||
.and_then(|body| body.get("instructions"))
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
plan.body
|
||||
.json_body
|
||||
@@ -3856,7 +3863,7 @@ async fn gateway_handles_openai_responses_test_model_locally_impl() {
|
||||
.json_body
|
||||
.as_ref()
|
||||
.and_then(|body| body.get("prompt_cache_key"))
|
||||
.is_some());
|
||||
.is_none());
|
||||
Json(json!({
|
||||
"request_id": plan.request_id,
|
||||
"candidate_id": plan.candidate_id,
|
||||
@@ -3960,8 +3967,8 @@ async fn gateway_handles_openai_image_test_model_locally_impl() {
|
||||
assert_eq!(plan.client_api_format, "openai:image");
|
||||
assert_eq!(plan.provider_api_format, "openai:image");
|
||||
assert_eq!(plan.model_name.as_deref(), Some("gpt-image-1"));
|
||||
assert_eq!(plan.url, "https://api.openai.example/v1/responses");
|
||||
assert!(plan.stream);
|
||||
assert_eq!(plan.url, "https://api.openai.example/v1/images/generations");
|
||||
assert!(!plan.stream);
|
||||
assert_eq!(
|
||||
plan.headers.get("authorization").map(String::as_str),
|
||||
Some("Bearer sk-test-image")
|
||||
@@ -3971,38 +3978,42 @@ async fn gateway_handles_openai_image_test_model_locally_impl() {
|
||||
.json_body
|
||||
.as_ref()
|
||||
.and_then(|body| body.get("model")),
|
||||
Some(&json!(crate::ai_serving::CODEX_OPENAI_IMAGE_INTERNAL_MODEL))
|
||||
Some(&json!("gpt-image-1"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.body
|
||||
.json_body
|
||||
.as_ref()
|
||||
.and_then(|body| body.get("input"))
|
||||
.and_then(|input| input.as_array())
|
||||
.and_then(|items| items.first())
|
||||
.and_then(|item| item.get("content"))
|
||||
.and_then(|body| body.get("prompt"))
|
||||
.and_then(|value| value.as_str()),
|
||||
Some("Draw a small blue square")
|
||||
);
|
||||
assert!(plan
|
||||
.body
|
||||
.json_body
|
||||
.as_ref()
|
||||
.is_some_and(|body| body.get("stream").is_none()));
|
||||
Json(json!({
|
||||
"request_id": plan.request_id,
|
||||
"candidate_id": plan.candidate_id,
|
||||
"status_code": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"body_bytes_b64": base64::engine::general_purpose::STANDARD.encode(
|
||||
concat!(
|
||||
"event: response.created\n",
|
||||
"data: {\"type\":\"response.created\",\"response\":{\"created_at\":1776839946}}\n\n",
|
||||
"event: response.output_item.done\n",
|
||||
"data: {\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"type\":\"image_generation_call\",\"output_format\":\"png\",\"revised_prompt\":\"revised prompt\",\"result\":\"aGVsbG8=\"}}\n\n",
|
||||
"event: response.completed\n",
|
||||
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_img_123\",\"model\":\"gpt-image-1\",\"status\":\"completed\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":171,\"output_tokens\":1372,\"total_tokens\":1543}}}}\n\n"
|
||||
)
|
||||
.as_bytes()
|
||||
)
|
||||
"json_body": {
|
||||
"created": 1776839946,
|
||||
"model": "gpt-image-1",
|
||||
"data": [{
|
||||
"b64_json": "aGVsbG8=",
|
||||
"revised_prompt": "revised prompt"
|
||||
}],
|
||||
"usage": {
|
||||
"input_tokens": 171,
|
||||
"output_tokens": 1372,
|
||||
"total_tokens": 1543
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry": {
|
||||
"elapsed_ms": 19
|
||||
|
||||
@@ -1122,7 +1122,7 @@ async fn gateway_creates_admin_provider_locally_with_trusted_admin_principal() {
|
||||
.as_ref()
|
||||
.and_then(|value| value.get("upstream_stream_policy"))
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("force_stream")
|
||||
None
|
||||
);
|
||||
assert!(responses_endpoint.body_rules.is_none());
|
||||
assert!(compact_endpoint.body_rules.is_none());
|
||||
@@ -1248,7 +1248,7 @@ async fn gateway_updates_fixed_provider_and_reconciles_template_managed_endpoint
|
||||
.as_ref()
|
||||
.and_then(|value| value.get("upstream_stream_policy"))
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("force_stream")
|
||||
None
|
||||
);
|
||||
let keys = provider_catalog_repository
|
||||
.list_keys_by_provider_ids(&["provider-codex".to_string()])
|
||||
|
||||
@@ -1379,7 +1379,7 @@ async fn gateway_handles_admin_stats_leaderboard_models_locally_with_trusted_adm
|
||||
assert_eq!(payload["metric"], "tokens");
|
||||
assert_eq!(payload["items"][0]["rank"], 1);
|
||||
assert_eq!(payload["items"][0]["id"], "gpt-5");
|
||||
assert_eq!(payload["items"][0]["value"], 160);
|
||||
assert_eq!(payload["items"][0]["value"], 150);
|
||||
assert_eq!(payload["items"][1]["id"], "claude-3-5-sonnet");
|
||||
assert_eq!(payload["items"][1]["value"], 100);
|
||||
assert_eq!(*upstream_hits.lock().expect("mutex should lock"), 0);
|
||||
|
||||
@@ -641,7 +641,7 @@ async fn gateway_handles_admin_usage_aggregation_stats_locally_with_trusted_admi
|
||||
assert_eq!(items[0]["model"], "gpt-5");
|
||||
assert_eq!(items[0]["request_count"], 2);
|
||||
assert_eq!(items[0]["output_tokens"], 40);
|
||||
assert_eq!(items[0]["effective_input_tokens"], 150);
|
||||
assert_eq!(items[0]["effective_input_tokens"], 120);
|
||||
assert_eq!(items[0]["total_input_context"], 160);
|
||||
assert_eq!(items[0]["cache_creation_tokens"], 30);
|
||||
assert_eq!(items[0]["cache_creation_ephemeral_5m_tokens"], 12);
|
||||
@@ -1026,7 +1026,7 @@ async fn gateway_handles_admin_usage_active_locally_with_trusted_admin_principal
|
||||
let payload: serde_json::Value = response.json().await.expect("json body should parse");
|
||||
assert_eq!(payload["requests"].as_array().expect("array").len(), 1);
|
||||
assert_eq!(payload["requests"][0]["id"], "usage-pending");
|
||||
assert_eq!(payload["requests"][0]["effective_input_tokens"], 5);
|
||||
assert_eq!(payload["requests"][0]["effective_input_tokens"], 0);
|
||||
assert_eq!(payload["requests"][0]["provider"], "OpenAI");
|
||||
assert_eq!(payload["requests"][0]["api_key_name"], "fresh-primary");
|
||||
assert_eq!(payload["requests"][0]["has_fallback"], true);
|
||||
@@ -1326,7 +1326,7 @@ async fn gateway_handles_admin_usage_records_locally_with_trusted_admin_principa
|
||||
payload["records"][0]["provider_key_name"],
|
||||
"upstream-primary"
|
||||
);
|
||||
assert_eq!(payload["records"][0]["effective_input_tokens"], 35);
|
||||
assert_eq!(payload["records"][0]["effective_input_tokens"], 20);
|
||||
assert_eq!(payload["records"][0]["first_byte_time_ms"], 120);
|
||||
assert_eq!(*upstream_hits.lock().expect("mutex should lock"), 0);
|
||||
|
||||
@@ -2053,8 +2053,8 @@ async fn gateway_handles_admin_usage_detail_locally_with_trusted_admin_principal
|
||||
assert_eq!(payload["api_key"]["name"], "primary");
|
||||
assert_eq!(payload["provider"], "OpenAI");
|
||||
assert_eq!(payload["model"], "gpt-5");
|
||||
assert_eq!(payload["effective_input_tokens"], 115);
|
||||
assert_eq!(payload["total_tokens"], 165);
|
||||
assert_eq!(payload["effective_input_tokens"], 100);
|
||||
assert_eq!(payload["total_tokens"], 150);
|
||||
assert_eq!(payload["cache_creation_cost"], 0.0);
|
||||
assert_eq!(payload["cache_read_cost"], 0.0);
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user