@@ -153,6 +153,79 @@ def test_codex_catalog_uses_route_modalities_and_defaults_undeclared_to_text(
153153 assert undeclared ["models" ][0 ]["input_modalities" ] == ["text" ]
154154
155155
156+ def test_codex_launcher_discovers_modalities_for_every_catalog_entry (
157+ monkeypatch : pytest .MonkeyPatch ,
158+ tmp_path : Path ,
159+ ) -> None :
160+ import switchyard .cli .launchers .codex_cli_launcher as launcher
161+
162+ class FakeServer :
163+ port = 4321
164+ stats = object ()
165+
166+ def __init__ (self ) -> None :
167+ self .queried_models : list [str ] = []
168+ self .closed = False
169+
170+ def caller_auth_kind (self , model : str ) -> str | None :
171+ assert model == "switchyard/text"
172+ return None
173+
174+ def input_modalities (self , model : str ) -> list [str ]:
175+ self .queried_models .append (model )
176+ return {
177+ "switchyard/text" : ["text" ],
178+ "switchyard/vision" : ["text" , "image" ],
179+ }[model ]
180+
181+ def close (self ) -> None :
182+ self .closed = True
183+
184+ server = FakeServer ()
185+ captured_modalities : dict [str , list [str ]] = {}
186+
187+ def write_catalog (
188+ _codex_bin : str ,
189+ _entries : object ,
190+ input_modalities_by_model : dict [str , list [str ]] | None = None ,
191+ ) -> None :
192+ captured_modalities .update (input_modalities_by_model or {})
193+
194+ monkeypatch .setattr (launcher , "_find_codex_binary" , lambda : "codex" )
195+ monkeypatch .setattr (launcher , "silence_launch_loggers" , lambda ** _kwargs : None )
196+ monkeypatch .setattr (
197+ launcher ,
198+ "configure_debug_file_logging" ,
199+ lambda ** _kwargs : tmp_path / "switchyard.log" ,
200+ )
201+ monkeypatch .setattr (launcher , "_start_native_server" , lambda _config : server )
202+ monkeypatch .setattr (launcher , "_write_codex_model_catalog" , write_catalog )
203+ monkeypatch .setattr (launcher , "_wait_ready" , lambda _port : True )
204+ monkeypatch .setattr (launcher , "print_ready_banner" , lambda ** _kwargs : None )
205+ monkeypatch .setattr (launcher , "stdin_is_tty" , lambda : False )
206+ monkeypatch .setattr (launcher , "_supervise_codex" , lambda _command , _env : 0 )
207+ monkeypatch .setattr (launcher , "print_session_summary" , lambda _stats : None )
208+ monkeypatch .setattr (launcher , "_remove_codex_model_catalog" , lambda _path : None )
209+
210+ result = launcher ._run_codex_with_switchyard (
211+ tmp_path / "routes.toml" ,
212+ display_model = "switchyard/text" ,
213+ codex_args = [],
214+ codex_model_catalog = [
215+ ("switchyard/text" , "Text" , "Text route" ),
216+ ("switchyard/vision" , "Vision" , "Vision route" ),
217+ ],
218+ )
219+
220+ assert result == 0
221+ assert server .queried_models == ["switchyard/text" , "switchyard/vision" ]
222+ assert captured_modalities == {
223+ "switchyard/text" : ["text" ],
224+ "switchyard/vision" : ["text" , "image" ],
225+ }
226+ assert server .closed
227+
228+
156229def test_native_server_exposes_route_derived_modalities (tmp_path : Path ) -> None :
157230 config = tmp_path / "modalities.toml"
158231 config .write_text (
0 commit comments