@@ -21,33 +21,53 @@ def test_display(self):
2121
2222
2323class TestRenderOverlay :
24- def test_sets_anthropic_model (self ):
25- overlay , _ = claude .render_overlay (WS , "databricks-claude-sonnet-4" )
26- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "databricks-claude-sonnet-4"
24+ def test_does_not_set_anthropic_model_env (self ):
25+ # We deliberately don't pin ANTHROPIC_MODEL: when set, Claude Code's
26+ # /model picker surfaces a duplicate catalog row on top of the family
27+ # alias from ANTHROPIC_DEFAULT_OPUS_MODEL. Default falls back to the
28+ # active family alias instead.
29+ overlay , _ = claude .render_overlay (
30+ WS , "databricks-claude-opus-4-7" , claude_models = {"opus" : "databricks-claude-opus-4-7" }
31+ )
32+ assert "ANTHROPIC_MODEL" not in overlay ["env" ]
2733
2834 def test_adds_1m_suffix_for_opus_4_6_and_later (self ):
29- overlay , _ = claude .render_overlay (WS , "databricks-claude-opus-4-7" )
30- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "databricks-claude-opus-4-7[1m]"
35+ overlay , _ = claude .render_overlay (
36+ WS , "s4" , claude_models = {"opus" : "databricks-claude-opus-4-7" }
37+ )
38+ assert overlay ["env" ]["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "databricks-claude-opus-4-7[1m]"
3139
3240 def test_adds_1m_suffix_for_sonnet_4_6_and_later (self ):
33- overlay , _ = claude .render_overlay (WS , "databricks-claude-sonnet-4-7" )
34- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "databricks-claude-sonnet-4-7[1m]"
41+ overlay , _ = claude .render_overlay (
42+ WS , "s4" , claude_models = {"sonnet" : "databricks-claude-sonnet-4-7" }
43+ )
44+ assert (
45+ overlay ["env" ]["ANTHROPIC_DEFAULT_SONNET_MODEL" ] == "databricks-claude-sonnet-4-7[1m]"
46+ )
3547
36- def test_does_not_add_1m_suffix_for_other_models (self ):
37- overlay , _ = claude .render_overlay (WS , "databricks-claude-haiku-4-6" )
38- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "databricks-claude-haiku-4-6"
48+ def test_does_not_add_1m_suffix_for_haiku (self ):
49+ overlay , _ = claude .render_overlay (
50+ WS , "s4" , claude_models = {"haiku" : "databricks-claude-haiku-4-6" }
51+ )
52+ assert overlay ["env" ]["ANTHROPIC_DEFAULT_HAIKU_MODEL" ] == "databricks-claude-haiku-4-6"
3953
4054 def test_does_not_duplicate_1m_suffix (self ):
41- overlay , _ = claude .render_overlay (WS , "databricks-claude-opus-4-7[1m]" )
42- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "databricks-claude-opus-4-7[1m]"
55+ overlay , _ = claude .render_overlay (
56+ WS , "s4" , claude_models = {"opus" : "databricks-claude-opus-4-7[1m]" }
57+ )
58+ assert overlay ["env" ]["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "databricks-claude-opus-4-7[1m]"
4359
4460 def test_adds_1m_suffix_for_model_services_name (self ):
45- overlay , _ = claude .render_overlay (WS , "system.ai.claude-opus-4-8" )
46- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
61+ overlay , _ = claude .render_overlay (
62+ WS , "s4" , claude_models = {"opus" : "system.ai.claude-opus-4-8" }
63+ )
64+ assert overlay ["env" ]["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
4765
4866 def test_no_1m_suffix_for_model_services_haiku (self ):
49- overlay , _ = claude .render_overlay (WS , "system.ai.claude-haiku-4-6" )
50- assert overlay ["env" ]["ANTHROPIC_MODEL" ] == "system.ai.claude-haiku-4-6"
67+ overlay , _ = claude .render_overlay (
68+ WS , "s4" , claude_models = {"haiku" : "system.ai.claude-haiku-4-6" }
69+ )
70+ assert overlay ["env" ]["ANTHROPIC_DEFAULT_HAIKU_MODEL" ] == "system.ai.claude-haiku-4-6"
5171
5272 def test_sets_anthropic_base_url (self ):
5373 overlay , _ = claude .render_overlay (WS , "s4" )
@@ -90,6 +110,25 @@ def test_model_overrides_not_set_when_no_models(self):
90110 env = overlay ["env" ]
91111 assert "ANTHROPIC_DEFAULT_SONNET_MODEL" not in env
92112
113+ def test_picker_labels_show_raw_routable_id (self ):
114+ # We deliberately don't set the `_NAME` companion env vars. Showing the
115+ # raw `system.ai.…` / `databricks-…` id in the picker label tells users
116+ # exactly which gateway-routable model is behind each shortcut, which is
117+ # more useful than a friendly catalog label for Databricks routing.
118+ models = {
119+ "opus" : "system.ai.claude-opus-4-8" ,
120+ "sonnet" : "databricks-claude-sonnet-4-6" ,
121+ "haiku" : "system.ai.claude-haiku-4-5" ,
122+ }
123+ overlay , _ = claude .render_overlay (WS , "s4" , claude_models = models )
124+ env = overlay ["env" ]
125+ assert env ["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
126+ assert "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME" not in env
127+ assert env ["ANTHROPIC_DEFAULT_SONNET_MODEL" ] == "databricks-claude-sonnet-4-6[1m]"
128+ assert "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME" not in env
129+ assert env ["ANTHROPIC_DEFAULT_HAIKU_MODEL" ] == "system.ai.claude-haiku-4-5"
130+ assert "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME" not in env
131+
93132 def test_managed_keys_include_api_key_helper (self ):
94133 _ , keys = claude .render_overlay (WS , "s4" )
95134 assert ["apiKeyHelper" ] in keys
@@ -357,3 +396,82 @@ def fake_execvp(binary: str, args: list[str]) -> None:
357396 ["claude" , "--settings" , str (claude .CLAUDE_SETTINGS_PATH ), "--debug" ],
358397 )
359398 ]
399+
400+
401+ class TestWriteToolConfigPrunesStaleModelEnv :
402+ """Stale ucode-managed model env keys (ANTHROPIC_MODEL, etc.) from earlier
403+ ucode versions must be removed on every launch — otherwise they linger in
404+ settings.json and re-introduce the duplicate /model picker row that this
405+ change is meant to remove.
406+ """
407+
408+ def _patch (self , monkeypatch , existing_settings ):
409+ monkeypatch .setattr (claude , "backup_existing_file" , lambda * a , ** kw : True )
410+ monkeypatch .setattr (claude , "read_json_safe" , lambda path : existing_settings )
411+ written : dict = {}
412+
413+ def fake_write (path , payload ):
414+ written ["payload" ] = payload
415+
416+ monkeypatch .setattr (claude , "write_json_file" , fake_write )
417+ monkeypatch .setattr (claude , "save_state" , lambda state : None )
418+ monkeypatch .setattr (claude , "_register_web_search_mcp" , lambda * a , ** kw : True )
419+ return written
420+
421+ def test_prunes_stale_anthropic_model_from_prior_run (self , monkeypatch ):
422+ existing = {
423+ "env" : {
424+ "ANTHROPIC_MODEL" : "system.ai.claude-opus-4-8[1m]" ,
425+ "ANTHROPIC_DEFAULT_OPUS_MODEL" : "system.ai.claude-opus-4-8[1m]" ,
426+ "MY_CUSTOM_VAR" : "keep-me" ,
427+ }
428+ }
429+ written = self ._patch (monkeypatch , existing )
430+ state = {
431+ "workspace" : WS ,
432+ "claude_models" : {"opus" : "system.ai.claude-opus-4-8" },
433+ }
434+ claude .write_tool_config (state , "system.ai.claude-opus-4-8" )
435+ env = written ["payload" ]["env" ]
436+ assert "ANTHROPIC_MODEL" not in env
437+ # Family default we still write this run is preserved.
438+ assert env ["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
439+ # User-owned keys are untouched.
440+ assert env ["MY_CUSTOM_VAR" ] == "keep-me"
441+
442+ def test_prunes_unused_family_default_when_models_change (self , monkeypatch ):
443+ # Earlier launch wrote a sonnet default; the new state only has opus.
444+ # The stale sonnet keys should be removed.
445+ existing = {
446+ "env" : {
447+ "ANTHROPIC_DEFAULT_SONNET_MODEL" : "databricks-claude-sonnet-4-6[1m]" ,
448+ }
449+ }
450+ written = self ._patch (monkeypatch , existing )
451+ state = {"workspace" : WS , "claude_models" : {"opus" : "system.ai.claude-opus-4-8" }}
452+ claude .write_tool_config (state , "system.ai.claude-opus-4-8" )
453+ env = written ["payload" ]["env" ]
454+ assert "ANTHROPIC_DEFAULT_SONNET_MODEL" not in env
455+ assert env ["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
456+
457+ def test_prunes_stale_name_companion_keys_from_older_ucode (self , monkeypatch ):
458+ # An older ucode build briefly wrote `_NAME` companion env vars to give
459+ # the picker friendly labels. The current build only writes the raw id,
460+ # so any leftover `_NAME` keys must be pruned — otherwise users who
461+ # tested the in-between version would see stale labels.
462+ existing = {
463+ "env" : {
464+ "ANTHROPIC_DEFAULT_OPUS_MODEL" : "system.ai.claude-opus-4-8[1m]" ,
465+ "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME" : "Opus 4.8 (1M)" ,
466+ "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME" : "Sonnet 4.6 (1M)" ,
467+ "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME" : "Haiku 4.5" ,
468+ }
469+ }
470+ written = self ._patch (monkeypatch , existing )
471+ state = {"workspace" : WS , "claude_models" : {"opus" : "system.ai.claude-opus-4-8" }}
472+ claude .write_tool_config (state , "system.ai.claude-opus-4-8" )
473+ env = written ["payload" ]["env" ]
474+ assert env ["ANTHROPIC_DEFAULT_OPUS_MODEL" ] == "system.ai.claude-opus-4-8[1m]"
475+ assert "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME" not in env
476+ assert "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME" not in env
477+ assert "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME" not in env
0 commit comments