diff --git a/config/plano_config_schema.yaml b/config/plano_config_schema.yaml index 3439ebee..b71f53cf 100644 --- a/config/plano_config_schema.yaml +++ b/config/plano_config_schema.yaml @@ -177,6 +177,11 @@ properties: passthrough_auth: type: boolean description: "When true, forwards the client's Authorization header to upstream instead of using the configured access_key. Useful for routing to services like LiteLLM that validate their own virtual keys." + http_headers: + type: object + description: "Custom HTTP headers to include in requests to this LLM provider. Useful for providers requiring non-standard authentication or telemetry headers." + additionalProperties: + type: string http_host: type: string provider_interface: @@ -226,6 +231,11 @@ properties: passthrough_auth: type: boolean description: "When true, forwards the client's Authorization header to upstream instead of using the configured access_key. Useful for routing to services like LiteLLM that validate their own virtual keys." + http_headers: + type: object + description: "Custom HTTP headers to include in requests to this LLM provider. Useful for providers requiring non-standard authentication or telemetry headers." + additionalProperties: + type: string http_host: type: string provider_interface: diff --git a/crates/common/src/configuration.rs b/crates/common/src/configuration.rs index 028c8046..880f918d 100644 --- a/crates/common/src/configuration.rs +++ b/crates/common/src/configuration.rs @@ -481,6 +481,7 @@ pub struct LlmProvider { pub base_url_path_prefix: Option, pub internal: Option, pub passthrough_auth: Option, + pub http_headers: Option>, } pub trait IntoModels { @@ -524,6 +525,7 @@ impl Default for LlmProvider { base_url_path_prefix: None, internal: None, passthrough_auth: None, + http_headers: None, } } } diff --git a/crates/common/src/llm_providers.rs b/crates/common/src/llm_providers.rs index b5c03b30..0c9a0017 100644 --- a/crates/common/src/llm_providers.rs +++ b/crates/common/src/llm_providers.rs @@ -277,6 +277,7 @@ mod tests { internal: None, stream: None, passthrough_auth: None, + http_headers: None, } } diff --git a/crates/llm_gateway/src/stream_context.rs b/crates/llm_gateway/src/stream_context.rs index e7763ee0..0e94b82b 100644 --- a/crates/llm_gateway/src/stream_context.rs +++ b/crates/llm_gateway/src/stream_context.rs @@ -244,6 +244,14 @@ impl StreamContext { Ok(()) } + fn set_custom_provider_headers(&mut self) { + if let Some(http_headers) = self.llm_provider().http_headers.clone() { + for (key, value) in &http_headers { + self.set_http_request_header(key.as_str(), Some(value.as_str())); + } + } + } + fn delete_content_length_header(&mut self) { // Remove the Content-Length header because further body manipulations in the gateway logic will invalidate it. // Server's generally throw away requests whose body length do not match the Content-Length header. @@ -891,6 +899,7 @@ impl HttpContext for StreamContext { self.send_server_error(error, Some(StatusCode::BAD_REQUEST)); } } + self.set_custom_provider_headers(); } self.delete_content_length_header();