Skip to content

fix(proxy): Gemini function id 触发词兼容 JSON 转义引号并整段匹配路径,修复生产漏检 - #1322

Merged
ding113 merged 2 commits into
ding113:devfrom
wu452148993:fix/gemini-function-id-escaped-quotes
Jul 22, 2026
Merged

fix(proxy): Gemini function id 触发词兼容 JSON 转义引号并整段匹配路径,修复生产漏检#1322
ding113 merged 2 commits into
ding113:devfrom
wu452148993:fix/gemini-function-id-escaped-quotes

Conversation

@wu452148993

@wu452148993 wu452148993 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

问题

#1308 的 Gemini function id 整流器在生产环境(v0.8.10 + Vertex 直连)实测不触发:Vertex 400 依旧透传给客户端,重试发送的是原始未整流请求体,且无任何 rectifier 日志。

根因:tryApplyReactiveRectifier 收到的 errorMessage 来自 getDetailedErrorMessage(),其中上游 JSON body 被原样拼入

Provider Vertex AI - wulf returned 400: ... | Upstream: {
  "error": {
    "message": "Invalid JSON payload received. Unknown name \"id\" at 'contents[2].parts[0].function_call': Cannot find field.\n...",
    ...

message 字段内层引号处于 JSON 转义形态\"id\"),而触发词正则匹配的是裸引号 "id",因此永远检测不到。既有 thinking 系列整流器的触发词均不含引号,此形态差异此前未暴露过(smartTruncate 对 JSON body 走 JSON.stringify(parsed) 完整保留,转义形态是结构性保证)。

修复(两处)

  1. 转义兼容ID_VIOLATION_PATTERNid 两侧允许任意个反斜杠,兼容裸引号(解码后文本)与 \"/多重转义形态:
-const ID_VIOLATION_PATTERN = /unknown name "id" at\s+(?:'([^':\n]+)'|([^\s':\n]+))/g;
+const ID_VIOLATION_PATTERN = /unknown name \\*"id\\*" at\s+(?:'([^':\n]+)'|([^\s':\n]+))/g;
  1. 路径段精确匹配:函数字段判断由子串 includes 改为按 . 分段、剥数组下标后整段比对。避免 tool_config.function_calling_config / toolConfig.functionCallingConfig 等真实 Gemini 路径因含 function_call 子串被误判——误判 + 剥离无效(applied=false)会把错误强改为 NON_RETRYABLE_CLIENT_ERROR,压制正常供应商故障转移。

验证

  • 生产实测(修复 1 已以 hotpatch 形式在生产验证):直连 Vertex → 400 → Gemini function id rectifier applied, retrying → attempt 2 → 200,功能闭环
  • 单测 21/21 全过,含 3 例新增回归:生产 forwarder 详细错误消息原样形态| Upstream: {...} + \" 转义 + 字面量 \n 分隔多violations)、转义形态无关路径不触发、function_calling_config 两种命名不误判
  • 仍接受的路径形态:contents[2].parts[0].function_call、camelCase、网关追加 .id 后缀的变体
  • bun run typecheck 通过,biome 干净

🤖 Generated with Claude Code

Greptile Summary

