mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 23:47:54 +08:00
core/agent: share stream chunk builders across responses and messages bridges
This commit is contained in:
@@ -30,14 +30,9 @@ from plyngent.lmproto.openai_compatible.model import (
|
||||
AssistantFunctionTool,
|
||||
AssistantFunctionToolCall,
|
||||
ChatCompletionChoice,
|
||||
ChatCompletionChunk,
|
||||
ChatCompletionResponse,
|
||||
ChatCompletionsParam,
|
||||
ChunkChoice,
|
||||
DeltaMessage,
|
||||
DeveloperChatMessage,
|
||||
StreamFunctionDelta,
|
||||
StreamToolCallDelta,
|
||||
SystemChatMessage,
|
||||
ToolFunctionItem,
|
||||
UserChatMessage,
|
||||
@@ -290,88 +285,6 @@ def anthropic_response_to_chat_completion(
|
||||
)
|
||||
|
||||
|
||||
def finish_reason_chunk(
|
||||
*,
|
||||
model: str,
|
||||
finish_reason: str,
|
||||
created: int = 0,
|
||||
) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="anthropic-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(),
|
||||
finish_reason=cast("Any", finish_reason),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def text_delta_chunk(*, model: str, content: str, created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="anthropic-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(content=content),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def tool_call_delta_chunk(
|
||||
*,
|
||||
model: str,
|
||||
index: int,
|
||||
call_id: str | None = None,
|
||||
name: str | None = None,
|
||||
arguments: str | None = None,
|
||||
created: int = 0,
|
||||
) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="anthropic-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(
|
||||
tool_calls=[
|
||||
StreamToolCallDelta(
|
||||
index=index,
|
||||
id=call_id if call_id is not None else UNSET,
|
||||
type="function",
|
||||
function=StreamFunctionDelta(
|
||||
name=name if name is not None else UNSET,
|
||||
arguments=arguments if arguments is not None else UNSET,
|
||||
),
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def usage_chunk(*, model: str, usage: dict[str, Any], created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="anthropic-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[],
|
||||
usage=usage,
|
||||
)
|
||||
|
||||
|
||||
def _max_tokens_from_param(param: ChatCompletionsParam) -> int:
|
||||
if param.max_completion_tokens is not UNSET:
|
||||
return int(param.max_completion_tokens)
|
||||
|
||||
@@ -13,6 +13,8 @@ from plyngent.agent.messages_bridge import (
|
||||
anthropic_stop_to_finish_reason,
|
||||
anthropic_usage_to_dict,
|
||||
chat_param_to_anthropic_param,
|
||||
)
|
||||
from plyngent.agent.stream_chunks import (
|
||||
finish_reason_chunk,
|
||||
text_delta_chunk,
|
||||
tool_call_delta_chunk,
|
||||
|
||||
@@ -27,11 +27,7 @@ from plyngent.lmproto.openai_compatible.model import (
|
||||
ChatCompletionChunk,
|
||||
ChatCompletionResponse,
|
||||
ChatCompletionsParam,
|
||||
ChunkChoice,
|
||||
DeltaMessage,
|
||||
DeveloperChatMessage,
|
||||
StreamFunctionDelta,
|
||||
StreamToolCallDelta,
|
||||
SystemChatMessage,
|
||||
ToolFunctionItem,
|
||||
UserChatMessage,
|
||||
@@ -204,58 +200,6 @@ def response_to_chat_completion(response: Response) -> ChatCompletionResponse:
|
||||
)
|
||||
|
||||
|
||||
def finish_reason_chunk(
|
||||
*,
|
||||
model: str,
|
||||
finish_reason: str,
|
||||
created: int = 0,
|
||||
) -> ChatCompletionChunk:
|
||||
"""Terminal stream chunk carrying only ``finish_reason`` (no delta text)."""
|
||||
return ChatCompletionChunk(
|
||||
id="resp-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(),
|
||||
finish_reason=cast("Any", finish_reason),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def text_delta_chunk(*, model: str, content: str, created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="resp-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(content=content),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def reasoning_delta_chunk(*, model: str, content: str, created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="resp-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(reasoning_content=content),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def tool_call_chunks_from_response(
|
||||
response: Response,
|
||||
*,
|
||||
@@ -263,50 +207,28 @@ def tool_call_chunks_from_response(
|
||||
created: int = 0,
|
||||
) -> list[ChatCompletionChunk]:
|
||||
"""Emit complete tool-call stream deltas (one chunk per call) for loop merge."""
|
||||
from .stream_chunks import tool_call_delta_chunk
|
||||
|
||||
calls = response_function_calls(response)
|
||||
chunks: list[ChatCompletionChunk] = []
|
||||
for index, call in enumerate(calls):
|
||||
chunks.append(
|
||||
ChatCompletionChunk(
|
||||
id=response.id,
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(
|
||||
tool_calls=[
|
||||
StreamToolCallDelta(
|
||||
index=index,
|
||||
id=call.call_id,
|
||||
type="function",
|
||||
function=StreamFunctionDelta(
|
||||
name=call.name,
|
||||
arguments=call.arguments,
|
||||
),
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
return [
|
||||
tool_call_delta_chunk(
|
||||
model=model,
|
||||
index=index,
|
||||
call_id=call.call_id,
|
||||
name=call.name,
|
||||
arguments=call.arguments,
|
||||
created=created,
|
||||
)
|
||||
return chunks
|
||||
for index, call in enumerate(calls)
|
||||
]
|
||||
|
||||
|
||||
def usage_chunk_from_response(response: Response, *, model: str) -> ChatCompletionChunk | None:
|
||||
from .stream_chunks import usage_chunk
|
||||
|
||||
if response.usage is UNSET or response.usage is None:
|
||||
return None
|
||||
created = int(response.created_at)
|
||||
return ChatCompletionChunk(
|
||||
id=response.id,
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[],
|
||||
usage=response.usage,
|
||||
)
|
||||
return usage_chunk(model=model, usage=response.usage, created=int(response.created_at))
|
||||
|
||||
|
||||
def _merge_response_tools(
|
||||
|
||||
@@ -16,15 +16,17 @@ from msgspec import UNSET
|
||||
|
||||
from plyngent.agent.responses_bridge import (
|
||||
chat_param_to_responses_kwargs,
|
||||
finish_reason_chunk,
|
||||
reasoning_delta_chunk,
|
||||
response_to_assistant_message,
|
||||
response_to_chat_completion,
|
||||
responses_status_to_finish_reason,
|
||||
text_delta_chunk,
|
||||
tool_call_chunks_from_response,
|
||||
usage_chunk_from_response,
|
||||
)
|
||||
from plyngent.agent.stream_chunks import (
|
||||
finish_reason_chunk,
|
||||
reasoning_delta_chunk,
|
||||
text_delta_chunk,
|
||||
)
|
||||
from plyngent.lmproto.openai.model import Response as ResponseModel
|
||||
from plyngent.lmproto.openai.model import ResponsesCreateParam
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
"""Shared chat-completions stream chunk builders for protocol bridges.
|
||||
|
||||
Both the Responses bridge and the Anthropic Messages bridge synthesize
|
||||
``ChatCompletionChunk`` objects so the agent loop can consume provider streams
|
||||
uniformly. The generic builders below are provider-agnostic; provider bridges
|
||||
map their events onto them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from msgspec import UNSET
|
||||
|
||||
from plyngent.lmproto.openai_compatible.model import (
|
||||
ChatCompletionChunk,
|
||||
ChunkChoice,
|
||||
DeltaMessage,
|
||||
StreamFunctionDelta,
|
||||
StreamToolCallDelta,
|
||||
)
|
||||
|
||||
|
||||
def finish_reason_chunk(
|
||||
*,
|
||||
model: str,
|
||||
finish_reason: str,
|
||||
created: int = 0,
|
||||
) -> ChatCompletionChunk:
|
||||
"""Terminal stream chunk carrying only ``finish_reason`` (no delta text)."""
|
||||
return ChatCompletionChunk(
|
||||
id="bridge-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(),
|
||||
finish_reason=cast("Any", finish_reason),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def text_delta_chunk(*, model: str, content: str, created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="bridge-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(content=content),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def reasoning_delta_chunk(*, model: str, content: str, created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="bridge-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(reasoning_content=content),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def tool_call_delta_chunk(
|
||||
*,
|
||||
model: str,
|
||||
index: int,
|
||||
call_id: str | None = None,
|
||||
name: str | None = None,
|
||||
arguments: str | None = None,
|
||||
created: int = 0,
|
||||
) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="bridge-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[
|
||||
ChunkChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(
|
||||
tool_calls=[
|
||||
StreamToolCallDelta(
|
||||
index=index,
|
||||
id=call_id if call_id is not None else UNSET,
|
||||
type="function",
|
||||
function=StreamFunctionDelta(
|
||||
name=name if name is not None else UNSET,
|
||||
arguments=arguments if arguments is not None else UNSET,
|
||||
),
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def usage_chunk(*, model: str, usage: dict[str, Any], created: int = 0) -> ChatCompletionChunk:
|
||||
return ChatCompletionChunk(
|
||||
id="bridge-stream",
|
||||
object="chat.completion.chunk",
|
||||
created=created,
|
||||
model=model,
|
||||
choices=[],
|
||||
usage=usage,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"finish_reason_chunk",
|
||||
"reasoning_delta_chunk",
|
||||
"text_delta_chunk",
|
||||
"tool_call_delta_chunk",
|
||||
"usage_chunk",
|
||||
]
|
||||
Reference in New Issue
Block a user