From 5af3199f5ac72446e35d6188a57000c39248eb26 Mon Sep 17 00:00:00 2001 From: Spherrrical Date: Mon, 20 Apr 2026 13:18:44 -0700 Subject: [PATCH] Address PR feedback: error on stream=false for ChatGPT, fix auth file permissions --- cli/planoai/chatgpt_auth.py | 3 ++- crates/brightstaff/src/handlers/llm/mod.rs | 10 +++++++- crates/hermesllm/src/providers/request.rs | 29 +++++++++++++++------- crates/llm_gateway/src/stream_context.rs | 15 ++++++++++- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/cli/planoai/chatgpt_auth.py b/cli/planoai/chatgpt_auth.py index df4890de..dbbde3ac 100644 --- a/cli/planoai/chatgpt_auth.py +++ b/cli/planoai/chatgpt_auth.py @@ -51,7 +51,8 @@ def load_auth() -> Optional[Dict[str, Any]]: def save_auth(data: Dict[str, Any]): """Save auth data to disk.""" _ensure_auth_dir() - with open(CHATGPT_AUTH_FILE, "w") as f: + fd = os.open(CHATGPT_AUTH_FILE, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + with os.fdopen(fd, "w") as f: json.dump(data, f, indent=2) diff --git a/crates/brightstaff/src/handlers/llm/mod.rs b/crates/brightstaff/src/handlers/llm/mod.rs index 80455cfb..8e996a21 100644 --- a/crates/brightstaff/src/handlers/llm/mod.rs +++ b/crates/brightstaff/src/handlers/llm/mod.rs @@ -228,7 +228,15 @@ async fn llm_chat_inner( if let Some(ref client_api_kind) = client_api { let upstream_api = provider_id.compatible_api_for_client(client_api_kind, is_streaming_request); - client_request.normalize_for_upstream(provider_id, &upstream_api); + if let Err(e) = client_request.normalize_for_upstream(provider_id, &upstream_api) { + warn!( + "request_id={}: normalize_for_upstream failed: {}", + request_id, e + ); + let mut bad_request = Response::new(full(e.message)); + *bad_request.status_mut() = StatusCode::BAD_REQUEST; + return Ok(bad_request); + } } // --- Phase 2: Resolve conversation state (v1/responses API) --- diff --git a/crates/hermesllm/src/providers/request.rs b/crates/hermesllm/src/providers/request.rs index 76202080..aa100a17 100644 --- a/crates/hermesllm/src/providers/request.rs +++ b/crates/hermesllm/src/providers/request.rs @@ -77,7 +77,7 @@ impl ProviderRequestType { &mut self, provider_id: ProviderId, upstream_api: &SupportedUpstreamAPIs, - ) { + ) -> Result<(), ProviderRequestError> { if provider_id == ProviderId::XAI && matches!( upstream_api, @@ -110,6 +110,12 @@ impl ProviderRequestType { } } req.store = Some(false); + if req.stream == Some(false) { + return Err(ProviderRequestError { + message: "Non-streaming requests are not supported for the ChatGPT Codex provider. Set stream=true or omit the stream field.".to_string(), + source: None, + }); + } req.stream = Some(true); // ChatGPT backend requires input to be a list, not a plain string @@ -124,6 +130,7 @@ impl ProviderRequestType { } } } + Ok(()) } } @@ -859,10 +866,12 @@ mod tests { ..Default::default() }); - request.normalize_for_upstream( - ProviderId::XAI, - &SupportedUpstreamAPIs::OpenAIChatCompletions(OpenAIApi::ChatCompletions), - ); + request + .normalize_for_upstream( + ProviderId::XAI, + &SupportedUpstreamAPIs::OpenAIChatCompletions(OpenAIApi::ChatCompletions), + ) + .unwrap(); let ProviderRequestType::ChatCompletionsRequest(req) = request else { panic!("expected chat request"); @@ -887,10 +896,12 @@ mod tests { ..Default::default() }); - request.normalize_for_upstream( - ProviderId::OpenAI, - &SupportedUpstreamAPIs::OpenAIChatCompletions(OpenAIApi::ChatCompletions), - ); + request + .normalize_for_upstream( + ProviderId::OpenAI, + &SupportedUpstreamAPIs::OpenAIChatCompletions(OpenAIApi::ChatCompletions), + ) + .unwrap(); let ProviderRequestType::ChatCompletionsRequest(req) = request else { panic!("expected chat request"); diff --git a/crates/llm_gateway/src/stream_context.rs b/crates/llm_gateway/src/stream_context.rs index e8e9b0d7..9e3f3a99 100644 --- a/crates/llm_gateway/src/stream_context.rs +++ b/crates/llm_gateway/src/stream_context.rs @@ -1056,7 +1056,20 @@ impl HttpContext for StreamContext { match ProviderRequestType::try_from((deserialized_client_request, upstream)) { Ok(mut request) => { - request.normalize_for_upstream(self.get_provider_id(), upstream); + if let Err(e) = + request.normalize_for_upstream(self.get_provider_id(), upstream) + { + warn!( + "request_id={}: normalize_for_upstream failed: {}", + self.request_identifier(), + e + ); + self.send_server_error( + ServerError::LogicError(e.message), + Some(StatusCode::BAD_REQUEST), + ); + return Action::Pause; + } debug!( "request_id={}: upstream request payload: {}", self.request_identifier(),