mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 10:27:46 +08:00
feat(openai): align GPT-5.6 and Codex request contracts
This commit is contained in:
@@ -71,6 +71,7 @@ pub(crate) fn build_passthrough_stream_plan_from_decision(
|
||||
.content_type
|
||||
.take()
|
||||
.or_else(|| provider_request_headers.get("content-type").cloned());
|
||||
let stream = payload.upstream_is_stream;
|
||||
let plan = build_ai_execution_plan_from_decision(
|
||||
&mut payload,
|
||||
AiExecutionPlanFromDecisionParts {
|
||||
@@ -84,7 +85,7 @@ pub(crate) fn build_passthrough_stream_plan_from_decision(
|
||||
body_bytes_b64: None,
|
||||
body_ref: None,
|
||||
},
|
||||
stream: true,
|
||||
stream,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
+18
-2
@@ -60,7 +60,9 @@ pub(crate) async fn resolve_local_same_format_provider_decision_input(
|
||||
state,
|
||||
auth_context,
|
||||
Some(requested_model.as_str()),
|
||||
decision.auth_endpoint_signature.as_deref(),
|
||||
None,
|
||||
&decision.model_directive_policy,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -115,15 +117,22 @@ pub(crate) async fn materialize_local_same_format_provider_candidate_attempts(
|
||||
input.required_capabilities.as_ref(),
|
||||
LocalCandidatePersistencePolicyKind::SameFormatProviderDecision,
|
||||
);
|
||||
let model_directive_resolution = input
|
||||
.model_directive_policy
|
||||
.resolve_reasoning(spec_metadata.api_format, Some(&input.requested_model));
|
||||
let routing_model = model_directive_resolution
|
||||
.base_model()
|
||||
.unwrap_or(&input.requested_model);
|
||||
let (candidates, preselection_skipped) = planner_state
|
||||
.list_selectable_candidates_with_skip_reasons(
|
||||
spec_metadata.api_format,
|
||||
&input.requested_model,
|
||||
routing_model,
|
||||
spec_metadata.require_streaming,
|
||||
input.required_capabilities.as_ref(),
|
||||
Some(&input.auth_snapshot),
|
||||
input.client_session_affinity.as_ref(),
|
||||
current_unix_secs(),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let outcome = materialize_local_execution_candidates_with_serving(
|
||||
@@ -212,15 +221,22 @@ pub(crate) async fn build_local_same_format_provider_candidate_attempt_source<'a
|
||||
input.required_capabilities.as_ref(),
|
||||
LocalCandidatePersistencePolicyKind::SameFormatProviderDecision,
|
||||
);
|
||||
let model_directive_resolution = input
|
||||
.model_directive_policy
|
||||
.resolve_reasoning(spec_metadata.api_format, Some(&input.requested_model));
|
||||
let routing_model = model_directive_resolution
|
||||
.base_model()
|
||||
.unwrap_or(&input.requested_model);
|
||||
let (candidates, preselection_skipped) = planner_state
|
||||
.list_selectable_candidates_with_skip_reasons(
|
||||
spec_metadata.api_format,
|
||||
&input.requested_model,
|
||||
routing_model,
|
||||
spec_metadata.require_streaming,
|
||||
input.required_capabilities.as_ref(),
|
||||
Some(&input.auth_snapshot),
|
||||
input.client_session_affinity.as_ref(),
|
||||
current_unix_secs(),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::ai_serving::planner::report_context::{
|
||||
use crate::ai_serving::planner::spec_metadata::local_same_format_provider_spec_metadata;
|
||||
use crate::ai_serving::planner::CandidateFailureDiagnostic;
|
||||
use crate::ai_serving::planner::{
|
||||
build_ai_execution_decision_response, resolve_transport_request_gzip_policy,
|
||||
build_ai_execution_decision_response, resolve_transport_request_encoding_policy,
|
||||
AiExecutionDecisionResponseParts,
|
||||
};
|
||||
use crate::ai_serving::transport::{
|
||||
@@ -184,7 +184,7 @@ pub(crate) async fn maybe_build_local_same_format_provider_decision_payload_for_
|
||||
compatibility_edits: _,
|
||||
request_redacted: _,
|
||||
} = resolved;
|
||||
let request_gzip = resolve_transport_request_gzip_policy(&transport);
|
||||
let request_encoding = resolve_transport_request_encoding_policy(&transport);
|
||||
|
||||
let mut decision = build_ai_execution_decision_response(AiExecutionDecisionResponseParts {
|
||||
decision_is_stream: spec_metadata.require_streaming,
|
||||
@@ -194,6 +194,7 @@ pub(crate) async fn maybe_build_local_same_format_provider_decision_payload_for_
|
||||
request_id: trace_id.to_string(),
|
||||
candidate_id: candidate_id.to_string(),
|
||||
provider_name: transport.provider.name.clone(),
|
||||
provider_type: transport.provider.provider_type.clone(),
|
||||
provider_id: candidate.provider_id.clone(),
|
||||
endpoint_id: candidate.endpoint_id.clone(),
|
||||
key_id: candidate.key_id.clone(),
|
||||
@@ -211,8 +212,8 @@ pub(crate) async fn maybe_build_local_same_format_provider_decision_payload_for_
|
||||
provider_request_body: Some(provider_request_body),
|
||||
provider_request_body_base64: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
content_encoding: None,
|
||||
request_gzip,
|
||||
content_encoding: request_encoding.content_encoding,
|
||||
request_gzip: request_encoding.request_gzip,
|
||||
proxy,
|
||||
transport_profile,
|
||||
timeouts: resolve_transport_execution_timeouts(&transport),
|
||||
@@ -221,7 +222,11 @@ pub(crate) async fn maybe_build_local_same_format_provider_decision_payload_for_
|
||||
report_context: Some(report_context),
|
||||
auth_context: input.auth_context.clone(),
|
||||
});
|
||||
apply_provider_request_routing_policy_to_decision(input, &mut decision)?;
|
||||
apply_provider_request_routing_policy_to_decision(
|
||||
input,
|
||||
&mut decision,
|
||||
Some(transport.as_ref()),
|
||||
)?;
|
||||
Ok(Some(decision))
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,9 @@ use super::{
|
||||
LocalSameFormatProviderCandidateAttempt, LocalSameFormatProviderDecisionInput,
|
||||
LocalSameFormatProviderSpec,
|
||||
};
|
||||
use crate::ai_serving::planner::standard::same_format_provider_request_body_failure_extra_data;
|
||||
use crate::ai_serving::planner::standard::{
|
||||
codex_model_capabilities_for_transport, same_format_provider_request_body_failure_extra_data,
|
||||
};
|
||||
|
||||
pub(crate) fn resolve_same_format_provider_transport_unsupported_reason_for_trace(
|
||||
transport: &GatewayProviderTransportSnapshot,
|
||||
@@ -137,13 +139,26 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let enable_model_directives =
|
||||
crate::system_features::reasoning_model_directive_enabled_for_api_format_and_model(
|
||||
state,
|
||||
spec.api_format,
|
||||
Some(&input.requested_model),
|
||||
)
|
||||
.await;
|
||||
let model_directive_resolution = input
|
||||
.model_directive_policy
|
||||
.resolve_reasoning(spec.api_format, Some(&input.requested_model));
|
||||
let model_directive_mapping =
|
||||
match model_directive_resolution.mapping_patch_for_mapped_model(&prepared.mapped_model) {
|
||||
Ok(mapping) => mapping,
|
||||
Err(skip_reason) => {
|
||||
mark_skipped_local_same_format_provider_candidate(
|
||||
state,
|
||||
input,
|
||||
trace_id,
|
||||
candidate,
|
||||
attempt.candidate_index,
|
||||
&attempt.candidate_id,
|
||||
skip_reason,
|
||||
)
|
||||
.await;
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let effective_headers = input.effective_headers(&parts.headers);
|
||||
let redaction = resolve_provider_chat_pii_redaction(
|
||||
state,
|
||||
@@ -169,7 +184,7 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
prepared.force_body_stream_field,
|
||||
prepared.kiro_auth.as_ref(),
|
||||
prepared.is_claude_code,
|
||||
enable_model_directives,
|
||||
false,
|
||||
)
|
||||
else {
|
||||
mark_skipped_local_same_format_provider_candidate_with_extra_data(
|
||||
@@ -196,18 +211,11 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
};
|
||||
let mut base_provider_request_body = base_provider_request.body;
|
||||
let mut compatibility_edits = base_provider_request.compatibility_edits;
|
||||
if let Some(mapping) =
|
||||
crate::system_features::reasoning_model_directive_mapping_for_api_format_and_model(
|
||||
state,
|
||||
spec.api_format,
|
||||
Some(&input.requested_model),
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Some(mapping) = model_directive_mapping.as_ref() {
|
||||
let before_mapping = base_provider_request_body.clone();
|
||||
crate::ai_serving::apply_model_directive_mapping_patch(
|
||||
&mut base_provider_request_body,
|
||||
&mapping,
|
||||
mapping,
|
||||
);
|
||||
if before_mapping != base_provider_request_body {
|
||||
compatibility_edits.push(SameFormatProviderCompatibilityEdit {
|
||||
@@ -230,6 +238,48 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
}
|
||||
}
|
||||
|
||||
let source_model = body_json
|
||||
.get("model")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or(input.requested_model.as_str());
|
||||
let codex_model_capabilities = codex_model_capabilities_for_transport(
|
||||
&transport,
|
||||
prepared.provider_api_format.as_str(),
|
||||
prepared.mapped_model.as_str(),
|
||||
source_model,
|
||||
);
|
||||
if crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities(
|
||||
&mut base_provider_request_body,
|
||||
crate::ai_serving::OpenAiProviderRequestFinalization {
|
||||
source_api_format: spec.api_format,
|
||||
provider_api_format: prepared.provider_api_format.as_str(),
|
||||
provider_type: transport.provider.provider_type.as_str(),
|
||||
provider_model: prepared.mapped_model.as_str(),
|
||||
source_model,
|
||||
body_rules: transport.endpoint.body_rules.as_ref(),
|
||||
upstream_is_stream: prepared.upstream_is_stream,
|
||||
require_body_stream_field: request_requires_body_stream_field(
|
||||
body_json,
|
||||
prepared.force_body_stream_field,
|
||||
),
|
||||
},
|
||||
codex_model_capabilities.as_ref(),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
mark_skipped_local_same_format_provider_candidate(
|
||||
state,
|
||||
input,
|
||||
trace_id,
|
||||
candidate,
|
||||
attempt.candidate_index,
|
||||
&attempt.candidate_id,
|
||||
"provider_request_body_missing",
|
||||
)
|
||||
.await;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let antigravity_auth = if prepared.is_antigravity {
|
||||
let mut antigravity_support = classify_local_antigravity_request_support(
|
||||
&transport,
|
||||
@@ -467,6 +517,27 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
.await;
|
||||
return Ok(None);
|
||||
};
|
||||
crate::ai_serving::apply_codex_openai_special_headers(
|
||||
&mut provider_request_headers,
|
||||
&provider_request_body,
|
||||
effective_headers,
|
||||
transport.provider.provider_type.as_str(),
|
||||
prepared.provider_api_format.as_str(),
|
||||
Some(trace_id),
|
||||
transport.key.decrypted_auth_config.as_deref(),
|
||||
);
|
||||
let provider_model = provider_request_body
|
||||
.get("model")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or(prepared.mapped_model.as_str());
|
||||
crate::ai_serving::apply_codex_openai_responses_lite_header_with_capabilities(
|
||||
&mut provider_request_headers,
|
||||
transport.provider.provider_type.as_str(),
|
||||
prepared.provider_api_format.as_str(),
|
||||
provider_model,
|
||||
source_model,
|
||||
codex_model_capabilities.as_ref(),
|
||||
);
|
||||
request_identity_response_encoding_when_redacted(
|
||||
&mut provider_request_headers,
|
||||
redaction.redacted,
|
||||
|
||||
Reference in New Issue
Block a user