mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-23 05:55:16 +08:00
core/cli: /models and remote catalog for model selection
Cache GET /models, merge with config ids for Tab and choose; free-form model ids allowed.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from plyngent.cli.models_source import (
|
||||
client_supports_models,
|
||||
config_model_ids,
|
||||
fetch_remote_model_ids,
|
||||
merge_model_choices,
|
||||
model_choices_for_provider,
|
||||
)
|
||||
from plyngent.config.models import ModelConfig, OpenAICompatibleProvider
|
||||
|
||||
|
||||
def test_merge_model_choices_union() -> None:
|
||||
assert merge_model_choices(["b", "a"], ["a", "c"]) == ["a", "b", "c"]
|
||||
assert merge_model_choices(["a"], None) == ["a"]
|
||||
assert merge_model_choices([], ["z"]) == ["z"]
|
||||
|
||||
|
||||
def test_model_choices_for_provider() -> None:
|
||||
provider = OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"cfg": ModelConfig()},
|
||||
)
|
||||
assert config_model_ids(provider) == ["cfg"]
|
||||
assert model_choices_for_provider(provider, remote_ids=["remote", "cfg"]) == ["cfg", "remote"]
|
||||
|
||||
|
||||
def test_client_supports_models() -> None:
|
||||
class Ok:
|
||||
async def models(self) -> list[str]:
|
||||
return ["m"]
|
||||
|
||||
class No:
|
||||
pass
|
||||
|
||||
assert client_supports_models(Ok())
|
||||
assert not client_supports_models(No())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_remote_model_ids() -> None:
|
||||
class Ok:
|
||||
async def models(self) -> list[str]:
|
||||
return ["z", "a"]
|
||||
|
||||
assert await fetch_remote_model_ids(Ok()) == ["z", "a"]
|
||||
|
||||
with pytest.raises(TypeError, match="does not support"):
|
||||
_ = await fetch_remote_model_ids(object())
|
||||
@@ -235,7 +235,7 @@ async def test_provider_switch_prompts_when_model_missing(
|
||||
# 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",
|
||||
lambda provider, preferred=None, interactive=True, choices=None: "only-b",
|
||||
)
|
||||
assert await handle_slash(state, "/provider b") is True
|
||||
assert state.provider_name == "b"
|
||||
|
||||
@@ -64,11 +64,25 @@ def test_select_provider_interactive_choose() -> None:
|
||||
assert name == "b"
|
||||
|
||||
|
||||
def test_select_model_when_preferred_missing_raises() -> None:
|
||||
def test_select_model_preferred_not_in_config_allowed() -> None:
|
||||
"""Explicit model ids are accepted; the API validates at chat time."""
|
||||
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")
|
||||
assert select_model(provider, preferred="nope") == "nope"
|
||||
assert select_model(provider, preferred=" custom ") == "custom"
|
||||
|
||||
|
||||
def test_select_model_choices_override() -> None:
|
||||
from plyngent.prompting import temporary_backend
|
||||
from tests.test_prompting import ScriptedBackend
|
||||
|
||||
provider = OpenAICompatibleProvider(
|
||||
access_key_or_token="sk",
|
||||
url="https://x/v1",
|
||||
models={"m1": ModelConfig()},
|
||||
)
|
||||
with temporary_backend(ScriptedBackend(["remote-x"])):
|
||||
assert select_model(provider, choices=["remote-x", "m1"]) == "remote-x"
|
||||
|
||||
Reference in New Issue
Block a user