mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-11 11:49:50 +08:00
对齐 Codex CLI 0.159.3 的通用画像、模型能力与原生协议
This commit is contained in:
@@ -101,7 +101,9 @@ fn build_sync_plan_payload_from_decision(
|
||||
OPENAI_RESPONSES_SYNC_PLAN_KIND => {
|
||||
build_openai_responses_sync_plan_from_decision(parts, body_json, payload, false)?
|
||||
}
|
||||
OPENAI_IMAGE_SYNC_PLAN_KIND | OPENAI_SEARCH_SYNC_PLAN_KIND => {
|
||||
OPENAI_IMAGE_SYNC_PLAN_KIND
|
||||
| OPENAI_SEARCH_SYNC_PLAN_KIND
|
||||
| aether_ai_formats::contracts::OPENAI_MEMORIES_SYNC_PLAN_KIND => {
|
||||
build_passthrough_sync_plan_from_decision(parts, payload)?
|
||||
}
|
||||
OPENAI_RESPONSES_COMPACT_SYNC_PLAN_KIND => {
|
||||
|
||||
@@ -123,6 +123,8 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
transport: Option<&GatewayProviderTransportSnapshot>,
|
||||
websocket_continuation: bool,
|
||||
) -> Result<(), GatewayError> {
|
||||
let native_memories = decision.decision_kind.as_deref()
|
||||
== Some(aether_ai_formats::contracts::OPENAI_MEMORIES_SYNC_PLAN_KIND);
|
||||
let provider_api_format = decision
|
||||
.provider_api_format
|
||||
.clone()
|
||||
@@ -150,7 +152,12 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
input.requested_model.as_str(),
|
||||
)
|
||||
});
|
||||
crate::ai_serving::apply_codex_openai_responses_lite_header_for_request_body_with_capabilities(
|
||||
if native_memories {
|
||||
decision
|
||||
.provider_request_headers
|
||||
.retain(|name, _| !name.eq_ignore_ascii_case(CODEX_RESPONSES_LITE_HEADER));
|
||||
} else {
|
||||
crate::ai_serving::apply_codex_openai_responses_lite_header_for_request_body_with_capabilities(
|
||||
&mut decision.provider_request_headers,
|
||||
decision.provider_request_body.as_ref(),
|
||||
provider_type.as_str(),
|
||||
@@ -159,6 +166,7 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
input.requested_model.as_str(),
|
||||
model_capabilities.as_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
let Some(context) = input.routing_context.as_ref() else {
|
||||
// Cache identity headers are projected only at the terminal boundary. Any non-empty
|
||||
@@ -260,7 +268,7 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
provider_headers.insert(HeaderName::from_static(name), value);
|
||||
}
|
||||
}
|
||||
if original_provider_request_body.is_some() {
|
||||
if original_provider_request_body.is_some() && !native_memories {
|
||||
let provider_model = provider_request_body
|
||||
.get("model")
|
||||
.and_then(Value::as_str)
|
||||
@@ -318,6 +326,12 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
}
|
||||
.map_err(|_| invalid_routing_provider_contract())?;
|
||||
}
|
||||
if native_memories {
|
||||
crate::ai_serving::transport::enforce_same_format_provider_api_operation_body_policy(
|
||||
&mut provider_request_body,
|
||||
Some(crate::ai_serving::ApiOperation::OpenAiMemoriesSummarize),
|
||||
);
|
||||
}
|
||||
let provider_model = provider_request_body
|
||||
.get("model")
|
||||
.and_then(Value::as_str)
|
||||
@@ -339,7 +353,11 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
provider_type.as_str(),
|
||||
provider_api_format.as_str(),
|
||||
);
|
||||
crate::ai_serving::apply_codex_openai_responses_lite_header_for_request_body_with_capabilities(
|
||||
if native_memories {
|
||||
provider_request_headers
|
||||
.retain(|name, _| !name.eq_ignore_ascii_case(CODEX_RESPONSES_LITE_HEADER));
|
||||
} else {
|
||||
crate::ai_serving::apply_codex_openai_responses_lite_header_for_request_body_with_capabilities(
|
||||
&mut provider_request_headers,
|
||||
Some(&provider_request_body),
|
||||
provider_type.as_str(),
|
||||
@@ -348,6 +366,7 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_m
|
||||
input.requested_model.as_str(),
|
||||
model_capabilities.as_ref(),
|
||||
);
|
||||
}
|
||||
crate::ai_serving::apply_codex_openai_compact_terminal_headers(
|
||||
&mut provider_request_headers,
|
||||
provider_type.as_str(),
|
||||
@@ -382,6 +401,17 @@ fn apply_provider_outbound_request_policies_to_decision(
|
||||
let Some(context) = input.provider_outbound_context.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let native_context;
|
||||
let context = if decision.decision_kind.as_deref()
|
||||
== Some(aether_ai_formats::contracts::OPENAI_MEMORIES_SYNC_PLAN_KIND)
|
||||
{
|
||||
native_context = context
|
||||
.clone()
|
||||
.with_api_operation(crate::ai_serving::ApiOperation::OpenAiMemoriesSummarize);
|
||||
&native_context
|
||||
} else {
|
||||
context
|
||||
};
|
||||
let results = crate::ai_serving::transport::apply_provider_outbound_request_policies(
|
||||
transport,
|
||||
provider_api_format,
|
||||
|
||||
@@ -255,7 +255,9 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
// re-enforce stream-field policy afterward.
|
||||
// Kiro behavior classification already hard-requires upstream streaming,
|
||||
// and the Kiro envelope does not use a top-level body stream field.
|
||||
if prepared.kiro_auth.is_none() {
|
||||
if prepared.kiro_auth.is_none()
|
||||
&& spec.operation != Some(crate::ai_serving::ApiOperation::OpenAiMemoriesSummarize)
|
||||
{
|
||||
enforce_provider_body_stream_policy(
|
||||
&mut base_provider_request_body,
|
||||
prepared.provider_api_format.as_str(),
|
||||
@@ -275,7 +277,8 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
prepared.mapped_model.as_str(),
|
||||
source_model,
|
||||
);
|
||||
if let Err(violation) =
|
||||
if spec.operation != Some(crate::ai_serving::ApiOperation::OpenAiMemoriesSummarize) {
|
||||
if let Err(violation) =
|
||||
crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy(
|
||||
&mut base_provider_request_body,
|
||||
crate::ai_serving::OpenAiProviderRequestFinalization {
|
||||
@@ -313,6 +316,7 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
.await;
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
// Same-format requests skip `apply_transport_request_body_semantics`, so the opt-in
|
||||
// Claude Code body mimicry has to be applied here as well.
|
||||
@@ -597,6 +601,14 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
source_model,
|
||||
codex_model_capabilities.as_ref(),
|
||||
);
|
||||
if spec.operation == Some(crate::ai_serving::ApiOperation::OpenAiMemoriesSummarize) {
|
||||
provider_request_headers.retain(|name, _| {
|
||||
!name.eq_ignore_ascii_case(
|
||||
aether_ai_formats::formats::openai::responses::codex::CODEX_RESPONSES_LITE_HEADER,
|
||||
)
|
||||
});
|
||||
provider_request_headers.insert("accept".to_string(), "application/json".to_string());
|
||||
}
|
||||
crate::ai_serving::transport::xai::insert_cli_identity_headers_if_needed(
|
||||
transport.as_ref(),
|
||||
prepared.provider_api_format.as_str(),
|
||||
|
||||
@@ -3,7 +3,7 @@ use serde_json::Value;
|
||||
use super::super::LocalSameFormatProviderSpec;
|
||||
use crate::ai_serving::transport::{
|
||||
build_same_format_provider_request_body as build_same_format_provider_request_body_impl,
|
||||
build_same_format_provider_request_body_with_compatibility_report_and_reasoning_replay_policy as build_same_format_provider_request_body_with_compatibility_report_impl,
|
||||
build_same_format_provider_request_body_for_operation as build_same_format_provider_request_body_with_compatibility_report_impl,
|
||||
SameFormatProviderFamily, SameFormatProviderRequestBodyInput,
|
||||
SameFormatProviderRequestBodyOutput,
|
||||
};
|
||||
@@ -69,6 +69,7 @@ pub(crate) fn build_same_format_provider_request_body_with_compatibility_report(
|
||||
enable_model_directives,
|
||||
},
|
||||
reasoning_replay_policy,
|
||||
spec.operation,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user