mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
fix(compact): 移除 OpenAI Compact 请求中不受支持的 store 参数
- 在 OpenAI Compact 请求规范化流程中剥离 `store` - 将 compact 默认 body rules 与 Codex CLI 默认规则拆分 - 补充 same-format 和转换链路的 compact 回归测试
This commit is contained in:
@@ -26,7 +26,7 @@ fn applies_codex_defaults_when_body_rules_do_not_handle_fields() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn defers_to_user_body_rules_for_handled_fields() {
|
fn strips_store_for_compact_even_when_body_rules_handle_it() {
|
||||||
let body_rules = json!([
|
let body_rules = json!([
|
||||||
{"action":"set","path":"store","value":true},
|
{"action":"set","path":"store","value":true},
|
||||||
{"action":"set","path":"instructions","value":"Keep custom"},
|
{"action":"set","path":"instructions","value":"Keep custom"},
|
||||||
@@ -51,7 +51,7 @@ fn defers_to_user_body_rules_for_handled_fields() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert!(body.get("max_output_tokens").is_none());
|
assert!(body.get("max_output_tokens").is_none());
|
||||||
assert_eq!(body["store"], true);
|
assert!(body.get("store").is_none());
|
||||||
assert_eq!(body["instructions"], "Keep custom");
|
assert_eq!(body["instructions"], "Keep custom");
|
||||||
assert_eq!(body["metadata"]["mode"], "custom");
|
assert_eq!(body["metadata"]["mode"], "custom");
|
||||||
assert_eq!(body["top_p"], 0.5);
|
assert_eq!(body["top_p"], 0.5);
|
||||||
|
|||||||
@@ -267,4 +267,32 @@ mod tests {
|
|||||||
assert_eq!(converted["store"], false);
|
assert_eq!(converted["store"], false);
|
||||||
assert_eq!(converted["instructions"], "You are GPT-5.");
|
assert_eq!(converted["instructions"], "You are GPT-5.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strips_store_for_openai_compact_requests() {
|
||||||
|
let request = json!({
|
||||||
|
"model": "gpt-5",
|
||||||
|
"messages": [{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hello from OpenAI Chat"
|
||||||
|
}],
|
||||||
|
"store": true
|
||||||
|
});
|
||||||
|
|
||||||
|
let converted = build_standard_request_body(
|
||||||
|
&request,
|
||||||
|
"openai:chat",
|
||||||
|
"gpt-5",
|
||||||
|
"openai",
|
||||||
|
"openai:compact",
|
||||||
|
"/v1/chat/completions",
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("openai chat should convert to openai compact");
|
||||||
|
|
||||||
|
assert_eq!(converted["model"], "gpt-5");
|
||||||
|
assert!(converted.get("store").is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::super::codex::apply_codex_openai_cli_special_body_edits;
|
|
||||||
use crate::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
use crate::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
||||||
use crate::ai_pipeline::transport::apply_local_body_rules;
|
use crate::ai_pipeline::transport::apply_local_body_rules;
|
||||||
use crate::ai_pipeline::transport::url::{
|
use crate::ai_pipeline::transport::url::{
|
||||||
@@ -8,6 +7,7 @@ use crate::ai_pipeline::transport::url::{
|
|||||||
build_openai_cli_url, build_passthrough_path_url,
|
build_openai_cli_url, build_passthrough_path_url,
|
||||||
};
|
};
|
||||||
use crate::ai_pipeline::{
|
use crate::ai_pipeline::{
|
||||||
|
apply_codex_openai_cli_special_body_edits, apply_openai_compact_special_body_edits,
|
||||||
build_cross_format_openai_chat_request_body as pipeline_build_cross_format_openai_chat_request_body,
|
build_cross_format_openai_chat_request_body as pipeline_build_cross_format_openai_chat_request_body,
|
||||||
build_local_openai_chat_request_body as pipeline_build_local_openai_chat_request_body,
|
build_local_openai_chat_request_body as pipeline_build_local_openai_chat_request_body,
|
||||||
GatewayProviderTransportSnapshot,
|
GatewayProviderTransportSnapshot,
|
||||||
@@ -74,6 +74,7 @@ pub(crate) fn build_cross_format_openai_chat_request_body(
|
|||||||
body_rules,
|
body_rules,
|
||||||
user_api_key_id,
|
user_api_key_id,
|
||||||
);
|
);
|
||||||
|
apply_openai_compact_special_body_edits(&mut provider_request_body, provider_api_format);
|
||||||
Some(provider_request_body)
|
Some(provider_request_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::collections::BTreeMap;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
|
|
||||||
use super::super::codex::apply_codex_openai_cli_special_body_edits;
|
|
||||||
use crate::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
use crate::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
||||||
use crate::ai_pipeline::transport::antigravity::{
|
use crate::ai_pipeline::transport::antigravity::{
|
||||||
build_antigravity_v1internal_url, AntigravityRequestUrlAction,
|
build_antigravity_v1internal_url, AntigravityRequestUrlAction,
|
||||||
@@ -14,6 +13,7 @@ use crate::ai_pipeline::transport::url::{
|
|||||||
build_openai_cli_url, build_passthrough_path_url,
|
build_openai_cli_url, build_passthrough_path_url,
|
||||||
};
|
};
|
||||||
use crate::ai_pipeline::{
|
use crate::ai_pipeline::{
|
||||||
|
apply_codex_openai_cli_special_body_edits, apply_openai_compact_special_body_edits,
|
||||||
build_cross_format_openai_cli_request_body as pipeline_build_cross_format_openai_cli_request_body,
|
build_cross_format_openai_cli_request_body as pipeline_build_cross_format_openai_cli_request_body,
|
||||||
build_local_openai_cli_request_body as pipeline_build_local_openai_cli_request_body,
|
build_local_openai_cli_request_body as pipeline_build_local_openai_cli_request_body,
|
||||||
GatewayProviderTransportSnapshot,
|
GatewayProviderTransportSnapshot,
|
||||||
@@ -40,6 +40,7 @@ pub(crate) fn build_local_openai_cli_request_body(
|
|||||||
body_rules,
|
body_rules,
|
||||||
user_api_key_id,
|
user_api_key_id,
|
||||||
);
|
);
|
||||||
|
apply_openai_compact_special_body_edits(&mut provider_request_body, provider_api_format);
|
||||||
Some(provider_request_body)
|
Some(provider_request_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ pub(crate) fn build_cross_format_openai_cli_request_body(
|
|||||||
body_rules,
|
body_rules,
|
||||||
user_api_key_id,
|
user_api_key_id,
|
||||||
);
|
);
|
||||||
|
apply_openai_compact_special_body_edits(&mut provider_request_body, provider_api_format);
|
||||||
Some(provider_request_body)
|
Some(provider_request_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,28 @@ fn local_openai_cli_wrapper_preserves_body_order_after_edits() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_openai_compact_wrapper_strips_store_for_same_format_requests() {
|
||||||
|
let body_json = json!({
|
||||||
|
"model": "gpt-5.4",
|
||||||
|
"input": [],
|
||||||
|
"store": true
|
||||||
|
});
|
||||||
|
|
||||||
|
let provider_request_body = build_local_openai_cli_request_body(
|
||||||
|
&body_json,
|
||||||
|
"gpt-5.4",
|
||||||
|
false,
|
||||||
|
"openai",
|
||||||
|
"openai:compact",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("local openai compact body should build");
|
||||||
|
|
||||||
|
assert!(provider_request_body.get("store").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strips_metadata_for_codex_openai_cli_requests() {
|
fn strips_metadata_for_codex_openai_cli_requests() {
|
||||||
let body_json = json!({
|
let body_json = json!({
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ pub(crate) use aether_ai_pipeline::api::{
|
|||||||
aggregate_openai_chat_stream_sync_response, aggregate_openai_cli_stream_sync_response,
|
aggregate_openai_chat_stream_sync_response, aggregate_openai_cli_stream_sync_response,
|
||||||
aggregate_standard_chat_stream_sync_response, aggregate_standard_cli_stream_sync_response,
|
aggregate_standard_chat_stream_sync_response, aggregate_standard_cli_stream_sync_response,
|
||||||
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
||||||
augment_sync_report_context, build_core_error_body_for_client_format,
|
apply_openai_compact_special_body_edits, augment_sync_report_context,
|
||||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_cli_request_body,
|
build_core_error_body_for_client_format, build_cross_format_openai_chat_request_body,
|
||||||
build_generated_tool_call_id, build_kiro_final_message_sse_events,
|
build_cross_format_openai_cli_request_body, build_generated_tool_call_id,
|
||||||
build_kiro_initial_sse_events, build_kiro_stream_error_sse_events,
|
build_kiro_final_message_sse_events, build_kiro_initial_sse_events,
|
||||||
build_local_openai_chat_request_body, build_local_openai_cli_request_body,
|
build_kiro_stream_error_sse_events, build_local_openai_chat_request_body,
|
||||||
build_local_success_background_report, build_local_success_conversion_background_report,
|
build_local_openai_cli_request_body, build_local_success_background_report,
|
||||||
build_openai_cli_response, build_standard_request_body,
|
build_local_success_conversion_background_report, build_openai_cli_response,
|
||||||
build_standard_request_body_from_canonical, build_standard_upstream_url,
|
build_standard_request_body, build_standard_request_body_from_canonical,
|
||||||
calculate_kiro_context_input_tokens, canonicalize_tool_arguments,
|
build_standard_upstream_url, calculate_kiro_context_input_tokens, canonicalize_tool_arguments,
|
||||||
convert_claude_chat_response_to_openai_chat, convert_claude_cli_response_to_openai_cli,
|
convert_claude_chat_response_to_openai_chat, convert_claude_cli_response_to_openai_cli,
|
||||||
convert_gemini_chat_response_to_openai_chat, convert_gemini_cli_response_to_openai_cli,
|
convert_gemini_chat_response_to_openai_chat, convert_gemini_cli_response_to_openai_cli,
|
||||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||||
|
|||||||
@@ -139,9 +139,9 @@ pub use crate::planner::specialized::{
|
|||||||
};
|
};
|
||||||
pub use crate::planner::standard::{
|
pub use crate::planner::standard::{
|
||||||
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
||||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_cli_request_body,
|
apply_openai_compact_special_body_edits, build_cross_format_openai_chat_request_body,
|
||||||
build_local_openai_chat_request_body, build_local_openai_cli_request_body,
|
build_cross_format_openai_cli_request_body, build_local_openai_chat_request_body,
|
||||||
build_standard_request_body, build_standard_upstream_url,
|
build_local_openai_cli_request_body, build_standard_request_body, build_standard_upstream_url,
|
||||||
claude::{
|
claude::{
|
||||||
resolve_stream_spec as resolve_claude_stream_spec,
|
resolve_stream_spec as resolve_claude_stream_spec,
|
||||||
resolve_sync_spec as resolve_claude_sync_spec,
|
resolve_sync_spec as resolve_claude_sync_spec,
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ fn is_codex_openai_cli_request(provider_type: &str, provider_api_format: &str) -
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_openai_compact_request(provider_api_format: &str) -> bool {
|
||||||
|
provider_api_format
|
||||||
|
.trim()
|
||||||
|
.eq_ignore_ascii_case("openai:compact")
|
||||||
|
}
|
||||||
|
|
||||||
fn build_stable_codex_prompt_cache_key(user_api_key_id: &str) -> Option<String> {
|
fn build_stable_codex_prompt_cache_key(user_api_key_id: &str) -> Option<String> {
|
||||||
let normalized = user_api_key_id.trim();
|
let normalized = user_api_key_id.trim();
|
||||||
if normalized.is_empty() {
|
if normalized.is_empty() {
|
||||||
@@ -135,6 +141,22 @@ fn maybe_inject_codex_prompt_cache_key(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_openai_compact_special_body_edits(
|
||||||
|
provider_request_body: &mut Value,
|
||||||
|
provider_api_format: &str,
|
||||||
|
) {
|
||||||
|
if !is_openai_compact_request(provider_api_format) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(body_object) = provider_request_body.as_object_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// `/v1/responses/compact` does not accept `store`.
|
||||||
|
body_object.remove("store");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply_codex_openai_cli_special_body_edits(
|
pub fn apply_codex_openai_cli_special_body_edits(
|
||||||
provider_request_body: &mut Value,
|
provider_request_body: &mut Value,
|
||||||
provider_type: &str,
|
provider_type: &str,
|
||||||
@@ -162,7 +184,9 @@ pub fn apply_codex_openai_cli_special_body_edits(
|
|||||||
if !body_rules_handle_path(body_rules, "metadata") {
|
if !body_rules_handle_path(body_rules, "metadata") {
|
||||||
body_object.remove("metadata");
|
body_object.remove("metadata");
|
||||||
}
|
}
|
||||||
if !body_rules_handle_path(body_rules, "store") {
|
if is_openai_compact_request(provider_api_format) {
|
||||||
|
body_object.remove("store");
|
||||||
|
} else if !body_rules_handle_path(body_rules, "store") {
|
||||||
body_object.insert("store".to_string(), json!(false));
|
body_object.insert("store".to_string(), json!(false));
|
||||||
}
|
}
|
||||||
if !body_rules_handle_path(body_rules, "instructions")
|
if !body_rules_handle_path(body_rules, "instructions")
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use crate::conversion::request::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
codex::apply_codex_openai_cli_special_body_edits,
|
apply_openai_compact_special_body_edits, codex::apply_codex_openai_cli_special_body_edits,
|
||||||
normalize::build_local_openai_chat_request_body,
|
normalize::build_local_openai_chat_request_body,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ pub fn build_standard_request_body(
|
|||||||
body_rules,
|
body_rules,
|
||||||
user_api_key_id,
|
user_api_key_id,
|
||||||
);
|
);
|
||||||
|
apply_openai_compact_special_body_edits(&mut provider_request_body, provider_api_format);
|
||||||
Some(provider_request_body)
|
Some(provider_request_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub mod openai_cli;
|
|||||||
|
|
||||||
pub use codex::{
|
pub use codex::{
|
||||||
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
apply_codex_openai_cli_special_body_edits, apply_codex_openai_cli_special_headers,
|
||||||
|
apply_openai_compact_special_body_edits,
|
||||||
};
|
};
|
||||||
pub use family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
pub use family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
||||||
pub use matrix::{
|
pub use matrix::{
|
||||||
|
|||||||
Reference in New Issue
Block a user