"""运行时 Hook 载荷序列化辅助。""" from __future__ import annotations from typing import Any, Dict, List, Sequence from src.chat.message_receive.message import SessionMessage from src.common.data_models.llm_service_data_models import PromptMessage from src.llm_models.payload_content.message import Message from src.llm_models.payload_content.tool_option import ToolCall, ToolDefinitionInput, normalize_tool_options from src.plugin_runtime.host.message_utils import PluginMessageUtils def serialize_session_message(message: SessionMessage) -> Dict[str, Any]: """将会话消息序列化为 Hook 可传输载荷。 Args: message: 待序列化的会话消息。 Returns: Dict[str, Any]: 可通过插件运行时传输的消息字典。 """ return dict(PluginMessageUtils._session_message_to_dict(message)) def deserialize_session_message(raw_message: Any) -> SessionMessage: """从 Hook 载荷恢复会话消息。 Args: raw_message: Hook 返回的消息字典。 Returns: SessionMessage: 恢复后的会话消息对象。 Raises: ValueError: 消息结构不合法时抛出。 """ if not isinstance(raw_message, dict): raise ValueError("Hook 返回的 `message` 必须是字典") return PluginMessageUtils._build_session_message_from_dict(raw_message) def serialize_tool_calls(tool_calls: Sequence[ToolCall] | None) -> List[Dict[str, Any]]: """将工具调用列表序列化为 Hook 可传输载荷。 Args: tool_calls: 原始工具调用列表。 Returns: List[Dict[str, Any]]: 序列化后的工具调用列表。 """ if not tool_calls: return [] return [ { "id": tool_call.call_id, "function": { "name": tool_call.func_name, "arguments": dict(tool_call.args or {}), }, } for tool_call in tool_calls ] def deserialize_tool_calls(raw_tool_calls: Any) -> List[ToolCall]: """从 Hook 载荷恢复工具调用列表。 Args: raw_tool_calls: Hook 返回的工具调用列表。 Returns: List[ToolCall]: 恢复后的工具调用列表。 Raises: ValueError: 结构不合法时抛出。 """ if raw_tool_calls in (None, []): return [] if not isinstance(raw_tool_calls, list): raise ValueError("Hook 返回的 `tool_calls` 必须是列表") normalized_tool_calls: List[ToolCall] = [] for raw_tool_call in raw_tool_calls: if not isinstance(raw_tool_call, dict): raise ValueError("Hook 返回的工具调用项必须是字典") function_info = raw_tool_call.get("function", {}) if isinstance(function_info, dict): function_name = function_info.get("name") function_arguments = function_info.get("arguments") else: function_name = raw_tool_call.get("name") function_arguments = raw_tool_call.get("arguments") call_id = raw_tool_call.get("id") or raw_tool_call.get("call_id") if not isinstance(call_id, str) or not isinstance(function_name, str): raise ValueError("Hook 返回的工具调用缺少 `id` 或函数名称") normalized_tool_calls.append( ToolCall( call_id=call_id, func_name=function_name, args=function_arguments if isinstance(function_arguments, dict) else {}, ) ) return normalized_tool_calls def serialize_prompt_messages(messages: Sequence[Message]) -> List[PromptMessage]: """将 LLM 消息列表序列化为 Hook 可传输载荷。 Args: messages: 原始 LLM 消息列表。 Returns: List[PromptMessage]: 序列化后的消息字典列表。 """ serialized_messages: List[PromptMessage] = [] for message in messages: serialized_message: PromptMessage = { "role": message.role.value, "content": message.content, } if message.tool_call_id: serialized_message["tool_call_id"] = message.tool_call_id if message.tool_calls: serialized_message["tool_calls"] = serialize_tool_calls(message.tool_calls) serialized_messages.append(serialized_message) return serialized_messages def deserialize_prompt_messages(raw_messages: Any) -> List[Message]: """从 Hook 载荷恢复 LLM 消息列表。 Args: raw_messages: Hook 返回的消息列表。 Returns: List[Message]: 恢复后的 LLM 消息列表。 Raises: ValueError: 结构不合法时抛出。 """ if not isinstance(raw_messages, list): raise ValueError("Hook 返回的 `messages` 必须是列表") from src.services.llm_service import _build_message_from_dict normalized_messages: List[Message] = [] for raw_message in raw_messages: if not isinstance(raw_message, dict): raise ValueError("Hook 返回的消息项必须是字典") normalized_messages.append(_build_message_from_dict(raw_message)) return normalized_messages def serialize_tool_definitions(tool_definitions: Sequence[ToolDefinitionInput]) -> List[Dict[str, Any]]: """将工具定义列表序列化为 Hook 可传输载荷。 Args: tool_definitions: 原始工具定义列表。 Returns: List[Dict[str, Any]]: 序列化后的工具定义列表。 """ normalized_tool_options = normalize_tool_options(list(tool_definitions)) if not normalized_tool_options: return [] return [tool_option.to_openai_function_schema() for tool_option in normalized_tool_options]