Files
AstrBot/src-new/astrbot_sdk/api/provider/entities.py
whatevertogo cdf72b75a4 feat: 实现 v4 API 兼容层,支持旧版插件导入路径
新增模块:
- api/basic/: AstrBotConfig, BaseConversationManager, Conversation
- api/event/: AstrMessageEvent, AstrBotMessage, EventType, MessageType,
  MessageSession, EventResult 等核心事件类型
- api/message/: MessageChain 及所有消息组件 (Plain, At, Image, File 等)
- api/platform/: PlatformMetadata 平台元数据类型
- api/provider/: LLMResponse 提供者响应实体
- api/star/star.py: StarMetadata 插件元数据类型

更新模块:
- api/__init__.py: 导出所有子模块
- api/components/: 扩展 Command 兼容性
- api/event/filter.py: 增强 filter 装饰器兼容性
- context.py, decorators.py, events.py: 顶层兼容入口

测试更新:
- test_api_event_filter.py: 验证 filter 兼容性
- test_api_modules.py: 验证新模块可导入
- test_handler_dispatcher.py: 验证处理器分发

文档更新:
- AGENTS.md/CLAUDE.md: 添加兼容层设计说明,避免重复造轮子

设计原则:
- 兼容层通过 thin re-export 方式暴露旧版 API
- 不复制独立运行时逻辑,保持架构清晰
- 新版推荐使用顶层模块导入路径
2026-03-13 03:17:03 +08:00

111 lines
3.3 KiB
Python

"""旧版 Provider 实体兼容类型。"""
from __future__ import annotations
import json
from dataclasses import dataclass
from typing import Any
from ..message import components as Comp
from ..message.chain import MessageChain
try:
from astr_agent_sdk.message import ToolCall as _ToolCall
except ImportError:
@dataclass(slots=True)
class _ToolCallFunctionBody:
name: str
arguments: str
@dataclass(slots=True)
class _ToolCall:
id: str
function: _ToolCallFunctionBody
FunctionBody = _ToolCallFunctionBody
@dataclass(init=False)
class LLMResponse:
"""兼容旧版 LLM 响应对象。"""
role: str
result_chain: MessageChain | None
tools_call_args: list[dict[str, Any]]
tools_call_name: list[str]
tools_call_ids: list[str]
raw_completion: Any | None
_new_record: dict[str, Any] | None
_completion_text: str
is_chunk: bool
def __init__(
self,
role: str,
completion_text: str = "",
result_chain: MessageChain | None = None,
tools_call_args: list[dict[str, Any]] | None = None,
tools_call_name: list[str] | None = None,
tools_call_ids: list[str] | None = None,
raw_completion: Any | None = None,
_new_record: dict[str, Any] | None = None,
is_chunk: bool = False,
) -> None:
self.role = role
self.result_chain = result_chain
self.tools_call_args = list(tools_call_args or [])
self.tools_call_name = list(tools_call_name or [])
self.tools_call_ids = list(tools_call_ids or [])
self.raw_completion = raw_completion
self._new_record = _new_record
self._completion_text = completion_text
self.is_chunk = is_chunk
@property
def completion_text(self) -> str:
if self.result_chain:
return self.result_chain.get_plain_text()
return self._completion_text
@completion_text.setter
def completion_text(self, value: str) -> None:
if self.result_chain:
self.result_chain.chain = [
component
for component in self.result_chain.chain
if not isinstance(component, Comp.Plain)
]
self.result_chain.chain.insert(0, Comp.Plain(text=value))
return
self._completion_text = value
def to_openai_tool_calls(self) -> list[dict[str, Any]]:
ret: list[dict[str, Any]] = []
for idx, tool_call_arg in enumerate(self.tools_call_args):
ret.append(
{
"id": self.tools_call_ids[idx],
"function": {
"name": self.tools_call_name[idx],
"arguments": json.dumps(tool_call_arg),
},
"type": "function",
}
)
return ret
def to_openai_to_calls_model(self) -> list[_ToolCall]:
ret: list[_ToolCall] = []
for idx, tool_call_arg in enumerate(self.tools_call_args):
ret.append(
_ToolCall(
id=self.tools_call_ids[idx],
function=_ToolCall.FunctionBody(
name=self.tools_call_name[idx],
arguments=json.dumps(tool_call_arg),
),
)
)
return ret