Antigravity2API 是单个 Go 进程:公开协议适配、账户池、上游客户端、请求账本、管理 API 与内嵌的 React 管理端都在同一监听上运行。上游请求的格式、身份与伴随请求见 协议参考,日志与请求账本见 运行日志与请求账本,对齐官方新版本的方法见 逆向指南。
| 场景 | 必需组件 |
|---|---|
| 运行 Release | 对应平台的可执行文件或安装包 |
| 命令行版源码构建 | Go 1.26、Node.js 22.22+ 或 24+、pnpm 11.10 |
| 桌面版源码构建 | 另需 Wails v3 CLI v3.0.0-beta.29;macOS 与 Linux 需要 CGO |
| Linux 桌面版 | libgtk-4-dev、libwebkitgtk-6.0-dev |
Go 程序以 go:embed 内嵌 internal/webui/dist,构建 Go 之前先构建前端:
cd web
pnpm install --frozen-lockfile
pnpm run build # 输出到 ../internal/webui/dist
cd ..
go build ./cmd/antigravity2api # 命令行版
go build -tags desktop,production ./cmd/antigravity2api # 桌面版Windows 上构建前用 wails3 generate syso 生成图标、清单与版本信息资源,命令行版与桌面版都带这些资源;桌面版另加 -ldflags='-H windowsgui'。前端开发时运行 pnpm dev,Vite 把 /api、/v1 与 /v1beta 代理到 http://127.0.0.1:8017。
前端检查与 CI 相同:
pnpm run lint
pnpm run typecheck.github/workflows/build.yml 在推送 main、推送 v* 标签、PR 与手动触发时运行:
| 作业 | 内容 | 产物 |
|---|---|---|
web |
前端检查与构建,解析版本 | internal/webui/dist |
headless |
测试、检查、构建与交叉编译 | Linux 与 macOS 共 4 个命令行包 |
desktop-windows |
desktop,production 构建,GUI 子系统,带图标、清单与版本信息 |
<版本>-windows-amd64.zip |
desktop-macos |
arm64 与 amd64 合并为通用二进制,ad-hoc 签名的 Antigravity2API.app |
desktop-<版本>-darwin-universal.tar.gz |
desktop-linux |
amd64 与 arm64 | desktop-<版本>-linux-<架构>.tar.gz |
release |
只在推送标签时运行 | GitHub Release |
docker |
只在推送标签时运行 | ghcr.io/mag1cfall/antigravity2api |
- 工具链:全部作业设
GOTOOLCHAIN=local。web作业用 Node.js 22.23.3 与web/package.json的packageManager指定的 pnpm 11.10.0;headless作业先以go.mod的 Go 1.26.0 运行go test、go vet与构建,再装最新稳定版 Go 交叉编译命令行包;desktop-windows、desktop-macos、desktop-linux以最新稳定版 Go 构建 - 包版本:标签构建为标签名,其余构建为提交号前 7 位,用于包名与可执行文件资源;资源与桌面包的数字版本去掉
v与-之后的部分,非标签构建为0.0.0。程序报告的版本取 Go 构建信息中的模块版本(见在线更新) - 命令行包:
linux/amd64、linux/arm64、darwin/amd64、darwin/arm64,CGO_ENABLED=0、-trimpath -ldflags='-s -w',tar.gz 中只有antigravity2api - Windows 包:zip 中只有桌面版
antigravity2api.exe(-H windowsgui);带子命令启动时附加启动它的控制台,没有控制台时新建一个,重定向的标准输入输出保持不变 - 桌面包:macOS 为通用
Antigravity2API.app的 tar.gz,Linux 为只含antigravity2api的 tar.gz - 包名:Windows 包与命令行包为
antigravity2api-<版本>-<系统>-<架构>,macOS 与 Linux 桌面包为antigravity2api-desktop-<版本>-<平台> - Release:标签含
-时标为预发布,说明由 GitHub 生成 - 镜像:
linux/amd64与linux/arm64,标签取 Git 标签原文(如v0.1.3),标签不含-时另推latest Dockerfile分三段:node:22-trixie-slim以 corepack 启用 pnpm 构建前端;golang:1.27-trixie以CGO_ENABLED=0交叉编译;debian:trixie-slim加装ca-certificates与tzdata运行,工作目录/data,LISTEN=0.0.0.0:8017,暴露 8017,默认命令antigravity2api serve
cmd/antigravity2api/ # 子命令、命令行版与桌面版入口(构建标签 desktop)
internal/
antigravity/ # 上游客户端:OAuth、设备档案、初始化、伴随请求、目录、信封、SSE 解码、图像与语音转写
api/ # OpenAI、Anthropic、Gemini 公开协议,Files、Images、Audio、Interactions
app/ # 监听装配、访问日志、请求记录、管理 API、管理事件流、登录与配对、版本检查
auth/ # auth/<账户>/ 的读写与官方客户端凭据导入
balancer/ # 账户池:模型可用性、冷却、并发槽位、会话粘连
config/ # .env 读取、校验、保存与代理选择
proxypool/ # PROXY 代理池:账户绑定、检测与改绑
desktop/ # Wails 窗口、托盘、单实例与开机启动
logging/ # slog 输出、日志文件轮转与崩溃文件
prompt/ # 各系统提示档位的官方段与 user 轮模板
requestdb/ # SQLite 请求账本、汇总、额度快照、日志与费用估算
service/ # 生成服务:模型解析、会话记录、请求改写、输出核对、换号与账户生命周期
tokencount/ # Gemma 3、cl100k_base 与 o200k_base 分词的本地 token 估算
webui/ # 内嵌管理端静态资源
web/ # 管理端源码(React 19、Vite、Tailwind CSS)
build/ # 桌面版图标、Windows 清单与版本信息、Info.plist
build/ 中的打包资源,0.0.0 在 CI 中替换为数字版本:
| 文件 | 关键字段 |
|---|---|
darwin/Info.plist |
CFBundleIdentifier 为 com.mag1cfall.antigravity2api |
darwin/Info.plist |
CFBundleName 为 Antigravity2API,CFBundleExecutable 为 antigravity2api |
darwin/Info.plist |
CFBundleIconFile 为 icons,对应 darwin/icons.icns |
darwin/Info.plist |
LSMinimumSystemVersion 为 12.0.0,NSHighResolutionCapable 为 true |
darwin/Info.plist |
NSAppTransportSecurity.NSAllowsLocalNetworking 为 true |
darwin/Info.plist |
CFBundleVersion、CFBundleShortVersionString 为版本占位 |
windows/wails.exe.manifest |
assemblyIdentity 名称 com.mag1cfall.antigravity2api |
windows/wails.exe.manifest |
依赖 Common-Controls 6.0 |
windows/wails.exe.manifest |
dpiAware 为 true/pm,dpiAwareness 为 permonitorv2,permonitor |
windows/wails.exe.manifest |
requestedExecutionLevel 为 asInvoker |
windows/info.json |
ProductName 为 Antigravity2API,CompanyName 为 Mag1cFall |
windows/info.json |
FileDescription 为 Google Antigravity API proxy |
windows/info.json |
LegalCopyright 为 Copyright (c) 2026 Mag1cFall |
windows/icon.ico |
可执行文件图标 |
依赖方向:
cmd ──► app ──► api ──► antigravity
│ ├────► service ──► balancer, prompt, tokencount, auth, requestdb, config ──► antigravity
│ └────► auth, config, logging, requestdb
└────► desktop, webui
recordPublic位于 api 层之前:满足条件的 POST 都写入请求账本,包括随后被浏览器来源检查或请求体上限拒绝的请求;API key 不匹配的请求不入账antigravity不依赖其他内部包;api只依赖antigravity的类型与Service接口(Models、Generate、CountTokens)service.Service实现antigravity.Service;app用recordingService包装它,在生成开始时写请求日志并转发事件给请求记录logging只依赖config的日志文件大小常量
公开生成请求的处理链:
HTTP 请求
-> access:生成请求 ID,写 X-Request-ID,结束后写访问日志
-> securityHeaders
-> recordPublic(POST,且 API key 与配置的某个 key 相同或未配置 key):建立请求记录、管理端停止入口
-> api:CORS、请求体上限、浏览器来源检查、API key、Files 存储
-> 协议适配:转成规范 GenerateRequest
-> recordingService.Generate:写“请求开始”,转发事件并检测停顿
-> service.Generate:解析模型、取得会话、改写请求、选账户、组装信封
-> antigravity.Client.StreamGenerateContent -> DecodeStream
-> service 输出处理:思考可见性、停止序列、工具约定、JSON 校验、输出上限
-> 协议投影:SSE 或 JSON
-> 请求结束:写入请求账本,推送 request 事件,写“请求完成”
api 层的公开接口规则:
- CORS:响应带
Access-Control-Allow-Origin: *与Access-Control-Expose-Headers: *;OPTIONS预检回显Access-Control-Request-Headers,允许GET, POST, PUT, DELETE, OPTIONS,返回 204 - 请求体上限 716876456 字节(512 MiB 文件的 base64 长度加 1 MiB),超出时读取请求体失败,返回 400
- 浏览器来源:
API_KEYS为空时,Origin为null、无法解析,或为http、https且主机不是 localhost 与回环地址的请求返回 401,错误体与 API key 不匹配时相同;配置了 key 时不检查来源 - API key:依次取
X-Goog-API-Key、X-API-Key、Authorization: Bearer、?key=,任一项与配置的某个 key 相同即通过,记录与用量按该 key 统计;都不匹配时返回所属协议的 401,消息为Invalid API Key - 401 的协议:路径以
/v1beta/、/upload/或/v1/interactions开头为 GeminiUNAUTHENTICATED,路径以/v1/messages开头或带anthropic-version头为 Anthropicauthentication_error,其余为 OpenAIinvalid_api_key;错误体见协议参考“错误映射” - 未知路径:
/v1/、/v1beta/、/upload/下的请求先经过上面的检查,再由 GoServeMux匹配端点;没有匹配的端点时(路径不存在,或路径存在而方法不同,如GET /v1/chat/completions)以所属协议的错误体返回 404(见协议文档“API 投影”的错误映射);任一路径的OPTIONS都返回 204 - 客户端 IP:取直连地址
配置项、默认值与含义见 README 的“环境变量”。读取顺序:
- 当前目录的
.env;文件不存在时全部取默认值 - 进程环境变量中的同名项覆盖文件值
- 启动参数
--listen、--auth、--runtime、--proxy覆盖LISTEN、AUTH_DIR、RUNTIME_DIR、PROXY
.env 的解析规则:
| 项 | 规则 |
|---|---|
空行、# 开头的行 |
跳过 |
没有 = 的行 |
报错,带文件名与行号 |
| 不在配置项清单中的键 | 忽略 |
| 单引号值 | 原文 |
| 双引号值 | 按 Go 字符串字面量解码 |
| 裸值 | 去掉 # 之后的行尾注释 |
列表项(API_KEYS、PROXY、SYSTEM_PROMPT_SECTIONS、PREFER_LOWER_TIER_MODELS、MODEL_MAPPING) |
按逗号切分,见表下 |
MODEL_MAPPING |
每项以最后一个 : 分成别名与模型 ID,两边各去掉首尾空白 |
REQUEST_TIMEOUT、QUOTA_REFRESH_INTERVAL |
Go 时长,例如 30s、5m;QUOTA_REFRESH_INTERVAL 另接受 0 |
布尔项(WEEKLY_QUOTA_WARMUP、LOG_FILE、REQUEST_LOG_BODIES、ADMIN_AUTH_ENABLED) |
Go strconv.ParseBool,见表下 |
整数项(ACCOUNT_CONCURRENCY、QUOTA_RESERVE_PERCENT、LOG_MAX_TOTAL_MB) |
十进制整数,其他值报错 |
MEDIA_OUTPUT、LOG_LEVEL、LOG_FORMAT |
去掉首尾空白后转小写 |
| 其他文本项 | 去掉首尾空白,大小写敏感 |
- 列表项每项去掉首尾空白,空项忽略;
PROXY保存为去掉首尾空白的原文,使用时切分 - 布尔项接受
1、t、T、true、TRUE、True与0、f、F、false、FALSE、False,其他值报错 ADMIN_PASSWORD保留原文
解析或校验失败时启动报错,管理端保存时返回 400 invalid_settings,不取默认值:
| 项 | 合法值 |
|---|---|
LISTEN |
host:port |
AUTH_DIR、RUNTIME_DIR |
非空 |
PROXY |
带主机的 http、https 或 socks5 URL,逗号分隔 |
SYSTEM_PROMPT |
full、medium、aggressive、custom |
SYSTEM_PROMPT_SECTIONS |
官方段名 |
SYSTEM_PROMPT_WRAP |
full、time、none |
MODEL_MAPPING |
每项为 别名:模型 ID,两边非空 |
MEDIA_OUTPUT |
inline、url |
MEDIA_BASE_URL |
空或带主机的 http、https URL |
ACCOUNT_CONCURRENCY |
正整数,没有上限 |
ROUTING_STRATEGY |
round-robin、fill-first |
REQUEST_TIMEOUT |
正数时长 |
QUOTA_REFRESH_INTERVAL |
0 或不小于 1m |
QUOTA_RESERVE_PERCENT |
0 到 99 |
LOG_LEVEL |
debug、info、warn、error |
LOG_FORMAT |
json、text |
LOG_MAX_TOTAL_MB |
不小于 20 |
ADMIN_AUTH_ENABLED |
为 true 时 ADMIN_USERNAME 与 ADMIN_PASSWORD 非空 |
- 账户代理同样只接受
http、https、socks5URL,另接受direct
管理端保存设置(PATCH /api/settings)的步骤:
| 步骤 | 规则 |
|---|---|
| 读取 | .env 叠加进程环境变量,启动参数不参与 |
| 合并 | 只替换提交的键,按上方解析与校验规则检查,失败返回 400 invalid_settings |
| 写回内容 | 全部项按清单顺序写成 键=值 行,见表下 |
| 列表值 | 以 , 相连,MODEL_MAPPING 每项为 别名:模型 ID |
| 字面量 | 含空格、制表符、回车、换行、#、" 或 ' 的值写成 Go 双引号字面量 |
| 时长 | 最短形式,如 30s、5m、1h |
| 布尔 | true、false |
| 写入 | 经同目录临时文件原子替换,权限 0600 |
- 写回的文件只含配置项清单中的键;叠加的环境变量值同样写入文件
保存后的生效:
- 运行配置随之替换,
LISTEN、AUTH_DIR与RUNTIME_DIR保持启动值,启动时给出--proxy时运行配置的PROXY保持该值,其余项在下一次请求生效 - 日志级别、格式、日志文件与正文保存立即切换
- 管理登录配置变化时撤销全部管理会话
- 代理池换成新的
PROXY列表并请求一次检测
上游代理的选择顺序:账户自设的代理(direct 为直连)、PROXY 代理池为账户绑定的代理、环境变量 HTTPS_PROXY、HTTP_PROXY 与 NO_PROXY、Windows 当前用户的系统代理设置;不属于某个账户的请求(登录、官方更新清单、在线更新)取 PROXY 的第一项。
代理池(internal/proxypool):PROXY 的各项(只有一项时也是)组成代理池,未设账户代理的账户在每次请求时取绑定的代理:
| 情形 | 处理 |
|---|---|
| 首次检测完成前 | 各代理视为可用 |
| 账户首次请求 | 绑定账户最少的可用代理 |
| 绑定的代理不可用 | 改绑到账户最少的可用代理 |
| 全部代理不可用 | 沿用当前绑定 |
| 保存设置 | 保留仍在列表中的代理的检测结果与绑定 |
| 保存设置后 | 改绑已删除代理上的账户,再重新均衡 |
| 账户停用、删除或改设账户代理 | 解除绑定 |
| 检测 | 并行检测各代理 |
- 账户最少的代理有多个时取列表中靠前的;全部代理不可用时,未绑定的账户在全部代理中取账户最少的
- 已删除代理上的账户按 ID 字典序依次改绑到账户最少的可用代理
- 重新均衡:在可用代理(全部不可用时为全部代理)中,反复把账户最多的代理上 ID 字典序最大的账户移到账户最少的代理,直到两者相差不超过一个;账户最多或最少的代理有多个时取列表中靠前的
- 检测:经代理 GET
https://www.gstatic.com/generate_204,20 秒内收到任何 HTTP 响应为可用;时机见下表
| 检测时机 | 规则 |
|---|---|
| 服务启动 | 立即检测一次 |
| 定时 | 启动后每 5 分钟,计时不因其他检测重置 |
| 请求出错 | 生成类请求的上游尝试遇到连接错误且客户端未取消时请求一次检测 |
| 保存设置 | 请求一次检测 |
POST /api/proxies/check |
在该请求内检测并返回结果 |
- 生成类请求指生成、图像生成、语音转写与 Tab 补全;连接错误的定义见“失败与换号”
- “请求一次检测”交给后台检测循环:已有待处理的请求时合并,检测进行中收到的请求在本次结束后再检测一次
代理池的状态在设置页“网络”分区显示,只有一个代理时同样显示。
系统代理只在 ProxyEnable 开启时使用,ProxyServer 为 host:port 时作为 HTTP 代理,为 http=…;https=…;socks=… 时按请求协议选择、其次用 socks 项(SOCKS5),ProxyOverride 中的主机与 <local>(不含点的主机名)直连,回环地址始终直连。
- 系统代理读自注册表
HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings的ProxyEnable、ProxyServer、ProxyOverride,每次选择代理(即每个上游连接请求)都重新读取,运行中修改系统代理后下一个请求即按新设置 ProxyOverride以;分隔,每项按 Gopath.Match通配匹配小写主机名- 环境变量
HTTPS_PROXY、HTTP_PROXY、NO_PROXY经 Gohttp.ProxyFromEnvironment读取,进程内只读一次 - Windows 以外的系统只用环境变量
AUTH_DIR 下每个账户一个子目录,目录名为邮箱:
| 文件 | 内容 |
|---|---|
account.json |
账户资料与设备档案 |
token.json |
Go oauth2.Token 的 JSON |
token.json的字段为access_token、token_type、refresh_token、expiry(RFC 3339)与可省略的expires_in;id_token不保存
account.json 字段:
| 字段 | 内容 |
|---|---|
id、email |
邮箱 |
label |
备注 |
proxy |
账户代理,空为跟随全局,direct 为直连 |
project |
loadCodeAssist 的 cloudaicompanionProject,空表示待走登录序列 |
tier、paid_tier |
currentTier.id 与 paidTier.id |
region |
fetchUserInfo 的 regionCode |
device |
设备档案 |
auth_method |
认证方式,见表下 |
wif_provider |
企业 WIF 账户登录时的 --provider,个人账户省略 |
enabled |
是否参与调度 |
priority |
调度优先级,越大越先使用,为 0 时省略 |
ai_credits |
额度用尽后继续以 Google One AI 积分生成,关闭时省略 |
added_at |
添加时间,RFC 3339 带纳秒 |
auth_method为空或personal_consumer时是个人账户,business_licensed_enterprise为企业 WIF 账户added_at为 Gotime.Time的 JSON;账户按它排序,相同时按 ID
设备档案在账户首次加入时生成,之后保持不变:login 与管理端登录的新账户沿用登录前虚拟进程的档案(installation_id、系统与时区,用户名与 app_data_dir 按邮箱补齐),import 与远程配对的新账户随机生成;已有账户再次登录、导入或配对时只更新 token.json,档案与其他资料不变。
| 字段 | 取值 |
|---|---|
os、arch |
生成时运行平台的 GOOS、GOARCH |
user_name |
邮箱本地部分中的字母与数字 |
app_data_dir |
按系统的主目录路径,见表下 |
time_zone |
本机 IANA 时区名 |
installation_id |
随机 UUID |
app_data_dir:WindowsC:\Users\<用户名>\.gemini\antigravity,macOS/Users/<用户名>/.gemini/antigravity,其余/home/<用户名>/.gemini/antigravitytime_zone取TZ或/etc/localtime链接,都没有时为±hh:mm
档案字段的使用位置:
| 档案字段 | 使用位置 |
|---|---|
os、arch |
User-Agent、JSON 风格、unleash、Hub 事件、系统提示、主机名 |
user_name |
unleash instanceId;macOS 与 Linux 主机名 |
app_data_dir |
系统提示中的路径 |
time_zone |
user 轮本地时间与 unleash 时间的时区 |
installation_id |
Windows 主机名;Hub 事件的安装标识;登录前错误上报 |
os、arch决定 User-Agent 的系统、架构与构建号,JSON 正文结构逗号后的空格(macOS 与 Linux 带空格),unleash 的platformVersion,Hub 事件的os,系统提示的 OS 与路径分隔符,以及主机名形式
主机名:Windows 为 DESKTOP- 加 SHA-256(installation_id 的 UUID 文本) 以 RFC 4648 标准 Base32 字母表 A–Z2–7 编码后的前 7 个字符,macOS 为 <用户名>s-MacBook-Pro.local,Linux 为 <用户名>-pc。
两个文件都是两个空格缩进、以换行结尾的 JSON,经同目录临时文件原子替换写入,目录权限 0700。
账户目录的读取:
| 情形 | 启动与子命令(Open) |
每 2 秒同步(Sync) |
|---|---|---|
| 不是目录的项 | 跳过 | 跳过 |
子目录没有 account.json |
跳过 | 视为删除 |
account.json 无法读取或解析 |
失败退出 | 视为删除 |
token.json 缺失或无法解析 |
失败退出 | 保持内存中的账户 |
AUTH_DIR 无法列出 |
失败退出 | 记 读取账户目录失败 |
- 服务启动与每个读取账户的子命令(
accounts、login、import、status等)都以Open读取账户目录;失败时打印错误并以状态 1 退出 - 账户以
account.json的id为键,与目录名无关;写回account.json与token.json时写到<AUTH_DIR>/<id>/ - 多个目录的
id相同时,按目录名排序靠后的生效 Sync只在token.json的 refresh token 与内存不同时换用目录中的资料与 token;目录中消失的账户从账户池移除
| 路径 | 内容 |
|---|---|
requests.db |
请求账本(SQLite,WAL) |
logs/antigravity2api.log |
服务日志,轮转文件在同目录 |
logs/crash.log |
未恢复的 panic 与致命错误 |
files/<ID>、files/<ID>.json |
Files API 上传的内容与元数据 |
media/<SHA-256>.<扩展名> |
MEDIA_OUTPUT=url 时按内容命名保存的生成媒体 |
conversations/<cascade_id>.json |
会话记录,空闲 24 小时后删除 |
catalogs/<账户>.json |
该账户最近一次读到的模型目录条目 |
hub/<账户>.json |
虚拟 Hub 状态:该账户经服务开始过的会话数与模型选择器最后选定的模型 |
warmups.json |
各账户各每周额度桶最近一次唤醒的时间 |
cooldowns.json |
各账户未到期的冷却,服务重启后恢复 |
.updaterId |
版本检查使用的更新器标识 |
webview/ |
桌面版 WebView 数据 |
运行目录中的 JSON 文件:
| 文件 | 字段 |
|---|---|
catalogs/<账户>.json |
目录条目数组,见表下 |
hub/<账户>.json |
{"conversations": <会话数>, "model": "<模型枚举>"} |
warmups.json |
{"<账户>": {"<额度桶 ID>": "<RFC 3339 时间>"}} |
cooldowns.json |
{"<账户>": {"<额度组或模型 ID>": "<RFC 3339 截止时间>"}} |
catalogs/<账户>.json按公开目录的顺序,每项为fetchAvailableModels的条目字段加id、agent(Agent 模型为 true,否则省略)与kind(image、transcription或tab,普通条目省略,含义见协议参考“fetchAvailableModels顶层字段”)hub/<账户>.json在没有选定过模型时省略modelcooldowns.json为紧凑 JSON,每次冷却变化时整体重写
会话记录 conversations/<cascade_id>.json 为紧凑 JSON 对象:
| 字段 | 类型 | 内容 |
|---|---|---|
cascade、trajectory |
UUID 字符串 | 会话 ID 与轨迹 ID |
length |
整数 | 最近一次请求在摘要链中的位置 |
digest |
十六进制字符串 | 该位置的链摘要 |
answer |
字符串,可省略 | 该次成功生成的回答指纹 |
times |
整数数组 | 各条消息首次出现的 Unix 秒 |
prompt |
对象,可省略 | 最近一次成功生成的提示规模 |
signatures |
对象,可省略 | 函数调用 ID 到思考签名 |
origins |
对象,可省略 | 签名指纹到模型族 |
used |
RFC 3339 字符串 | 最近使用时间,带纳秒 |
prompt 字段 |
类型 | 内容 |
|---|---|---|
model |
字符串 | 模型 ID |
length |
整数 | 规范消息条数 |
digest |
十六进制字符串 | 该处链摘要 |
contents |
整数 | 上游 contents 条数 |
tokens |
整数 | 上游 promptTokenCount |
origins的键为签名 SHA-256 前 16 字节的小写十六进制,值为生成它的模型的modelProvider(MODEL_PROVIDER_GOOGLE、MODEL_PROVIDER_ANTHROPIC、MODEL_PROVIDER_OPENAI)- 会话记录写入时先写同目录临时文件再替换;启动时读入全部记录,任一文件无法解析时服务启动失败
- 写入时机:请求开始时(取得会话后、选择账户前)写
length、digest、times与used,answer清空;times先截到上一次的length再按当前时刻补齐本次多出的消息。生成正常结束后再写prompt、signatures、origins,会话仍停在本次请求时写answer - 失败或取消的请求只有请求开始时的写入;之后原样重发时按协议参考「会话 ID」第 3 步匹配回同一会话,沿用已写的
times - 摘要链:
digest(prev, data) = hex(SHA-256(prev + data)),prev为上一项的小写十六进制文本;d0 = digest("", {"Session":<分区>,"System":<去掉计费行后的客户端系统提示>,"Tools":<规范工具>}),di = digest(d(i-1), 第 i 条规范消息的 JSON) - 回答指纹:
digest("", 正文 + NUL + 调用)。正文为各非思考 part 的text相连后按 Gostrings.Fields切分、以单个空格相连;调用为各函数调用的“函数名 + 参数 JSON”以 NUL 相连,参数 JSON 先解析再编码,对象键按字典序 - 摘要链与回答指纹中的 JSON 为 Go
encoding/json编码:字段按下表顺序,标为可省略的字段为零值时不写,[]byte为标准 Base64,json.RawMessage去掉空白,字符串中的<、>、&写成\u003c、\u003e、\u0026
规范类型(internal/antigravity/types.go) |
JSON 字段,按顺序 | 可省略 |
|---|---|---|
Content |
role(user、assistant、tool)、parts |
— |
Part |
text、inline_data、file、function_call、function_result、thought、thought_signature、video_metadata、media_resolution |
全部 |
Blob |
mime、data |
— |
FileRef |
id、name、mime |
name、mime |
FunctionCall |
id、name、arguments、thought_signature |
thought_signature |
FunctionResult |
id、name、content、parts |
name、parts |
Tools |
functions、google_search、search、tool_config |
除 tool_config 外 |
FunctionDeclaration |
name、description、parameters、schema、strict、response、response_json_schema、behavior |
除 name 外 |
SearchOptions |
context_size、location、allowed_domains、blocked_domains |
全部 |
ToolConfig |
mode、allowed_function_names、parallel_calls |
全部 |
-
video_metadata与media_resolution为客户端 JSON 原文去掉空白 -
SearchOptions.location为字符串:城市、地区、国家以,相连,有时区时接; time zone <时区> -
ToolConfig.mode为字符串auto、required、validated或none,allowed_function_names为字符串数组,parallel_calls为布尔值,客户端没有给出时省略 -
FunctionDeclaration.parameters为投影后的上游 Schema(见协议参考“工具声明”,键序与编码同marshalSchema);schema为整理后的客户端 JSON Schema:null、空、true与{}换成{"type":"object"},required列出而properties中没有的属性补为{};description含投影时追加的完整 Schema 说明 -
google_search为客户端googleSearch的 JSON 原文,search为SearchOptions对象 -
目录文件无法解析时跳过该账户
login、import、远程配对与管理端登录都把 OAuth token 交给账户库:邮箱取自 id_token 载荷,没有 id_token(官方客户端保存的 token)时以该 token 请求 userinfo;新账户生成设备档案(来源见“账户目录”)并启用,已有账户更新 token 并清除 auth_method 与 wif_provider,企业 WIF 登录随后写回这两项。import 先读系统凭据库(服务 gemini、用户 antigravity),读取失败时再读 ~/.gemini/jetski-standalone-oauth-token,取 JSON 的 token 字段,导入这一个账户;凭据的 auth_method 不参与,导入的账户为个人账户。POST /api/accounts/import 的 accounts 因此只有一项。
系统凭据库经 zalando/go-keyring v0.2.8 读写,与官方客户端使用同一位置:
| 系统 | 位置 | 值 |
|---|---|---|
| Windows | 凭据管理器的普通凭据,目标名 gemini:antigravity,用户名 antigravity |
UTF-8 JSON 文本 |
| macOS | 登录钥匙串的通用密码,服务 gemini,账户 antigravity |
写入为 go-keyring-base64: 加 JSON 的 Base64;读取另接受 go-keyring-encoded: 加十六进制与原文 |
| Linux | Secret Service 的 login 集合(没有时为默认集合),标签 Password for 'antigravity' on 'gemini',属性 service=gemini、username=antigravity |
JSON 文本 |
运行中的服务每 2 秒重新读取账户目录:其他进程(login、import 或复制进 auth/ 的目录)加入的账户、refresh token 与内存不同的账户与被删除的账户目录反映到账户库,有变化时后台刷新账户池。
switch <邮箱> 与 POST /api/accounts/{id}/switch 把账户库中的账户交给本机官方客户端,方向与 import 相反,实现在 internal/auth(official.go、official_windows.go、official_other.go):
- 找到官方客户端,结束它的全部进程并等待退出(下表)
- 把 token 写入官方客户端的凭据存储(下表)
- 重新启动官方客户端,language_server 启动时读取新 token
| 步骤 | Windows | macOS | Linux |
|---|---|---|---|
| 找到客户端 | 注册表中 antigravity 协议的打开命令 |
/Applications/Antigravity.app |
PATH 中的 antigravity |
| 结束进程 | 安装目录内的全部进程 | pkill -KILL -f <app>/ |
pkill -KILL -f <安装目录>/ |
| 等待退出 | 逐个等待进程结束 | 每 100 ms 执行 pgrep -f |
同 macOS |
| 记下参数 | 主进程的启动参数 | — | — |
| 启动 | 以记下的参数运行 | open <app> --args |
在 setsid 新会话中运行 |
- Windows 打开命令为
HKEY_CLASSES_ROOT\antigravity\shell\open\command的默认值,可执行文件取其中引号内的路径,没有引号时取第一个空格前的部分;安装目录为它所在的目录 - Windows 结束映像路径位于安装目录内的全部进程,
TerminateProcess后逐个等待,无权结束的进程跳过;主进程为映像是该可执行文件、命令行不含--type=的进程 - Windows 启动时工作目录为安装目录,客户端原本没有运行时不带参数
- Linux 的可执行文件为 PATH 中
antigravity解析符号链接后的文件,安装目录为它所在的目录,启动时工作目录为安装目录 - macOS 与 Linux 在
pgrep -f查不到进程时视为已退出
写入的凭据为官方客户端登录后保存的 JSON {"token":{"access_token","token_type","refresh_token","expiry"},"auth_method":"consumer"},位置取决于标记文件 ~/.gemini/cache/antigravity-keyring-unavailable:
| 情形 | 写入 |
|---|---|
| 标记的修改时间在 1 小时内 | 令牌文件,系统凭据库已有可读凭据时一并更新 |
| 标记不存在或超过 1 小时 | 系统凭据库 |
| 系统凭据库写入失败 | 标记与令牌文件 |
agy 会话文件存在 |
另写该文件 |
- 令牌文件为
~/.gemini/jetski-standalone-oauth-token;官方客户端优先读取系统凭据库 - 系统凭据库写入失败的情形如 Linux 没有 Secret Service,此时与官方客户端一样写入标记
agyCLI 的会话文件为~/.gemini/antigravity-cli/antigravity-oauth-token;agy先读系统凭据库再读该文件,切换后新启动的agy以该账户运行- 文件权限为 0600
服务启动后与账户变化后在后台刷新账户池,同一时间只运行一次,进行中再次请求时合并为下一次:
- 按添加时间逐个处理启用账户,跳过已初始化且代理与 refresh token 都未变的账户;相邻两次初始化之间随机间隔 1–3 秒
- 每个账户以设备档案与代理创建上游客户端,读取
RUNTIME_DIR/hub/<账户>.json,立即开始 unleash 与 clearcut 上报两项伴随请求,0.6–0.8 秒后初始化 - 企业账户(
auth_method为business_licensed_enterprise)走BusinessInitialize;个人账户在project为空或 refresh token 已变时走登录序列,其余走冷启动序列(序列见协议参考)。fetchUserInfo显示遥测开启时发setUserSettings关闭 - 成功时写回
project、tier、paid_tier、region,以目录的公开条目加入账户池并保存到RUNTIME_DIR/catalogs/<账户>.json,记录额度快照并开始其余伴随请求;失败时停止该账户的全部伴随请求,记下原因并移出调度 - 停用与已删除的账户移出调度,停止全部伴随请求
伴随请求指虚拟进程在生成请求之外发出的上游请求,清单与时机见协议参考“伴随请求”。
账户池与目录:
- 账户池顺序为各账户最近一次初始化成功的先后:初始化成功时账户先移出再加到末尾;
fill-first的首选账户与公开目录的合并都按此顺序 - 伴随请求的第 6、12、18… 轮实验轮询(虚拟进程启动后 6 分 0.7 秒起每 6 分钟)重读目录,更新账户池中的条目与保存的目录,账户位置不变
- 公开模型目录是账户池中各账户目录的合集,再加上尚未就绪的启用账户保存的目录,服务重启后账户初始化完成前即列出全部模型
额度读取:
| 时机 | 读取的账户 |
|---|---|
定时:服务启动 60 秒后,此后按 QUOTA_REFRESH_INTERVAL |
全部账户 |
| 管理端刷新全部或单个账户 | 所选账户 |
生成请求遇到额度耗尽(QUOTA_EXHAUSTED 或 INSUFFICIENT_G1_CREDITS_BALANCE,图像生成模型除外) |
该账户,后台读取 |
| 账户初始化后首次成功生成 | 该账户,不先发 loadCodeAssist |
| 周额度唤醒成功 | 该账户 |
- 定时读取由服务启动时开始的每分钟计时器驱动,从服务启动起计时,不对齐时钟整分
- 第 1 次在启动 60 秒后
- 之后每次计时器触发时,距上次读取的分钟数乘 1 分钟不小于
QUOTA_REFRESH_INTERVAL时读取,间隔因此向上取整到整分钟 - 修改间隔在下一次计时器触发时生效;为 0 时不定时读取
- 每次定时读取后,依次重新初始化启用中但初始化失败、认证失败或需要验证的账户(相邻两次间隔 1–3 秒),再执行周额度唤醒
- 已初始化的账户经自己的上游客户端读取,其余账户(含停用账户)以保存的 token、设备档案与代理读取;除首次成功生成后的那次外,每次读取先发
loadCodeAssist(端点见协议参考“retrieveUserQuotaSummary的发送时机”),项目、当前套餐或付费套餐变化时写回account.json并更新调度用的套餐等级 - 同时最多读取 5 个账户,与账户池刷新依次进行
- 每个账户保留最近一次读到的额度摘要及读取时间:刷新账户池时,还没有读取的账户取请求账本中 7 天内最近一次额度快照;冷启动初始化不读额度,沿用最近一次读取;账户出错或移出调度后保留
周额度唤醒在 WEEKLY_QUOTA_WARMUP 开启时、每次定时读取额度之后执行,对满足下表全部条件的账户与额度桶各发一次请求:
| 条件 | 规则 |
|---|---|
| 账户 | 在账户池中 |
| 额度桶 | window 为 weekly,窗口未开始计时 |
| 间隔 | 该账户该桶 6 天内没有唤醒过 |
| 模型 | 该桶额度组中估算费用最低的对话模型 |
- 窗口未开始计时:最近一次读到的该桶剩余比例不低于 99.9%,且
resetTime减读取时间不小于 7 天减 1 分钟;窗口未开始计时时resetTime随读取时间后移 - 额度组为桶 ID 中
-之前的部分;对话模型为该账户目录中属于该组且kind为空的模型 - 费用按 1000 输入 token 与 1000 输出 token 以
requestdb.Cost估算;没有单价的模型排在有单价的之后,同价取目录中靠前的;没有对话模型时跳过该桶 - 请求:经生成路径以
AccountID指定该账户,发一条 user 消息Hi,没有客户端系统提示与工具,使用当前的系统提示档位,读完回答;会话分区为空,会话记录空闲 24 小时即删除,因此每次唤醒都新建会话并发writeTrajectoryAcls与标题请求;唤醒请求不写请求账本 - 结果:成功时记入
RUNTIME_DIR/warmups.json并重新读取该账户的额度;失败写 WARN 日志周额度唤醒失败(见运行日志文档“账户事件”),下一次定时读取后再试
管理端“验证”同步重新初始化单个账户(企业账户走 BusinessInitialize,个人账户在 project 为空时走登录序列),需要验证或初始化失败的账户由此恢复调度。
生成类请求以外的上游请求失败时:
| 请求 | 失败时 |
|---|---|
| 初始化 | 记下原因并移出调度 |
| 刷新轮 | 只写 upstream.request 日志 |
| 额度读取 | 写 WARN 日志,列入 failed |
- 初始化失败的原因为错误文本;上游返回 403
VALIDATION_REQUIRED时原因为需要验证:<上游错误正文>,管理端从中取验证链接。这类账户在每次定时读取额度后与管理端“验证”时重新初始化 - 刷新轮为每 6 轮实验轮询附带的
loadCodeAssist、fetchAvailableModels、userinfo、头像与fetchUserInfo;账户保持调度,读到的目录更新账户池,读到的项目与套餐用于该账户之后的上游请求,account.json与调度用的套餐等级在下一次额度读取时更新 - 额度读取的
loadCodeAssist或retrieveUserQuotaSummary失败时账户保持调度,额度沿用上一次读取;loadCodeAssist成功且项目或套餐变化时先写回account.json并更新调度用的套餐等级
| 状态 | 条件 |
|---|---|
disabled |
已停用 |
error |
初始化失败或被移出调度,带原因 |
pending |
启用但尚未完成初始化 |
cooling |
至少一个额度组或模型在冷却 |
ready |
可调度 |
- 账户池为初始化成功且未移出调度的账户,含
cooling状态的账户;本文与协议参考中的“就绪账户”都指账户池中的账户 - 按账户池计的位置:选择账户、
GET /api/models的accounts、GET /api/accounts的shared、周额度唤醒;仪表盘“就绪数”只计ready
error 状态的原因(GET /api/accounts 的 error):
| 失败 | 原因文案 |
|---|---|
| 初始化失败 | 错误文本 |
| 需要验证 | 需要验证:<上游错误正文> |
| 认证失败 | 认证失败:<错误文本> |
| 违反条款 | 违反服务条款已停用:<上游错误正文> |
- 违反条款时写回
account.json失败,原因后追加;写回账户失败:<错误文本>;该账户已停用,状态显示为disabled - 尚未完成初始化的账户没有原因;“模型只在未就绪账户的目录中”与模型列表(
账户尚未就绪,还没有模型目录)的 503 把它写为初始化中
冷却包括调度记下的冷却与额度耗尽:额度摘要中该组的桶或目录 quotaInfo 的 remainingFraction 不大于 QUOTA_RESERVE_PERCENT 对应的比例(默认 0)时,到 resetTime 前视为冷却。开启 AI 积分超额使用(ai_credits)的账户在 QUOTA_RESERVE_PERCENT 为 0 时不按剩余比例视为耗尽,由上游的额度耗尽错误决定冷却。
- 账户池为空时返回 503,不解析模型名;否则解析模型名(规则见协议参考“模型 ID 与思考档位”),名称只在未就绪账户保存的目录中时返回 503,都不存在时返回 404;消息见下表
- 候选账户:目录中有该模型、未被本次请求排除、该模型未冷却;冷却截止取额度组冷却、模型冷却与额度耗尽重置时间中最晚者
- 没有候选时:本次请求还没有上游失败则返回 429,
Retry-After为该模型最早的恢复时刻;已有上游失败则返回最近一次失败,该模型的账户都在冷却时带上其中最早的恢复时刻作为Retry-After - 会话粘连:同一会话(会话记录的
cascade_id)一小时内沿用上次的账户,该账户在候选中且有空闲槽位时直接使用,否则按第 5、6 步改选;每次选中都把会话绑定到选中的账户,有效期为一小时;粘连每分钟清理一次过期项 - 在有空闲槽位的候选中取
priority最大的一组;模型在PREFER_LOWER_TIER_MODELS中(按目录 ID 或去掉-low、-medium、-high后缀的族 ID 匹配)时,再取其中套餐等级最低的一组。套餐等级按paid_tier,没有时按tier:ID 含ultra为 Ultra,含pro为 Pro,其余为 Free fill-first:其中账户池顺序的第一个;round-robin:其中进行中请求最少者,并列时取最近一次被选中最早者(从未被选中的最先),再并列时取账户池顺序靠前者;“被选中”按选中时刻计,会话粘连与第 5、6 步的选中都算一次- 候选都没有空闲槽位时等待,直到槽位释放或账户池变化后重新选择;等待计入从生成开始的
REQUEST_TIMEOUT,超时返回 504等待上游超过 REQUEST_TIMEOUT,客户端断开时停止等待
| 情形 | 状态码 | 消息 |
|---|---|---|
| 账户池为空 | 503 | 首行 没有就绪账户 |
| 模型只在未就绪账户的目录中 | 503 | 首行 模型 <名称> 所在的账户尚未就绪 |
| 模型不存在 | 404 | 模型 <名称> 不在账户目录中 |
| 周额度唤醒的账户不在账户池 | 503 | 账户 <账户> 未就绪 <原因> |
- 账户池为空时,首行之后每行一个
<账户>: <原因>,只列出有原因的账户(含因违反条款停用的账户),尚未完成初始化的账户不在其中,按行的字典序排列 - 模型只在未就绪账户的目录中时,首行之后每行一个
<账户>: <原因>,列出目录含该模型的已启用未就绪账户,按添加时间排列,没有原因时写初始化中
图像、语音转写与 Tab 补全请求按同样的步骤选择账户,“目录中有该模型”指账户的公开目录(含 imageGenerationModelIds、audioTranscriptionModelIds 的条目与 Tab 补全条目)中有该 ID;Tab 补全不按会话粘连。
单账户并发上限为 ACCOUNT_CONCURRENCY,调度策略为 ROUTING_STRATEGY,额度保留比例为 QUOTA_RESERVE_PERCENT,每个请求读取当前值。开启 AI 积分超额使用的账户发出的 agent 请求,信封带 enabledCreditTypes: ["GOOGLE_ONE_AI"](见协议参考)。
生成从开始到首个上游事件、相邻两个上游事件之间各受 REQUEST_TIMEOUT 限制;超时时取消上游,首个事件前返回 504,流开始后以超时错误事件结束。
- 401:上游返回 401 时丢弃 access token,在同一账户上重发一次;token 端点拒绝刷新时不重发
- 处理顺序:仍失败时按下表的原因处理账户,再决定是否换账户
- 换号上限:一个请求依次尝试可调度的账户,每个账户一次,最多 12 个;本次失败为没有恢复时刻的限速 429 时最多 2 个
- 结束:失败不换账户、达到换号上限或候选用尽时返回最近一次失败(候选用尽见“选择账户”第 3 步),超过
REQUEST_TIMEOUT时返回 504 - 流中错误:上游流以错误中断时,流式请求在客户端收到首个事件前、非流式请求在生成结束前(非流式请求的事件在生成结束后才写出)同样按原因换账户重新生成
- 已写出事件:客户端已收到事件后的错误只处理账户,不换号
| 失败 | 判定 | 账户处理 | 换账户 |
|---|---|---|---|
| 认证失败 | token 端点以 4xx 拒绝刷新,或重发后仍为 401 | 移出调度 | 是 |
| 需要验证 | 403,VALIDATION_REQUIRED 或消息含 verify your account |
移出调度,保持启用 | 是 |
| 违反条款 | 403,TOS_VIOLATION 或消息含 terms of service |
写为停用 | 是 |
| 没有许可 | 403,SUBSCRIPTION_REQUIRED 或消息含 license、subscription |
该模型冷却 1 小时 | 是 |
| 额度耗尽 | QUOTA_EXHAUSTED、INSUFFICIENT_G1_CREDITS_BALANCE |
额度组冷却到恢复时刻 | 是 |
| 容量不足 | MODEL_CAPACITY_EXHAUSTED |
不冷却 | 是 |
| 请求内容 | 429,没有 ErrorInfo 与恢复时刻 | 不冷却 | 否 |
| 限速 | 其他 429 | 该模型冷却到恢复时刻,没有时 1 分钟 | 是 |
| 内部错误 | 500 INTERNAL |
该模型冷却 n 分钟,n 为连续次数 | 是 |
| 连接错误 | 没有 Cloud Code 的 HTTP 错误响应 | 不冷却,请求检测代理池 | 是 |
| 已下线模型 | 下线提示,见协议参考“已下线与不存在的模型 ID” | 不冷却 | 否,返回 404 |
| 输入过滤 | 过滤提示,见协议参考“输入过滤” | 不冷却 | 否,返回 400 |
| 其他 | 其余上游错误 | 不冷却 | 否 |
- 额度耗尽:同一共享额度池的账户一起冷却,后台读取该账户额度;图像生成模型只冷却该账户的该模型
- 连接错误:DNS、TCP、TLS 与代理失败,token 端点的 5xx 与 429,语音转写的 gRPC 错误;客户端未取消时才请求检测代理池。请求账本中这类尝试的状态码为 0,错误阶段为
network - 恢复时刻依次取 RetryInfo
retryDelay、ErrorInfometadata.quotaResetDelay与quotaResetTimeStamp;额度耗尽都没有时取目录quotaInfo.resetTime,再没有时 1 分钟 - 连续 INTERNAL 次数在该账户下一次成功生成后清零
- 限速的恢复时刻在 5 秒内时,请求等到恢复时刻后再次使用该账户,同一请求在每个账户上只等一次,不计入 12 个账户的上限
- 移出调度的原因显示在管理端;需要验证时正文中的
validation_url作为验证链接 - 图像、语音转写与 Tab 补全请求按同一张表处理失败;上游请求成功返回后流中出现的错误不换账户
同一 Google 家庭方案的成员账户共享同一组额度桶,本文称为共享额度池。两个就绪账户在某额度组(gemini 或 3p)属于同一共享额度池,条件是两者最近一次读到的额度摘要中该组的窗口集合相同,且每个窗口的 resetTime 文本完全相同;判定随时按最近一次读取进行,与是否耗尽无关。
| 使用位置 | 规则 |
|---|---|
| 额度耗尽 | 某账户额度组耗尽时,同一共享额度池的其他账户一起冷却到同一时刻 |
GET /api/accounts 的 shared |
{"gemini":["<邮箱>"],"3p":["<邮箱>"]} |
| 账户页 | 有 shared 时显示家庭组徽标(账户表中只有图标,详情中带“家庭组”文字),悬停列出各组成员 |
| 仪表盘额度均值、托盘额度 | 同一共享额度池只计一次 |
shared按账户池顺序列出同一池的其他成员,没有成员的组省略,两组都没有时省略shared
管理 API 挂在 /api/,与公开 API 共用监听:
- 只接受同源请求:
Sec-Fetch-Site: cross-site或Origin与Host不一致时返回 403admin_origin_forbidden - 本机回环访问免登录:对端地址是回环 IP,
Host的主机部分为localhost(不区分大小写)或回环 IP(如localhost:8017、127.0.0.1:8017、[::1]:8017),且没有X-Forwarded-For、Forwarded、X-Real-IP - 远程访问需要
ADMIN_AUTH_ENABLED=true,否则返回 401admin_remote_disabled;未登录返回 401admin_login_required - 会话 Cookie
antigravity_admin:12 小时,Path=/api、HttpOnly、SameSite=Strict,经 TLS 或X-Forwarded-Proto: https时带 Secure;会话结束时取消该会话的进行中管理请求 - 同一客户端 IP 一分钟内登录失败 5 次后返回 429
login_rate_limited,Retry-After: 60 - 响应带
Cache-Control: no-store;错误体为{"error":{"code","message"}};未知路由返回 404not_found,消息为管理 API 不存在: <方法> <路径>
| 方法与路径 | 作用 |
|---|---|
GET /api/session |
是否开启登录、当前请求是否可访问 |
POST /api/session |
用户名与密码登录 |
DELETE /api/session |
退出登录 |
GET /api/status |
宿主、版本、监听地址、启动时间、模拟的客户端版本、官方最新版本 |
GET /api/update、POST /api/update |
本程序的最新发行版本与在线更新,见第 6 节 |
GET /api/proxies |
代理池中每个代理的地址(密码替换为 xxxxx)、是否可用、检测时间、延迟、错误与绑定的账户 |
POST /api/proxies/check |
立即检测代理池,返回检测后的状态 |
GET /api/accounts |
全部账户 |
PATCH /api/accounts/{id} |
启用、停用,设置账户代理、优先级、备注名或 AI 积分超额使用 |
DELETE /api/accounts/{id} |
删除账户目录 |
POST /api/accounts/{id}/verify |
重新初始化 error 状态的账户 |
POST /api/accounts/import |
导入本机官方客户端账户 |
POST /api/accounts/{id}/switch |
把账户写入本机官方客户端并重新启动它 |
POST /api/accounts/{id}/quota |
读取该账户的额度并返回账户 |
POST /api/accounts/refresh |
同步刷新账户池并读取全部账户的额度 |
POST /api/logins |
开始登录,mode 为 browser 或 code |
POST /api/logins/{id}/code |
提交授权码或回调地址,等到登录结束 |
DELETE /api/logins/{id} |
取消登录 |
POST /api/pairing |
生成远程配对令牌 |
POST /api/pairing/accounts |
凭配对令牌导入 token,不经管理会话 |
GET /api/models |
公开模型目录与各模型的就绪账户数 |
GET /api/quota/snapshots |
范围内的额度快照 |
GET /api/usage |
用量报告 |
GET /api/usage/records |
一页请求记录 |
GET /api/usage/records.csv |
导出请求记录 |
GET /api/usage/records/{id} |
请求记录、公开正文与上游尝试正文 |
GET /api/requests |
进行中的公开请求 |
POST /api/requests/{id}/cancel |
停止进行中的请求 |
GET /api/logs |
一页已入库的 WARN 以上日志 |
DELETE /api/logs |
清空日志 |
GET /api/prompt/preview |
系统提示档位的原文预览 |
GET /api/settings |
.env 中保存的配置 |
PATCH /api/settings |
合并保存配置 |
GET /api/events |
管理事件流(SSE) |
各接口的请求体与响应:
| 接口 | 请求体 | 成功响应 | 错误 |
|---|---|---|---|
GET /api/session |
— | {"enabled","authenticated"}:是否开启登录、当前请求是否可访问 |
— |
POST /api/session |
{"username","password"} |
{"enabled":true,"authenticated":true} 并设置 Cookie |
400 invalid_request、admin_auth_disabled,401 invalid_credentials,429 login_rate_limited |
DELETE /api/session |
— | 204 并清除 Cookie | — |
GET /api/status |
— | {"host","version","listen","started_at","client_version","latest_version"},latest_version 未读到时为空串 |
— |
GET /api/update |
— | {"current","latest","available","mode","notes","url","published_at","checked_at","error","updating"},空值字段省略 |
502 update_check_failed,见“在线更新” |
POST /api/update |
— | 202,同上 | 409 update_conflict,502 update_failed |
GET /api/proxies、POST /api/proxies/check |
— | {"proxies":[{"url","healthy","checked_at","latency_ms","error","accounts"}]} |
— |
GET /api/accounts |
— | {"accounts":[账户]} |
— |
PATCH /api/accounts/{id} |
见下方 | 账户 | 400 invalid_request、invalid_proxy,404 account_not_found,500 account_update_failed |
DELETE /api/accounts/{id} |
— | 204 | 404 account_not_found,500 account_delete_failed |
POST /api/accounts/{id}/verify |
— | 账户 | 404 account_not_found,409 account_not_verifiable,502 account_verify_failed |
POST /api/accounts/import |
— | {"accounts":["<邮箱>"]} |
502 import_failed |
POST /api/accounts/{id}/switch |
— | {"account":"<邮箱>"} |
404 account_not_found,502 switch_failed |
POST /api/accounts/{id}/quota |
— | 账户 | 404 account_not_found,502 quota_refresh_failed |
POST /api/accounts/refresh |
— | {"accounts":[账户],"failed":{"<邮箱>":"<原因>"}} |
— |
POST /api/logins |
{"mode":"browser"或"code"} |
201 登录状态 | 400 invalid_request,502 login_failed |
POST /api/logins/{id}/code |
{"code":"<授权码或回调地址>"} |
登录结束后的登录状态 | 400 invalid_request、login_callback_rejected,404 login_not_found,409 login_code_submitted |
DELETE /api/logins/{id} |
— | 204 | 404 login_not_found |
POST /api/pairing |
— | 201 {"token","expires_at"} |
— |
POST /api/pairing/accounts |
oauth2.Token JSON,Authorization: Bearer <令牌> |
201 {"account":"<邮箱>"} |
400 invalid_request,401 pairing_token_invalid,502 pairing_import_failed |
GET /api/models |
— | {"models":[公开模型对象加 "accounts"]} |
502 models_failed |
GET /api/requests |
— | {"requests":[请求记录]},按开始时间升序 |
— |
POST /api/requests/{id}/cancel |
— | 204 | 404 request_not_found |
DELETE /api/logs |
— | 204 | 500 logs_clear_failed |
GET /api/settings、PATCH /api/settings |
见“设置与系统提示预览” | 设置对象 | 400 invalid_request、invalid_settings,500 settings_unreadable、settings_save_failed、settings_apply_failed |
-
请求体不是合法 JSON 时返回 400
invalid_request -
switch在找不到官方客户端、无法结束它或写入凭据失败时返回 502switch_failed -
POST /api/logins的mode为browser时等待回环回调,其余值都按code模式运行,登录状态的mode为提交的原值 -
登录状态为
{"id","mode","url","state","account","error","expires_at"}:state为pending、completed、failed或canceled,account只在completed时出现,error只在failed与canceled时出现;事件流的login事件携带同一对象 -
请求记录与用量的字段见 运行日志与请求账本;进行中请求的
state为running,结束后的取值见其中的“请求结果”;请求结果写作cancelled,登录状态写作canceled -
进行中请求的记录:
time为开始时间,duration_ms为截至读取时的已用时间,account为最近一次分配的账户,尚未分配时为空串,其余字段为截至读取时的值 -
公开模型对象为
antigravity.Model的 JSON:id、name、description、methods、input_token_limit、output_token_limit、capabilities、provider、quota_group、thinking_levels、default_thinking_level,空值省略 -
accounts为就绪账户中目录含该模型的账户数:族条目按族内任一档位计,每个账户计一次;别名取目标模型的值
同一监听上的其他入口:/v1/、/v1beta/、/upload/ 为公开 API(未知路径见第 2 节“api 层的公开接口规则”),/media/ 为生成媒体(不校验 API key),POST /api/pairing/accounts 为远程配对上传;其余路径由管理端静态资源处理:
| 请求 | 响应 |
|---|---|
GET、HEAD 以外的方法 |
405,Allow: GET, HEAD |
assets/ 下存在的文件 |
该文件,Cache-Control: public, max-age=31536000, immutable |
| 其他存在的文件 | 该文件,Cache-Control: no-cache |
assets/ 下不存在的文件 |
404 |
/、/index.html 与其他路径 |
200 入口页 index.html,Cache-Control: no-cache |
同一监听上的全部响应带 X-Frame-Options: DENY、Content-Security-Policy: frame-ancestors 'none'、X-Content-Type-Options: nosniff 与 Referrer-Policy: no-referrer。
GET /api/accounts 的每个账户:
| 字段 | 内容 |
|---|---|
id |
邮箱 |
label |
备注名,没有时省略 |
state |
见“账户状态” |
tier |
有付费套餐时为 paid_tier,否则 tier |
project |
上游项目 |
proxy |
账户代理,密码替换为 xxxxx |
added_at、token_expiry |
添加时间、access token 到期时间 |
priority |
调度优先级 |
ai_credits |
是否开启 AI 积分超额使用 |
active |
进行中请求数 |
error、verify_url |
停止调度的原因、验证链接 |
cooldown |
冷却中的额度组或模型 ID 到截止时间 |
quota、quota_at |
最近一次读到的额度桶(bucket_id、window、remaining_fraction、reset_time)及读取时间,尚未读取时 quota 为空数组、省略 quota_at |
shared |
按额度组列出同一共享额度池的其他就绪账户,形状见“共享额度池” |
device |
设备档案各字段,加上由档案得出的 hostname 与 user_agent |
PATCH /api/accounts/{id} 接受 {"enabled": bool, "proxy": "<URL>", "priority": int, "label": "<备注名>", "ai_credits": bool} 中的任意几项,proxy 去掉首尾空白后为空串时跟随全局,为 direct 时直连,其余须为带主机的 http、https 或 socks5 URL,否则返回 400 invalid_proxy;label 去掉首尾空白后保存,为空时清除;保存后后台刷新账户池,代理变化的账户重新初始化。
管理端登录:
POST /api/logins在后台开始一次 OAuth 登录,ID 为小写随机文本,限时 5 分钟;授权期间以新生成的设备档案运行登录前虚拟进程- 取得授权链接后返回 201
{id, mode, url, state: "pending", expires_at},并推送login事件 code模式:把页面给出的授权码或带code参数的地址提交给POST /api/logins/{id}/code;已提交过时返回 409login_code_submittedbrowser模式:服务在本机回环端口等待回调(地址取授权链接的redirect_uri);浏览器不在同一台机器时,把地址栏中的回调地址提交给/code,服务把其中的查询参数转交给回环监听;回环监听返回 302 以外的状态时返回 400login_callback_rejected,消息为回调地址被拒绝:加回环监听的应答正文(state mismatch或OAuth error: <error>)。回调带error(在授权页拒绝)而state正确时回环监听返回 400,登录以OAuth error: <error>结束为failed(见协议参考「回环回调」)/code等到登录结束后返回登录状态;DELETE /api/logins/{id}取消登录- 结束时推送
login事件:成功为completed(带account),随后后台刷新账户池
| 结束情形 | state |
error |
|---|---|---|
| 账户已写入账户目录 | completed |
— |
| 取消或服务退出 | canceled |
登录已取消 |
| 超过 5 分钟 | failed |
5 分钟内没有完成 Google 登录 |
| 其他错误 | failed |
错误文本 |
远程配对:POST /api/pairing 生成 10 分钟有效的令牌,同时只有一个有效令牌,服务只保存其 SHA-256。login --remote <地址> --token <令牌>:
- 本机:与
login相同地运行登录前虚拟进程并完成浏览器或授权码登录,拿到 token 后不写本机auth/ - 上传:把
oauth2.Token的 JSON(access_token、token_type、refresh_token、expiry,不含id_token)以Authorization: Bearer <令牌>POST 到<地址>/api/pairing/accounts,经进程环境变量的代理发出;返回 201 以外时打印远程服务返回 <状态>: <正文>并失败 - 远程:以 userinfo 取得邮箱,新账户随机生成设备档案,已有账户只更新 token;成功返回 201
{"account": "<邮箱>"}并使令牌失效,本机打印已添加账户 <邮箱> 到 <地址>
GET /api/settings 返回设置对象:
| 字段 | 内容 |
|---|---|
values |
.env 叠加进程环境变量后的各项,不含 ADMIN_PASSWORD |
admin_password_set |
是否已设置管理密码 |
restart_required |
需要重启才生效的项 |
values不叠加启动参数,各值按写回.env的格式写成文本(见“配置”)restart_required列出该配置叠加启动参数后与启动值不同的LISTEN、AUTH_DIR、RUNTIME_DIR
PATCH /api/settings 接受 {"values": {键: 文本值}}:
- 只合并提交的键,校验失败返回 400
invalid_settings - 提交
ADMIN_PASSWORD时以提交值(含空串)替换密码,不提交时保持原值;管理端只在密码输入框非空时提交该键
GET /api/prompt/preview?tier=§ions=&wrap= 以占位数据渲染档位,返回 {system, user, sections}:
| 字段 | 内容 |
|---|---|
system |
系统指令 |
user |
首个 user 轮 <user message> 包装后的文本 |
sections |
[{"name","text"}],按官方顺序列出 10 个段 |
| 占位项 | 值 |
|---|---|
| 客户端系统提示 | <client system prompt> |
| 会话 ID | <conversation-id> |
AppDataDir |
C:\Users\user\.gemini\antigravity |
| 系统 | windows |
| 模型名 | <model> |
| 本地时间 | 2026-10-15T14:00:00+08:00 |
sections的text为以同一占位数据渲染的段原文- 省略的参数取当前配置;
sections与wrap只用于custom - 参数无效时返回 400
invalid_prompt
| 参数 | 用于 | 含义 |
|---|---|---|
from、to |
全部查询 | RFC 3339 时间范围,含 from 不含 to,必填 |
model、account、api_key、protocol、state、quota_group |
用量、记录 | 逗号分隔的筛选值,同一维度多值为或,维度之间为且 |
bucket |
用量 | auto 或 60、300、900、3600、86400 秒 |
tz |
用量 | 分桶对齐的 IANA 时区,默认 UTC |
stack |
用量 | 堆叠维度,取筛选维度之一,默认 model |
status、q |
记录 | HTTP 状态码、关键字 |
limit、cursor |
记录 | 页大小(正整数,默认 50)、上一页的 next_cursor |
level、source、request_id、model、q、limit、before |
日志 | 见下方日志参数 |
account |
额度快照 | 账户 |
bucket=auto 时按范围选择:2 小时内 1 分钟,12 小时内 5 分钟,8 天内 1 小时,更长 1 天;分桶数超过 1500 时返回 400。报告与记录的字段见 运行日志与请求账本。
| 接口 | 成功响应 | 账本读取失败 |
|---|---|---|
GET /api/usage |
用量报告对象 | 500 usage_failed |
GET /api/usage/records |
{items, next_cursor} |
500 records_failed |
GET /api/usage/records.csv |
CSV 附件 | 响应在出错处结束,写 ERROR 日志 |
GET /api/usage/records/{id} |
{record, body, upstream} |
500 record_failed |
GET /api/quota/snapshots |
{snapshots} |
500 quota_snapshots_failed |
GET /api/logs |
{items, next_before} |
500 logs_failed |
next_cursor只在还有更早的记录时出现,原样作为下一页的cursor;next_before只在还有更早的日志时出现,作为下一页的before- 列表为空时
items与snapshots为[];报告、记录与额度快照中的时间及日志条目的time为 UTC 的 RFC 3339 文本 - 参数无效返回 400
invalid_request,message说明原因:from或to不是 RFC 3339、tz不是 IANA 时区名、bucket不在可选值中、分桶数超过 1500、stack不是筛选维度、status或before不是整数、limit不是正整数、cursor无效 - 记录不存在返回 404
record_not_found
日志参数:
| 参数 | 匹配 |
|---|---|
source、request_id、model |
单个值,完全相等 |
level |
error 只返回 ERROR,其他值返回全部 |
q |
消息与属性文本的子串 |
limit |
页大小,默认 100 |
before |
序号小于该值 |
level不区分大小写;已入库的日志只有 WARN 与 ERROR,level为error以外的值或省略时两者都返回q去掉首尾空白后匹配,ASCII 字母不区分大小写,%、_、\按字面匹配before省略或不大于 0 时从最新一条开始;日志按序号从新到旧排列
| 页面 | 内容 |
|---|---|
| 仪表盘 | 首次使用三步引导、账户与额度总览、推荐账户、最近请求、额度变化 |
| 账户 | 添加、刷新、筛选、搜索、排序、分页、额度与重置倒计时、刷新单个账户额度、家庭组徽标(共享额度池)、验证、启停、批量操作、详情、调度优先级、备注名、AI 积分超额使用、设备档案、切换官方客户端、代理、删除 |
| 接入 | OpenAI、Anthropic 与 Gemini 兼容接口的 base URL(OpenAI 兼容含 Chat 与 Responses 两个协议)、API key 管理、客户端配置片段 |
| 模型 | 额度组、上下文与输出上限、思考档位、可用账户数、模型映射(可编辑) |
| 请求 | 进行中请求(可停止)、请求记录、用量、日志 |
| 设置 | 服务、网络、系统提示(各系统提示档位的原文,custom 的段落与包装)、调度(含优先用低套餐账户的模型、额度保留比例与周额度唤醒)、日志、远程访问、关于 |
各页面的组成:
| 页面 | 区块 | 内容 |
|---|---|---|
| 账户 | 账户表 | 列为账户、状态、Gemini、Claude 与 GPT、操作,各行等高 |
| 账户 | 账户详情 | 额度、调度设置、用量、资料、设备档案与操作 |
| 模型 | 模型映射卡片 | 逐行编辑别名与目标模型 |
| 仪表盘 | 最近请求 | 近 24 小时最近 5 条请求 |
| 账户 | 搜索与分页 | 匹配邮箱、备注名与项目,每页 20 个 |
| 模型 | 搜索 | 匹配模型 ID 与显示名 |
| 请求 | 进行中 | 进行中请求与“停止” |
| 请求 | 记录表 | 每条请求一行 |
| 请求 | 记录详情 | 单条记录与各上游尝试 |
| 用量 | 统计卡片 | 请求、缓存命中率、token、耗时、费用 |
| 用量 | 趋势与分项 | 用量趋势图与分项表 |
- 账户详情:额度与刷新、调度优先级、备注名、AI 积分超额使用、近 30 天用量、资料(套餐、项目、代理、添加时间、access token 到期)、设备档案;操作为重新初始化账户、代理、参与调度、删除、切换到官方客户端
- 模型映射卡片:目标模型的下拉为目录中的模型,可增删行;保存时以
PATCH /api/settings只提交MODEL_MAPPING;别名须非空、不含逗号、不重复,目标模型必选 - 进行中:只在有进行中请求时显示,数据来自事件流;列为时间与协议、模型、账户、已用时、“停止”(
POST /api/requests/{id}/cancel) - 记录表的列为时间、结果、状态码、模型、账户、首字、耗时、输入·缓存·输出、估算费用
- 记录详情:失败阶段、上游状态码、协议与路径、请求模型、上游模型、账户、排队·首字·总耗时、token、估算费用、工具调用、流式、请求类型与系统提示档位、会话与步序、API key、客户端、响应 ID、客户端请求 ID、各上游尝试(账户、状态、耗时、错误、重试等待、traceId)与正文
- 统计卡片的耗时为 p50、p95 与首字;分项表的列为请求数、占比、失败、限流、缓存、思考、回复、p50、p95、费用
- 界面上的“首字”为请求记录的首事件耗时
first_event_ms:请求进入到首个正文、思考或工具调用事件的毫秒数,见运行日志文档 - 仪表盘最近请求:读取
GET /api/usage/records?from=<当前时间减 24 小时>&to=<当前时间加 1 秒>&limit=5;每行为结果徽标、模型、账户(为空时—)、完成时间与总耗时,点击打开/requests?id=<ID>;没有记录时显示链接到接入页的提示;收到请求结束的request事件后重新读取 - 缓存命中率按 token 计,为
cached_tokens / input_tokens,没有输入 token 时为 0;统计卡片取范围合计,分项表按各行计算 - 账户用量:账户详情的“近 30 天用量”、账户表的“最近使用”与按最近使用排序都读取
GET /api/usage?from=<当前时间减 30 天>&to=<当前时间加 1 秒>&tz=<浏览器时区>&bucket=auto,取groups.account中该账户的一项;详情显示requests、total_tokens与cost_usd,标题旁显示last_at的相对时间,没有该项时显示“30 天内未使用” - 账户页与模型页的
q去掉首尾空白后不区分大小写地按子串匹配:账户页匹配邮箱(id)、备注名与项目,模型页匹配模型 ID 与显示名 - 账户页每页 20 个账户,
page小于 1 时为第 1 页,超过总页数时为最后一页 - 账户表各行等高:账户列为邮箱、标签区与“最近使用”和代理一行,标签区在窗口宽度 1280 以下分两行(备注名与套餐;家庭组、优先级与 AI 积分的图标标签),1280 及以上为一行;状态列为状态标签、原因(异常账户一行,其余至多两行)与“重试”按钮,待验证账户的原因为“打开验证页面”链接;每个额度组固定两个额度桶的高度;截断的文字与图标标签的全文在提示中
- 操作结果以右下角轻提示显示,5 秒后消失;新提示使总数超过 3 条时,从最早的开始移除不带操作按钮的提示,新提示与带“撤销”的提示保留
设置页各分区的配置项(数字项的取值范围见下方):
| 分区 | 配置项 |
|---|---|
服务 service |
LISTEN、AUTH_DIR、RUNTIME_DIR、API key(链接到接入页)、MEDIA_OUTPUT、MEDIA_BASE_URL |
网络 network |
PROXY(每行一个)与代理池状态 |
系统提示 prompt |
SYSTEM_PROMPT、原文预览、SYSTEM_PROMPT_SECTIONS、SYSTEM_PROMPT_WRAP |
调度 scheduling |
ROUTING_STRATEGY、PREFER_LOWER_TIER_MODELS、ACCOUNT_CONCURRENCY、REQUEST_TIMEOUT、QUOTA_REFRESH_INTERVAL、QUOTA_RESERVE_PERCENT、WEEKLY_QUOTA_WARMUP |
日志 logging |
LOG_LEVEL、LOG_FORMAT、LOG_FILE、LOG_MAX_TOTAL_MB、REQUEST_LOG_BODIES |
远程访问 remote |
ADMIN_AUTH_ENABLED、ADMIN_USERNAME、ADMIN_PASSWORD(已设置时输入框为空并显示占位) |
关于 about |
版本与在线更新、宿主、监听地址、API 地址、启动时间、模拟的客户端版本与官方最新版本、许可证、主页、发行页 |
| 数字项 | 加减按钮范围 | 可提交的值 |
|---|---|---|
ACCOUNT_CONCURRENCY |
1–64 | 正整数 |
QUOTA_RESERVE_PERCENT |
0–99 | 0–99 的整数 |
LOG_MAX_TOTAL_MB |
20–100000 | 不小于 20 的整数 |
- 加减按钮到达范围端点时停用;输入框中直接键入的值不受按钮范围限制,按“可提交的值”校验,与服务端一致
前端源码在 web/src,路由定义在 app/router.tsx,页面按路由拆分加载。除 /login 外,页面都在外壳 app/Layout.tsx(顶栏与内容区)内。
| 路径 | 页面 | 查询参数 |
|---|---|---|
/login |
登录 | next |
/ |
仪表盘 | — |
/accounts |
账户 | state、q、sort、page、account |
/connect |
接入 | client |
/models |
模型 | group、q |
/requests |
请求记录 | range、state、protocol、model、account、q、cursor、id |
/requests/usage |
用量 | range、by |
/requests/logs |
日志 | view、level、source、q、range、request_id |
/settings/:分区 |
设置 | — |
| 其余路径 | 页面不存在 | — |
设置分区为 service、network、prompt、scheduling、logging、remote、about,路径中没有或不认识的分区显示 service。
- 外壳先读
GET /api/session,authenticated为 false 时以替换历史的方式转到/login?next=<原路径与查询> - 任一查询返回 401 时重新读取会话,会话无效即转到登录页;查询遇到 5xx 时重试 2 次,4xx 与网络错误不重试
- 登录页:
enabled为 false 时只显示开启方法;提交POST /api/session,401 显示用户名或密码错误,429 显示一分钟后再试;成功后转到next(不以/开头时转到/),已登录时直接转到next - 顶栏导航为仪表盘、账户、接入、模型、请求、设置;仪表盘只在路径为
/时高亮,其余按路径前缀高亮;“退出登录”只在开启登录且已登录时显示,DELETE /api/session后转到/login - 登录后订阅
/api/events:连接打开时清空日志与进行中请求的缓存;accounts替换账户列表,log追加日志(页面保留最近 2000 条),request维护进行中请求并在请求结束时刷新请求记录,login更新对应的登录;断开时内容区顶部显示断线提示,浏览器自动重连并重新收到初始快照
添加账户对话框有浏览器登录、粘贴授权码、导入官方客户端、远程配对四种方式。打开时的默认方式:桌面窗口,或页面主机为 localhost、127.0.0.1、[::1] 时为浏览器登录,其余为粘贴授权码;从仪表盘引导的方式卡片打开时选中该方式。
| 方式 | 流程 |
|---|---|
| 浏览器登录 | POST /api/logins mode=browser → 登录链接与倒计时 → 等待回调或提交回调地址 → 结束 |
| 粘贴授权码 | POST /api/logins mode=code → 登录链接与倒计时 → 提交授权码 → 结束 |
| 导入官方客户端 | POST /api/accounts/import → 导入数量 |
| 远程配对 | POST /api/pairing → 配对命令与倒计时 → 过期后重新生成 |
- 登录链接可打开或复制,倒计时取
expires_at,格式为m:ss;回调地址与授权码都经POST /api/logins/{id}/code提交,提交前去掉首尾空白,为空时提示先粘贴 - 登录状态取自
login事件与提交结果:completed显示账户邮箱与“完成”按钮;failed显示原因;canceled或倒计时归零显示已过期;失败与过期时可“重新开始”生成新链接 - 关闭对话框时,
pending的登录以DELETE /api/logins/{id}取消;切换方式时清空当前登录与提交状态 - 配对命令为
antigravity2api login --remote <页面 origin> --token <令牌>
账户列表为空时仪表盘显示三步引导。引导期间添加了账户时保留引导并显示“进入仪表盘”;之后再打开仪表盘时显示总览。
| 步骤 | 完成条件 |
|---|---|
| 添加账户 | 账户列表非空 |
| 复制接口地址与 API key | 复制过任一接口地址或 API key,或近 24 小时有请求 |
| 复制客户端配置 | 复制过任一客户端配置片段或配置项,或近 24 小时有请求 |
- 复制记录保存在
localStorage的antigravity2api.setup,内容为{"endpoint": bool, "client": bool, "dismissed": bool};本地存储不可用时只在当前页面有效 - 有账户、后两步未全部完成且
dismissed不为 true 时,总览顶部显示三步进度条,“隐藏”写入dismissed
接口地址取页面自身的 origin:OpenAI 兼容为 <origin>/v1,Anthropic 兼容与 Gemini 兼容为 <origin>。
API key 列表取自 GET /api/settings 的 API_KEYS(逗号分隔):
- “添加 API key”对话框预填随机值:
sk-加 32 位字母与数字,取自crypto.getRandomValues;可重新生成或换成自定义值 - 修改打开同一对话框,预填原值
- 保存前去掉首尾空白;值不能为空、不能含空白或逗号、不能与其他 key 相同
- 添加、修改与删除都以
PATCH /api/settings只提交API_KEYS;删除立即保存,5 秒内可撤销,撤销时写回原列表
客户端配置片段中的占位取值:
| 占位 | 取值 |
|---|---|
<origin> |
页面 origin |
<key> |
选中的 API key,默认第一个;没有 key 时为 antigravity2api |
<model> |
选中的模型 |
<small> |
Claude Code 后台任务模型 |
- 可选模型为实时目录中的 Agent 模型或普通对话模型,不含图像生成、语音转写与 Tab 补全模型;目录为空时
<model>与<small>写成<模型 ID> <model>的默认值:Claude Code 取第一个provider含 anthropic 的模型,其余客户端取第一个 ID 含flash的模型,没有时取第一个模型;<small>默认取第一个 ID 含flash的模型- 环境变量按终端选择写法:macOS / Linux 为
export NAME=value,Windows PowerShell 为$env:NAME = "value";默认值按浏览器 User-Agent 是否含Windows选择 - 选中的客户端写入
?client=,取值为claude-code(默认)、codex、opencode、cherry-studio、curl
Claude Code 的终端命令(PowerShell 写法同上替换)与 ~/.claude/settings.json:
export ANTHROPIC_BASE_URL=<origin>
export ANTHROPIC_AUTH_TOKEN=<key>
export ANTHROPIC_MODEL=<model>
export ANTHROPIC_DEFAULT_HAIKU_MODEL=<small>
claude{
"env": {
"ANTHROPIC_BASE_URL": "<origin>",
"ANTHROPIC_AUTH_TOKEN": "<key>",
"ANTHROPIC_MODEL": "<model>",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "<small>"
}
}Codex 的 ~/.codex/config.toml 与终端命令:
model = "<model>"
model_provider = "antigravity"
[model_providers.antigravity]
name = "Antigravity2API"
base_url = "<origin>/v1"
env_key = "ANTIGRAVITY2API_KEY"
wire_api = "responses"export ANTIGRAVITY2API_KEY=<key>
codexOpenCode 的 ~/.config/opencode/opencode.json,models 列出全部可选模型,名称为目录中的显示名,没有时为 ID:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"antigravity2api": {
"npm": "@ai-sdk/openai-compatible",
"name": "Antigravity2API",
"options": { "baseURL": "<origin>/v1", "apiKey": "<key>" },
"models": { "<模型 ID>": { "name": "<显示名>" } }
}
},
"model": "antigravity2api/<model>"
}Cherry Studio 在“设置 › 模型服务”中添加提供商,各项单独复制:
| 项 | 值 |
|---|---|
| 提供商类型 | OpenAI |
| API 地址 | <origin> |
| API 密钥 | <key> |
| 模型 | 全部可选模型 ID,逗号分隔 |
curl 给出三个请求:
curl <origin>/v1/chat/completions \
-H "Authorization: Bearer <key>" \
-H "Content-Type: application/json" \
-d '{"model": "<model>", "stream": true, "messages": [{"role": "user", "content": "Hello"}]}'
curl <origin>/v1/messages \
-H "x-api-key: <key>" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model": "<model>", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}'
curl "<origin>/v1beta/models/<model>:generateContent" \
-H "x-goog-api-key: <key>" \
-H "Content-Type: application/json" \
-d '{"contents": [{"role": "user", "parts": [{"text": "Hello"}]}]}'- 勾选账户后显示批量操作栏:启用、停用、刷新额度、重新初始化(只作用于所选账户中
state为error的账户)、删除;对所选账户逐个调用单账户接口,结束后提示完成数量与失败的账户;批量删除 5 秒内可撤销 - 排序:按添加时间(默认);按重置时间,取各额度桶中剩余比例低于 100% 的最早
reset_time,从早到晚;按最近使用,取近 30 天用量中各账户的last_at,从近到远。没有对应时间的账户排在后面,保持添加顺序
| 量 | 计算 |
|---|---|
| 可用比例 | 一个额度组 5 小时与每周 remaining_fraction 中较小的一项 |
| Gemini 额度、Claude 与 GPT 额度 | 两项,分别对应额度组 gemini 与 3p:已启用账户该组可用比例的平均 |
| 5 小时、每周均值 | 每个额度组各一对:已启用账户该组该窗口剩余比例的平均 |
| 低额度账户 | 已启用且任一额度桶低于 20% 的账户数 |
| 就绪账户 | state 为 ready 的账户数 / 总数,说明中列出其余状态的数量 |
| 24 小时请求 | 近 24 小时请求数、失败数与估算费用 |
| 推荐账户 | 每个额度组中可用比例最高的账户 |
- 已启用指
state不是disabled;计算额度均值时,同一共享额度池的账户只取列表中第一个出现的,没有该组额度的账户不计入 - 推荐账户的候选:界面状态为就绪或冷却中、该组不在
cooldown中、可用比例大于 0;比例相同时取列表靠前的账户 - 界面状态:
error且带verify_url为“需验证”,其余与state相同 - 比例条颜色:不低于 30% 为绿色,10% 到 30% 为黄色,低于 10% 为红色
- 重置倒计时取
reset_time与当前时间之差,向上取整到分钟,写成6d 15h、1h 16m、12m,为零的部分省略,已过重置时间时不显示;账户页与仪表盘每 30 秒刷新一次
| 图表 | 数据 | 系列与单位 | 范围 |
|---|---|---|---|
| 用量趋势 | GET /api/usage 的 buckets |
逐桶请求数柱状图 | 24 小时、7 天(默认)、30 天、90 天 |
| 额度变化 | GET /api/quota/snapshots |
四个额度桶的剩余比例折线,0–100% | 24 小时(默认)、7 天 |
- 用量趋势:分桶由服务按
bucket=auto选择,tz为浏览器时区;柱高按范围内最大请求数归一,有请求的桶至少 2%;分组为“日期”时以bucket=86400按本机自然日分桶,不显示趋势 - 额度变化:24 小时分 96 段,7 天分 168 段;每段取各账户在段末之前最近一次快照的剩余比例再求平均,段末之前没有快照的桶在该段断开;Gemini 为蓝色、Claude 与 GPT 为紫色,实线为 5 小时、虚线为每周;可按账户筛选,范围与账户不写入 URL
- 页面上的筛选、范围、分组、视图、客户端、页码与打开的详情写入查询参数(见路由表),刷新或分享链接得到同一页面
- 不认识或缺省的取值使用默认值:账户状态全部、按添加时间排序,模型额度组全部,请求记录范围
24h,用量范围7d、分组model,日志视图live、级别全部,已保存日志范围24h;用量页之外的默认值不写入 URL - 筛选变化替换当前历史记录;请求记录翻页与打开详情新增历史记录,其余筛选变化同时清除
cursor - 请求记录与已保存日志的时间范围截止到当前时间之后 1 秒;实时日志在页面内按最低级别、来源与关键词(匹配消息与来源,不区分大小写)筛选
| 页面 | 参数取值 |
|---|---|
| 账户 | state:ready、cooling、verify、error、disabled;sort:reset、used |
| 模型 | group:gemini、3p |
| 请求记录 | range:1h、24h、7d、30d;state:结果;protocol:四种公开协议 |
| 用量 | range:24h、7d、30d、90d;by:model、api_key、account、day |
| 日志 | view:live、saved;实时 level:INFO、WARN、ERROR;已保存 range:24h、7d、30d,level=ERROR |
数字与时间用 Intl 按界面语言的区域格式化(简体中文 zh-CN、繁体中文 zh-TW、英文 en),时间按浏览器时区显示,全站使用等宽数字。
| 类型 | 格式 |
|---|---|
| 整数 | 千分位 |
| 大数 | 紧凑写法,最多 1 位小数 |
| token 上限 | 1024 的整数倍按 1024 进制,其余按 1000 进制,写成 K、M |
| 百分比 | 最多 1 位小数 |
| 费用 | 美元;大于 0 且小于 1 时保留 4 位有效数字,其余最多 2 位小数 |
| 时长 | 不足 1 秒为整数毫秒;不足 10 秒为秒且 2 位小数;不足 1 分钟为秒且 1 位小数;不足 1 小时为分钟;其余为小时 |
| 字节 | 1024 进制,字节取整,KB 起 1 位小数 |
| 相对时间 | 秒、分、时、天逐级进位 |
| 日期时间 | 当天只显示时分秒,其余加月日,24 小时制 |
| 完整时间 | 中等长度的日期与时间,24 小时制 |
- 语言:简体中文
zh、繁体中文(台湾)zh-TW、英文en,保存在localStorage的antigravity2api.language;没有保存值时依次查看浏览器的语言列表,第一个以zh开头的标签中zh-TW、zh-HK、zh-MO、zh-Hant开头的选繁体中文,其余选简体中文,先遇到en开头的标签时选英文,都没有时选英文;html的lang同步为对应区域 - 文案在
web/src/app/messages.ts(外壳与公共文案)与各功能目录的web/src/features/<功能>/messages.ts中,每份以defineMessages(简体中文, 英文, 繁体中文)声明,三种语言的键由类型检查保证一致 - 配色:跟随系统、浅色、深色;浅色与深色保存在
localStorage的antigravity2api.theme,跟随系统时删除该键;结果写入html的data-theme,跟随系统时随系统配色变化切换;index.html在样式表之前同步加载web/public/theme.js,首帧绘制前写入data-theme
| 按键 | 作用 | 生效位置 |
|---|---|---|
/ |
聚焦本页搜索框 | 账户、模型、请求记录、日志;焦点不在输入框且未按 Ctrl、⌘、Alt |
| Ctrl + S、⌘ + S | 保存设置 | 设置页 |
| Tab | 首个焦点为“跳到主要内容” | 全部页面 |
- 桌面版设置页的远程访问默认折叠,相关字段校验出错时展开
- 管理端从
/api/events接收账户、日志、请求与登录事件;静态资源的响应见“管理 API 与管理端”开头的入口表
服务启动 10 秒后读取一次官方客户端的更新清单,此后每小时一次,结果只保存在内存中,/api/status 的 latest_version 高于 client_version 时管理端提示有新版本。请求形态见 逆向指南 第 4 节。
| 项 | 命令行版 | 桌面版 |
|---|---|---|
| 构建 | 默认 | 标签 desktop,production |
| 工作目录 | 启动时的当前目录 | 见表下 |
| 不带参数启动 | serve --open-ui |
打开桌面窗口 |
| 子命令 | 支持 | 支持,见表下 |
| 管理端 | 系统浏览器 | 无边框 WebView 窗口,?shell=desktop |
| 宿主标识 | /api/status 的 host 为 web |
desktop |
- 桌面版的工作目录:Windows 为可执行文件所在目录(便携版);macOS 与 Linux 为用户配置目录下的
Antigravity2API;启动时创建并进入 - 桌面版执行子命令时不检查单实例;Windows 上附加启动它的控制台,没有控制台时新建一个
命令行版不带任何参数启动时等同 serve --open-ui:每 300 ms 请求一次 http://<监听地址的回环形式>/api/status,收到任意 HTTP 响应后用系统浏览器打开 http://<监听地址的回环形式>/,Windows 经 rundll32 url.dll,FileProtocolHandler,macOS 经 open,其余经 xdg-open。
桌面版:
- 单实例:Wails
SingleInstance的标识为com.mag1cfall.antigravity2api,再次启动时显示已有实例的窗口并退出;第一个参数是子命令(--hidden除外)时先执行子命令,不经过单实例检查 - 服务开始监听后显示窗口,服务启动失败时以原生对话框显示原因并退出;Windows 上配置错误等启动前的错误以系统消息框显示
- 窗口标题
Antigravity2API,无边框,背景色#e6e7ed,1280×800,最小 960×600;Windows 与 macOS 关闭窗口后应用留在托盘,窗口与 WebView 进程一并结束,再次显示时重建窗口并载入管理端;Linux 关闭窗口即退出 - 托盘:提示文字为
Antigravity2API,点击图标在新的 goroutine 中显示窗口,窗口重建期间的再次点击(如双击)等重建完成后显示同一窗口;菜单文案为固定的简体中文,依次为:
| 菜单项 | 文案与行为 |
|---|---|
| 额度组剩余(不可点) | Gemini 剩余 <x>%、Claude 与 GPT 剩余 <x>% |
子菜单 各账户额度 |
每个账户一行,见表下 |
刷新额度 |
POST /api/accounts/refresh 后重建菜单 |
显示窗口 |
有 WebView2 时出现 |
在浏览器中打开 |
系统浏览器打开管理端 |
复制 API 地址 |
复制 http://<监听地址的回环形式> |
开机启动 |
勾选项,见下方开机启动表 |
退出 |
结束应用 |
- 额度组剩余没有数据时
<x>%为— 各账户额度每行为<备注名或邮箱> Gemini <x>% · Claude 与 GPT <y>%,停用账户为<名称> 已停用;没有账户时省略该子菜单- 托盘额度经回环地址读取
GET /api/accounts,应用启动后每分钟与“刷新额度”完成后重建菜单:账户在一个额度组的可用比例为该组各额度桶中最低的一项;额度组的剩余为已启用账户可用比例的平均,同一共享额度池的账户只计一次;百分比向下取整;“刷新额度”之后与“开机启动”前后各有一条分隔线 - 带
--hidden启动时只显示托盘,首次显示时创建窗口;开机启动项是否带它见下表 - 页面中的外部链接经系统浏览器打开;Windows 上 WebView 数据保存在
RUNTIME_DIR/webview - Windows 上 WebView2 以
--disable-lcd-text启动,文字使用灰度抗锯齿 - Windows 上经 Wails 查不到 WebView2 运行时版本时只创建托盘,菜单没有“显示窗口”:服务就绪后(
--hidden除外)在默认浏览器打开管理端,单击托盘图标或再次运行可执行文件也打开管理端
窗口地址为 http://<监听地址的回环形式>/?shell=desktop。监听地址的回环形式由 LISTEN 按下表得到,托盘“复制 API 地址”、窗口地址与 status 子命令都用它:
LISTEN 的主机 |
回环形式 |
|---|---|
空(:8017)、0.0.0.0、::([::]:8017) |
127.0.0.1:<端口> |
| 其他(回环地址、局域网 IP、主机名) | 原样,IPv6 带方括号 |
无法按 host:port 解析 |
原文 |
启动时服务在后台协程运行,桌面壳每 50ms 尝试连接监听地址,连上后才运行窗口。
页面与桌面壳的接口:
- 页面把
?shell=desktop存入sessionStorage的antigravity2api.shell(web/src/lib/desktop.ts),同一窗口内跳转与刷新保持桌面模式,顶栏显示窗口按钮并成为拖动区 - 页面加载完成时(Windows
WebViewNavigationCompleted、macOSWebViewDidFinishNavigation、LinuxWindowLoadFinished),桌面壳先代页面发出wails:runtime:ready,使窗口立即执行脚本,再注入internal/desktop/page.js(pageScript)并发送一次最大化状态 - 页面经
window._wails.invoke(<字符串>)向桌面壳发消息:
| 消息 | 作用 |
|---|---|
desktop:open:<绝对地址> |
系统浏览器打开,只接受 http 与 https |
desktop:window:minimise |
最小化 |
desktop:window:toggle-maximise |
最大化或还原 |
desktop:window:close |
关闭窗口 |
wails:drag |
开始拖动窗口 |
wails:resize:<方向>-resize |
从边缘缩放,方向为 n、s、e、w 与组合 |
desktop:open:与desktop:window:由RawMessageHandler按前缀openPrefix、windowPrefix处理,窗口动作取自windowActions,其他动作名忽略;关闭窗口在 Windows 与 macOS 上结束窗口、应用留在托盘- 注入脚本:
target="_blank"或跨源链接的点击、window.open都换成desktop:open:,相对地址按页面地址补全;在计算样式--wails-draggable为drag的元素上按下左键并移动时发wails:drag,双击时发desktop:window:toggle-maximise;距窗口边缘 5px、角落 15px 内按下左键并移动时发缩放消息,鼠标经过边缘时显示对应光标;macOS 与窗口最大化时不做边缘缩放 - 最大化同步:每次窗口尺寸变化与页面加载后,桌面壳执行
window.dispatchEvent(new CustomEvent("desktop:maximised", {detail: <是否最大化>}))(maximisedEvent);注入脚本据此停用边缘缩放,顶栏按钮在“最大化 / 还原”之间切换
开机启动由托盘菜单开关,标识为 com.mag1cfall.antigravity2api(enableAutostart):
| 平台 | 注册方式 | 保存位置 | 启动参数 |
|---|---|---|---|
| Windows | 注册表 Run 项 | HKCU\Software\Microsoft\Windows\CurrentVersion\Run 下同名值 |
--hidden |
macOS 13 及以上的 .app |
SMAppService 登录项 | 系统设置的登录项 | 无 |
| macOS 其他情况 | LaunchAgent | ~/Library/LaunchAgents/com.mag1cfall.antigravity2api.plist |
--hidden |
| Linux | XDG autostart | $XDG_CONFIG_HOME/autostart/com.mag1cfall.antigravity2api.desktop |
无 |
- 开机启动由 Wails
v3.0.0-beta.29的 autostart 实现;“可执行文件”为当前可执行文件解析符号链接后的绝对路径 - Windows:Run 值的数据为可执行文件路径加
--hidden;路径含空格、制表符或"时按 Windows 命令行规则加引号 - macOS:从带 bundle ID 的
.app运行且系统主版本不低于 13 时注册 SMAppService 登录项;其余情况(含 SMAppService 不可用)写 LaunchAgent plist 并以launchctl载入,plist 的Label为com.mag1cfall.antigravity2api,ProgramArguments为可执行文件与--hidden,RunAtLoad为 true,KeepAlive为 false - Linux:
$XDG_CONFIG_HOME未设置时为~/.config;.desktop文件内容如下,Exec为可执行文件,含空格或制表符时加双引号并转义"、\、`、$,不带参数
[Desktop Entry]
Type=Application
Name=Antigravity2API
Exec=<可执行文件>
X-GNOME-Autostart-enabled=true
Hidden=false
NoDisplay=false
Terminal=false- 托盘“开机启动”的勾选状态在每次重建菜单(每分钟与“刷新额度”之后)时读取:Windows 为 Run 值的第一个参数与可执行文件相同(不区分大小写),macOS 为 SMAppService 状态为已启用或 plist 的第一个程序参数与可执行文件相同,Linux 为
.desktop的Exec第一个参数与可执行文件相同 - 切换失败时勾选状态恢复原值,并以对话框显示错误
子命令出错时把错误文本写到标准错误,以退出码 1 结束;成功时退出码为 0。accounts 与 status 的表格由 Go text/tabwriter(最小宽度 0、制表宽度 4、间距 2、以空格填充)写出:每列宽为该列最长单元格的字符数加 2,最后一列不补空格。
| 子命令 | 输出 |
|---|---|
version |
一行 app.Version():标签构建为发行版本号,源码构建为伪版本或 (devel) |
accounts |
账户表,见表下 |
status |
服务概况与账户表,见表下 |
login |
见下方登录过程表 |
import |
每个导入的账户一行 已导入账户 <邮箱> |
switch |
成功时 官方客户端已切换到账户 <邮箱> |
accounts:表头账户 套餐 状态 添加时间,每个账户一行:邮箱、account.json的tier(currentTier.id)、启用或停用、本地时区的YYYY-MM-DD HH:MM:SS;按添加时间排序status:第一行Antigravity2API <版本> 监听 <listen>,自 <本地时间 YYYY-MM-DD HH:MM:SS> 运行;随后表头账户 状态 套餐 额度,每个账户一行:/api/accounts的id、state、tier(有付费套餐时为付费套餐)、额度
login 的过程输出:
| 方式 | 打印 | 等待 | 成功 |
|---|---|---|---|
| 默认 | 在浏览器中完成 Google 登录:、授权链接 |
回环端口收到回调 | 已添加账户 <邮箱> |
--code |
提示、授权链接、授权码: |
标准输入的一行 | 已添加账户 <邮箱> |
--cloud |
提示、授权链接 | 回环端口收到回调 | 已添加企业账户 <邮箱> |
--remote |
同默认或 --code |
同默认或 --code |
已添加账户 <邮箱> 到 <地址> |
- 默认与
--cloud打印链接后用系统浏览器打开它,打开命令同“命令行版不带任何参数启动”,启动失败时以该错误结束 --cloud的提示为在浏览器中完成 Continue with Google Cloud 登录:--code的提示为在任意设备的浏览器中打开链接完成 Google 登录,把页面给出的授权码粘贴到这里:;授权码:之后不换行,读到的行去掉首尾空白后为空时以授权码为空结束- 等待没有时限,Ctrl+C 或 SIGTERM 取消,以
context canceled结束;回调的state与本次登录不同时回环端口返回 400state mismatch并继续等待;state相同而带error时回环端口返回 400,以OAuth error: <error>结束 --remote的远程服务返回 201 以外时以远程服务返回 <状态码>: <正文>结束
参数与用法错误:
| 情形 | 标准错误 |
|---|---|
| 未知子命令 | 未知子命令 "<名称>",可用:serve、login、import、switch、accounts、status、version |
--cloud 与 --remote 或 --code 同时使用 |
--cloud 在本机以浏览器登录并写入本机账户库,不能与 --remote、--code 同时使用 |
--remote 没有 --token |
--remote 需要同时提供 --token |
switch 的参数不是一个邮箱 |
用法: antigravity2api switch [参数] <账户邮箱> |
-h、-help |
Usage of <子命令>: 与各参数的默认值和说明,再一行 flag: help requested |
| 未定义的参数或参数值无效 | Go flag 包的错误与用法,再一行同一错误 |
- 以上情形的退出码都为 1;命令行版第一个参数以
-开头时按serve的参数解析,用法标题为Usage of serve: - 各子命令接受
--listen、--auth、--runtime、--proxy;serve另有--open-ui,login另有--code、--cloud、--provider、--remote、--token;参数写作-名称或--名称均可
| 参数 | 类型 | 默认值 | 说明文字 |
|---|---|---|---|
--listen |
字符串 | 空 | 监听地址,覆盖 LISTEN |
--auth |
字符串 | 空 | 账户目录,覆盖 AUTH_DIR |
--runtime |
字符串 | 空 | 运行数据目录,覆盖 RUNTIME_DIR |
--proxy |
字符串 | 空 | 上游代理,多个以逗号分隔,覆盖 PROXY |
serve --open-ui |
布尔 | 见表下 | 启动后用系统浏览器打开管理端,不带任何参数启动时默认打开 |
login --code |
布尔 | false | 打印授权链接并粘贴授权码,用于没有浏览器的环境 |
login --cloud |
布尔 | false | 以 Continue with Google Cloud 的企业 WIF 方式登录 |
login --provider |
字符串 | 空 | 企业 WIF 登录的 provider 名 |
login --remote |
字符串 | 空 | 把账户添加到远程服务,值为其管理端地址,例如 http://server:8017 |
login --token |
字符串 | 空 | 远程服务管理端生成的配对令牌 |
桌面版 --hidden |
布尔 | false | 启动后只显示托盘 |
-
--open-ui在serve子命令中默认为 false,命令行版不带任何参数启动时为 true -
四个通用参数为空或只有空白时不覆盖配置;
--proxy按PROXY的规则校验 -
--cloud不带--provider时授权链接的provider参数为空;--provider只在--cloud时使用,--token只在--remote时使用,单独给出时不起作用 -
桌面版的用法标题为
Usage of Antigravity2API: -
桌面版不带子命令启动时,参数解析与配置错误以原生对话框显示;桌面版的参数为
--hidden与上述四个通用参数 -
serve启动时没有账户,在标准错误打印没有账户,执行 antigravity2api login 添加,或在管理端添加并继续运行 -
status的额度列为各额度桶<bucket_id> <剩余百分比>%以空格相连,百分比按%.0f四舍五入;账户带error时额度列为该错误文本 -
status经http://<监听地址的回环形式>读取/api/status与/api/accounts;/api/status连接失败或返回 200 以外时打印服务未在 <LISTEN> 运行: <原因>
$ antigravity2api accounts
账户 套餐 状态 添加时间
alice@example.com free-tier 启用 2026-10-14 14:47:22
bob@example.com standard-tier 停用 2026-10-15 09:03:10
$ antigravity2api status
Antigravity2API v0.1.3 监听 127.0.0.1:8017,自 2026-10-23 09:00:00 运行
账户 状态 套餐 额度
alice@example.com ready g1-ultra-lite-tier gemini-weekly 100% gemini-5h 97% 3p-weekly 100% 3p-5h 100%
bob@example.com error free-tier 需要验证:...
在线更新在 internal/app/update.go(版本查询、下载与校验)、update_headless.go 与 update_desktop.go(按构建选择发行包与安装方式)和 internal/desktop/update.go(Wails 更新器):
GET /api/update读取 GitHub 最新发行版本(缓存一小时,?refresh=1重新读取),返回current、latest、available、mode、发布说明与时间;POST /api/update重新读取后安装,成功返回 202,已是最新、源码构建、容器部署或更新进行中返回 409update_conflict,下载或校验失败返回 502update_failed;请求与下载都经PROXY,未设置时用系统代理GET /api/update读取 GitHub 失败时返回 200,error为失败原因,latest、notes、url与published_at保留上一次成功读取的值;失败的读取同样更新checked_at并缓存一小时。读取过程中客户端断开时返回 502update_check_failed。mode不为binary时不读取 GitHub- 版本取构建信息的模块版本,没有时为
(devel):不带预发布与构建后缀的语义化版本为binary,伪版本、预发布标签、+dirty与(devel)为development;binary版本在存在/.dockerenv或/run/.containerenv时为container - 镜像构建的上下文包含
.git与全部受版本管理的文件,.dockerignore只排除 Git 忽略的产物与本地数据:标签构建的镜像中版本为该标签,mode为container;有未提交改动的工作区构建为+dirty版本,mode为development - 下载与校验:从 GitHub 最新发行版本接口(
https://api.github.com/repos/Mag1cFall/Antigravity2API/releases/latest)中找到同名资产,按其browser_download_url下载,以资产的digest字段(sha256:<十六进制>)校验整个发行包;没有该字段或摘要不一致时失败
| 运行方式 | 发行包 | 安装 |
|---|---|---|
| 命令行版 | antigravity2api-<版本>-<系统>-<架构>,Windows 为 Windows 包 |
取出可执行文件,经 minio/selfupdate 替换后重启 |
桌面版的 serve 子命令 |
当前平台桌面包,Windows 为 Windows 包 | 同命令行版 |
| 桌面窗口 | 当前平台桌面包 | 经 Wails 更新器暂存,Windows 与 Linux 为包中的可执行文件,macOS 为 Antigravity2API.app 的 tar.gz |
- 替换后重启:停止服务后以
serve、原参数与--open-ui=false启动新版本;Windows 上新进程沿用当前控制台,其他系统原地替换进程;HTTP 服务关闭超时也照常重启 - Wails 更新器重启:更新器的辅助进程等当前进程结束后替换文件并启动新版本;Linux 与 macOS 的暂存目录与替换目标位于同一目录
- Windows 上被替换的旧文件留在同一目录:命令行版为隐藏文件
.antigravity2api.exe.old,桌面版为antigravity2api.exe.old.<时间戳> - 管理端事件流断开重连后读取
/api/status,版本与上次不同时刷新页面,在线更新重启后任何页面都切换到新版本
设置页“关于”分区的“版本与在线更新”一项读取 GET /api/update,按第一条符合的行显示:
| 状态 | 显示 |
|---|---|
| 读取中 | 正在读取最新版本 |
| 读取失败 | 无法读取更新状态:<错误> 与“检查更新” |
mode 为 container |
Docker 部署随镜像更新,拉取新镜像后重建容器 |
mode 为 development |
源码构建不支持在线更新,新版本从发布页下载 |
updating |
正在重启到 <latest>,页面在新版本就绪后自动刷新 |
带 error |
无法读取最新版本:<error> |
available |
新版本 <latest> · <published_at>发布 与“更新到 ” |
| 其他 | 已是最新版本 · <checked_at>检查 |
- 后三行都带“检查更新”按钮,它请求
GET /api/update?refresh=1并以结果替换显示,失败时弹出错误提示;带error且available时同样显示“更新到 ” - “更新到 ”打开确认对话框:标题
更新到 <latest>,说明下载 <latest> 的发行包并校验 SHA-256,替换程序后重启,页面在新版本就绪后自动刷新。,按钮“取消”与“确认更新”;“确认更新”发POST /api/update,成功时关闭对话框,失败时弹出错误提示 - 时间按界面语言的完整日期时间显示;
notes与url不在该项中显示
go test ./...
go vet ./...| 包 | 单元测试内容 |
|---|---|
config |
.env 往返、环境变量覆盖、校验、启动参数覆盖、系统代理解析 |
balancer |
按目录选账户、最久未选中者轮换、等待槽位、冷却、会话粘连、排除账户、目录合并 |
app |
远程管理需要登录、验证链接、代理脱敏 |
requestdb |
记录查询与详情、正文保留条数、过期清理、汇总与记录一致、日志查询、结果判定、上游错误读取、费用 |
service |
流中错误原样返回、客户端取消后排空上游 |
api |
空消息过滤、Gemini 输出 part 与签名、inlineData 兼容、API key 匹配 |
修改协议实现时,先对照协议参考中的官方现场形态,再在本地服务上用对应 SDK 发请求核对输出。