lmproto: add DeepSeek Responses client

This commit is contained in:
2026-08-01 02:01:06 +08:00
parent 8ad33af652
commit db6d2a83f4
5 changed files with 153 additions and 2 deletions
+4 -2
View File
@@ -3,8 +3,10 @@
from __future__ import annotations
from plyngent.lmproto.anthropic.client import AnthropicClient
from plyngent.lmproto.deepseek.openai_compat.client import DeepseekOpenAIClient
from plyngent.lmproto.deepseek import DeepseekOpenAIClient, DeepseekResponsesClient
from plyngent.lmproto.openai.client import OpenAIClient
from plyngent.lmproto.openai_compatible.client import OpenAICompatibleClient
type AnyLLMClient = OpenAICompatibleClient | DeepseekOpenAIClient | OpenAIClient | AnthropicClient
type AnyLLMClient = (
OpenAICompatibleClient | DeepseekOpenAIClient | DeepseekResponsesClient | OpenAIClient | AnthropicClient
)
@@ -6,3 +6,4 @@ from .openai_compat.model import DeepSeekReasoningEffort as DeepSeekReasoningEff
from .openai_compat.model import NamedChatMessage as NamedChatMessage
from .openai_compat.model import ThinkingOptions as ThinkingOptions
from .openai_compat.model import ToolChatMessage as ToolChatMessage
from .responses.client import DeepseekResponsesClient as DeepseekResponsesClient
@@ -0,0 +1 @@
from .client import DeepseekResponsesClient as DeepseekResponsesClient
@@ -0,0 +1,58 @@
"""DeepSeek Responses API client (``POST /responses`` on the DeepSeek endpoint)."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, cast, override
from plyngent.lmproto.openai.client import OpenAIClient
# DeepSeek Responses SSE streams end with a terminal event instead of
# ``data: [DONE]`` (see https://api-docs.deepseek.com/guides/responses_api).
_RESPONSES_TERMINAL_EVENTS = frozenset({"response.completed", "response.incomplete", "response.failed"})
if TYPE_CHECKING:
from collections.abc import AsyncIterator
from plyngent.lmproto.openai.model import ResponseStreamEvent
from plyngent.lmproto.openai_compatible.config import OpenAIConfig
class DeepseekResponsesClient(OpenAIClient):
"""DeepSeek Responses client: OpenAI Responses format on DeepSeek's endpoint.
Differs from :class:`~plyngent.lmproto.openai.OpenAIClient` only in
streaming: DeepSeek sends no ``data: [DONE]``, so the SSE loop stops at a
terminal event (``response.completed`` / ``response.incomplete`` /
``response.failed``) instead of waiting for ``[DONE]``.
"""
kind: str = "responses"
def __init__(self, config: OpenAIConfig) -> None:
super().__init__(config)
@override
async def _parse_response_sse(self, resp: object) -> AsyncIterator[ResponseStreamEvent]:
"""Yield Responses API SSE events; stop at terminal events (no ``[DONE]``)."""
from plyngent.lmproto.openai_compatible.client import (
close_async_response,
sse_data_payload,
)
typed = cast("Any", resp)
try:
await self._ensure_ok(typed, what="responses")
async for raw in typed.iter_lines():
if not raw:
continue
parsed = sse_data_payload(bytes(raw))
if parsed is None:
continue
if parsed is False:
break
event = self.response_event_decoder.decode(parsed)
yield event
if event.type in _RESPONSES_TERMINAL_EVENTS:
break
finally:
await close_async_response(typed)