From 35ab0c06be16e3e70366c424056527306277b83b Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 15 Mar 2026 13:31:38 +0800 Subject: [PATCH 1/2] Fix CreateSkillPayloadTool array schema missing items field The payload parameter's anyOf array variant lacked an items field, causing Gemini API to reject the tool declaration with 400 Bad Request: 'parameters.properties[payload].any_of[1].items: missing field.' Add items: {type: object} to the array variant to satisfy the Gemini API requirement for array type schemas. Fixes #6279 --- astrbot/core/computer/tools/neo_skills.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/computer/tools/neo_skills.py b/astrbot/core/computer/tools/neo_skills.py index 492b6e45ed..7dbbb6df68 100644 --- a/astrbot/core/computer/tools/neo_skills.py +++ b/astrbot/core/computer/tools/neo_skills.py @@ -164,7 +164,7 @@ class CreateSkillPayloadTool(NeoSkillToolBase): "type": "object", "properties": { "payload": { - "anyOf": [{"type": "object"}, {"type": "array"}], + "anyOf": [{"type": "object"}, {"type": "array", "items": {"type": "object"}}], "description": ( "Skill payload JSON. Typical schema: {skill_markdown, inputs, outputs, meta}. " "This only stores content and returns payload_ref; it does not create a candidate or release." From d9b403ac45359655506df17f147796fe248e4088 Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 15 Mar 2026 13:38:57 +0800 Subject: [PATCH 2/2] Fix TypeError when OpenAI-compatible API returns null choices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some providers (e.g. OpenRouter) may return a completion where choices is None rather than an empty list — for instance on rate limiting, content filtering, or transient errors. The existing code used len(completion.choices) which throws TypeError on None. Replace all len(...choices) == 0 checks with 'not ... .choices' which handles both None and empty list. Affects _query_stream, _parse_openai_completion, and _extract_reasoning_content. Fixes #6252 --- astrbot/core/provider/sources/openai_source.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index c40234ed47..5b0e94e4b1 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -311,7 +311,7 @@ async def _query_stream( state.handle_chunk(chunk) except Exception as e: logger.warning("Saving chunk state error: " + str(e)) - if len(chunk.choices) == 0: + if not chunk.choices: continue delta = chunk.choices[0].delta # logger.debug(f"chunk delta: {delta}") @@ -345,7 +345,7 @@ def _extract_reasoning_content( ) -> str: """Extract reasoning content from OpenAI ChatCompletion if available.""" reasoning_text = "" - if len(completion.choices) == 0: + if not completion.choices: return reasoning_text if isinstance(completion, ChatCompletion): choice = completion.choices[0] @@ -468,7 +468,7 @@ async def _parse_openai_completion( """Parse OpenAI ChatCompletion into LLMResponse""" llm_response = LLMResponse("assistant") - if len(completion.choices) == 0: + if not completion.choices: raise Exception("API 返回的 completion 为空。") choice = completion.choices[0]