Skip to content

fix: provide fallback items for Gemini array params#6150

Closed
tsubasakong wants to merge 1 commit intoAstrBotDevs:masterfrom
tsubasakong:fix/6029-gemini-array-items
Closed

fix: provide fallback items for Gemini array params#6150
tsubasakong wants to merge 1 commit intoAstrBotDevs:masterfrom
tsubasakong:fix/6029-gemini-array-items

Conversation

@tsubasakong
Copy link
Copy Markdown
Contributor

@tsubasakong tsubasakong commented Mar 12, 2026

Fixes #6029.

Modifications / 改动点

  • add a Gemini schema compatibility fallback so array parameters without an explicit items schema still serialize with items: {"type": "string"} instead of failing the whole request

  • preserve explicit array item schemas when they are already present

  • add focused unit coverage for both the fallback path and the explicit-items path

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

  • python3.11 -m ruff format astrbot/core/agent/tool.py tests/unit/test_tool_google_schema.py
  • python3.11 -m ruff check astrbot/core/agent/tool.py tests/unit/test_tool_google_schema.py
  • python3.11 -m pytest tests/unit/test_tool_google_schema.py -q
  • git diff --check

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

确保当数组参数省略 items 定义时,Gemini 工具的模式依然保持有效。

Bug Fixes:

  • 为缺少显式 items 定义的 Gemini 数组参数提供默认的字符串类型元素模式,避免请求失败。

Tests:

  • 添加单元测试,用于验证在数组缺少 items 时会应用默认元素模式,以及在存在显式数组元素模式时能够被正确保留。
Original summary in English

Summary by Sourcery

Ensure Gemini tool schemas remain valid when array parameters omit item definitions.

Bug Fixes:

  • Provide a default string item schema for Gemini array parameters that lack explicit items to avoid request failures.

Tests:

  • Add unit tests verifying default item schemas for arrays without items and preservation of explicit array item schemas.

@auto-assign auto-assign Bot requested review from Raven95676 and Soulter March 12, 2026 17:55
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Mar 12, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the convert_schema function to improve compatibility with the Gemini API. It addresses an issue where array parameters without an explicit items definition could cause API requests to fail. By introducing a default {"type": "string"} for such cases, the system becomes more robust, ensuring that tool calling remains functional while respecting any existing explicit schema definitions.

Highlights

  • Gemini Schema Compatibility: Implemented a fallback mechanism for Gemini array parameters. If an array parameter lacks an explicit items schema, it will now default to {"type": "string"} to prevent request failures.
  • Preservation of Explicit Schemas: Ensured that any explicitly defined items schemas for array parameters are preserved and not overwritten by the new fallback logic.
  • Unit Test Coverage: Added new unit tests to specifically cover both the fallback path for missing items and the preservation of explicit items schemas in Gemini tool declarations.
Changelog
  • astrbot/core/agent/tool.py
    • Modified the convert_schema function to include a compatibility fallback for Gemini array parameters, ensuring items: {"type": "string"} is added if items is missing.
    • Adjusted the logic to explicitly check for target_type == "array" before applying the items fallback or conversion.
  • tests/unit/test_tool_google_schema.py
    • Added a new test case test_google_schema_adds_default_items_for_array_parameters_without_items to verify the fallback behavior for array parameters.
    • Added a new test case test_google_schema_preserves_explicit_array_item_schema to confirm that existing explicit items schemas are correctly maintained.
Activity
  • The author executed ruff format and ruff check on the modified files to ensure code style and quality.
  • Unit tests for the new schema conversion logic were run using pytest.
  • A git diff --check was performed to verify the integrity of the changes.
  • The author confirmed that the changes are not breaking, have been well-tested, introduce no new dependencies, and contain no malicious code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - 我在这里给出了一些整体性的反馈:

  • 新增的 target_type == "array" 分支会把任何非字典或“假值”(falsy)的 items 都当成缺失处理,并且静默地用 { "type": "string" } 替换;建议只在完全不存在 "items" 字段时才应用这个回退逻辑,或者至少对非字典类型的 items 保持原样传递,这样更复杂的 JSON Schema 结构(例如 tuple 校验)就不会被意外覆盖。
  • 鉴于这段逻辑是 Gemini 特有的,或许可以把这个回退行为抽离到一个命名清晰的 helper 或某个后端专用的路径中,而不是直接写进通用的 convert_schema 函数里,这样未来再做后端特定的调整时会更容易理解和维护。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- The new `target_type == "array"` branch treats any non-dict or falsy `items` value as missing and silently replaces it with `{ "type": "string" }`; consider only applying the fallback when `"items"` is absent entirely, or at least passing through non-dict `items` unchanged so more complex JSON Schema constructs (e.g. tuple validation) aren't unexpectedly overridden.
- Given this logic is Gemini-specific, it may be worth isolating the fallback into a clearly named helper or backend-specific path rather than embedding Gemini behavior directly into the generic `convert_schema` function, to keep future backend-specific tweaks easier to reason about.

Sourcery 对开源项目是免费的——如果你觉得这些评审有帮助,欢迎分享给更多人 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈持续改进评审质量。
Original comment in English

Hey - I've left some high level feedback:

  • The new target_type == "array" branch treats any non-dict or falsy items value as missing and silently replaces it with { "type": "string" }; consider only applying the fallback when "items" is absent entirely, or at least passing through non-dict items unchanged so more complex JSON Schema constructs (e.g. tuple validation) aren't unexpectedly overridden.
  • Given this logic is Gemini-specific, it may be worth isolating the fallback into a clearly named helper or backend-specific path rather than embedding Gemini behavior directly into the generic convert_schema function, to keep future backend-specific tweaks easier to reason about.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `target_type == "array"` branch treats any non-dict or falsy `items` value as missing and silently replaces it with `{ "type": "string" }`; consider only applying the fallback when `"items"` is absent entirely, or at least passing through non-dict `items` unchanged so more complex JSON Schema constructs (e.g. tuple validation) aren't unexpectedly overridden.
