config: rename the DeepSeek flash model to deepseek-flash

DeepSeek dropped the `v4` prefix from its flash model, and the old id stays
valid only as a compatibility alias. Seed the default catalog with the current
name so a provider that omits `models` no longer offers a deprecated id, and
follow the rename in the wire fixtures and the minimal config template. An
explicit `deepseek-v4-flash` in TOML still passes through unchanged.
This commit is contained in:
2026-10-06 21:22:35 +08:00
parent 35dbd30328
commit ec5340bdce
10 changed files with 28 additions and 28 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ _MINIMAL_CONFIG = """\
# [providers.deepseek]
# preset = "deepseek"
# access_key_or_token = "sk-..."
# # models default to deepseek-v4-flash and deepseek-v4-pro if omitted
# # models default to deepseek-flash and deepseek-v4-pro if omitted
"""
+1 -1
View File
@@ -366,7 +366,7 @@ class AnthropicProvider(ProviderConfig, tag="anthropic"):
def _default_deepseek_models() -> dict[str, ModelConfig]:
"""Current DeepSeek text catalog when TOML omits ``models``."""
return {
"deepseek-v4-flash": ModelConfig(text=True),
"deepseek-flash": ModelConfig(text=True),
"deepseek-v4-pro": ModelConfig(text=True),
}
@@ -17,8 +17,8 @@ class DeepseekAnthropicClient(AnthropicClient):
(see https://api-docs.deepseek.com/guides/anthropic_api). ``x-api-key`` is fully
supported; ``anthropic-version`` / ``anthropic-beta`` headers are ignored by the
server but harmless. Model ids map server-side: ``claude-opus*`` → ``deepseek-v4-pro``,
``claude-haiku*`` / ``claude-sonnet*`` → ``deepseek-v4-flash``, unknown names →
``deepseek-v4-flash``; real DeepSeek ids pass through as-is.
``claude-haiku*`` / ``claude-sonnet*`` → ``deepseek-flash``, unknown names →
``deepseek-flash``; real DeepSeek ids pass through as-is.
``GET /models`` is not documented on the ``/anthropic`` base, so ``models()``
returns an empty list and model selection stays config-driven.
+1 -1
View File
@@ -167,7 +167,7 @@ def _reasoning_response(
return Response(
id="resp_r",
created_at=1,
model="deepseek-v4-flash",
model="deepseek-flash",
output=output,
reasoning=top_level,
)
+1 -1
View File
@@ -430,7 +430,7 @@ async def test_dispatch_stream_failed_raises_with_error_detail() -> None:
"id": "resp_1",
"object": "response",
"created_at": 1,
"model": "deepseek-v4-flash",
"model": "deepseek-flash",
"status": "failed",
"output": [],
"error": {"code": "rate_limit_exceeded", "message": "slow down"},
+8 -8
View File
@@ -46,8 +46,8 @@ def test_read_valid_config() -> None:
assert isinstance(providers["test3"], AnthropicProvider)
assert isinstance(providers["foo1"], DeepseekProvider)
# TOML omitted models → DeepSeek defaults.
assert set(providers["foo1"].models) == {"deepseek-v4-flash", "deepseek-v4-pro"}
assert providers["foo1"].models["deepseek-v4-flash"].text is True
assert set(providers["foo1"].models) == {"deepseek-flash", "deepseek-v4-pro"}
assert providers["foo1"].models["deepseek-flash"].text is True
db = config.database
assert db["implementation"] == "sqlite"
assert db["url"] == ":memory:"
@@ -57,7 +57,7 @@ def test_read_valid_config() -> None:
def test_deepseek_default_models_on_construct() -> None:
provider = DeepseekProvider(access_key_or_token="sk-test")
assert set(provider.models) == {"deepseek-v4-flash", "deepseek-v4-pro"}
assert set(provider.models) == {"deepseek-flash", "deepseek-v4-pro"}
def test_openai_default_models_on_construct() -> None:
@@ -179,7 +179,7 @@ preset = "deepseek"
access_key_or_token = "sk-test"
[providers.ds.models]
"deepseek-v4-flash" = { text = true, convention = "responses" }
"deepseek-flash" = { text = true, convention = "responses" }
"deepseek-v4-pro" = { text = true }
""",
encoding="utf-8",
@@ -187,7 +187,7 @@ access_key_or_token = "sk-test"
config = plyngent.config.load(path)
provider = config.providers["ds"]
assert isinstance(provider, DeepseekProvider)
assert provider.models["deepseek-v4-flash"].convention == "responses"
assert provider.models["deepseek-flash"].convention == "responses"
assert provider.models["deepseek-v4-pro"].convention == ""
@@ -314,7 +314,7 @@ reasoning_effort = "high"
[providers.ds.models]
"deepseek-v4-pro" = { text = true, reasoning_effort = "max", thinking_budget_tokens = 32000 }
"deepseek-v4-flash" = { text = true }
"deepseek-flash" = { text = true }
""",
encoding="utf-8",
)
@@ -327,8 +327,8 @@ reasoning_effort = "high"
assert provider.thinking_budget_tokens == 0
assert provider.models["deepseek-v4-pro"].reasoning_effort == "max"
assert provider.models["deepseek-v4-pro"].thinking_budget_tokens == 32000
assert provider.models["deepseek-v4-flash"].reasoning_effort == ""
assert provider.models["deepseek-v4-flash"].thinking_budget_tokens == 0
assert provider.models["deepseek-flash"].reasoning_effort == ""
assert provider.models["deepseek-flash"].thinking_budget_tokens == 0
def test_reasoning_effort_defaults_are_unset(tmp_path: Path) -> None:
@@ -17,7 +17,7 @@ def _sample_message_body() -> bytes:
return msgspec.json.encode(
AnthropicMessageResponse(
id="msg_1",
model="deepseek-v4-flash",
model="deepseek-flash",
content=[AnthropicResponseText(text="hello world")],
stop_reason="end_turn",
usage=AnthropicUsage(input_tokens=9, output_tokens=3),
@@ -52,7 +52,7 @@ async def test_client_messages_create(monkeypatch: pytest.MonkeyPatch) -> None:
return _Resp()
monkeypatch.setattr(client.session, "post", fake_post)
result = await client.messages(AnthropicMessagesParam(model="deepseek-v4-flash", messages=[]))
result = await client.messages(AnthropicMessagesParam(model="deepseek-flash", messages=[]))
assert isinstance(result, AnthropicMessageResponse)
assert result.content[0].text == "hello world"
assert result.usage.output_tokens == 3
@@ -78,7 +78,7 @@ async def test_client_messages_stream(monkeypatch: pytest.MonkeyPatch) -> None:
return _Resp()
monkeypatch.setattr(client.session, "post", fake_post)
stream = await client.messages(AnthropicMessagesParam(model="deepseek-v4-flash", messages=[]), stream=True)
stream = await client.messages(AnthropicMessagesParam(model="deepseek-flash", messages=[]), stream=True)
events = [event async for event in stream]
assert len(events) == 2
@@ -9,7 +9,7 @@ from plyngent.lmproto.openai_compatible.config import OpenAIConfig
def _sample_response_body() -> bytes:
return (
b'{"id":"resp_1","object":"response","created_at":1,"model":"deepseek-v4-flash",'
b'{"id":"resp_1","object":"response","created_at":1,"model":"deepseek-flash",'
b'"status":"completed","output":['
b'{"id":"msg_1","type":"message","role":"assistant","status":"completed",'
b'"content":[{"type":"output_text","text":"hello from deepseek","annotations":[]}]}'
@@ -40,7 +40,7 @@ async def test_client_responses_create(monkeypatch: pytest.MonkeyPatch) -> None:
return _Resp()
monkeypatch.setattr(client.session, "post", fake_post)
result = await client.responses(ResponsesCreateParam(model="deepseek-v4-flash", input="hi"))
result = await client.responses(ResponsesCreateParam(model="deepseek-flash", input="hi"))
assert isinstance(result, Response)
assert response_output_text(result) == "hello from deepseek"
@@ -62,7 +62,7 @@ async def test_client_responses_stream_stops_at_terminal(monkeypatch: pytest.Mon
yield (
b'data: {"type":"response.completed","sequence_number":2,'
b'"response":{"id":"resp_1","object":"response","created_at":1,'
b'"model":"deepseek-v4-flash","status":"completed","output":[]}}'
b'"model":"deepseek-flash","status":"completed","output":[]}}'
)
# Anything after the terminal event must not be consumed.
yield b'data: {"type":"response.output_text.delta","delta":"ignored"}'
@@ -77,7 +77,7 @@ async def test_client_responses_stream_stops_at_terminal(monkeypatch: pytest.Mon
monkeypatch.setattr(client.session, "post", fake_post)
stream = await client.responses(
ResponsesCreateParam(model="deepseek-v4-flash", input="hi"),
ResponsesCreateParam(model="deepseek-flash", input="hi"),
stream=True,
)
events = [event async for event in stream]
+2 -2
View File
@@ -169,12 +169,12 @@ async def test_session_llm_remembered(store: MemoryStore) -> None:
session = await store.create_session(
name="llm",
provider_name="deepseek",
model="deepseek-v4-flash",
model="deepseek-flash",
)
row = await store.get_session(session.sid)
assert row is not None
assert row.provider_name == "deepseek"
assert row.model == "deepseek-v4-flash"
assert row.model == "deepseek-flash"
updated = await store.update_session_llm(session.sid, model="deepseek-v4-pro")
assert updated.provider_name == "deepseek"
assert updated.model == "deepseek-v4-pro"
+5 -5
View File
@@ -60,7 +60,7 @@ def test_deepseek_openai_convention() -> None:
client = create_client(provider)
assert isinstance(client, DeepseekOpenAIClient)
assert provider_to_openai_config(provider).base_url == "https://api.deepseek.com"
assert "deepseek-v4-flash" in provider.models
assert "deepseek-flash" in provider.models
assert "deepseek-v4-pro" in provider.models
@@ -129,13 +129,13 @@ def test_deepseek_model_level_anthropic_convention() -> None:
access_key_or_token="sk-test",
models={
"claude-proxy": ModelConfig(convention="anthropic"),
"deepseek-v4-flash": ModelConfig(),
"deepseek-flash": ModelConfig(),
},
)
proxy = create_client(provider, model="claude-proxy")
assert isinstance(proxy, DeepseekAnthropicClient)
assert proxy.session.base_url == "https://api.deepseek.com/anthropic"
flash = create_client(provider, model="deepseek-v4-flash")
flash = create_client(provider, model="deepseek-flash")
assert isinstance(flash, DeepseekOpenAIClient)
@@ -145,11 +145,11 @@ def test_deepseek_model_level_convention_override() -> None:
provider = DeepseekProvider(
access_key_or_token="sk-test",
models={
"deepseek-v4-flash": ModelConfig(convention="responses"),
"deepseek-flash": ModelConfig(convention="responses"),
"deepseek-v4-pro": ModelConfig(),
},
)
flash = create_client(provider, model="deepseek-v4-flash")
flash = create_client(provider, model="deepseek-flash")
assert isinstance(flash, DeepseekResponsesClient)
assert flash.kind == "responses"
pro = create_client(provider, model="deepseek-v4-pro")