77import os
88from typing import Any
99
10-
1110logger = logging .getLogger (__name__ )
1211ARK_DEFAULT_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
12+ VEADK_SOURCE_HEADER = "veadk-source"
13+ VEADK_SOURCE_VALUE = "veadk"
1314_DISABLED_VALUES = {"0" , "false" , "off" , "none" , "disabled" }
15+ _HEADER_PATCH_MARKER = "__agentkit_veadk_source_header__"
1416_MODEL_PARAM_KEYS = {
1517 "frequency_penalty" ,
1618 "max_tokens" ,
@@ -49,6 +51,55 @@ def _replacement_enabled() -> bool:
4951 return value not in _DISABLED_VALUES
5052
5153
54+ def _merge_veadk_source_header (headers : Any = None ) -> dict [str , Any ]:
55+ merged = {
56+ key : value
57+ for key , value in dict (headers or {}).items ()
58+ if key .lower () != VEADK_SOURCE_HEADER
59+ }
60+ merged [VEADK_SOURCE_HEADER ] = VEADK_SOURCE_VALUE
61+ return merged
62+
63+
64+ def _header_kwarg_model_cls (base_cls : type [Any ], header_kwarg : str ) -> type [Any ]:
65+ if getattr (base_cls , _HEADER_PATCH_MARKER , False ):
66+ return base_cls
67+
68+ class AgentKitHeaderModel (base_cls ):
69+ def __init__ (self , * args : Any , ** kwargs : Any ) -> None :
70+ kwargs [header_kwarg ] = _merge_veadk_source_header (kwargs .get (header_kwarg ))
71+ super ().__init__ (* args , ** kwargs )
72+
73+ AgentKitHeaderModel .__name__ = base_cls .__name__
74+ AgentKitHeaderModel .__qualname__ = base_cls .__qualname__
75+ AgentKitHeaderModel .__module__ = base_cls .__module__
76+ setattr (AgentKitHeaderModel , _HEADER_PATCH_MARKER , True )
77+ return AgentKitHeaderModel
78+
79+
80+ def _openai_client_args_model_cls (base_cls : type [Any ]) -> type [Any ]:
81+ if getattr (base_cls , _HEADER_PATCH_MARKER , False ):
82+ return base_cls
83+
84+ class AgentKitHeaderModel (base_cls ):
85+ def __init__ (self , * args : Any , ** kwargs : Any ) -> None :
86+ if args or kwargs .get ("client" ) is not None :
87+ super ().__init__ (* args , ** kwargs )
88+ return
89+ client_args = dict (kwargs .get ("client_args" ) or {})
90+ client_args ["default_headers" ] = _merge_veadk_source_header (
91+ client_args .get ("default_headers" )
92+ )
93+ kwargs ["client_args" ] = client_args
94+ super ().__init__ (* args , ** kwargs )
95+
96+ AgentKitHeaderModel .__name__ = base_cls .__name__
97+ AgentKitHeaderModel .__qualname__ = base_cls .__qualname__
98+ AgentKitHeaderModel .__module__ = base_cls .__module__
99+ setattr (AgentKitHeaderModel , _HEADER_PATCH_MARKER , True )
100+ return AgentKitHeaderModel
101+
102+
52103def _replacement_model_config (config : dict [str , Any ]) -> dict [str , Any ]:
53104 model_id = _target_model_id ()
54105 if not model_id :
@@ -90,6 +141,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
90141 client_args = {
91142 "base_url" : _target_base_url (),
92143 "api_key" : api_key ,
144+ "default_headers" : _merge_veadk_source_header (),
93145 },
94146 ** _replacement_model_config (kwargs ),
95147 )
@@ -101,14 +153,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
101153def _patch_model_attr (module_name : str , attr : str , replacement : type [Any ]) -> bool :
102154 try :
103155 module = importlib .import_module (module_name )
104- except Exception :
156+ except Exception : # noqa: BLE001 - optional framework imports are best effort
105157 return False
106158 if hasattr (module , attr ):
107159 setattr (module , attr , replacement )
108160 return True
109161 return False
110162
111163
164+ def _patch_langchain_model_headers () -> bool :
165+ try :
166+ module = importlib .import_module ("langchain_openai.chat_models.base" )
167+ replacement = _header_kwarg_model_cls (module .ChatOpenAI , "default_headers" )
168+ except Exception : # noqa: BLE001 - optional framework imports are best effort
169+ return False
170+
171+ patched = False
172+ for module_name in (
173+ "langchain_openai" ,
174+ "langchain_openai.chat_models" ,
175+ "langchain_openai.chat_models.base" ,
176+ ):
177+ patched = _patch_model_attr (module_name , "ChatOpenAI" , replacement ) or patched
178+ return patched
179+
180+
181+ def _patch_adk_model_headers () -> bool :
182+ try :
183+ module = importlib .import_module ("google.adk.models.lite_llm" )
184+ replacement = _header_kwarg_model_cls (module .LiteLlm , "extra_headers" )
185+ except Exception : # noqa: BLE001 - optional framework imports are best effort
186+ return False
187+
188+ patched = False
189+ for module_name in ("google.adk.models" , "google.adk.models.lite_llm" ):
190+ patched = _patch_model_attr (module_name , "LiteLlm" , replacement ) or patched
191+ return patched
192+
193+
194+ def _patch_strands_openai_model_headers () -> bool :
195+ try :
196+ module = importlib .import_module ("strands.models.openai" )
197+ replacement = _openai_client_args_model_cls (module .OpenAIModel )
198+ except Exception : # noqa: BLE001 - optional framework imports are best effort
199+ return False
200+
201+ patched = False
202+ for module_name in ("strands.models" , "strands.models.openai" ):
203+ patched = _patch_model_attr (module_name , "OpenAIModel" , replacement ) or patched
204+ return patched
205+
206+
112207def _apply_env_aliases () -> bool :
113208 changed = False
114209 model_id = _target_model_id ()
@@ -138,7 +233,7 @@ def _apply_env_aliases() -> bool:
138233def _patch_strands_model_classes () -> bool :
139234 try :
140235 replacement = _agentkit_openai_model_cls ()
141- except Exception :
236+ except Exception : # noqa: BLE001 - optional framework imports are best effort
142237 return False
143238
144239 patched = False
@@ -155,21 +250,33 @@ def apply_agentkit_model_replacement() -> bool:
155250 """Apply explicit target-model replacement for generated migration wrappers.
156251
157252 The helper intentionally stays low-intrusion: it normalizes common model
158- environment variables and patches only stable Strands Bedrock/Anthropic
159- model classes before user code constructs them. It does not rewrite project
160- source code or chase framework-specific model SDK constructor details .
253+ environment variables and patches stable framework model constructors before
254+ user code constructs them. It does not rewrite project source code or patch
255+ global HTTP/OpenAI clients .
161256 """
162257
163258 if not _replacement_enabled ():
164259 logger .info ("AgentKit model replacement disabled by ARK_MODEL_REPLACEMENT." )
165260 return False
166261 env_changed = _apply_env_aliases ()
262+ langchain_headers_patched = _patch_langchain_model_headers ()
263+ adk_headers_patched = _patch_adk_model_headers ()
264+ strands_headers_patched = _patch_strands_openai_model_headers ()
167265 patched = _patch_strands_model_classes ()
168266 logger .info (
169- "AgentKit model replacement enabled: env_aliases=%s strands_model_patch=%s target_model_configured=%s base_url_configured=%s" ,
267+ "AgentKit model replacement enabled: env_aliases=%s langchain_headers=%s adk_headers=%s strands_headers=%s strands_model_patch=%s target_model_configured=%s base_url_configured=%s" ,
170268 env_changed ,
269+ langchain_headers_patched ,
270+ adk_headers_patched ,
271+ strands_headers_patched ,
171272 patched ,
172273 bool (_target_model_id ()),
173274 bool (_target_base_url ()),
174275 )
175- return env_changed or patched
276+ return (
277+ env_changed
278+ or langchain_headers_patched
279+ or adk_headers_patched
280+ or strands_headers_patched
281+ or patched
282+ )
0 commit comments