[GH-ISSUE #39] fix: 已修复gemini-3.1系列不可用问题:"Gemini 3.1 Pro is not available on this version. Please upgrade to the latest version." #36

Closed
opened 2026-02-27 15:38:02 +03:00 by kerem · 3 comments
Owner

Originally created by @JinchengGao-Infty on GitHub (Feb 20, 2026).
Original GitHub issue: https://github.com/NikkeTryHard/zerogravity/issues/39

What happened?

问题

Headless 模式下,LS 生成的 User-Agent 为 antigravity/ darwin/arm64(版本号为空)。
Google 通过 User-Agent 中的版本号来控制新模型(如 Gemini 3.1 Pro)的访问权限。
版本号为空时,Google 在 SSE 响应中直接返回:
"Gemini 3.1 Pro is not available on this version. Please upgrade to the latest version."
(HTTP 200,非错误码,是模型的回复文本)
我认为该问题影响所有平台,因为 LS 在 headless 模式下无法从父进程获取版本号。

定位过程

  1. 通过 MITM 抓取请求 header,发现 User-Agent: antigravity/ darwin/arm64 版本号为空
  2. 对比 Antigravity 正常请求,确认 JSON body 结构完全一致,差异仅在 User-Agent
  3. 在 LS binary 中搜索 "not available on this version" 字符串未找到,确认是 Google 服务端返回
  4. 修补 User-Agent 后,3.1 Pro 正常返回流式响应

修复

在 MITM 代理转发请求前,对 User-Agent header 做字节级替换:
antigravity/ antigravity/<检测到的版本号>
版本号从已安装的 Antigravity 应用自动检测。替换在 body 处理之前执行,避免破坏 chunked encoding。

验证

  • Gemini 3.1 Pro (High/Low) 正常返回流式响应,包含 thinking 和 content
  • Gemini 3 Flash、Claude Sonnet 4.6、Claude Opus 4.6 无回归

这个修改是根据作者大大初期开源的代码进行的修改,我没有将代码泄漏给任何人,我请求成为contributor,我的主要平台是macOS,主要使用的vibe coding为:openclaw,opencode,方便在Mac做适配,

How to reproduce

curl -s --max-time 60 -X POST http://127.0.0.1:8741/v1/chat/completions
-H "Content-Type: application/json"
-d '{"model":"gemini-3.1-pro-low","messages":[{"role":"user","content":"请介绍一下MLP(多层感知机)"}],"stream":false}'

正常返回:Gemini 3.1 Pro is not available on this version. Please upgrade to the latest version.

修复后:{"choices":[{"finish_reason":"stop","index":0,"logprobs":null,"message":{"content":"多层感知机(Multi-Layer Perceptron,简称 MLP)是深度学习和人工神经网络中最基础、最经典的架构之一。它属于前馈人工神经网络(Feedforward Neural Network),意味着信息在其中只能单向流动,从输入直接指向输出,没有循环或反馈。\n\n以下是关于 MLP 的详细介绍:\n\n### 1. 基本结构\n一个标准的 MLP 由多个由节点(神经元)组成的层(Layer)构成,至少包含三层:\n* 输入层(Input Layer):接收原始外部数据。这里的节点数通常与输入数据的特征数量相同。\n* 隐藏层(Hidden Layer):位于输入层和输出层之间,可以是一层或多层。这些层之所以被称为“隐藏层”,是因为它们不对外部直接可见。MLP 强大的拟合能力主要来源于隐藏层。\n* 输出层(Output Layer):网络的最后一层,负责输出最终的预测结果(例如分类的类别概率、回归的数值)。\n\n全连接(Fully Connected)特性:在 MLP 中,任意一层中的每个神经元都与上一层的所有神经元相连,并且也与下一层的所有神经元相连,这就构成了全连接网络(Dense Network)。\n\n### 2. 核心数学概念\n每个神经元的计算都可以分为两步:线性变换和非线性激活。\n\n1. 线性变换(加权求和):\n 每个神经元接收来自上一层的输入信号 $x_i$,每个输入连接都有一个对应的权重(Weight,$w_i$)。神经元会将所有输入信号与其权重相乘后求和,再加上一个偏置项(Bias,$b$):\n $$z = \sum (w_i \cdot x_i) + b$$\n * 权重决定了某个输入特征对当前神经元的影响程度。\n * 偏置相当于一个阈值,决定了神经元在没有输入时是否会被激活。\n\n2. 非线性激活函数(Activation Function):\n 如果仅仅进行加权求和,无论叠接度少层,MLP 的数学本质仍是一个简单的线性回归模型,无法处理复杂的现实问题。因此,我们需要将加权求和的结果 z 输入到一个非线性的激活函数 f(z) 中,从而为网络引入非线性特征。\n * 常见的激活函数有:ReLU(最常用)、SigmoidTanh 等。\n\n### 3. 工作与训练原理\nMLP 的训练过程本质上是一个让网络自己“学习”最合适的权重和偏置的过程,主要分为两个阶段:\n\n* 前向传播(Forward Propagation):\n 输入数据从输入层进入,经过每一层隐藏层的计算(加权求和 + 激活函数),一层层向后传递,最终在输出层生成一个预测结果。\n* 计算损失(Loss):\n 将网络的预测结果与真实的标签(Ground Truth)进行对比,使用损失函数(Loss Function)(如均方误差 MSE、交叉熵等)计算出误差有多大。\n* 反向传播(Backpropagation):\n 这是 MLP 训练的核心算法。系统通过微积分中的链式法则,从输出层算起,逆推计算出误差相对于每一个权重和偏置的梯度(即改变这个参数会让误差变大还是变小)。\n* 参数更新(优化,Optimization):\n 使用梯度下降法(Gradient Descent)或其优化形式(如 Adam、SGD),根据反向传播求出的梯度,稍微调整网络中所有的权重和偏置,以期望在下一次前向传播时,误差能够减小。\n\n经过成千上万次的循环迭代,网络的预测结果会越来越接近真实值,此时我们就可以说模型“收敛”或训练完成了。\n\n### 4. MLP 的优缺点\n\n优点:\n* 通用逼近定理:理论上,只要隐藏层的神经元足够多,一个包含哪怕只有一个隐藏层的 MLP 就可以拟合任何复杂的连续函数。\n* 应用广泛:可以直观地处理分类和回归问题。\n* 基础性:理解 MLP 是学习更复杂的网络(如 CNN卷积神经网络, RNN循环神经网络, Transformer大模型架构)必不可少的前置基石。\n\n缺点:\n* 参数量庞大:由于是“全连接”,如果输入图像等高维数据,参数量会呈指数级爆炸,非常容易导致内存耗尽并且发生过拟合(Overfitting)。\n* 忽略空间与时序信息:MLP 会将输入展平为一维向量,这破坏了图像的 2D 空间结构,也忽略了文本或时间序列前后的因果关系。(CNN 解决了图像空间问题,RNN/Transformer 解决了序列问题)。\n\n### 5. 常见应用场景\n现在的先进系统中,纯粹由多层 MLP 组成的独立模型已经较为少见,但它常常作为复杂网络结构的末端/局部组件出现:\n* 表格数据处理:在结构化数据(如 Excel 表格、CSV)的预测中,MLP 表现依然很好。\n* 深度学习网络的“分类头”:在 CNN(用于图像)或 Transformer(用于自然语言处理)提取出数据的深层特征后,通常会在网络的最末端接上几层 MLP(通常被称为全连接层 FC Layer),用来将特征映射到最终的分类概率上。","reasoning_content":"Analyzing Current Information\n\nI've been examining the available data to identify the most relevant pieces. My focus is on synthesizing this information to form a coherent understanding of the situation. I am currently working to evaluate the applicability of each of the data to the current circumstances.\n\n\nDefining MLP Fundamentals\n\nI'm now formulating a comprehensive introduction to Multi-Layer Perceptrons. I intend to detail its architecture, explain the operational mechanisms, and then cover activation functions used in training. I will conclude with a breakdown of its training, including both forward and backward propagation. I'm focusing on clarity and completeness for this fundamental concept.\n\n\n","role":"assistant"}}],"created":1771598804,"id":"chatcmpl-4944db97dfb54076b30b7feb1b3e1f89","model":"gemini-3.1-pro-low","object":"chat.completion","service_tier":"default","system_fingerprint":"fp_101","usage":{"completion_tokens":1226,"completion_tokens_details":{"reasoning_tokens":487},"prompt_tokens":5083,"prompt_tokens_details":{"cached_tokens":0},"total_tokens":6309}}%

Diagnostic Report

这没有意义:因为这是我的Claude按照作者大大的release高仿的,怎么样,还可以吧?


link@LinkdeMac-mini zerogravity % /Users/link/Desktop/zerogravity-dev/target/release/zg report
zg — ZeroGravity daemon manager

  Setup:
    init            First-run setup (extract token, configure)
    token           Extract OAuth token from Antigravity state.vscdb

  Service:
    start           Start the proxy daemon
    stop            Stop the proxy daemon
    restart         Rebuild + restart
    rebuild         Build release binary only
    status          Version, endpoints, quota, usage
    logs [N]        Show last N lines (default 30)
    logs-follow [N] Tail last N lines + follow
    logs-all        Full log dump
    test [msg]      Quick test request (gemini-3-flash)
    health          Health check

Additional Context

No response

Originally created by @JinchengGao-Infty on GitHub (Feb 20, 2026). Original GitHub issue: https://github.com/NikkeTryHard/zerogravity/issues/39 ### What happened? ## 问题 Headless 模式下,LS 生成的 User-Agent 为 `antigravity/ darwin/arm64`(版本号为空)。 Google 通过 User-Agent 中的版本号来控制新模型(如 Gemini 3.1 Pro)的访问权限。 版本号为空时,Google 在 SSE 响应中直接返回: "Gemini 3.1 Pro is not available on this version. Please upgrade to the latest version." (HTTP 200,非错误码,是模型的回复文本) 我认为该问题影响所有平台,因为 LS 在 headless 模式下无法从父进程获取版本号。 ## 定位过程 1. 通过 MITM 抓取请求 header,发现 `User-Agent: antigravity/ darwin/arm64` 版本号为空 2. 对比 Antigravity 正常请求,确认 JSON body 结构完全一致,差异仅在 User-Agent 3. 在 LS binary 中搜索 "not available on this version" 字符串未找到,确认是 Google 服务端返回 4. 修补 User-Agent 后,3.1 Pro 正常返回流式响应 ## 修复 在 MITM 代理转发请求前,对 User-Agent header 做字节级替换: `antigravity/ ` → `antigravity/<检测到的版本号> ` 版本号从已安装的 Antigravity 应用自动检测。替换在 body 处理之前执行,避免破坏 chunked encoding。 ## 验证 - Gemini 3.1 Pro (High/Low) 正常返回流式响应,包含 thinking 和 content - Gemini 3 Flash、Claude Sonnet 4.6、Claude Opus 4.6 无回归 **这个修改是根据作者大大初期开源的代码进行的修改,我没有将代码泄漏给任何人,我请求成为contributor,我的主要平台是macOS,主要使用的vibe coding为:openclaw,opencode,方便在Mac做适配,** ### How to reproduce curl -s --max-time 60 -X POST http://127.0.0.1:8741/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"gemini-3.1-pro-low","messages":[{"role":"user","content":"请介绍一下MLP(多层感知机)"}],"stream":false}' 正常返回:Gemini 3.1 Pro is not available on this version. Please upgrade to the latest version. 修复后:{"choices":[{"finish_reason":"stop","index":0,"logprobs":null,"message":{"content":"多层感知机(Multi-Layer Perceptron,简称 **MLP**)是深度学习和人工神经网络中最基础、最经典的架构之一。它属于**前馈人工神经网络**(Feedforward Neural Network),意味着信息在其中只能单向流动,从输入直接指向输出,没有循环或反馈。\n\n以下是关于 MLP 的详细介绍:\n\n### 1. 基本结构\n一个标准的 MLP 由多个由节点(神经元)组成的层(Layer)构成,至少包含三层:\n* **输入层(Input Layer)**:接收原始外部数据。这里的节点数通常与输入数据的特征数量相同。\n* **隐藏层(Hidden Layer)**:位于输入层和输出层之间,可以是一层或多层。这些层之所以被称为“隐藏层”,是因为它们不对外部直接可见。MLP 强大的拟合能力主要来源于隐藏层。\n* **输出层(Output Layer)**:网络的最后一层,负责输出最终的预测结果(例如分类的类别概率、回归的数值)。\n\n**全连接(Fully Connected)特性**:在 MLP 中,任意一层中的每个神经元都与上一层的所有神经元相连,并且也与下一层的所有神经元相连,这就构成了全连接网络(Dense Network)。\n\n### 2. 核心数学概念\n每个神经元的计算都可以分为两步:线性变换和非线性激活。\n\n1. **线性变换(加权求和)**:\n 每个神经元接收来自上一层的输入信号 $x_i$,每个输入连接都有一个对应的**权重(Weight,$w_i$)**。神经元会将所有输入信号与其权重相乘后求和,再加上一个**偏置项(Bias,$b$)**:\n $$z = \\sum (w_i \\cdot x_i) + b$$\n * *权重*决定了某个输入特征对当前神经元的影响程度。\n * *偏置*相当于一个阈值,决定了神经元在没有输入时是否会被激活。\n\n2. **非线性激活函数(Activation Function)**:\n 如果仅仅进行加权求和,无论叠接度少层,MLP 的数学本质仍是一个简单的线性回归模型,无法处理复杂的现实问题。因此,我们需要将加权求和的结果 $z$ 输入到一个非线性的**激活函数** $f(z)$ 中,从而为网络引入非线性特征。\n * 常见的激活函数有:**ReLU**(最常用)、**Sigmoid**、**Tanh** 等。\n\n### 3. 工作与训练原理\nMLP 的训练过程本质上是一个让网络自己“学习”最合适的权重和偏置的过程,主要分为两个阶段:\n\n* **前向传播(Forward Propagation)**:\n 输入数据从输入层进入,经过每一层隐藏层的计算(加权求和 + 激活函数),一层层向后传递,最终在输出层生成一个预测结果。\n* **计算损失(Loss)**:\n 将网络的预测结果与真实的标签(Ground Truth)进行对比,使用**损失函数(Loss Function)**(如均方误差 MSE、交叉熵等)计算出误差有多大。\n* **反向传播(Backpropagation)**:\n 这是 MLP 训练的核心算法。系统通过微积分中的链式法则,从输出层算起,逆推计算出误差相对于每一个权重和偏置的梯度(即改变这个参数会让误差变大还是变小)。\n* **参数更新(优化,Optimization)**:\n 使用**梯度下降法(Gradient Descent)**或其优化形式(如 Adam、SGD),根据反向传播求出的梯度,稍微调整网络中所有的权重和偏置,以期望在下一次前向传播时,误差能够减小。\n\n经过成千上万次的循环迭代,网络的预测结果会越来越接近真实值,此时我们就可以说模型“收敛”或训练完成了。\n\n### 4. MLP 的优缺点\n\n**优点**:\n* **通用逼近定理**:理论上,只要隐藏层的神经元足够多,一个包含哪怕只有一个隐藏层的 MLP 就可以拟合任何复杂的连续函数。\n* **应用广泛**:可以直观地处理分类和回归问题。\n* **基础性**:理解 MLP 是学习更复杂的网络(如 CNN卷积神经网络, RNN循环神经网络, Transformer大模型架构)必不可少的前置基石。\n\n**缺点**:\n* **参数量庞大**:由于是“全连接”,如果输入图像等高维数据,参数量会呈指数级爆炸,非常容易导致内存耗尽并且发生**过拟合(Overfitting)**。\n* **忽略空间与时序信息**:MLP 会将输入展平为一维向量,这破坏了图像的 2D 空间结构,也忽略了文本或时间序列前后的因果关系。(CNN 解决了图像空间问题,RNN/Transformer 解决了序列问题)。\n\n### 5. 常见应用场景\n现在的先进系统中,纯粹由多层 MLP 组成的独立模型已经较为少见,但它常常作为复杂网络结构的**末端/局部组件**出现:\n* **表格数据处理**:在结构化数据(如 Excel 表格、CSV)的预测中,MLP 表现依然很好。\n* **深度学习网络的“分类头”**:在 CNN(用于图像)或 Transformer(用于自然语言处理)提取出数据的深层特征后,通常会在网络的最末端接上几层 MLP(通常被称为全连接层 FC Layer),用来将特征映射到最终的分类概率上。","reasoning_content":"**Analyzing Current Information**\n\nI've been examining the available data to identify the most relevant pieces. My focus is on synthesizing this information to form a coherent understanding of the situation. I am currently working to evaluate the applicability of each of the data to the current circumstances.\n\n\n**Defining MLP Fundamentals**\n\nI'm now formulating a comprehensive introduction to Multi-Layer Perceptrons. I intend to detail its architecture, explain the operational mechanisms, and then cover activation functions used in training. I will conclude with a breakdown of its training, including both forward and backward propagation. I'm focusing on clarity and completeness for this fundamental concept.\n\n\n","role":"assistant"}}],"created":1771598804,"id":"chatcmpl-4944db97dfb54076b30b7feb1b3e1f89","model":"gemini-3.1-pro-low","object":"chat.completion","service_tier":"default","system_fingerprint":"fp_101","usage":{"completion_tokens":1226,"completion_tokens_details":{"reasoning_tokens":487},"prompt_tokens":5083,"prompt_tokens_details":{"cached_tokens":0},"total_tokens":6309}}% ### Diagnostic Report ```text 这没有意义:因为这是我的Claude按照作者大大的release高仿的,怎么样,还可以吧? link@LinkdeMac-mini zerogravity % /Users/link/Desktop/zerogravity-dev/target/release/zg report zg — ZeroGravity daemon manager Setup: init First-run setup (extract token, configure) token Extract OAuth token from Antigravity state.vscdb Service: start Start the proxy daemon stop Stop the proxy daemon restart Rebuild + restart rebuild Build release binary only status Version, endpoints, quota, usage logs [N] Show last N lines (default 30) logs-follow [N] Tail last N lines + follow logs-all Full log dump test [msg] Quick test request (gemini-3-flash) health Health check ``` ### Additional Context _No response_
kerem 2026-02-27 15:38:02 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@JinchengGao-Infty commented on GitHub (Feb 20, 2026):

这个问题不是更新版本的问题,我测试过docker和anti都更新到最新版也是一样的报错

<!-- gh-comment-id:3935387815 --> @JinchengGao-Infty commented on GitHub (Feb 20, 2026): 这个问题不是更新版本的问题,我测试过docker和anti都更新到最新版也是一样的报错
Author
Owner

@JinchengGao-Infty commented on GitHub (Feb 20, 2026):

如果代码结构还是这样的话,修改如下:(opencode里的Claude说的)

核心修改在 src/mitm/proxy.rs,在请求转发前加入 User-Agent 修补:
// Fix empty User-Agent version on macOS BEFORE any body processing.
// LS generates "antigravity/ darwin/arm64" (empty version) in headless mode
// because it can't read the version from the parent process.
// Google checks this to gate new models like Gemini 3.1 Pro.
{
let old_ua = b"User-Agent: antigravity/ ";
if let Some(pos) = request_buf[..headers_end]
.windows(old_ua.len())
.position(|w| w == old_ua)
{
let version = crate::constants::antigravity_version();
let new_ua = format!("User-Agent: antigravity/{version} ");
let mut new_buf = Vec::with_capacity(request_buf.len() + version.len());
new_buf.extend_from_slice(&request_buf[..pos]);
new_buf.extend_from_slice(new_ua.as_bytes());
new_buf.extend_from_slice(&request_buf[pos + old_ua.len()..]);
let len_diff = new_ua.len() as isize - old_ua.len() as isize;
headers_end = (headers_end as isize + len_diff) as usize;
request_buf = new_buf;
}
}
另外 headers_end 的声明需要改成 mut:
// 原来:
let (headers_end, content_length, _is_streaming_request) =
parse_http_request_meta(&request_buf);
// 改为:
let (mut headers_end, content_length, _is_streaming_request) =
parse_http_request_meta(&request_buf);
这段代码插入的位置是在 handle_http_over_tls 函数里,event_tx 声明之后、if req_path.contains("streamGenerateContent") 之前。

<!-- gh-comment-id:3935421372 --> @JinchengGao-Infty commented on GitHub (Feb 20, 2026): 如果代码结构还是这样的话,修改如下:(opencode里的Claude说的) 核心修改在 src/mitm/proxy.rs,在请求转发前加入 User-Agent 修补: // Fix empty User-Agent version on macOS BEFORE any body processing. // LS generates "antigravity/ darwin/arm64" (empty version) in headless mode // because it can't read the version from the parent process. // Google checks this to gate new models like Gemini 3.1 Pro. { let old_ua = b"User-Agent: antigravity/ "; if let Some(pos) = request_buf[..headers_end] .windows(old_ua.len()) .position(|w| w == old_ua) { let version = crate::constants::antigravity_version(); let new_ua = format!("User-Agent: antigravity/{version} "); let mut new_buf = Vec::with_capacity(request_buf.len() + version.len()); new_buf.extend_from_slice(&request_buf[..pos]); new_buf.extend_from_slice(new_ua.as_bytes()); new_buf.extend_from_slice(&request_buf[pos + old_ua.len()..]); let len_diff = new_ua.len() as isize - old_ua.len() as isize; headers_end = (headers_end as isize + len_diff) as usize; request_buf = new_buf; } } 另外 headers_end 的声明需要改成 mut: // 原来: let (headers_end, content_length, _is_streaming_request) = parse_http_request_meta(&request_buf); // 改为: let (mut headers_end, content_length, _is_streaming_request) = parse_http_request_meta(&request_buf); 这段代码插入的位置是在 handle_http_over_tls 函数里,event_tx 声明之后、if req_path.contains("streamGenerateContent") 之前。
Author
Owner

@NikkeTryHard commented on GitHub (Feb 20, 2026):

Fixed in main — the MITM proxy now patches the empty User-Agent version that the LS emits in headless mode. Thanks @JinchengGao-Infty for the excellent root cause analysis!

<!-- gh-comment-id:3937202846 --> @NikkeTryHard commented on GitHub (Feb 20, 2026): Fixed in main — the MITM proxy now patches the empty User-Agent version that the LS emits in headless mode. Thanks @JinchengGao-Infty for the excellent root cause analysis!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/zerogravity#36
No description provided.