Skip to content

Commit aa03d41

Browse files
blzjzhuclaude
andcommitted
feat: Update wire_api configuration to dynamically determine provider
- Modified codex tool to set wire_api based on actual provider of selected profile - Replaced hardcoded "copilot-api" with dynamic provider lookup - Added unit tests for wire_api configuration behavior This ensures wire_api is properly configured for the correct provider regardless of which endpoint serves GPT models. Co-Authored-By: Claude (grok-code-fast-1) <noreply@anthropic.com>
1 parent 52de8f4 commit aa03d41

2 files changed

Lines changed: 172 additions & 0 deletions

File tree

code_assistant_manager/tools/codex.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,32 @@ def run(self, args: List[str] = None) -> int:
201201
return 0
202202
selected_profile = profiles[idx]
203203

204+
# Configure wire_api based on model type
205+
from code_assistant_manager.configs import get_tool_config
206+
codex_config = get_tool_config("codex")
207+
if codex_config:
208+
# Determine the provider for the selected profile
209+
config_data = codex_config.load_config("user")
210+
profile_provider = None
211+
if config_data and "profiles" in config_data and selected_profile in config_data["profiles"]:
212+
profile_provider = config_data["profiles"][selected_profile].get("model_provider")
213+
214+
if profile_provider and selected_profile.startswith("gpt"):
215+
# Set wire_api to 'responses' for GPT models
216+
try:
217+
codex_config.set_value(f"model_providers.{profile_provider}.wire_api", "responses", "user")
218+
print(f"[code-assistant-manager] Set codex.model_providers.{profile_provider}.wire_api = 'responses' for GPT model")
219+
except Exception as e:
220+
print(f"[code-assistant-manager] Warning: Failed to set wire_api config: {e}")
221+
elif profile_provider:
222+
# Unset wire_api for non-GPT models
223+
try:
224+
found = codex_config.unset_value(f"model_providers.{profile_provider}.wire_api", "user")
225+
if found:
226+
print(f"[code-assistant-manager] Unset codex.model_providers.{profile_provider}.wire_api for non-GPT model")
227+
except Exception as e:
228+
print(f"[code-assistant-manager] Warning: Failed to unset wire_api config: {e}")
229+
204230
env = os.environ.copy()
205231
if selected_profile in profile_env:
206232
env_key, api_key = profile_env[selected_profile]

tests/unit/test_codex_tool_multi_provider.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)