mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-23 05:55:16 +08:00
core/config+cli: empty models are bad; prompt model on provider switch
Reject providers with no models into bad_providers and warn with reasons on chat/providers. When /provider changes and the current model is not listed, prompt for a new model (keep it when still supported).
This commit is contained in:
@@ -190,6 +190,67 @@ async def test_model_switch_persists(state: ReplState) -> None:
|
||||
assert row.model == "m2"
|
||||
|
||||
|
||||
async def test_provider_switch_prompts_when_model_missing(
|
||||
state: ReplState,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from plyngent.config.models import ModelConfig, OpenAICompatibleProvider, OpenAIProvider
|
||||
|
||||
state.config.providers = {
|
||||
"a": OpenAIProvider(
|
||||
access_key_or_token="sk",
|
||||
models={"shared": ModelConfig(), "only-a": ModelConfig()},
|
||||
),
|
||||
"b": OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"shared": ModelConfig(), "only-b": ModelConfig()},
|
||||
),
|
||||
}
|
||||
state.provider_name = "a"
|
||||
state.provider = state.config.providers["a"]
|
||||
state.model = "only-a"
|
||||
state.rebuild_client()
|
||||
|
||||
# When switching to b, only-a is missing → select_model is invoked interactively.
|
||||
monkeypatch.setattr(
|
||||
"plyngent.cli.slash.select_model",
|
||||
lambda provider, preferred=None, interactive=True: "only-b",
|
||||
)
|
||||
assert await handle_slash(state, "/provider b") is True
|
||||
assert state.provider_name == "b"
|
||||
assert state.model == "only-b"
|
||||
sid = state.session_id
|
||||
assert sid is not None
|
||||
row = await state.memory.get_session(sid)
|
||||
assert row is not None
|
||||
assert row.provider_name == "b"
|
||||
assert row.model == "only-b"
|
||||
|
||||
|
||||
async def test_provider_switch_keeps_shared_model(state: ReplState) -> None:
|
||||
from plyngent.config.models import ModelConfig, OpenAICompatibleProvider, OpenAIProvider
|
||||
|
||||
state.config.providers = {
|
||||
"a": OpenAIProvider(
|
||||
access_key_or_token="sk",
|
||||
models={"shared": ModelConfig()},
|
||||
),
|
||||
"b": OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"shared": ModelConfig()},
|
||||
),
|
||||
}
|
||||
state.provider_name = "a"
|
||||
state.provider = state.config.providers["a"]
|
||||
state.model = "shared"
|
||||
state.rebuild_client()
|
||||
assert await handle_slash(state, "/provider b") is True
|
||||
assert state.provider_name == "b"
|
||||
assert state.model == "shared"
|
||||
|
||||
|
||||
async def test_delete_slash_confirm(
|
||||
state: ReplState,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
|
||||
@@ -52,9 +52,23 @@ def test_select_provider_interactive_choose() -> None:
|
||||
from tests.test_prompting import ScriptedBackend
|
||||
|
||||
providers = {
|
||||
"a": OpenAIProvider(access_key_or_token="sk"),
|
||||
"b": OpenAICompatibleProvider(access_key_or_token="sk", url="https://x/v1"),
|
||||
"a": OpenAIProvider(access_key_or_token="sk", models={"m": ModelConfig()}),
|
||||
"b": OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"m": ModelConfig()},
|
||||
),
|
||||
}
|
||||
with temporary_backend(ScriptedBackend(["2"])):
|
||||
name, _ = select_provider(providers)
|
||||
assert name == "b"
|
||||
|
||||
|
||||
def test_select_model_when_preferred_missing_raises() -> None:
|
||||
provider = OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"m1": ModelConfig()},
|
||||
)
|
||||
with pytest.raises(Exception, match="unknown model"):
|
||||
_ = select_model(provider, preferred="nope")
|
||||
|
||||
Reference in New Issue
Block a user