@@ -134,3 +134,149 @@ def _run(cmd, env, *_args, **_kwargs):
134134 assert sorted (profile_menu ["options" ]) == ["new-model" , "old-profile-1" , "old-profile-2" ]
135135 # Verify the selected profile
136136 assert captured ["cmd" ][:3 ] == ["codex" , "-p" , "old-profile-1" ]
137+
138+
139+ def test_codex_tool_sets_wire_api_by_provider_for_gpt_models (monkeypatch ):
140+ """Test that wire_api is set dynamically by provider name for GPT models."""
141+ monkeypatch .delenv ("KEY1" , raising = False )
142+
143+ cfg = MagicMock ()
144+ cfg .get_sections .return_value = ["copilot-api" ]
145+
146+ def _get_ep_cfg (name : str ):
147+ return {"api_key_env" : "KEY1" }
148+
149+ cfg .get_endpoint_config .side_effect = _get_ep_cfg
150+
151+ tool = CodexTool (cfg )
152+ tool .endpoint_manager = MagicMock ()
153+ tool .endpoint_manager ._is_client_supported .return_value = True
154+ tool .endpoint_manager .get_endpoint_config .return_value = (
155+ True ,
156+ {"endpoint" : "https://copilot.example.com" , "actual_api_key" : "k1" },
157+ )
158+ tool .endpoint_manager .fetch_models .return_value = (True , ["gpt-4" , "claude-3" ])
159+
160+ # Mock the config system
161+ mock_codex_config = MagicMock ()
162+
163+ # Mock load_config to return profile data with provider info
164+ def mock_load_config (scope ):
165+ if scope == "user" :
166+ return {
167+ "profiles" : {
168+ "gpt-4" : {"model" : "gpt-4" , "model_provider" : "copilot-api" },
169+ "claude-3" : {"model" : "claude-3" , "model_provider" : "copilot-api" }
170+ }
171+ }
172+ return {}
173+
174+ mock_codex_config .load_config .side_effect = mock_load_config
175+
176+ with patch (
177+ "code_assistant_manager.tools.codex.upsert_codex_profile" ,
178+ return_value = {"changed" : True , "provider_existed" : False , "profile_existed" : False , "project_existed" : False },
179+ ):
180+ with patch .object (tool , "_ensure_tool_installed" , return_value = True ):
181+ with patch .object (tool , "_read_existing_profiles" , return_value = []):
182+ with patch ("code_assistant_manager.configs.get_tool_config" , return_value = mock_codex_config ):
183+ # Mock all menu interactions
184+ menu_calls = []
185+
186+ def mock_select_multiple_models (models , prompt , cancel_text = None ):
187+ menu_calls .append ({"type" : "select_multiple" , "models" : models , "prompt" : prompt })
188+ # Select gpt-4 (index 0)
189+ return True , ["gpt-4" ]
190+
191+ def mock_display_centered_menu (prompt , options , cancel_text = None ):
192+ menu_calls .append ({"type" : "display_centered" , "prompt" : prompt , "options" : options })
193+ # Select gpt-4 profile (should be index 0)
194+ return True , 0
195+
196+ with patch ("code_assistant_manager.menu.menus.select_multiple_models" , side_effect = mock_select_multiple_models ):
197+ with patch ("code_assistant_manager.menu.menus.display_centered_menu" , side_effect = mock_display_centered_menu ):
198+ captured = {}
199+
200+ def _run (cmd , env , * _args , ** _kwargs ):
201+ captured ["cmd" ] = cmd
202+ return 0
203+
204+ with patch .object (tool , "_run_tool_with_env" , side_effect = _run ):
205+ rc = tool .run ([])
206+
207+ assert rc == 0
208+ # Verify wire_api was set for the correct provider
209+ mock_codex_config .set_value .assert_called_with ("model_providers.copilot-api.wire_api" , "responses" , "user" )
210+
211+
212+ def test_codex_tool_unsets_wire_api_by_provider_for_non_gpt_models (monkeypatch ):
213+ """Test that wire_api is unset dynamically by provider name for non-GPT models."""
214+ monkeypatch .delenv ("KEY1" , raising = False )
215+
216+ cfg = MagicMock ()
217+ cfg .get_sections .return_value = ["copilot-api" ]
218+
219+ def _get_ep_cfg (name : str ):
220+ return {"api_key_env" : "KEY1" }
221+
222+ cfg .get_endpoint_config .side_effect = _get_ep_cfg
223+
224+ tool = CodexTool (cfg )
225+ tool .endpoint_manager = MagicMock ()
226+ tool .endpoint_manager ._is_client_supported .return_value = True
227+ tool .endpoint_manager .get_endpoint_config .return_value = (
228+ True ,
229+ {"endpoint" : "https://copilot.example.com" , "actual_api_key" : "k1" },
230+ )
231+ tool .endpoint_manager .fetch_models .return_value = (True , ["gpt-4" , "claude-3" ])
232+
233+ # Mock the config system
234+ mock_codex_config = MagicMock ()
235+
236+ # Mock load_config to return profile data with provider info
237+ def mock_load_config (scope ):
238+ if scope == "user" :
239+ return {
240+ "profiles" : {
241+ "gpt-4" : {"model" : "gpt-4" , "model_provider" : "copilot-api" },
242+ "claude-3" : {"model" : "claude-3" , "model_provider" : "copilot-api" }
243+ }
244+ }
245+ return {}
246+
247+ mock_codex_config .load_config .side_effect = mock_load_config
248+
249+ with patch (
250+ "code_assistant_manager.tools.codex.upsert_codex_profile" ,
251+ return_value = {"changed" : True , "provider_existed" : False , "profile_existed" : False , "project_existed" : False },
252+ ):
253+ with patch .object (tool , "_ensure_tool_installed" , return_value = True ):
254+ with patch .object (tool , "_read_existing_profiles" , return_value = []):
255+ with patch ("code_assistant_manager.configs.get_tool_config" , return_value = mock_codex_config ):
256+ # Mock all menu interactions
257+ menu_calls = []
258+
259+ def mock_select_multiple_models (models , prompt , cancel_text = None ):
260+ menu_calls .append ({"type" : "select_multiple" , "models" : models , "prompt" : prompt })
261+ # Select claude-3 (index 1)
262+ return True , ["claude-3" ]
263+
264+ def mock_display_centered_menu (prompt , options , cancel_text = None ):
265+ menu_calls .append ({"type" : "display_centered" , "prompt" : prompt , "options" : options })
266+ # Select claude-3 profile (should be index 1)
267+ return True , 1
268+
269+ with patch ("code_assistant_manager.menu.menus.select_multiple_models" , side_effect = mock_select_multiple_models ):
270+ with patch ("code_assistant_manager.menu.menus.display_centered_menu" , side_effect = mock_display_centered_menu ):
271+ captured = {}
272+
273+ def _run (cmd , env , * _args , ** _kwargs ):
274+ captured ["cmd" ] = cmd
275+ return 0
276+
277+ with patch .object (tool , "_run_tool_with_env" , side_effect = _run ):
278+ rc = tool .run ([])
279+
280+ assert rc == 0
281+ # Verify wire_api was unset for the correct provider
282+ mock_codex_config .unset_value .assert_called_with ("model_providers.copilot-api.wire_api" , "user" )
0 commit comments