This PR fixes two root causes that prevented the Gemini function-id rectifier from triggering in production (Vertex AI direct mode): the trigger regex failed to match JSON-escaped quotes (\"id\") that appear when the forwarder embeds the raw upstream JSON body in the error message, and path matching used substring .includes() which could false-positive on tool_config.function_calling_config and similar Gemini paths.

  • Fix 1 – Regex escape compatibility: ID_VIOLATION_PATTERN now uses \\*"id\\*" (zero-or-more literal backslashes on each side of the quote), covering bare "id" and every JSON-escaped depth.
  • Fix 2 – Exact segment matching: path checking switches from path.includes(...) to splitting on ., stripping trailing array indices, and looking up each segment in a FUNCTION_FIELD_SEGMENTS Set — preventing function_calling_config (which contains function_call as a substring) from being mistakenly treated as a function-field violation.
  • Test sync in response-handler-endpoint-circuit-isolation.test.ts: one existing test is updated to consume the Response returned by dispatch and to match renamed/re-signatured production helpers (clearSessionProvider, updateMessageRequestDetailsDurably).

Confidence Score: 5/5

Safe to merge — both changes are narrowly scoped to the trigger-detection function, have production-verified behavior, and are covered by 21 unit tests including three new regression cases.

Both changes are narrowly scoped to the trigger-detection function with no data mutations or new async paths. The regex change correctly uses \\* to match zero-or-more literal backslashes, and the segment-set replacement is strictly more precise than substring includes.

No files require special attention.

Important Files Changed

Filename Overview
src/app/v1/_lib/proxy/gemini-function-id-rectifier.ts Two targeted fixes: regex \\* quantifier to match JSON-escaped backslash-quote forms, and a Set-based exact-segment check replacing substring includes to prevent false positives on function_calling_config paths.
tests/unit/proxy/gemini-function-id-rectifier.test.ts Adds three regression tests: production forwarder error format with \" escaping and literal \n delimiters, JSON-escaped quote on an unrelated path (must not trigger), and function_calling_config/functionCallingConfig substring paths (must not trigger).
tests/unit/proxy/response-handler-endpoint-circuit-isolation.test.ts Syncs one test to match changed production API: dispatch now returns a Response that must be consumed before drainAsyncTasks; clearSessionProvider now takes a second numeric argument; updateMessageRequestDetails renamed to updateMessageRequestDetailsDurably with an extra options arg.

Reviews (3): Last reviewed commit: "test(proxy): consume Responses failure s..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

修改 Gemini 函数 ID 整流检测逻辑,支持转义形式的 id,并将函数字段路径判断改为按 . 分段精确匹配。新增相关单元测试,并调整响应处理器测试中的响应体消费和持久化断言。

Changes

Gemini 函数 ID 整流检测逻辑与测试

Layer / File(s) Summary
检测逻辑与匹配测试
src/app/v1/_lib/proxy/gemini-function-id-rectifier.ts, tests/unit/proxy/gemini-function-id-rectifier.test.ts
扩展转义 id 错误匹配,并使用去除数组索引后的路径段进行精确函数段匹配;测试覆盖相关正例及不相关路径、子串变体反例。

响应处理器测试断言

Layer / File(s) Summary
响应消费与持久化断言
tests/unit/proxy/response-handler-endpoint-circuit-isolation.test.ts
保存 dispatch 返回值并读取响应体,更新会话清理参数及带 onCommitted 回调的持久化更新断言。

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed 标题准确概括了对 Gemini function id 触发词兼容转义引号并改为整段路径匹配的核心修复。
Description check ✅ Passed 描述与变更内容一致,明确说明了生产问题、根因、两项修复和回归测试。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

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.

Code Review

This pull request updates the Gemini function ID rectifier to support JSON-escaped quotes in upstream error messages by modifying the ID_VIOLATION_PATTERN regex. It also improves path matching accuracy by checking for exact segments (using a predefined set of function field segments) instead of substring matching, preventing false positives on paths like tool_config.function_calling_config. Corresponding unit tests have been added to verify these changes. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@github-actions github-actions Bot added the size/XS Extra Small PR (< 50 lines) label Jul 7, 2026

@github-actions github-actions Bot left a comment

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.

Code Review Summary

This is a high-quality bug fix with surgical precision and comprehensive validation.

PR Size: XS

  • Lines changed: 60 (53 additions, 7 deletions)
  • Files changed: 2

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Review Summary

No significant issues identified. The fix correctly addresses the production bug with two precise changes:

  1. Regex escape tolerance: Pattern now matches "id" (JSON-escaped) and "id" (bare quotes) by allowing zero or more backslashes on each side (\\*"id\\*")
  2. Exact segment matching: Replaced substring includes() with split-by-dot + array-index-stripping + Set lookup, preventing false positives on legitimate Gemini paths like tool_config.function_calling_config

Validation Performed

Logic correctness: ✓

  • Regex pattern \\* correctly matches 0+ backslashes (handles all escape levels)
  • Segment extraction replace(/\[\d+\]$/, "") correctly strips array indices like [2]
  • Set-based exact matching prevents substring false positives
  • Lowercase normalization handles both snake_case and camelCase

Test coverage: ✓

  • 3 new regression tests cover production error format with escaped quotes
  • Tests verify both positive detection and false-positive prevention
  • Includes both function_calling_config variants (snake + camel)

Security: ✓

  • Negated character classes prevent regex DoS
  • No injection vectors introduced

Performance: ✓

  • Set lookup O(1), split/replace O(n) - appropriate for error path

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Comprehensive
  • Code clarity - Excellent

Automated review by Claude AI

生产验证发现(v0.8.10 + Vertex 直连实测):forwarder 的详细错误消息把
上游 JSON body 原样拼入(`| Upstream: {"error":{"message":"... Unknown
name \"id\" ..."}}`),message 字段内层引号处于 JSON 转义形态,裸引号
正则匹配不到 → 整流器从不触发,Vertex 400 依旧直达客户端。

两处修复:
- `id` 两侧允许任意个反斜杠(`\*"id\*"`),兼容转义/解码两种形态;
- 路径中的函数字段改为按路径段精确匹配(剥数组下标后整段比对),
  避免 `tool_config.function_calling_config` 等真实 Gemini 路径因含
  `function_call` 子串被误判,进而压制正常故障转移。

新增 3 例回归测试,其一取自生产 forwarder 详细错误消息原样形态。
修复后的正则已在生产实测:400 → rectifier applied → retry → 200。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ding113
ding113 force-pushed the fix/gemini-function-id-escaped-quotes branch from 4f46105 to 6701410 Compare July 22, 2026 19:59
@ding113
ding113 merged commit f21134b into ding113:dev Jul 22, 2026
9 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Error Rule area:Google Gemini bug Something isn't working size/XS Extra Small PR (< 50 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants