diff --git a/client/pyside6/components/provider_dialog.py b/client/pyside6/components/provider_dialog.py index 3c3926e..af7efce 100644 --- a/client/pyside6/components/provider_dialog.py +++ b/client/pyside6/components/provider_dialog.py @@ -47,6 +47,7 @@ def __init__(self, api, parent=None): self.preset = QComboBox() self.preset.addItem("智谱 AI(GLM-4.5-Flash)", "zhipu") self.preset.addItem("OpenAI", "openai") + self.preset.addItem("OrcaRouter", "orcarouter") self.preset.addItem("自定义 OpenAI 兼容服务", "custom") self.preset.currentIndexChanged.connect(self._preset_changed) self.name = QLineEdit() @@ -115,6 +116,11 @@ def _preset_changed(self, _index: int) -> None: self.base_url.setText("https://api.openai.com/v1") self.model.setText("gpt-4.1-mini") self.protocol.setCurrentIndex(0) + elif preset == "orcarouter": + self.name.setText("OrcaRouter") + self.base_url.setText("https://api.orcarouter.ai/v1") + self.model.setText("orcarouter/auto") + self.protocol.setCurrentIndex(0) def refresh(self) -> None: self.state.setText("正在加载模型服务…") diff --git a/tests/test_provider_presets.py b/tests/test_provider_presets.py new file mode 100644 index 0000000..e7e741b --- /dev/null +++ b/tests/test_provider_presets.py @@ -0,0 +1,59 @@ +"""Offscreen preset coverage for the remote provider dialog. + +The dialog is the desktop surface where users configure OpenAI-compatible +remote providers; named presets fill name/base_url/model so a provider is +used as a first-class service instead of an anonymous custom base URL. +""" + +from __future__ import annotations + +import os +import sys +from unittest.mock import MagicMock + +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") +ROOT = os.path.dirname(os.path.dirname(__file__)) +sys.path.insert(0, os.path.join(ROOT, "client", "pyside6")) + +from components.provider_dialog import RemoteProviderDialog +from PySide6.QtWidgets import QApplication + +_app = QApplication.instance() or QApplication([]) + + +def _dialog() -> RemoteProviderDialog: + api = MagicMock() + api.list_remote_providers.return_value = [] + return RemoteProviderDialog(api) + + +def test_orcarouter_preset_is_listed(): + dialog = _dialog() + try: + presets = [dialog.preset.itemData(index) for index in range(dialog.preset.count())] + assert "orcarouter" in presets + finally: + dialog.shutdown_async_api() + + +def test_orcarouter_preset_fills_named_provider_fields(): + dialog = _dialog() + try: + dialog.preset.setCurrentIndex(dialog.preset.findData("orcarouter")) + assert dialog.name.text() == "OrcaRouter" + assert dialog.base_url.text() == "https://api.orcarouter.ai/v1" + assert dialog.model.text() == "orcarouter/auto" + assert dialog.protocol.currentData() == "responses" + finally: + dialog.shutdown_async_api() + + +def test_openai_preset_is_preserved(): + dialog = _dialog() + try: + dialog.preset.setCurrentIndex(dialog.preset.findData("openai")) + assert dialog.name.text() == "OpenAI" + assert dialog.base_url.text() == "https://api.openai.com/v1" + assert dialog.model.text() == "gpt-4.1-mini" + finally: + dialog.shutdown_async_api()