mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 23:47:54 +08:00
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:
@@ -57,7 +57,7 @@ _MINIMAL_CONFIG = """\
|
|||||||
# [providers.deepseek]
|
# [providers.deepseek]
|
||||||
# preset = "deepseek"
|
# preset = "deepseek"
|
||||||
# access_key_or_token = "sk-..."
|
# 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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ class AnthropicProvider(ProviderConfig, tag="anthropic"):
|
|||||||
def _default_deepseek_models() -> dict[str, ModelConfig]:
|
def _default_deepseek_models() -> dict[str, ModelConfig]:
|
||||||
"""Current DeepSeek text catalog when TOML omits ``models``."""
|
"""Current DeepSeek text catalog when TOML omits ``models``."""
|
||||||
return {
|
return {
|
||||||
"deepseek-v4-flash": ModelConfig(text=True),
|
"deepseek-flash": ModelConfig(text=True),
|
||||||
"deepseek-v4-pro": 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
|
(see https://api-docs.deepseek.com/guides/anthropic_api). ``x-api-key`` is fully
|
||||||
supported; ``anthropic-version`` / ``anthropic-beta`` headers are ignored by the
|
supported; ``anthropic-version`` / ``anthropic-beta`` headers are ignored by the
|
||||||
server but harmless. Model ids map server-side: ``claude-opus*`` → ``deepseek-v4-pro``,
|
server but harmless. Model ids map server-side: ``claude-opus*`` → ``deepseek-v4-pro``,
|
||||||
``claude-haiku*`` / ``claude-sonnet*`` → ``deepseek-v4-flash``, unknown names →
|
``claude-haiku*`` / ``claude-sonnet*`` → ``deepseek-flash``, unknown names →
|
||||||
``deepseek-v4-flash``; real DeepSeek ids pass through as-is.
|
``deepseek-flash``; real DeepSeek ids pass through as-is.
|
||||||
|
|
||||||
``GET /models`` is not documented on the ``/anthropic`` base, so ``models()``
|
``GET /models`` is not documented on the ``/anthropic`` base, so ``models()``
|
||||||
returns an empty list and model selection stays config-driven.
|
returns an empty list and model selection stays config-driven.
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ def _reasoning_response(
|
|||||||
return Response(
|
return Response(
|
||||||
id="resp_r",
|
id="resp_r",
|
||||||
created_at=1,
|
created_at=1,
|
||||||
model="deepseek-v4-flash",
|
model="deepseek-flash",
|
||||||
output=output,
|
output=output,
|
||||||
reasoning=top_level,
|
reasoning=top_level,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ async def test_dispatch_stream_failed_raises_with_error_detail() -> None:
|
|||||||
"id": "resp_1",
|
"id": "resp_1",
|
||||||
"object": "response",
|
"object": "response",
|
||||||
"created_at": 1,
|
"created_at": 1,
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-flash",
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
"output": [],
|
"output": [],
|
||||||
"error": {"code": "rate_limit_exceeded", "message": "slow down"},
|
"error": {"code": "rate_limit_exceeded", "message": "slow down"},
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ def test_read_valid_config() -> None:
|
|||||||
assert isinstance(providers["test3"], AnthropicProvider)
|
assert isinstance(providers["test3"], AnthropicProvider)
|
||||||
assert isinstance(providers["foo1"], DeepseekProvider)
|
assert isinstance(providers["foo1"], DeepseekProvider)
|
||||||
# TOML omitted models → DeepSeek defaults.
|
# TOML omitted models → DeepSeek defaults.
|
||||||
assert set(providers["foo1"].models) == {"deepseek-v4-flash", "deepseek-v4-pro"}
|
assert set(providers["foo1"].models) == {"deepseek-flash", "deepseek-v4-pro"}
|
||||||
assert providers["foo1"].models["deepseek-v4-flash"].text is True
|
assert providers["foo1"].models["deepseek-flash"].text is True
|
||||||
db = config.database
|
db = config.database
|
||||||
assert db["implementation"] == "sqlite"
|
assert db["implementation"] == "sqlite"
|
||||||
assert db["url"] == ":memory:"
|
assert db["url"] == ":memory:"
|
||||||
@@ -57,7 +57,7 @@ def test_read_valid_config() -> None:
|
|||||||
|
|
||||||
def test_deepseek_default_models_on_construct() -> None:
|
def test_deepseek_default_models_on_construct() -> None:
|
||||||
provider = DeepseekProvider(access_key_or_token="sk-test")
|
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:
|
def test_openai_default_models_on_construct() -> None:
|
||||||
@@ -179,7 +179,7 @@ preset = "deepseek"
|
|||||||
access_key_or_token = "sk-test"
|
access_key_or_token = "sk-test"
|
||||||
|
|
||||||
[providers.ds.models]
|
[providers.ds.models]
|
||||||
"deepseek-v4-flash" = { text = true, convention = "responses" }
|
"deepseek-flash" = { text = true, convention = "responses" }
|
||||||
"deepseek-v4-pro" = { text = true }
|
"deepseek-v4-pro" = { text = true }
|
||||||
""",
|
""",
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
@@ -187,7 +187,7 @@ access_key_or_token = "sk-test"
|
|||||||
config = plyngent.config.load(path)
|
config = plyngent.config.load(path)
|
||||||
provider = config.providers["ds"]
|
provider = config.providers["ds"]
|
||||||
assert isinstance(provider, DeepseekProvider)
|
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 == ""
|
assert provider.models["deepseek-v4-pro"].convention == ""
|
||||||
|
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ reasoning_effort = "high"
|
|||||||
|
|
||||||
[providers.ds.models]
|
[providers.ds.models]
|
||||||
"deepseek-v4-pro" = { text = true, reasoning_effort = "max", thinking_budget_tokens = 32000 }
|
"deepseek-v4-pro" = { text = true, reasoning_effort = "max", thinking_budget_tokens = 32000 }
|
||||||
"deepseek-v4-flash" = { text = true }
|
"deepseek-flash" = { text = true }
|
||||||
""",
|
""",
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
@@ -327,8 +327,8 @@ reasoning_effort = "high"
|
|||||||
assert provider.thinking_budget_tokens == 0
|
assert provider.thinking_budget_tokens == 0
|
||||||
assert provider.models["deepseek-v4-pro"].reasoning_effort == "max"
|
assert provider.models["deepseek-v4-pro"].reasoning_effort == "max"
|
||||||
assert provider.models["deepseek-v4-pro"].thinking_budget_tokens == 32000
|
assert provider.models["deepseek-v4-pro"].thinking_budget_tokens == 32000
|
||||||
assert provider.models["deepseek-v4-flash"].reasoning_effort == ""
|
assert provider.models["deepseek-flash"].reasoning_effort == ""
|
||||||
assert provider.models["deepseek-v4-flash"].thinking_budget_tokens == 0
|
assert provider.models["deepseek-flash"].thinking_budget_tokens == 0
|
||||||
|
|
||||||
|
|
||||||
def test_reasoning_effort_defaults_are_unset(tmp_path: Path) -> None:
|
def test_reasoning_effort_defaults_are_unset(tmp_path: Path) -> None:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def _sample_message_body() -> bytes:
|
|||||||
return msgspec.json.encode(
|
return msgspec.json.encode(
|
||||||
AnthropicMessageResponse(
|
AnthropicMessageResponse(
|
||||||
id="msg_1",
|
id="msg_1",
|
||||||
model="deepseek-v4-flash",
|
model="deepseek-flash",
|
||||||
content=[AnthropicResponseText(text="hello world")],
|
content=[AnthropicResponseText(text="hello world")],
|
||||||
stop_reason="end_turn",
|
stop_reason="end_turn",
|
||||||
usage=AnthropicUsage(input_tokens=9, output_tokens=3),
|
usage=AnthropicUsage(input_tokens=9, output_tokens=3),
|
||||||
@@ -52,7 +52,7 @@ async def test_client_messages_create(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
return _Resp()
|
return _Resp()
|
||||||
|
|
||||||
monkeypatch.setattr(client.session, "post", fake_post)
|
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 isinstance(result, AnthropicMessageResponse)
|
||||||
assert result.content[0].text == "hello world"
|
assert result.content[0].text == "hello world"
|
||||||
assert result.usage.output_tokens == 3
|
assert result.usage.output_tokens == 3
|
||||||
@@ -78,7 +78,7 @@ async def test_client_messages_stream(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
return _Resp()
|
return _Resp()
|
||||||
|
|
||||||
monkeypatch.setattr(client.session, "post", fake_post)
|
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]
|
events = [event async for event in stream]
|
||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from plyngent.lmproto.openai_compatible.config import OpenAIConfig
|
|||||||
|
|
||||||
def _sample_response_body() -> bytes:
|
def _sample_response_body() -> bytes:
|
||||||
return (
|
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'"status":"completed","output":['
|
||||||
b'{"id":"msg_1","type":"message","role":"assistant","status":"completed",'
|
b'{"id":"msg_1","type":"message","role":"assistant","status":"completed",'
|
||||||
b'"content":[{"type":"output_text","text":"hello from deepseek","annotations":[]}]}'
|
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()
|
return _Resp()
|
||||||
|
|
||||||
monkeypatch.setattr(client.session, "post", fake_post)
|
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 isinstance(result, Response)
|
||||||
assert response_output_text(result) == "hello from deepseek"
|
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 (
|
yield (
|
||||||
b'data: {"type":"response.completed","sequence_number":2,'
|
b'data: {"type":"response.completed","sequence_number":2,'
|
||||||
b'"response":{"id":"resp_1","object":"response","created_at":1,'
|
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.
|
# Anything after the terminal event must not be consumed.
|
||||||
yield b'data: {"type":"response.output_text.delta","delta":"ignored"}'
|
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)
|
monkeypatch.setattr(client.session, "post", fake_post)
|
||||||
stream = await client.responses(
|
stream = await client.responses(
|
||||||
ResponsesCreateParam(model="deepseek-v4-flash", input="hi"),
|
ResponsesCreateParam(model="deepseek-flash", input="hi"),
|
||||||
stream=True,
|
stream=True,
|
||||||
)
|
)
|
||||||
events = [event async for event in stream]
|
events = [event async for event in stream]
|
||||||
|
|||||||
@@ -169,12 +169,12 @@ async def test_session_llm_remembered(store: MemoryStore) -> None:
|
|||||||
session = await store.create_session(
|
session = await store.create_session(
|
||||||
name="llm",
|
name="llm",
|
||||||
provider_name="deepseek",
|
provider_name="deepseek",
|
||||||
model="deepseek-v4-flash",
|
model="deepseek-flash",
|
||||||
)
|
)
|
||||||
row = await store.get_session(session.sid)
|
row = await store.get_session(session.sid)
|
||||||
assert row is not None
|
assert row is not None
|
||||||
assert row.provider_name == "deepseek"
|
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")
|
updated = await store.update_session_llm(session.sid, model="deepseek-v4-pro")
|
||||||
assert updated.provider_name == "deepseek"
|
assert updated.provider_name == "deepseek"
|
||||||
assert updated.model == "deepseek-v4-pro"
|
assert updated.model == "deepseek-v4-pro"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def test_deepseek_openai_convention() -> None:
|
|||||||
client = create_client(provider)
|
client = create_client(provider)
|
||||||
assert isinstance(client, DeepseekOpenAIClient)
|
assert isinstance(client, DeepseekOpenAIClient)
|
||||||
assert provider_to_openai_config(provider).base_url == "https://api.deepseek.com"
|
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
|
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",
|
access_key_or_token="sk-test",
|
||||||
models={
|
models={
|
||||||
"claude-proxy": ModelConfig(convention="anthropic"),
|
"claude-proxy": ModelConfig(convention="anthropic"),
|
||||||
"deepseek-v4-flash": ModelConfig(),
|
"deepseek-flash": ModelConfig(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
proxy = create_client(provider, model="claude-proxy")
|
proxy = create_client(provider, model="claude-proxy")
|
||||||
assert isinstance(proxy, DeepseekAnthropicClient)
|
assert isinstance(proxy, DeepseekAnthropicClient)
|
||||||
assert proxy.session.base_url == "https://api.deepseek.com/anthropic"
|
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)
|
assert isinstance(flash, DeepseekOpenAIClient)
|
||||||
|
|
||||||
|
|
||||||
@@ -145,11 +145,11 @@ def test_deepseek_model_level_convention_override() -> None:
|
|||||||
provider = DeepseekProvider(
|
provider = DeepseekProvider(
|
||||||
access_key_or_token="sk-test",
|
access_key_or_token="sk-test",
|
||||||
models={
|
models={
|
||||||
"deepseek-v4-flash": ModelConfig(convention="responses"),
|
"deepseek-flash": ModelConfig(convention="responses"),
|
||||||
"deepseek-v4-pro": ModelConfig(),
|
"deepseek-v4-pro": ModelConfig(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
flash = create_client(provider, model="deepseek-v4-flash")
|
flash = create_client(provider, model="deepseek-flash")
|
||||||
assert isinstance(flash, DeepseekResponsesClient)
|
assert isinstance(flash, DeepseekResponsesClient)
|
||||||
assert flash.kind == "responses"
|
assert flash.kind == "responses"
|
||||||
pro = create_client(provider, model="deepseek-v4-pro")
|
pro = create_client(provider, model="deepseek-v4-pro")
|
||||||
|
|||||||
Reference in New Issue
Block a user