fix(ws): harden Responses continuation state

This commit is contained in:
ZheFox
2026-08-20 08:51:16 +08:00
parent bef282cfee
commit 654f798d25
45 changed files with 6403 additions and 493 deletions
@@ -101,6 +101,22 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision(
input: &LocalRequestedModelDecisionInput,
decision: &mut AiExecutionDecision,
transport: Option<&GatewayProviderTransportSnapshot>,
) -> Result<(), GatewayError> {
apply_provider_request_routing_policy_to_decision_with_websocket_mode(
input, decision, transport, false,
)
}
/// Applies provider-request routing mutations while retaining the transport
/// boundary of a pinned Responses WebSocket continuation. Routing rules may
/// mutate the body and therefore require a second provider-contract pass; the
/// pass must use the same explicit continuation mode as the first pass rather
/// than guessing from JSON fields.
pub(crate) fn apply_provider_request_routing_policy_to_decision_with_websocket_mode(
input: &LocalRequestedModelDecisionInput,
decision: &mut AiExecutionDecision,
transport: Option<&GatewayProviderTransportSnapshot>,
websocket_continuation: bool,
) -> Result<(), GatewayError> {
let provider_api_format = decision
.provider_api_format
@@ -257,9 +273,8 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision(
input.requested_model.as_str(),
)
});
crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy(
&mut provider_request_body,
crate::ai_serving::OpenAiProviderRequestFinalization {
{
let finalization = crate::ai_serving::OpenAiProviderRequestFinalization {
source_api_format: context.client_api_format.as_str(),
provider_api_format: provider_api_format.as_str(),
provider_type: provider_type.as_str(),
@@ -270,17 +285,31 @@ pub(crate) fn apply_provider_request_routing_policy_to_decision(
require_body_stream_field: original_provider_request_body
.as_ref()
.is_some_and(|body| body.get("stream").is_some()),
},
model_capabilities.as_ref(),
transport
};
let reasoning_replay_policy = transport
.map(|transport| {
crate::ai_serving::openai_responses_reasoning_replay_policy(
transport.provider.provider_type.as_str(),
transport.endpoint.base_url.as_str(),
)
})
.unwrap_or_default(),
)
.unwrap_or_default();
if websocket_continuation {
crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy_for_websocket_continuation(
&mut provider_request_body,
finalization,
model_capabilities.as_ref(),
reasoning_replay_policy,
)
} else {
crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy(
&mut provider_request_body,
finalization,
model_capabilities.as_ref(),
reasoning_replay_policy,
)
}
}
.map_err(|violation| GatewayError::Client {
status: StatusCode::BAD_REQUEST,
message: format!("routing provider_request violates provider contract: {violation:?}"),