Skip to content

Commit 6013f05

Browse files
authored
Merge pull request #19 from zhujian0805/main
Fix profile selection to include all profiles from toml config
2 parents da55d62 + f4a4084 commit 6013f05

2 files changed

Lines changed: 105 additions & 17 deletions

File tree

code_assistant_manager/tools/codex.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,28 @@ def _write_profile(
4949

5050
return config_path
5151

52+
def _read_existing_profiles(self, config_path: Path) -> list[str]:
53+
"""Read existing profiles from Codex config.toml."""
54+
try:
55+
import tomllib
56+
except ImportError:
57+
try:
58+
import tomli as tomllib
59+
except ImportError:
60+
return []
61+
62+
if not config_path.exists():
63+
return []
64+
65+
try:
66+
with open(config_path, "rb") as f:
67+
config = tomllib.load(f)
68+
profiles = list(config.get("profiles", {}).keys())
69+
return profiles
70+
except Exception as e:
71+
logger.debug(f"Failed to read existing profiles from {config_path}: {e}")
72+
return []
73+
5274
def run(self, args: List[str] = None) -> int:
5375
args = args or []
5476

@@ -86,6 +108,9 @@ def run(self, args: List[str] = None) -> int:
86108
if not endpoints:
87109
return self._handle_error("No endpoints configured for codex")
88110

111+
config_path = Path.home() / ".codex" / "config.toml"
112+
existing_profiles = self._read_existing_profiles(config_path)
113+
89114
configured_profiles: list[str] = []
90115
profile_env: dict[str, tuple[str, str]] = {}
91116

@@ -140,10 +165,12 @@ def run(self, args: List[str] = None) -> int:
140165
if endpoint_config.get("actual_api_key"):
141166
profile_env[profile_name] = (env_key, endpoint_config.get("actual_api_key"))
142167

143-
if not configured_profiles:
168+
all_profiles = sorted(set(existing_profiles + configured_profiles))
169+
170+
if not all_profiles:
144171
return 0
145172

146-
profiles = sorted(set(configured_profiles))
173+
profiles = all_profiles
147174
if len(profiles) == 1:
148175
selected_profile = profiles[0]
149176
elif os.environ.get("CODE_ASSISTANT_MANAGER_NONINTERACTIVE") == "1":

tests/unit/test_codex_tool_multi_provider.py

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,88 @@ def _fetch_models(name: str, endpoint_config, use_cache_if_available=False):
4949
},
5050
):
5151
with patch.object(tool, "_ensure_tool_installed", return_value=True):
52-
# 1) pick model for ep1 (idx 0)
53-
# 2) pick model for ep2 (idx 0)
54-
# 3) pick profile to run => select second (idx 1) => m2
55-
menu_returns = [(True, 0), (True, 0), (True, 1)]
52+
with patch.object(tool, "_read_existing_profiles", return_value=[]):
53+
# 1) pick model for ep1 (idx 0)
54+
# 2) pick model for ep2 (idx 0)
55+
# 3) pick profile to run => select second (idx 1) => m2
56+
menu_returns = [(True, 0), (True, 0), (True, 1)]
5657

57-
with patch(
58-
"code_assistant_manager.menu.menus.display_centered_menu",
59-
side_effect=menu_returns,
60-
):
58+
with patch(
59+
"code_assistant_manager.menu.menus.display_centered_menu",
60+
side_effect=menu_returns,
61+
):
6162

62-
captured = {}
63+
captured = {}
6364

64-
def _run(cmd, env, *_args, **_kwargs):
65-
captured["cmd"] = cmd
66-
captured["env"] = env
67-
return 0
65+
def _run(cmd, env, *_args, **_kwargs):
66+
captured["cmd"] = cmd
67+
captured["env"] = env
68+
return 0
6869

69-
with patch.object(tool, "_run_tool_with_env", side_effect=_run):
70-
rc = tool.run([])
70+
with patch.object(tool, "_run_tool_with_env", side_effect=_run):
71+
rc = tool.run([])
7172

7273
assert rc == 0
7374
assert captured["cmd"][:3] == ["codex", "-p", "m2"]
7475
assert captured["env"].get("KEY2") == "k2"
7576
assert "NODE_TLS_REJECT_UNAUTHORIZED" in captured["env"]
77+
78+
79+
def test_codex_tool_includes_existing_profiles_from_toml(monkeypatch):
80+
"""Test that profile selection menu includes both existing and newly configured profiles."""
81+
monkeypatch.delenv("KEY1", raising=False)
82+
83+
cfg = MagicMock()
84+
cfg.get_sections.return_value = ["ep1"]
85+
86+
def _get_ep_cfg(name: str):
87+
return {"api_key_env": "KEY1"}
88+
89+
cfg.get_endpoint_config.side_effect = _get_ep_cfg
90+
91+
tool = CodexTool(cfg)
92+
tool.endpoint_manager = MagicMock()
93+
tool.endpoint_manager._is_client_supported.return_value = True
94+
tool.endpoint_manager.get_endpoint_config.return_value = (
95+
True,
96+
{"endpoint": "https://e1", "actual_api_key": "k1"},
97+
)
98+
tool.endpoint_manager.fetch_models.return_value = (True, ["new-model"])
99+
100+
with patch(
101+
"code_assistant_manager.tools.codex.upsert_codex_profile",
102+
return_value={"changed": True, "provider_existed": False, "profile_existed": False, "project_existed": False},
103+
):
104+
with patch.object(tool, "_ensure_tool_installed", return_value=True):
105+
with patch.object(tool, "_read_existing_profiles", return_value=["old-profile-1", "old-profile-2"]):
106+
# 1) pick model for ep1 (idx 0) -> new-model
107+
# 2) pick profile to run => old profiles + new profile should be shown
108+
# profiles should be: ["new-model", "old-profile-1", "old-profile-2"] (sorted)
109+
# select index 1 -> "old-profile-1"
110+
menu_calls = []
111+
112+
def _mock_menu(prompt, options, cancel_text=None):
113+
menu_calls.append({"prompt": prompt, "options": options, "cancel_text": cancel_text})
114+
if len(menu_calls) == 1:
115+
return (True, 0) # Select new-model
116+
else:
117+
return (True, 1) # Select old-profile-1
118+
119+
with patch("code_assistant_manager.menu.menus.display_centered_menu", side_effect=_mock_menu):
120+
captured = {}
121+
122+
def _run(cmd, env, *_args, **_kwargs):
123+
captured["cmd"] = cmd
124+
return 0
125+
126+
with patch.object(tool, "_run_tool_with_env", side_effect=_run):
127+
rc = tool.run([])
128+
129+
assert rc == 0
130+
assert len(menu_calls) == 2
131+
# Check that profile selection includes all profiles
132+
profile_menu = menu_calls[1]
133+
assert profile_menu["prompt"] == "Select Codex profile to run:"
134+
assert sorted(profile_menu["options"]) == ["new-model", "old-profile-1", "old-profile-2"]
135+
# Verify the selected profile
136+
assert captured["cmd"][:3] == ["codex", "-p", "old-profile-1"]

0 commit comments

Comments
 (0)