diff --git a/dikte/settings_ui.py b/dikte/settings_ui.py index 87fbdfc..b81cdde 100644 --- a/dikte/settings_ui.py +++ b/dikte/settings_ui.py @@ -906,7 +906,14 @@ class SettingsWindow(QDialog): self.cleanup_opencode_model = QComboBox() self.cleanup_opencode_model.setEditable(True) self.cleanup_opencode_model.addItems(OPENCODE_MODELS) - orr_form.addRow(t("Model"), self.cleanup_opencode_model) + self.cleanup_opencode_model.setToolTip(_typed_model_note("OpenCode Go")) + # Its own button, because a widget lives in one row and the OpenRouter + # button is hidden along with its box whenever OpenCode Go is chosen. + self.refresh_opencode_models = QPushButton(t("Fetch model list")) + self.refresh_opencode_models.clicked.connect(self._load_models) + self.cleanup_opencode_model_row = self._row(self.cleanup_opencode_model, + self.refresh_opencode_models) + orr_form.addRow(t("Model"), self.cleanup_opencode_model_row) self.cleanup_reasoning = QComboBox() for label, value in REASONING_LEVELS: @@ -1996,6 +2003,7 @@ class SettingsWindow(QDialog): def _load_models(self): self.refresh_models.setEnabled(False) + self.refresh_opencode_models.setEnabled(False) self.models_label.setText(t("Fetching model list…")) # Whichever provider is selected for cleanup is the one whose models are # fetched, so the list lands in the box of the provider on screen. @@ -2025,6 +2033,7 @@ class SettingsWindow(QDialog): def _on_models_loaded(self, models, error, provider): self.refresh_models.setEnabled(True) + self.refresh_opencode_models.setEnabled(True) if error: self.models_label.setText(t("Could not fetch the list: {error}", error=error)) return @@ -2334,7 +2343,7 @@ class SettingsWindow(QDialog): provider == "claude") self.cleanup_form.setRowVisible(self.cleanup_codex_model, provider == "codex") - self.cleanup_form.setRowVisible(self.cleanup_opencode_model, + self.cleanup_form.setRowVisible(self.cleanup_opencode_model_row, provider == "opencode") self.cleanup_form.setRowVisible(self.cleanup_reasoning, provider != "local") diff --git a/tests/test_ui.py b/tests/test_ui.py index a02d533..0ed35ab 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -261,7 +261,7 @@ class Settings(DikteTest): """An OpenRouter id and a Claude alias are not the same field.""" window = self.window(cfg.Config()) boxes = {"openrouter": window.cleanup_model_row, - "opencode": window.cleanup_opencode_model, + "opencode": window.cleanup_opencode_model_row, "claude": window.cleanup_claude_model, "codex": window.cleanup_codex_model} for provider, box in boxes.items(): @@ -285,6 +285,30 @@ class Settings(DikteTest): self.assertEqual(window.cleanup_codex_model.currentText(), "my-own-model") + def test_a_fetched_opencode_list_lands_in_opencode_s_own_box(self): + """The OpenRouter and meeting boxes are not refilled by another + provider's catalog, and the picked model survives the refill.""" + conf = self.config(cleanup_opencode_model="my-own-model", + meeting_model="some/meeting-model") + window = self.window(conf) + before = [window.meeting_model.itemText(i) + for i in range(window.meeting_model.count())] + window._on_models_loaded(["glm-5.3", "kimi-k3"], "", "opencode") + combo = window.cleanup_opencode_model + offered = [combo.itemText(i) for i in range(combo.count())] + self.assertEqual(offered, ["glm-5.3", "kimi-k3"]) + self.assertEqual(combo.currentText(), "my-own-model") + self.assertEqual([window.meeting_model.itemText(i) + for i in range(window.meeting_model.count())], before) + + def test_opencode_cleanup_still_offers_the_fetch_button(self): + """The OpenRouter button leaves the screen with its box, so OpenCode Go + carries its own.""" + window = self.window(cfg.Config()) + window._select_data(window.cleanup_provider, "opencode") + self.assertFalse(window.cleanup_opencode_model_row.isHidden()) + self.assertTrue(window.cleanup_model_row.isHidden()) + def test_the_update_line_names_the_version_that_is_running(self): window = self.window(cfg.Config()) self.assertIn(settings_ui.__version__, window.update_status.text())