Skip to content

Commit 8c707b3

Browse files
committed
chore(release): update 5.0.3-beta.1 release notes and fix GCP/autostart/multimodal issues (Fixes #3820, #3823, #3824)
1 parent bfe0939 commit 8c707b3

27 files changed

Lines changed: 366 additions & 73 deletions

‎CHANGELOG.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44

55
* **版本演进**:
66
* **v5.0.3-beta.1 (2026-11-04)**:
7+
- **[官方 GCP Vertex AI 企业账号支持与多协议凭据自适应隔离] (Fixes #3823)**:
8+
- **对齐官方 GCP 企业客户端凭据**: 深度逆向对齐官方 Antigravity 应用的 GCP / Vertex AI 企业授权协议架构,引入官方企业客户端(`884354919052-...`)及密钥体系,支持通过 `antigravity_gcp` 独立注册与动态鉴权,彻底解决企业组织账号授权后被误判为 Free Tier 或缺失 Vertex AI 项目配额的缺陷。(Fixes #3823)
9+
- **存量凭据数据严格向下兼容**: 账号凭据严格通过 `token.oauth_client_key` 与 `is_gcp_tos` 区分;存量使用个人版官方客户端授权的自定义域名企业邮箱(如 `@imsot.org`)100% 保持个人模式平滑刷新,杜绝因仅凭邮箱后缀切换客户端导致 Google 报 `400 invalid_grant` 的风险。
10+
- **添加账号全模式多语言支持**: 重构前端添加账号弹窗,将“个人账号 (Personal)”与“企业 / GCP (Vertex AI)”账号类型切换器提升至公共顶层区域,统一覆盖 OAuth 授权、Refresh Token 批量录入及本地 DB 导入全场景;并同步补齐了中英日繁韩西葡俄土越阿缅等 12 种主流语言的完整本地化翻译。(Fixes #3823)
11+
- **IDE 状态数据库与自适应刷新注入**: 在向本地 Antigravity IDE 数据库(`state.vscdb`)注入凭据时,根据客户端类型精准控制 Protobuf Field 6(`is_gcp_tos`)与 Vertex AI 项目映射;刷新机制自适应账号所属凭据类型,杜绝跨模式客户端混用。
12+
- **[修复免打扰模式开机自启仍弹出界面与自启状态同步] (Fixes #3820, Thanks to @W2514)**:
13+
- **启动项参数防御性模糊匹配**: 修复部分 Windows 启动项(注册表或快捷方式/任务计划)拼接参数或带引号导致启动入参无法被 `== "--minimized"` 精准全等匹配、从而错将开机自启识别为普通前台启动而弹出主窗口的缺陷;增强入参检测逻辑支持模糊包含匹配(`lower.contains("--minimized") || lower.contains("--silent") || lower.contains("--hidden")`),确保免打扰启动 100% 稳定留在系统托盘。(Fixes #3820, Thanks to @W2514)
14+
- **开机自启动配置状态原子同步**: 在 `toggle_auto_launch` 注册/注销系统自启动项时,同步将 `config.auto_launch` 原子持久化写入应用配置文件,消除前端界面配置与底层操作系统注册表之间的状态脱节。(Fixes #3820)
15+
- **[多模态保鲜滑窗默认启用与风控 403 粘性熔断自动禁用] (Fixes #3824)**:
16+
- **对齐官方多模态保鲜滑窗规范**: 深度逆向对齐官方 Antigravity 应用的旧图清理与尺寸收敛机制,将网关的多模态保鲜滑动窗口设为默认开启(`enable_sliding_window = true`),默认保留最新 5 张图片(`max_fresh_images = 5`);彻底杜绝在长对话中多轮历史图片累积导致请求体线性膨胀至数兆、引发上传堵塞及 504 Gateway Timeout 的硬伤。(Fixes #3824)
17+
- **上传速度自适应基准放宽**: 将默认最低上传带宽基准由 2.0 Mbps 宽限至 0.8 Mbps,增强慢速代理与复杂跨国网络环境下大图与附件上传的预算容忍度。
18+
- **403 人机验证阻断全链熔断与解绑**: 修复遇到 Google `VALIDATION_REQUIRED` 人机验证挑战时,粘性会话与调度快照未做阻断校验导致客户端多次重试死锁在同一故障账号的缺陷;现在检测到人机验证阻断后,立即强制解除会话粘性绑定(`session_accounts.remove`),并在快照生成与固定账号选择中无缝降级迁移至池中健康账号。
19+
- **403 自动触发禁用反代**: 发生 403 验证阻断时,同步调用 `toggle_proxy_status` 将账号标记为 `proxy_disabled = true`,使账号即刻在前端直观呈现停用状态并彻底退出反代调度池。
720
- **[网关超时全链路预算安全截断与终态会话粘性解绑] (Fixes #3821, Thanks to @jeikl, @cubelikeplayDaniel)**:
821
- **客户端安全超时绝对硬顶**: 引入 `MAX_CLIENT_SAFE_TOTAL_BUDGET_SECS = 160s` 全链路安全硬上限;解决此前长文本结合多模态增量与多端点重试时总预算累加膨胀至 190s~256s 击穿下游客户端(如 JeikCode)180s 内置看门狗导致连接被强行切断为 canceled 孤儿请求的问题,为客户端看门狗预留出至少 20s 的安全缓冲,确保网关永远早于客户端吐出标准的结构化 504 响应。(Fixes #3821, Thanks to @jeikl, @cubelikeplayDaniel)
922
- **首字预算基准与媒体上限压制**: 将上游首字节等待预算基准 `MAX_FIRST_BYTE_BUDGET_SECS` 压制至 135s,媒体增量上限 `MAX_FIRST_BYTE_CEILING_SECS` 压制至 145s;200k+ 超大上下文自适应 TTFT 下限同步对齐至 135s。(Fixes #3821, Thanks to @jeikl)

‎CHANGELOG_EN.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
55
* **Version History**:
66
* **v5.0.3-beta.1 (2026-11-04)**:
7+
- **[Official GCP Vertex AI Enterprise Account Support & Adaptive Credential Isolation] (Fixes #3823)**:
8+
- **Aligned with Official GCP Enterprise OAuth Credentials**: Reverse-engineered and matched the official Antigravity application architecture for GCP / Vertex AI enterprise authorization, integrating the official GCP enterprise client (`884354919052-...`) under `antigravity_gcp`. Completely resolves the issue where enterprise accounts were misidentified as Free Tier or lost access to Vertex AI project quotas. (Fixes #3823)
9+
- **Strict Backward Compatibility for Legacy Accounts**: Credentials strictly differentiate via `token.oauth_client_key` and `is_gcp_tos`; legacy accounts with custom domain emails (e.g. `@imsot.org`) previously authorized via the personal client retain 100% personal-mode refresh compatibility, preventing Google `400 invalid_grant` errors caused by naive domain-based client switching.
10+
- **Top-Level Account Type Selector Across All Import Modes with Full i18n**: Redesigned the Add Account dialog by hoisting the "Personal Account" vs. "Enterprise / GCP (Vertex AI)" type switcher to the top-level common area across OAuth, Refresh Token, and DB import modes; added complete translations across 12 languages including JA, ZH-TW, KO, ES, PT, RU, TR, VI, AR, and MY. (Fixes #3823)
11+
- **IDE Database Injection & Adaptive Refresh Integration**: Accurately toggles Protobuf Field 6 (`is_gcp_tos`) and maps the Vertex AI project when injecting credentials into the Antigravity IDE SQLite store (`state.vscdb`); ensures token refresh strictly honors the originating client descriptor.
12+
- **[Fix Quiet Autostart Still Showing Window and Sync Autostart Config] (Fixes #3820, Thanks to @W2514)**:
13+
- **Defensive Startup Argument Substring Matching**: Resolved an issue where quoted or concatenated startup parameters from certain Windows Run registry keys, shortcuts, or Task Scheduler instances failed strict equality comparisons (`== "--minimized"`), erroneously triggering an interactive window presentation on login; reinforced the check with substring pattern matching (`lower.contains("--minimized") || lower.contains("--silent") || lower.contains("--hidden")`), ensuring quiet login launch consistently stays in the system tray. (Fixes #3820, Thanks to @W2514)
14+
- **Atomic Autostart State Persistence**: Synchronously updated and persisted `config.auto_launch` to the app configuration file whenever toggling autostart via `toggle_auto_launch`, eliminating state drift between UI controls and OS registry entries. (Fixes #3820)
15+
- **[Default Multimodal Sliding Window & Automatic 403 Validation Circuit Breaking] (Fixes #3824)**:
16+
- **Aligned with Official Antigravity Multimodal Pruning**: Reverse-engineered and matched the official Antigravity app's image cleanup behavior by enabling the multimodal sliding freshness window by default (`enable_sliding_window = true`) and keeping the latest 5 images (`max_fresh_images = 5`). Prevents multiround conversations from accumulating dozens of images, inflating request payloads to multi-megabytes, and triggering upload congestion or 504 Gateway Timeouts. (Fixes #3824)
17+
- **Relaxed Adaptive Upload Bandwidth Floor**: Lowered the minimum upload speed baseline from 2.0 Mbps to 0.8 Mbps to offer higher tolerance for slow proxies and volatile cross-border networks during large payload uploads.
18+
- **Full-Chain Circuit Breaking & Session Unbinding for 403 Challenges**: Fixed an issue where encountering Google's `VALIDATION_REQUIRED` challenge failed to unbind sticky sessions or filter snapshot pools, causing repeated client retries to deadlock on the same failing account. Sticky sessions are now immediately severed (`session_accounts.remove`), and pool selection automatically fails over to healthy accounts.
19+
- **Automatic Proxy Disabling on 403**: Synchronously marks the account as `proxy_disabled = true` upon validation failure, immediately reflecting the disabled state on the GUI and cleanly removing it from proxy rotation.
720
- **[Client-Safe Gateway Timeout Clamping and Session Affinity Release on Terminal Failures] (Fixes #3821, Thanks to @jeikl, @cubelikeplayDaniel)**:
821
- **Client-Safe Timeout Hard Ceiling**: Introduced `MAX_CLIENT_SAFE_TOTAL_BUDGET_SECS = 160s` across the entire upstream call pipeline. Resolved an issue where long requests combining multimodal media offsets and multi-endpoint fallbacks ballooned to 190s~256s, exceeding client-side 180s watchdogs (such as JeikCode) and severing the connection into orphan canceled requests; guarantees a ≥20s safe window so the gateway always delivers a structured 504 error before the client disconnects. (Fixes #3821, Thanks to @jeikl, @cubelikeplayDaniel)
922
- **First-Byte Budget Baseline and Media Cap Tightening**: Clamped `MAX_FIRST_BYTE_BUDGET_SECS` to 135s and the media-augmented ceiling `MAX_FIRST_BYTE_CEILING_SECS` to 145s; aligned the 200k+ large-context adaptive TTFT floor to 135s. (Fixes #3821, Thanks to @jeikl)

‎src-tauri/src/commands/autostart.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ pub async fn toggle_auto_launch(app: tauri::AppHandle, enable: bool) -> Result<(
2828
}
2929
}
3030

31+
// 同步将开机自启状态持久化到 app_config,确保系统配置与自启项保持原子一致
32+
if let Ok(mut config) = crate::modules::config::load_app_config() {
33+
if config.auto_launch != enable {
34+
config.auto_launch = enable;
35+
let _ = crate::modules::config::save_app_config(&config);
36+
}
37+
}
38+
3139
Ok(())
3240
}
3341

‎src-tauri/src/lib.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ fn apply_login_launch_policy(app: &tauri::App) {
8787
|| lower == "--hidden"
8888
|| lower == "-s"
8989
|| lower == "/minimized"
90+
|| lower.contains("--minimized")
91+
|| lower.contains("--silent")
92+
|| lower.contains("--hidden")
9093
});
9194
if !launched_by_login {
9295
return;

‎src-tauri/src/modules/account.rs‎

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,11 +2056,12 @@ pub async fn switch_account(
20562056
}
20572057

20582058
fn is_enterprise_client(client_key: Option<&str>) -> bool {
2059-
client_key
2060-
.map(str::trim)
2061-
.filter(|key| !key.is_empty())
2062-
.map(|key| key.eq_ignore_ascii_case("antigravity_enterprise"))
2063-
.unwrap_or(false)
2059+
crate::modules::oauth::is_gcp_enterprise_client(client_key)
2060+
|| client_key
2061+
.map(str::trim)
2062+
.filter(|key| !key.is_empty())
2063+
.map(|key| key.eq_ignore_ascii_case("antigravity_enterprise"))
2064+
.unwrap_or(false)
20642065
}
20652066

20662067
fn normalize_project_id(project_id: Option<&str>) -> Option<String> {
@@ -3271,14 +3272,25 @@ pub async fn fetch_quota_with_retry(account: &mut Account) -> crate::error::AppR
32713272
}
32723273
};
32733274

3275+
let is_gcp_tos = if crate::modules::oauth::is_gcp_enterprise_client(
3276+
token_res
3277+
.oauth_client_key
3278+
.as_deref()
3279+
.or(account.token.oauth_client_key.as_deref()),
3280+
) {
3281+
true
3282+
} else {
3283+
account.token.is_gcp_tos
3284+
};
3285+
32743286
let new_token = TokenData::new(
32753287
token_res.access_token.clone(),
32763288
account.token.refresh_token.clone(),
32773289
token_res.expires_in,
32783290
account.token.email.clone(),
32793291
account.token.project_id.clone(), // Keep original project_id
32803292
None, // Add None as session_id
3281-
account.token.is_gcp_tos,
3293+
is_gcp_tos,
32823294
token_res.id_token.clone(),
32833295
)
32843296
.with_oauth_client_key(
@@ -3772,6 +3784,16 @@ pub async fn batch_import_accounts_logic(
37723784
)
37733785
.await;
37743786

3787+
let is_gcp_tos = if crate::modules::oauth::is_gcp_enterprise_client(
3788+
token_res.oauth_client_key.as_deref(),
3789+
) {
3790+
true
3791+
} else if let Ok(existing_acc) = load_account(&account_id) {
3792+
existing_acc.token.is_gcp_tos
3793+
} else {
3794+
false
3795+
};
3796+
37753797
// 5. 构造 TokenData 与 Account(若为既有账号,保留原有偏好与配额数据原地更新,杜绝重复凭据文件!)
37763798
let mut account = if let Ok(mut existing_acc) = load_account(&account_id) {
37773799
existing_acc.token = crate::models::TokenData::new(
@@ -3781,7 +3803,7 @@ pub async fn batch_import_accounts_logic(
37813803
Some(real_email.clone()),
37823804
project_id.or(existing_acc.token.project_id.clone()),
37833805
None,
3784-
false,
3806+
is_gcp_tos,
37853807
token_res.id_token,
37863808
)
37873809
.with_oauth_client_key(token_res.oauth_client_key);
@@ -3803,7 +3825,7 @@ pub async fn batch_import_accounts_logic(
38033825
Some(real_email.clone()),
38043826
project_id,
38053827
None,
3806-
false,
3828+
is_gcp_tos,
38073829
token_res.id_token,
38083830
)
38093831
.with_oauth_client_key(token_res.oauth_client_key);

‎src-tauri/src/modules/db.rs‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,18 @@ pub fn inject_token(
113113
) -> Result<String, String> {
114114
crate::modules::logger::log_info("Starting Token injection...");
115115

116-
// 如果使用的是本项目的内置 Client ID (antigravity_enterprise 实际上是标准版)
117-
// 则强制关闭 GCP TOS 标志,以确保 IDE 使用标准 Client ID 进行刷新
116+
// 针对个人客户端(如内置标准客户端 antigravity_enterprise),若检测到误标 is_gcp_tos 则进行修正
117+
// 但若为企业/GCP 客户端 (antigravity_gcp 等),必须保留 is_gcp_tos = true
118118
if let Some(key) = oauth_client_key {
119-
if key == "antigravity_enterprise" {
119+
if crate::modules::oauth::is_gcp_enterprise_client(Some(key)) {
120+
crate::modules::logger::log_info(
121+
"[DB] GCP Enterprise client detected, preserving is_gcp_tos = true for injection.",
122+
);
123+
is_gcp_tos = true;
124+
} else if key == "antigravity_enterprise" || key == "antigravity_personal" {
120125
if is_gcp_tos {
121126
crate::modules::logger::log_info(
122-
"[DB] Built-in client detected, forcing Standard mode for injection.",
127+
"[DB] Standard client detected, forcing Standard mode for injection.",
123128
);
124129
is_gcp_tos = false;
125130
}

‎src-tauri/src/modules/oauth.rs‎

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
use serde::{Deserialize, Serialize};
22

33
// Google OAuth configuration
4+
// 个人版官方客户端 (IDE 默认)
45
const CLIENT_ID: &str = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
56
const CLIENT_SECRET: &str = "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";
7+
8+
// 企业版 / GCP (Vertex AI) 官方客户端
9+
const GCP_CLIENT_ID: &str =
10+
"884354919052-36trc1jjb3tguiac32ov6cod268c5blh.apps.googleusercontent.com";
11+
const GCP_CLIENT_SECRET: &str = "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";
12+
13+
pub const BUILTIN_PERSONAL_CLIENT_KEY: &str = "antigravity_personal";
14+
pub const BUILTIN_ENTERPRISE_CLIENT_KEY: &str = "antigravity_enterprise";
15+
pub const BUILTIN_GCP_CLIENT_KEY: &str = "antigravity_gcp";
16+
617
const TOKEN_URL: &str = "https://oauth2.googleapis.com/token";
718
const USERINFO_URL: &str = "https://www.googleapis.com/oauth2/v2/userinfo";
819
const TOKEN_REFRESH_SKEW_SECONDS: i64 = 900;
@@ -74,6 +85,8 @@ pub struct OAuthClientDescriptor {
7485
pub client_id: String,
7586
pub is_active: bool,
7687
pub is_builtin: bool,
88+
#[serde(default)]
89+
pub is_gcp_tos: bool,
7790
}
7891

7992
const OAUTH_CLIENTS_ENV: &str = "ANTIGRAVITY_OAUTH_CLIENTS";
@@ -87,14 +100,31 @@ fn normalize_client_key(key: &str) -> String {
87100
key.trim().to_ascii_lowercase()
88101
}
89102

103+
pub fn is_gcp_enterprise_client(client_key: Option<&str>) -> bool {
104+
let key = match client_key.map(str::trim).filter(|k| !k.is_empty()) {
105+
Some(k) => k.to_ascii_lowercase(),
106+
None => return false,
107+
};
108+
key == BUILTIN_GCP_CLIENT_KEY || key.contains("gcp") || key.contains("vertex")
109+
}
110+
90111
fn build_registry() -> OAuthClientRegistry {
91-
let mut clients: Vec<OAuthClientConfig> = vec![OAuthClientConfig {
92-
key: normalize_client_key(DEFAULT_OAUTH_CLIENT_KEY),
93-
label: "Antigravity Enterprise".to_string(),
94-
client_id: CLIENT_ID.to_string(),
95-
client_secret: CLIENT_SECRET.to_string(),
96-
is_builtin: true,
97-
}];
112+
let mut clients: Vec<OAuthClientConfig> = vec![
113+
OAuthClientConfig {
114+
key: normalize_client_key(DEFAULT_OAUTH_CLIENT_KEY),
115+
label: "Antigravity (Standard)".to_string(),
116+
client_id: CLIENT_ID.to_string(),
117+
client_secret: CLIENT_SECRET.to_string(),
118+
is_builtin: true,
119+
},
120+
OAuthClientConfig {
121+
key: normalize_client_key(BUILTIN_GCP_CLIENT_KEY),
122+
label: "Google Cloud / Vertex AI (Enterprise)".to_string(),
123+
client_id: GCP_CLIENT_ID.to_string(),
124+
client_secret: GCP_CLIENT_SECRET.to_string(),
125+
is_builtin: true,
126+
},
127+
];
98128

99129
if let Ok(raw_extra_clients) = std::env::var(OAUTH_CLIENTS_ENV) {
100130
for entry in raw_extra_clients.split(';') {
@@ -293,6 +323,7 @@ pub fn list_oauth_clients() -> Result<Vec<OAuthClientDescriptor>, String> {
293323
client_id: client.client_id.clone(),
294324
is_active: client.key == registry.active_key,
295325
is_builtin: client.is_builtin,
326+
is_gcp_tos: is_gcp_enterprise_client(Some(&client.key)),
296327
})
297328
.collect())
298329
}

0 commit comments

Comments
 (0)