diff --git a/apps/aether-gateway/src/control/tests/admin_pool.rs b/apps/aether-gateway/src/control/tests/admin_pool.rs index dd177c268..373d818d7 100644 --- a/apps/aether-gateway/src/control/tests/admin_pool.rs +++ b/apps/aether-gateway/src/control/tests/admin_pool.rs @@ -1,6 +1,8 @@ use http::Uri; use super::{classify_control_route, headers}; +use crate::control::GatewayPublicRequestContext; +use crate::handlers::shared::local_proxy_route_requires_buffered_body; #[test] fn classifies_admin_pool_overview_as_admin_proxy_route() { @@ -92,6 +94,16 @@ fn classifies_admin_pool_provider_key_routes_as_admin_proxy_route() { batch_update.route_kind.as_deref(), Some("batch_update_keys") ); + let batch_update_context = GatewayPublicRequestContext::from_request_parts( + "trace-admin-pool-batch-update", + &http::Method::PATCH, + &batch_update_uri, + &headers, + Some(batch_update), + ); + assert!(local_proxy_route_requires_buffered_body( + &batch_update_context + )); let resolve_selection_uri: Uri = "/api/admin/pool/provider-1/keys/resolve-selection" .parse() diff --git a/apps/aether-gateway/src/handlers/shared/request_utils.rs b/apps/aether-gateway/src/handlers/shared/request_utils.rs index 8267b1382..a9a7895fb 100644 --- a/apps/aether-gateway/src/handlers/shared/request_utils.rs +++ b/apps/aether-gateway/src/handlers/shared/request_utils.rs @@ -377,6 +377,7 @@ pub(crate) fn admin_proxy_local_requires_buffered_body( | (Some("users_manage"), http::Method::PATCH, Some("lock_user_api_key")) | (Some("pool_manage"), http::Method::POST, Some("batch_import_keys")) | (Some("pool_manage"), http::Method::POST, Some("batch_action_keys")) + | (Some("pool_manage"), http::Method::PATCH, Some("batch_update_keys")) | (Some("pool_manage"), http::Method::POST, Some("resolve_selection")) | (Some("usage_manage"), http::Method::POST, Some("replay")) | (Some("wallets_manage"), http::Method::POST, Some("adjust_balance")) diff --git a/apps/aether-gateway/src/tests/control/admin/pool.rs b/apps/aether-gateway/src/tests/control/admin/pool.rs index a2c98945a..c201ce0e8 100644 --- a/apps/aether-gateway/src/tests/control/admin/pool.rs +++ b/apps/aether-gateway/src/tests/control/admin/pool.rs @@ -3615,19 +3615,26 @@ async fn gateway_batch_updates_shared_pool_key_configuration() { Vec::new(), vec![first_key, second_key], )); - let state = AppState::new() - .expect("gateway should build") - .with_data_state_for_tests( - GatewayDataState::with_provider_catalog_repository_for_tests(Arc::clone( - &provider_catalog_repository, - )), - ); + let gateway = build_router_with_state( + AppState::new() + .expect("gateway should build") + .with_data_state_for_tests( + GatewayDataState::with_provider_catalog_repository_for_tests(Arc::clone( + &provider_catalog_repository, + )), + ), + ); + let (gateway_url, gateway_handle) = start_server(gateway).await; - let response = local_admin_pool_response( - &state, - http::Method::PATCH, - "/api/admin/pool/provider-openai/keys/batch-update", - Some(json!({ + let response = reqwest::Client::new() + .patch(format!( + "{gateway_url}/api/admin/pool/provider-openai/keys/batch-update" + )) + .header(crate::constants::GATEWAY_HEADER, "rust-phase3b") + .header(TRUSTED_ADMIN_USER_ID_HEADER, "admin-user-123") + .header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin") + .header(TRUSTED_ADMIN_SESSION_ID_HEADER, "session-123") + .json(&json!({ "key_ids": ["key-openai-b", "key-openai-a", "key-openai-a"], "patch": { "api_formats": ["openai:responses"], @@ -3638,17 +3645,13 @@ async fn gateway_batch_updates_shared_pool_key_configuration() { "locked_models": [], "note": null } - })), - ) - .await; + })) + .send() + .await + .expect("request should succeed"); assert_eq!(response.status(), StatusCode::OK); - let payload: serde_json::Value = serde_json::from_slice( - &to_bytes(response.into_body(), usize::MAX) - .await - .expect("body should read"), - ) - .expect("json body should parse"); + let payload: serde_json::Value = response.json().await.expect("json body should parse"); assert_eq!(payload["affected"], json!(2)); assert_eq!(payload["model_sync"], serde_json::Value::Null); @@ -3670,6 +3673,8 @@ async fn gateway_batch_updates_shared_pool_key_configuration() { assert_eq!(key.locked_models, None); assert_eq!(key.note, None); } + + gateway_handle.abort(); } #[tokio::test] diff --git a/crates/aether-ai/formats/src/formats/openai/chat/stream.rs b/crates/aether-ai/formats/src/formats/openai/chat/stream.rs index cf5950cf6..fd9be3bbe 100644 --- a/crates/aether-ai/formats/src/formats/openai/chat/stream.rs +++ b/crates/aether-ai/formats/src/formats/openai/chat/stream.rs @@ -2226,7 +2226,7 @@ impl OpenAIResponsesClientEmitter { fn reasoning_item_id(&self) -> String { self.reasoning_item_id .clone() - .unwrap_or_else(|| openai_responses_synthetic_reasoning_item_id(&self.response_id(), 0)) + .unwrap_or_else(|| openai_responses_synthetic_reasoning_item_id(self.response_id(), 0)) } fn ensure_message_item_id(&mut self) -> String { @@ -2239,7 +2239,7 @@ impl OpenAIResponsesClientEmitter { fn ensure_reasoning_item_id(&mut self) -> String { if self.reasoning_item_id.is_none() { self.reasoning_item_id = Some(openai_responses_synthetic_reasoning_item_id( - &self.response_id(), + self.response_id(), 0, )); }