Skip to content

fix(chat): strip functionCall.id from Gemini requests#84

Open
yhny1001 wants to merge 1 commit into
Darkatse:devfrom
yhny1001:fix/gemini-function-call-id
Open

fix(chat): strip functionCall.id from Gemini requests#84
yhny1001 wants to merge 1 commit into
Darkatse:devfrom
yhny1001:fix/gemini-function-call-id

Conversation

@yhny1001

@yhny1001 yhny1001 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

背景 / 问题

通过 Gemini(makersuite / vertexai)跑带工具调用的 agent 时,第二轮回放会报:

Validation error: Invalid JSON payload received. Unknown name "id" at 'contents[N].parts[M].function_call'

导致工具调用循环(含子 agent)中断。

根因

  1. Gemini 响应里的 functionCallid(Gemini 3 尤甚)。归一化器读取该 id 用于匹配,同时把整段候选 content 原样存入 native.gemininormalizers.rs)。
  2. 下一轮 encode.rs::copy_native_continuationnative.gemini 原样塞回消息,makersuite.rs::message_native_gemini_parts 又原样取出当请求体 parts。
  3. Gemini 的 generateContent 请求端不接受 functionCall.id(只在响应里返回),于是被拒。

核心矛盾:Gemini 响应的 functionCall 带 id,但请求的 functionCall 不允许 id,而我们原样回放了。

修复

payload/makersuite.rs 构建每条消息发往 Gemini 的 parts 出口处,统一剥掉 functionCall.idstrip_function_call_ids)。一处出口覆盖原生回放、content 透传、工具调用三条路径,且 makersuite 与 vertexai 共用 convert_messages,两种来源都生效。

为什么安全

  • functionCall.id 本就只存在于响应、请求端不接受,删除是符合 Gemini 契约的。
  • id 仍保留在归一化的 tool_calls 里做内部记账。
  • Gemini 的 functionResponsename 配对,不靠 id,故工具调用/结果配对不受影响。

改动符合的约定

  • 分层:只在请求构建器(application 层 payload 出口)做 Gemini 请求格式清洗,不改归一化存储,依赖方向不变。
  • 最小改动:单文件、纯新增,无无关重构。
  • 测试就近:新增回归测试 makersuite_strips_function_call_id_from_replayed_native_parts,模拟带 id 的原生 Gemini functionCall 回放,断言请求里 id 被剥、name 保留。

Test plan

  • cd src-tauri && cargo test --lib makersuite
  • 实机:用 Gemini 模型跑一次含工具调用的多轮 agent,确认不再报 Unknown name "id" ... function_call

Made with Cursor

Gemini responses return a `functionCall.id`, which we persist verbatim in
`native.gemini` and echo back on the next tool-call turn. The Gemini
`generateContent` request API rejects that field ("Unknown name \"id\" at
'contents[N].parts[M].function_call'"), breaking agent tool-call loops.

Strip the response-only `id` from every `functionCall` part at the request
build boundary (covers native replay, content passthrough, and tool calls;
applies to both makersuite and vertexai). The id stays in the normalized
`tool_calls`, and Gemini pairs `functionResponse` by name, so pairing is
unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Darkatse

Darkatse commented Jun 5, 2026

Copy link
Copy Markdown
Owner
image image

我在使用Google AI Studio的时候好像没遇到这个问题诶,能否进一步缩小下范围?

@yhny1001

yhny1001 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

openai接口用gemini时,三方聚合公益站

@Darkatse

Darkatse commented Jun 5, 2026

Copy link
Copy Markdown
Owner

看Gemini官方文档是需要回传id的,是第三方的问题吗
https://ai.google.dev/gemini-api/docs/function-calling?hl=zh-cn&example=meeting#how-it-works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants