@@ -94,6 +94,12 @@ impl<H: HttpInfra> OpenAIProvider<H> {
9494 }
9595 forge_domain:: AuthMethod :: GoogleAdc => { }
9696 } ) ;
97+ // Append provider-level custom headers (from provider.json config)
98+ if let Some ( custom_headers) = & self . provider . custom_headers {
99+ for ( k, v) in custom_headers {
100+ headers. push ( ( k. clone ( ) , v. clone ( ) ) ) ;
101+ }
102+ }
97103 headers
98104 }
99105
@@ -274,6 +280,7 @@ mod tests {
274280 response : Some ( ProviderResponse :: OpenAI ) ,
275281 url : Url :: parse ( "https://api.openai.com/v1/chat/completions" ) . unwrap ( ) ,
276282 credential : make_credential ( ProviderId :: OPENAI , key) ,
283+ custom_headers : None ,
277284 auth_methods : vec ! [ forge_domain:: AuthMethod :: ApiKey ] ,
278285 url_params : vec ! [ ] ,
279286 models : Some ( forge_domain:: ModelSource :: Url (
@@ -289,6 +296,7 @@ mod tests {
289296 response : Some ( ProviderResponse :: OpenAI ) ,
290297 url : Url :: parse ( "https://api.z.ai/api/paas/v4/chat/completions" ) . unwrap ( ) ,
291298 credential : make_credential ( ProviderId :: ZAI , key) ,
299+ custom_headers : None ,
292300 auth_methods : vec ! [ forge_domain:: AuthMethod :: ApiKey ] ,
293301 url_params : vec ! [ ] ,
294302 models : Some ( forge_domain:: ModelSource :: Url (
@@ -304,6 +312,7 @@ mod tests {
304312 response : Some ( ProviderResponse :: OpenAI ) ,
305313 url : Url :: parse ( "https://api.z.ai/api/coding/paas/v4/chat/completions" ) . unwrap ( ) ,
306314 credential : make_credential ( ProviderId :: ZAI_CODING , key) ,
315+ custom_headers : None ,
307316 auth_methods : vec ! [ forge_domain:: AuthMethod :: ApiKey ] ,
308317 url_params : vec ! [ ] ,
309318 models : Some ( forge_domain:: ModelSource :: Url (
@@ -319,6 +328,7 @@ mod tests {
319328 response : Some ( ProviderResponse :: Anthropic ) ,
320329 url : Url :: parse ( "https://api.anthropic.com/v1/messages" ) . unwrap ( ) ,
321330 credential : make_credential ( ProviderId :: ANTHROPIC , key) ,
331+ custom_headers : None ,
322332 auth_methods : vec ! [ forge_domain:: AuthMethod :: ApiKey ] ,
323333 url_params : vec ! [ ] ,
324334 models : Some ( forge_domain:: ModelSource :: Url (
@@ -383,6 +393,7 @@ mod tests {
383393 response : Some ( ProviderResponse :: OpenAI ) ,
384394 url : reqwest:: Url :: parse ( base_url) ?,
385395 credential : make_credential ( ProviderId :: OPENAI , "test-api-key" ) ,
396+ custom_headers : None ,
386397 auth_methods : vec ! [ forge_domain:: AuthMethod :: ApiKey ] ,
387398 url_params : vec ! [ ] ,
388399 models : Some ( forge_domain:: ModelSource :: Url (
@@ -691,6 +702,51 @@ mod tests {
691702 let error_string = format ! ( "{:#}" , actual) ;
692703 insta:: assert_snapshot!( error_string) ;
693704 }
705+
706+ #[ test]
707+ fn test_get_headers_includes_custom_headers ( ) {
708+ let mut provider = openai ( "test-key" ) ;
709+ let mut custom = std:: collections:: HashMap :: new ( ) ;
710+ custom. insert ( "User-Agent" . to_string ( ) , "KimiCLI/1.0.0" . to_string ( ) ) ;
711+ custom. insert ( "X-Custom" . to_string ( ) , "custom-value" . to_string ( ) ) ;
712+ provider. custom_headers = Some ( custom) ;
713+
714+ let http_client = Arc :: new ( MockHttpClient :: new ( ) ) ;
715+ let openai_provider = OpenAIProvider :: new ( provider, http_client) ;
716+ let headers = openai_provider. get_headers ( ) ;
717+
718+ assert ! (
719+ headers
720+ . iter( )
721+ . any( |( k, v) | k == "User-Agent" && v == "KimiCLI/1.0.0" )
722+ ) ;
723+ assert ! (
724+ headers
725+ . iter( )
726+ . any( |( k, v) | k == "X-Custom" && v == "custom-value" )
727+ ) ;
728+ assert ! (
729+ headers
730+ . iter( )
731+ . any( |( k, v) | k == "authorization" && v == "Bearer test-key" )
732+ ) ;
733+ }
734+
735+ #[ test]
736+ fn test_get_headers_no_custom_headers ( ) {
737+ let provider = openai ( "test-key" ) ;
738+ let http_client = Arc :: new ( MockHttpClient :: new ( ) ) ;
739+ let openai_provider = OpenAIProvider :: new ( provider, http_client) ;
740+ let headers = openai_provider. get_headers ( ) ;
741+
742+ // Only authorization header should be present
743+ assert_eq ! ( headers. len( ) , 1 ) ;
744+ assert ! (
745+ headers
746+ . iter( )
747+ . any( |( k, v) | k == "authorization" && v == "Bearer test-key" )
748+ ) ;
749+ }
694750}
695751
696752/// Repository for OpenAI-compatible provider responses
0 commit comments