mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
Implement transport profile routing
This commit is contained in:
@@ -364,7 +364,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".to_string(),
|
||||
model_name: Some("gpt-5".to_string()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ async fn execute_mcp_request(
|
||||
provider_api_format: plan.provider_api_format.clone(),
|
||||
model_name: plan.model_name.clone(),
|
||||
proxy: plan.proxy.clone(),
|
||||
tls_profile: plan.tls_profile.clone(),
|
||||
transport_profile: plan.transport_profile.clone(),
|
||||
timeouts: plan.timeouts.clone(),
|
||||
};
|
||||
let result = DirectSyncExecutionRuntime::new()
|
||||
@@ -538,7 +538,7 @@ async fn discover_kiro_profile_arn_in_region(
|
||||
provider_api_format: "kiro:profiles".to_string(),
|
||||
model_name: Some("kiro-list-available-profiles".to_string()),
|
||||
proxy: plan.proxy.clone(),
|
||||
tls_profile: plan.tls_profile.clone(),
|
||||
transport_profile: plan.transport_profile.clone(),
|
||||
timeouts: plan.timeouts.clone(),
|
||||
};
|
||||
let result = DirectSyncExecutionRuntime::new()
|
||||
@@ -1208,7 +1208,7 @@ mod tests {
|
||||
provider_api_format: "claude:messages".to_string(),
|
||||
model_name: Some("claude-sonnet-4.6".to_string()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,6 +352,7 @@ impl IntoResponse for ExecutionRuntimeAppError {
|
||||
| ExecutionRuntimeTransportError::InvalidHeaderName(_)
|
||||
| ExecutionRuntimeTransportError::InvalidHeaderValue(_)
|
||||
| ExecutionRuntimeTransportError::InvalidProxy(_)
|
||||
| ExecutionRuntimeTransportError::UnsupportedTransportProfile(_)
|
||||
| ExecutionRuntimeTransportError::BodyEncode(_),
|
||||
) => StatusCode::BAD_REQUEST,
|
||||
ExecutionRuntimeServerError::Transport(
|
||||
@@ -422,7 +423,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(30_000),
|
||||
|
||||
@@ -2504,7 +2504,7 @@ mod tests {
|
||||
provider_api_format: "openai:responses".into(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2625,7 +2625,7 @@ mod tests {
|
||||
provider_api_format: "openai:responses".into(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2733,7 +2733,7 @@ mod tests {
|
||||
provider_api_format: "openai:image".into(),
|
||||
model_name: Some("gpt-image-1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2822,7 +2822,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2951,7 +2951,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
|
||||
@@ -777,7 +777,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -868,7 +868,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".to_string(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -986,7 +986,7 @@ mod tests {
|
||||
provider_api_format: "openai:responses".to_string(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1115,7 +1115,7 @@ mod tests {
|
||||
provider_api_format: "openai:image".to_string(),
|
||||
model_name: Some("gpt-image-1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1224,7 +1224,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1368,7 +1368,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-5".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
|
||||
@@ -64,7 +64,7 @@ fn missing_exact_provider_request_payload(decision_kind: &str) -> AiExecutionDec
|
||||
provider_request_body_base64: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
upstream_is_stream: false,
|
||||
report_kind: Some("openai_chat_sync_success".to_string()),
|
||||
@@ -806,7 +806,7 @@ fn bypasses_execution_runtime_for_codex_plan_variant() {
|
||||
provider_api_format: "openai:responses".to_string(),
|
||||
model_name: Some("gpt-5.4".to_string()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ use std::io::Write;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use aether_contracts::{
|
||||
ExecutionPlan, ExecutionResult, ExecutionTelemetry, ProxySnapshot, ResponseBody,
|
||||
EXECUTION_REQUEST_FOLLOW_REDIRECTS_HEADER, EXECUTION_REQUEST_HTTP1_ONLY_HEADER,
|
||||
ExecutionPlan, ExecutionResult, ExecutionTelemetry, ProxySnapshot, ResolvedTransportProfile,
|
||||
ResponseBody, EXECUTION_REQUEST_FOLLOW_REDIRECTS_HEADER, EXECUTION_REQUEST_HTTP1_ONLY_HEADER,
|
||||
TRANSPORT_BACKEND_REQWEST_RUSTLS, TRANSPORT_HTTP_MODE_HTTP1_ONLY,
|
||||
};
|
||||
use aether_data::repository::proxy_nodes::ProxyNodeTrafficMutation;
|
||||
use aether_http::{apply_http_client_config, HttpClientConfig};
|
||||
@@ -102,6 +103,8 @@ pub(crate) enum ExecutionRuntimeTransportError {
|
||||
InvalidHeaderValue(String),
|
||||
#[error("invalid proxy configuration: {0}")]
|
||||
InvalidProxy(reqwest::Error),
|
||||
#[error("unsupported transport profile backend: {0}")]
|
||||
UnsupportedTransportProfile(String),
|
||||
#[error("failed to encode request body: {0}")]
|
||||
BodyEncode(serde_json::Error),
|
||||
#[error("failed to build HTTP client: {0}")]
|
||||
@@ -116,6 +119,9 @@ pub(crate) enum ExecutionRuntimeTransportError {
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RelayRequestMeta {
|
||||
provider_id: String,
|
||||
endpoint_id: String,
|
||||
key_id: String,
|
||||
method: String,
|
||||
url: String,
|
||||
headers: BTreeMap<String, String>,
|
||||
@@ -124,6 +130,8 @@ struct RelayRequestMeta {
|
||||
follow_redirects: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
http1_only: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
transport_profile: Option<ResolvedTransportProfile>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@@ -531,12 +539,16 @@ fn build_direct_tunnel_request_meta(
|
||||
transport_controls: ExecutionTransportControls,
|
||||
) -> tunnel_protocol::RequestMeta {
|
||||
tunnel_protocol::RequestMeta {
|
||||
provider_id: Some(plan.provider_id.clone()),
|
||||
endpoint_id: Some(plan.endpoint_id.clone()),
|
||||
key_id: Some(plan.key_id.clone()),
|
||||
method: plan.method.clone(),
|
||||
url: plan.url.clone(),
|
||||
headers: header_map_to_string_map(headers).into_iter().collect(),
|
||||
timeout: resolve_relay_timeout_seconds(plan),
|
||||
follow_redirects: transport_controls.follow_redirects,
|
||||
http1_only: transport_controls.http1_only,
|
||||
transport_profile: plan.transport_profile.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,7 +589,7 @@ async fn send_request(
|
||||
let client = build_client(
|
||||
plan.timeouts.as_ref(),
|
||||
plan.proxy.as_ref(),
|
||||
plan.tls_profile.as_deref(),
|
||||
plan.transport_profile.as_ref(),
|
||||
transport_controls,
|
||||
)?;
|
||||
let mut request = client.request(method, &plan.url);
|
||||
@@ -604,12 +616,16 @@ async fn send_via_tunnel_relay(
|
||||
let timeout_secs = resolve_relay_timeout_seconds(plan);
|
||||
let envelope = build_relay_envelope(
|
||||
RelayRequestMeta {
|
||||
provider_id: plan.provider_id.clone(),
|
||||
endpoint_id: plan.endpoint_id.clone(),
|
||||
key_id: plan.key_id.clone(),
|
||||
method: method.as_str().to_string(),
|
||||
url: plan.url.clone(),
|
||||
headers: header_map_to_string_map(&headers),
|
||||
timeout: timeout_secs,
|
||||
follow_redirects: transport_controls.follow_redirects,
|
||||
http1_only: transport_controls.http1_only,
|
||||
transport_profile: plan.transport_profile.clone(),
|
||||
},
|
||||
&body_bytes,
|
||||
)?;
|
||||
@@ -856,14 +872,15 @@ fn resolve_local_tunnel_node_id(state: &AppState, proxy: Option<&ProxySnapshot>)
|
||||
fn build_client(
|
||||
timeouts: Option<&aether_contracts::ExecutionTimeouts>,
|
||||
proxy: Option<&ProxySnapshot>,
|
||||
tls_profile: Option<&str>,
|
||||
transport_profile: Option<&ResolvedTransportProfile>,
|
||||
transport_controls: ExecutionTransportControls,
|
||||
) -> Result<reqwest::Client, ExecutionRuntimeTransportError> {
|
||||
validate_reqwest_transport_profile(transport_profile)?;
|
||||
let mut builder = reqwest::Client::builder();
|
||||
if transport_controls.follow_redirects != Some(true) {
|
||||
builder = builder.redirect(Policy::none());
|
||||
}
|
||||
if transport_controls.http1_only {
|
||||
if transport_controls.http1_only || transport_profile_http1_only(transport_profile) {
|
||||
builder = builder.http1_only();
|
||||
}
|
||||
let mut builder = apply_http_client_config(
|
||||
@@ -873,7 +890,10 @@ fn build_client(
|
||||
..HttpClientConfig::default()
|
||||
},
|
||||
);
|
||||
builder = apply_tls_profile(builder, tls_profile);
|
||||
builder = apply_tls_profile(
|
||||
builder,
|
||||
transport_profile.map(|profile| profile.profile_id.as_str()),
|
||||
);
|
||||
if let Some(proxy_url) = resolve_proxy_url(proxy)? {
|
||||
let proxy = reqwest::Proxy::all(&proxy_url)
|
||||
.map_err(ExecutionRuntimeTransportError::InvalidProxy)?;
|
||||
@@ -884,11 +904,40 @@ fn build_client(
|
||||
.map_err(ExecutionRuntimeTransportError::ClientBuild)
|
||||
}
|
||||
|
||||
fn validate_reqwest_transport_profile(
|
||||
transport_profile: Option<&ResolvedTransportProfile>,
|
||||
) -> Result<(), ExecutionRuntimeTransportError> {
|
||||
let Some(profile) = transport_profile else {
|
||||
return Ok(());
|
||||
};
|
||||
if profile
|
||||
.backend
|
||||
.trim()
|
||||
.eq_ignore_ascii_case(TRANSPORT_BACKEND_REQWEST_RUSTLS)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
Err(ExecutionRuntimeTransportError::UnsupportedTransportProfile(
|
||||
profile.backend.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
fn transport_profile_http1_only(transport_profile: Option<&ResolvedTransportProfile>) -> bool {
|
||||
transport_profile
|
||||
.map(|profile| {
|
||||
profile
|
||||
.http_mode
|
||||
.trim()
|
||||
.eq_ignore_ascii_case(TRANSPORT_HTTP_MODE_HTTP1_ONLY)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn apply_tls_profile(
|
||||
builder: reqwest::ClientBuilder,
|
||||
tls_profile: Option<&str>,
|
||||
profile_id: Option<&str>,
|
||||
) -> reqwest::ClientBuilder {
|
||||
let profile = normalize_tls_profile(tls_profile);
|
||||
let profile = normalize_tls_profile(profile_id);
|
||||
if profile.is_none() {
|
||||
return builder;
|
||||
}
|
||||
@@ -1136,7 +1185,7 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use aether_contracts::{
|
||||
ExecutionPlan, ExecutionTimeouts, ProxySnapshot, RequestBody,
|
||||
ExecutionPlan, ExecutionTimeouts, ProxySnapshot, RequestBody, ResolvedTransportProfile,
|
||||
EXECUTION_REQUEST_FOLLOW_REDIRECTS_HEADER, EXECUTION_REQUEST_HTTP1_ONLY_HEADER,
|
||||
};
|
||||
use aether_data::repository::proxy_nodes::{
|
||||
@@ -1154,7 +1203,8 @@ mod tests {
|
||||
use super::{
|
||||
build_client, execute_sync_plan, record_manual_proxy_request_failure,
|
||||
record_manual_proxy_request_outcome, record_manual_proxy_request_success,
|
||||
record_manual_proxy_stream_error, DirectSyncExecutionRuntime, ExecutionTransportControls,
|
||||
record_manual_proxy_stream_error, DirectSyncExecutionRuntime,
|
||||
ExecutionRuntimeTransportError, ExecutionTransportControls,
|
||||
};
|
||||
use crate::constants::{
|
||||
EXECUTION_RUNTIME_LOOP_GUARD_HEADER, EXECUTION_RUNTIME_LOOP_GUARD_VIA_TOKEN,
|
||||
@@ -1346,7 +1396,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1394,7 +1444,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(manual_proxy_snapshot("manual-node-1")),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1438,7 +1488,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(manual_proxy_snapshot("manual-node-1")),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1482,7 +1532,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(manual_proxy_snapshot("manual-node-1")),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1526,7 +1576,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(manual_proxy_snapshot("manual-node-1")),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1570,7 +1620,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(manual_proxy_snapshot("manual-node-1")),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1616,7 +1666,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: None,
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: None,
|
||||
};
|
||||
|
||||
@@ -1696,7 +1746,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot(format!("http://{addr}"))),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1748,7 +1798,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot("http://127.0.0.1:1".to_string())),
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1897,7 +1947,7 @@ mod tests {
|
||||
provider_api_format: "provider_ops:verify".into(),
|
||||
model_name: Some("verify-auth".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -1976,7 +2026,7 @@ mod tests {
|
||||
provider_api_format: "provider_oauth:exchange".into(),
|
||||
model_name: Some("oauth-exchange".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2006,8 +2056,12 @@ mod tests {
|
||||
post(|Path(node_id): Path<String>, body: Bytes| async move {
|
||||
let (meta, request_body) = decode_relay_envelope(&body);
|
||||
assert_eq!(node_id, "node-1");
|
||||
assert_eq!(meta["provider_id"], "prov-1");
|
||||
assert_eq!(meta["endpoint_id"], "ep-1");
|
||||
assert_eq!(meta["key_id"], "key-1");
|
||||
assert_eq!(meta["http1_only"], true);
|
||||
assert_eq!(meta["follow_redirects"], json!(false));
|
||||
assert_eq!(meta["transport_profile"]["profile_id"], "relay-profile");
|
||||
let request_json: serde_json::Value =
|
||||
serde_json::from_slice(&request_body).expect("request body should be json");
|
||||
assert_eq!(request_json["model"], "gpt-4.1");
|
||||
@@ -2047,7 +2101,9 @@ mod tests {
|
||||
provider_api_format: "provider_ops:verify".into(),
|
||||
model_name: Some("verify-auth".into()),
|
||||
proxy: Some(tunnel_proxy_snapshot(format!("http://{addr}"))),
|
||||
tls_profile: None,
|
||||
transport_profile: Some(ResolvedTransportProfile::from_legacy_tls_profile(
|
||||
"relay-profile",
|
||||
)),
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2107,7 +2163,7 @@ mod tests {
|
||||
provider_api_format: "claude:messages".into(),
|
||||
model_name: Some("claude-3.7-sonnet".into()),
|
||||
proxy: None,
|
||||
tls_profile: Some("claude_code_nodejs".into()),
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2126,6 +2182,33 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_sync_execution_runtime_rejects_unsupported_transport_backend() {
|
||||
let profile = ResolvedTransportProfile {
|
||||
profile_id: "chrome-120".into(),
|
||||
backend: "utls".into(),
|
||||
http_mode: "auto".into(),
|
||||
pool_scope: "key".into(),
|
||||
extra: None,
|
||||
};
|
||||
|
||||
let error = match build_client(
|
||||
None,
|
||||
None,
|
||||
Some(&profile),
|
||||
ExecutionTransportControls::default(),
|
||||
) {
|
||||
Ok(_) => panic!("unsupported backend should fail"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
ExecutionRuntimeTransportError::UnsupportedTransportProfile(backend)
|
||||
if backend == "utls"
|
||||
));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn direct_sync_execution_runtime_compresses_json_body_when_requested() {
|
||||
let listener = crate::test_support::bind_loopback_listener()
|
||||
@@ -2182,7 +2265,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
@@ -2243,7 +2326,7 @@ mod tests {
|
||||
provider_api_format: "openai:chat".into(),
|
||||
model_name: Some("gpt-4.1".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
transport_profile: None,
|
||||
timeouts: Some(ExecutionTimeouts {
|
||||
connect_ms: Some(5_000),
|
||||
total_ms: Some(5_000),
|
||||
|
||||
Reference in New Issue
Block a user