@@ -202,20 +202,29 @@ def test_usage_stats_property(stub_model_facade: ModelFacade) -> None:
202202
203203
204204def test_consolidate_kwargs (stub_model_configs : list [Any ], stub_model_facade : ModelFacade ) -> None :
205- # Model config generate kwargs are used as base, and purpose is removed
205+ # Model config generate kwargs are used as base, and purpose is removed.
206+ # When telemetry is enabled (default), X-Title is injected.
206207 result = stub_model_facade .consolidate_kwargs (purpose = "test" )
207- assert result == stub_model_configs [0 ].inference_parameters .generate_kwargs
208+ assert result == {
209+ ** stub_model_configs [0 ].inference_parameters .generate_kwargs ,
210+ "extra_headers" : {"X-Title" : "NeMo Data Designer" },
211+ }
208212
209213 # kwargs overrides model config generate kwargs
210214 result = stub_model_facade .consolidate_kwargs (temperature = 0.01 , purpose = "test" )
211- assert result == {** stub_model_configs [0 ].inference_parameters .generate_kwargs , "temperature" : 0.01 }
215+ assert result == {
216+ ** stub_model_configs [0 ].inference_parameters .generate_kwargs ,
217+ "temperature" : 0.01 ,
218+ "extra_headers" : {"X-Title" : "NeMo Data Designer" },
219+ }
212220
213221 # Provider extra_body overrides all other kwargs
214222 stub_model_facade .model_provider .extra_body = {"foo_provider" : "bar_provider" }
215223 result = stub_model_facade .consolidate_kwargs (extra_body = {"foo" : "bar" }, purpose = "test" )
216224 assert result == {
217225 ** stub_model_configs [0 ].inference_parameters .generate_kwargs ,
218226 "extra_body" : {"foo_provider" : "bar_provider" , "foo" : "bar" },
227+ "extra_headers" : {"X-Title" : "NeMo Data Designer" },
219228 }
220229
221230 # Provider extra_headers merges with caller headers (provider takes precedence)
@@ -224,8 +233,117 @@ def test_consolidate_kwargs(stub_model_configs: list[Any], stub_model_facade: Mo
224233 result = stub_model_facade .consolidate_kwargs (extra_headers = {"hello" : "caller" , "X-Trace-ID" : "abc" })
225234 assert result == {
226235 ** stub_model_configs [0 ].inference_parameters .generate_kwargs ,
227- "extra_headers" : {"hello" : "world" , "hola" : "mundo" , "X-Trace-ID" : "abc" },
236+ "extra_headers" : {"X-Title" : "NeMo Data Designer" , "hello" : "world" , "hola" : "mundo" , "X-Trace-ID" : "abc" },
237+ }
238+
239+
240+ @patch ("data_designer.engine.models.facade.TELEMETRY_ENABLED" , False )
241+ def test_consolidate_kwargs_telemetry_disabled (stub_model_configs : list [Any ], stub_model_facade : ModelFacade ) -> None :
242+ """Framework attribution headers are omitted when telemetry is disabled."""
243+ result = stub_model_facade .consolidate_kwargs ()
244+ assert "extra_headers" not in result
245+
246+ # Provider extra_headers still applied even with telemetry off
247+ stub_model_facade .model_provider .extra_headers = {"Custom" : "header" }
248+ result = stub_model_facade .consolidate_kwargs ()
249+ assert result ["extra_headers" ] == {"Custom" : "header" }
250+
251+
252+ def test_consolidate_kwargs_user_x_title_override (
253+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
254+ ) -> None :
255+ """User-supplied X-Title takes precedence over the framework default."""
256+ stub_model_facade .model_provider .extra_headers = {"X-Title" : "My Custom App" }
257+ result = stub_model_facade .consolidate_kwargs ()
258+ assert result ["extra_headers" ]["X-Title" ] == "My Custom App"
259+
260+ stub_model_facade .model_provider .extra_headers = None
261+ result = stub_model_facade .consolidate_kwargs (extra_headers = {"X-Title" : "Caller App" })
262+ assert result ["extra_headers" ]["X-Title" ] == "Caller App"
263+
264+
265+ def test_consolidate_kwargs_with_explicit_none_extra_headers (
266+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
267+ ) -> None :
268+ """Explicit None extra_headers does not break provider merges or framework attribution."""
269+ stub_model_facade .model_provider .extra_headers = {"hello" : "world" }
270+ result = stub_model_facade .consolidate_kwargs (extra_headers = None )
271+ assert result ["extra_headers" ] == {"X-Title" : "NeMo Data Designer" , "hello" : "world" }
272+
273+
274+ def test_consolidate_kwargs_openrouter_attribution (
275+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
276+ ) -> None :
277+ """OpenRouter-specific attribution headers are injected when provider is openrouter."""
278+ stub_model_facade .model_provider .name = "openrouter"
279+ stub_model_facade .model_provider .extra_headers = None
280+ result = stub_model_facade .consolidate_kwargs ()
281+ assert result ["extra_headers" ] == {
282+ "X-Title" : "NeMo Data Designer" ,
283+ "HTTP-Referer" : "https://github.com/NVIDIA-NeMo/DataDesigner" ,
284+ "X-OpenRouter-Title" : "NeMo Data Designer" ,
285+ "X-OpenRouter-Categories" : "programming-app" ,
286+ }
287+
288+
289+ def test_consolidate_kwargs_openrouter_user_override_preserved (
290+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
291+ ) -> None :
292+ """User-supplied OpenRouter headers take precedence over framework defaults."""
293+ stub_model_facade .model_provider .name = "openrouter"
294+ stub_model_facade .model_provider .extra_headers = None
295+ result = stub_model_facade .consolidate_kwargs (
296+ extra_headers = {"X-OpenRouter-Title" : "Custom App" , "X-Custom" : "value" }
297+ )
298+ # User-supplied X-OpenRouter-Title should NOT be overwritten
299+ assert result ["extra_headers" ]["X-OpenRouter-Title" ] == "Custom App"
300+ assert result ["extra_headers" ]["X-Custom" ] == "value"
301+ # Framework defaults still fill in missing keys
302+ assert result ["extra_headers" ]["HTTP-Referer" ] == "https://github.com/NVIDIA-NeMo/DataDesigner"
303+ assert result ["extra_headers" ]["X-OpenRouter-Categories" ] == "programming-app"
304+ assert result ["extra_headers" ]["X-Title" ] == "NeMo Data Designer"
305+
306+
307+ def test_consolidate_kwargs_openrouter_provider_headers_preserved (
308+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
309+ ) -> None :
310+ """Provider-level OpenRouter headers override programmatic injection."""
311+ stub_model_facade .model_provider .name = "openrouter"
312+ stub_model_facade .model_provider .extra_headers = {
313+ "HTTP-Referer" : "https://custom-site.example.com" ,
314+ "X-OpenRouter-Title" : "Provider Title" ,
228315 }
316+ result = stub_model_facade .consolidate_kwargs ()
317+ # Provider-level values take precedence
318+ assert result ["extra_headers" ]["HTTP-Referer" ] == "https://custom-site.example.com"
319+ assert result ["extra_headers" ]["X-OpenRouter-Title" ] == "Provider Title"
320+ # Framework still fills in what's missing
321+ assert result ["extra_headers" ]["X-OpenRouter-Categories" ] == "programming-app"
322+ assert result ["extra_headers" ]["X-Title" ] == "NeMo Data Designer"
323+
324+
325+ @patch ("data_designer.engine.models.facade.TELEMETRY_ENABLED" , False )
326+ def test_consolidate_kwargs_openrouter_no_attribution_when_telemetry_off (
327+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
328+ ) -> None :
329+ """OpenRouter attribution headers are NOT injected when telemetry is disabled."""
330+ stub_model_facade .model_provider .name = "openrouter"
331+ stub_model_facade .model_provider .extra_headers = None
332+ result = stub_model_facade .consolidate_kwargs ()
333+ assert "extra_headers" not in result
334+
335+
336+ def test_consolidate_kwargs_non_openrouter_no_openrouter_headers (
337+ stub_model_configs : list [Any ], stub_model_facade : ModelFacade
338+ ) -> None :
339+ """Non-openrouter providers do NOT get OpenRouter-specific headers."""
340+ stub_model_facade .model_provider .name = "nvidia"
341+ stub_model_facade .model_provider .extra_headers = None
342+ result = stub_model_facade .consolidate_kwargs ()
343+ assert result ["extra_headers" ] == {"X-Title" : "NeMo Data Designer" }
344+ assert "HTTP-Referer" not in result ["extra_headers" ]
345+ assert "X-OpenRouter-Title" not in result ["extra_headers" ]
346+ assert "X-OpenRouter-Categories" not in result ["extra_headers" ]
229347
230348
231349@pytest .mark .parametrize (
0 commit comments