- Given this logic is Gemini-specific, it may be worth isolating the fallback into a clearly named helper or backend-specific path rather than embedding Gemini behavior directly into the generic `convert_schema` function, to keep future backend-specific tweaks easier to reason about.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot dosubot Bot added the area:core The bug / feature is about astrbot's core, backend label Mar 12, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request addresses an issue with serializing array parameters for Gemini tools. When an array parameter in a JSON schema omits the items property, Gemini's API rejects the request. The change introduces a fallback, defaulting to items: {"type": "string"} for such cases, ensuring the request doesn't fail. The change also correctly preserves existing items definitions. The fix is well-tested with new unit tests covering both the fallback and the explicit-items scenarios. The implementation is correct and the added tests are well-focused. I've suggested a minor refactoring to improve code readability.

Comment on lines +302 to +305
if isinstance(schema.get("items"), dict) and schema["items"]:
result["items"] = convert_schema(schema["items"])
else:
result["items"] = {"type": "string"}
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

For better readability and to avoid multiple calls to schema.get("items"), it's good practice to store the result of schema.get("items") in a local variable. This also makes the subsequent logic clearer.

Suggested change
if isinstance(schema.get("items"), dict) and schema["items"]:
result["items"] = convert_schema(schema["items"])
else:
result["items"] = {"type": "string"}
items = schema.get("items")
if isinstance(items, dict) and items:
result["items"] = convert_schema(items)
else:
result["items"] = {"type": "string"}

@dosubot
Copy link
Copy Markdown

dosubot Bot commented Mar 12, 2026

Related Documentation

1 document(s) may need updating based on files changed in this PR:

AstrBotTeam's Space

pr4697的改动
View Suggested Changes
@@ -468,11 +468,58 @@
   - `on_task_canceled`:任务被取消时触发
   - `on_task_result_ignored`:任务结果被忽略时触发(如状态已变化)
 
+#### Gemini 工具架构兼容性(PR #6150)
+
+[PR #6150](https://github.com/AstrBotDevs/AstrBot/pull/6150) 修复了工具架构转换系统在 Gemini API 下的兼容性问题,确保外部工具(如 MCP 工具)生成的不完整 JSON Schema 定义不会导致请求失败。
+
+**问题背景**
+
+Gemini API 严格要求数组类型参数必须包含 `items` 字段定义数组元素类型,否则会拒绝请求并返回 `items: missing field` 错误。然而,外部工具(特别是 MCP 工具)生成的 JSON Schema 定义有时会省略 `items` 字段,导致工具调用失败。
+
+**技术实现**
+
+工具架构转换系统(`FunctionTool.convert_schema()`)新增 Gemini 兼容性回退机制:
+
+1. **自动回退策略**:
+   - 当数组类型参数缺少 `items` 字段时,系统自动提供回退架构:`{"type": "string"}`
+   - 确保工具调用请求能够正常发送到 Gemini API,而非因架构不完整而失败
+
+2. **显式架构保留**:
+   - 如果数组参数已明确提供 `items` 架构,系统会完整保留原始定义
+   - 递归转换嵌套的 `items` 架构,确保复杂类型正确映射
+
+**技术细节**
+
+修复前,架构转换逻辑仅在 `schema` 中存在 `items` 字段时才处理,导致缺少 `items` 的数组参数被忽略。修复后,逻辑调整为:
+
+```python
+if target_type == "array":
+    if isinstance(schema.get("items"), dict) and schema["items"]:
+        result["items"] = convert_schema(schema["items"])
+    else:
+        result["items"] = {"type": "string"}
+```
+
+该修复确保所有数组类型参数在转换为 Gemini 架构时都包含有效的 `items` 定义。
+
+**影响范围**
+
+- **外部工具集成**:提升与 MCP 工具等外部工具源的兼容性,防止架构不完整导致的工具调用失败
+- **Gemini API 兼容性**:确保所有工具架构符合 Gemini API 规范,避免 `items: missing field` 错误
+- **架构正确性**:显式定义的数组元素类型得到完整保留,不影响已有的正确架构
+
+**用户收益**
+
+- 外部工具(如 MCP 工具)在 Gemini 模型下可正常使用,无需手动修复架构定义
+- 工具调用稳定性提升,减少因架构不完整导致的请求失败
+- 开发者无需关注外部工具架构的完整性,系统自动提供兼容性保障
+
 #### 注意事项
 - 工具需在对应 SubAgent/Persona 配置中声明
 - 动态注册工具时需确保配置同步更新
 - 后台任务需正确设置 `background_task: true` 参数
 - 后台任务执行通过 `HandoffExecutor.execute_queued_task()` 方法完成,该方法从数据库中恢复任务上下文并执行
+- 外部工具(如 MCP 工具)生成的数组参数架构会自动获得回退 `items` 定义(`{"type": "string"}`),确保 Gemini API 兼容性
 
 #### Neo 技能生命周期工具(PR #5028)
 

[Accept] [Decline]

Note: You must be authenticated to accept/decline updates.

How did I do? Any feedback?  Join Discord

@Soulter
Copy link
Copy Markdown
Member

Soulter commented Mar 21, 2026

already fixed in #6051, thanks!

@Soulter Soulter closed this Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] [Gemini] 客户端构造请求时的 schema错误,导致LLM调用全部失败

2 participants