11from __future__ import annotations
22
33import logging
4- from collections .abc import Callable
4+ from collections .abc import Callable , Mapping
55from typing import Any , cast
66
77import httpx
@@ -58,6 +58,22 @@ def _build_openrouter_header_context(self) -> dict[str, str]:
5858
5959 return {"app_site_url" : referer , "app_x_title" : title }
6060
61+ @staticmethod
62+ def _authorization_includes_api_key (
63+ headers : Mapping [str , str ], api_key : str | None
64+ ) -> bool :
65+ """Check whether the Authorization header contains the expected API key."""
66+
67+ if not api_key :
68+ return True
69+
70+ for header_name , value in headers .items ():
71+ if header_name .lower () == "authorization" and isinstance (value , str ):
72+ if api_key in value :
73+ return True
74+
75+ return False
76+
6177 def _resolve_headers_from_provider (self ) -> dict [str , str ]:
6278 """Call the configured headers provider with appropriate arguments."""
6379 if not self .headers_provider or not self .api_key :
@@ -69,26 +85,57 @@ def _resolve_headers_from_provider(self) -> dict[str, str]:
6985 provider = self .headers_provider
7086 errors : list [Exception ] = []
7187
72- if self . key_name is not None :
88+ def _try_provider_call ( * args : Any ) -> dict [ str , str ] | None :
7389 try :
74- return provider (self . key_name , self . api_key )
90+ result = provider (* args )
7591 except (AttributeError , TypeError ) as exc :
7692 errors .append (exc )
93+ return None
94+ except Exception as exc :
95+ errors .append (exc )
96+ return None
7797
78- context = self ._build_openrouter_header_context ()
79- try :
80- return provider (context , self .api_key )
81- except Exception as exc : # pragma: no cover - should not happen in normal flow
82- if errors :
83- logger .debug (
84- "Headers provider rejected key_name input: %s" ,
85- errors [- 1 ],
86- exc_info = True ,
98+ if not isinstance (result , Mapping ):
99+ errors .append (
100+ TypeError ("OpenRouter headers provider must return a mapping." ),
87101 )
88- raise AuthenticationError (
89- message = "OpenRouter headers provider failed to produce headers." ,
90- code = "missing_credentials" ,
91- ) from exc
102+ return None
103+
104+ headers = dict (result )
105+ if not self ._authorization_includes_api_key (headers , self .api_key ):
106+ errors .append (
107+ ValueError (
108+ "OpenRouter headers provider did not include API key in Authorization header." ,
109+ )
110+ )
111+ return None
112+
113+ return headers
114+
115+ if self .key_name is not None :
116+ headers = _try_provider_call (self .key_name , self .api_key )
117+ if headers is not None :
118+ return headers
119+
120+ headers = _try_provider_call (self .api_key , self .key_name )
121+ if headers is not None :
122+ return headers
123+
124+ context = self ._build_openrouter_header_context ()
125+ headers = _try_provider_call (context , self .api_key )
126+ if headers is not None :
127+ return headers
128+
129+ if errors :
130+ logger .debug (
131+ "Headers provider attempts failed: %s" ,
132+ errors [- 1 ],
133+ exc_info = True ,
134+ )
135+ raise AuthenticationError (
136+ message = "OpenRouter headers provider failed to produce headers." ,
137+ code = "missing_credentials" ,
138+ )
92139
93140 def get_headers (self ) -> dict [str , str ]:
94141 if not self .headers_provider or not self .api_key :
0 commit comments