diff --git a/crates/brightstaff/src/handlers/agent_chat_completions.rs b/crates/brightstaff/src/handlers/agent_chat_completions.rs index a1a00f88..3a90fc48 100644 --- a/crates/brightstaff/src/handlers/agent_chat_completions.rs +++ b/crates/brightstaff/src/handlers/agent_chat_completions.rs @@ -37,7 +37,38 @@ pub async fn agent_chat( match handle_agent_chat(request, router_service, agents_list, listeners).await { Ok(response) => Ok(response), Err(err) => { - // Print detailed error information with full error chain + // Check if this is a client error from the pipeline that should be cascaded + if let AgentFilterChainError::Pipeline(PipelineError::ClientError { + agent, + status, + body, + }) = &err + { + warn!( + "Client error from agent '{}' (HTTP {}): {}", + agent, status, body + ); + + // Create error response with the original status code and body + let error_json = serde_json::json!({ + "error": "ClientError", + "agent": agent, + "status": status, + "agent_response": body + }); + + let json_string = error_json.to_string(); + let mut response = Response::new(ResponseHandler::create_full_body(json_string)); + *response.status_mut() = hyper::StatusCode::from_u16(*status) + .unwrap_or(hyper::StatusCode::INTERNAL_SERVER_ERROR); + response.headers_mut().insert( + hyper::header::CONTENT_TYPE, + "application/json".parse().unwrap(), + ); + return Ok(response); + } + + // Print detailed error information with full error chain for other errors let mut error_chain = Vec::new(); let mut current_error: &dyn std::error::Error = &err; diff --git a/crates/brightstaff/src/handlers/pipeline_processor.rs b/crates/brightstaff/src/handlers/pipeline_processor.rs index b62ce175..4d83325a 100644 --- a/crates/brightstaff/src/handlers/pipeline_processor.rs +++ b/crates/brightstaff/src/handlers/pipeline_processor.rs @@ -19,6 +19,18 @@ pub enum PipelineError { NoChoicesInResponse(String), #[error("No content in response from agent '{0}'")] NoContentInResponse(String), + #[error("Client error from agent '{agent}' (HTTP {status}): {body}")] + ClientError { + agent: String, + status: u16, + body: String, + }, + #[error("Server error from agent '{agent}' (HTTP {status}): {body}")] + ServerError { + agent: String, + status: u16, + body: String, + }, } /// Service for processing agent pipelines @@ -122,8 +134,30 @@ impl PipelineProcessor { .send() .await?; + let status = response.status(); let response_bytes = response.bytes().await?; + // Check for HTTP errors and handle them appropriately + if !status.is_success() { + let error_body = String::from_utf8_lossy(&response_bytes).to_string(); + + if status.is_client_error() { + // 4xx errors - cascade back to developer + return Err(PipelineError::ClientError { + agent: agent.id.clone(), + status: status.as_u16(), + body: error_body, + }); + } else if status.is_server_error() { + // 5xx errors - server/agent error + return Err(PipelineError::ServerError { + agent: agent.id.clone(), + status: status.as_u16(), + body: error_body, + }); + } + } + // Parse the response as JSON to extract the content let response_json: serde_json::Value = serde_json::from_slice(&response_bytes)?;