Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions astrbot/core/agent/runners/tool_loop_agent_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,10 @@ async def _complete_with_assistant_response(self, llm_resp: LLMResponse) -> None
if llm_resp.completion_text:
parts.append(TextPart(text=llm_resp.completion_text))
if len(parts) == 0:
logger.warning("LLM returned empty assistant message with no tool calls.")
self.run_context.messages.append(Message(role="assistant", content=parts))
logger.warning("LLM returned empty assistant message with no tool calls. Skipping message.")
# 不添加空消息到上下文,避免严格 API(如 DeepSeek R1)返回 400 错误
else:
self.run_context.messages.append(Message(role="assistant", content=parts))

try:
await self.agent_hooks.on_agent_done(self.run_context, llm_resp)
Expand Down
51 changes: 37 additions & 14 deletions astrbot/core/provider/sources/openai_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ async def _fallback_to_text_only_and_retry(
image_fallback_used,
)

def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient:
def _create_http_client(self, provider_config: dict) -> httpx.AsyncClient | None:
"""创建带代理的 HTTP 客户端"""
proxy = provider_config.get("proxy", "")
return create_proxy_client("OpenAI", proxy)
Expand Down Expand Up @@ -546,23 +546,23 @@ async def _query(self, payloads: dict, tools: ToolSet | None) -> LLMResponse:
extra_body.update(custom_extra_body)
self._apply_provider_specific_extra_body_overrides(extra_body)

model = payloads.get("model", "").lower()

# 在调用 self.client.chat.completions.create 之前添加清理逻辑
if "messages" in payloads and isinstance(payloads["messages"], list):
cleaned_messages = []
for idx, msg in enumerate(payloads["messages"]):
# 过滤空的 assistant 消息,防止严格 API(如 Moonshot)返回 400 错误
if msg.get("role") == "assistant":
content = msg.get("content")
tool_calls = msg.get("tool_calls")

# 情况1: 空/null content 且无 tool_calls -> 过滤掉
if not tool_calls and (content == "" or content is None):
logger.warning(f"过滤第 {idx} 条空 assistant 消息 (无工具调用)")
# 空内容:空字符串、None 或空列表
empty_content = content in ("", None, [])
if not tool_calls and empty_content:
# 无 tool_calls 且内容为空 -> 过滤掉,避免 400 错误
logger.debug(f"过滤第 {idx} 条空 assistant 消息 (无工具调用)")
continue

# 情况2: 空 content 但有 tool_calls -> 设为 None (符合 OpenAI 规范)
if content == "" and tool_calls:
# 有 tool_calls 但 content 为空 -> 设为 None(API 可接受)
if empty_content and tool_calls:
msg["content"] = None

cleaned_messages.append(msg)
Expand Down Expand Up @@ -605,20 +605,43 @@ async def _query_stream(
# 不在默认参数中的参数放在 extra_body 中
extra_body = {}

# 读取并合并 custom_extra_body 配置
custom_extra_body = self.provider_config.get("custom_extra_body", {})
if isinstance(custom_extra_body, dict):
extra_body.update(custom_extra_body)

to_del = []
for key in payloads:
if key not in self.default_params:
extra_body[key] = payloads[key]
to_del.append(key)
for key in to_del:
del payloads[key]

# 读取并合并 custom_extra_body 配置(custom 优先级高于 payload 中的扩展参数)
custom_extra_body = self.provider_config.get("custom_extra_body", {})
if isinstance(custom_extra_body, dict):
extra_body.update(custom_extra_body)
self._apply_provider_specific_extra_body_overrides(extra_body)

# 在调用 self.client.chat.completions.create 之前添加清理逻辑(与非流式 _query 方法保持一致)
if "messages" in payloads and isinstance(payloads["messages"], list):
cleaned_messages = []
for idx, msg in enumerate(payloads["messages"]):
if msg.get("role") == "assistant":
content = msg.get("content")
tool_calls = msg.get("tool_calls")

# 空内容:空字符串、None 或空列表
empty_content = content in ("", None, [])
if not tool_calls and empty_content:
# 无 tool_calls 且内容为空 -> 过滤掉,避免 400 错误
logger.debug(f"过滤第 {idx} 条空 assistant 消息 (无工具调用)")
continue

# 有 tool_calls 但 content 为空 -> 设为 None(API 可接受)
if empty_content and tool_calls:
msg["content"] = None

cleaned_messages.append(msg)

payloads["messages"] = cleaned_messages

stream = await self.client.chat.completions.create(
**payloads,
stream=True,
Expand Down
Loading