Skip to content
Merged
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
15 changes: 15 additions & 0 deletions astrbot/core/provider/sources/openai_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,9 @@ async def _prepare_chat_payload(

def _finally_convert_payload(self, payloads: dict) -> None:
"""Finally convert the payload. Such as think part conversion, tool inject."""
model = payloads.get("model", "").lower()
is_gemini = "gemini" in model

for message in payloads.get("messages", []):
if message.get("role") == "assistant" and isinstance(
message.get("content"), list
Expand All @@ -855,6 +858,18 @@ def _finally_convert_payload(self, payloads: dict) -> None:
if reasoning_content:
message["reasoning_content"] = reasoning_content

# Gemini 的 function_response 要求 google.protobuf.Struct(即 JSON 对象),
# 纯文本会触发 400 Invalid argument,需要包一层 JSON。
if is_gemini and message.get("role") == "tool":
content = message.get("content", "")
if isinstance(content, str):
try:
json.loads(content)
except (json.JSONDecodeError, ValueError):
message["content"] = json.dumps(
{"result": content}, ensure_ascii=False
)
Comment on lines +866 to +871
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Gemini 的 function_response 明确要求是一个 JSON 对象(对应 google.protobuf.Struct)。虽然 json.loads() 可以验证字符串是否为合法的 JSON,但它不能保证解析后是一个对象。例如,如果工具返回的是纯数字 123 或 JSON 字符串 "success"json.loads() 会成功解析,但如果代理层没有自动包装,可能仍然会导致 400 错误。建议检查解析后的结果是否为字典类型。

Suggested change
try:
json.loads(content)
except (json.JSONDecodeError, ValueError):
message["content"] = json.dumps(
{"result": content}, ensure_ascii=False
)
try:
if not isinstance(json.loads(content), dict):
raise ValueError()
except (json.JSONDecodeError, ValueError):
message["content"] = json.dumps(
{"result": content}, ensure_ascii=False
)


async def _handle_api_error(
self,
e: Exception,
Expand Down
Loading