# Antigravity Provider 插件文档 > 版本: 1.0.0 > 仓库: `aiclientproxy/antigravity-provider` > 类型: OAuth Provider Plugin --- ## 一、概述 ### 1.1 插件简介 Antigravity Provider 是 Lime 的 OAuth Provider 插件,用于对接 **Google 内部 Gemini CLI** 服务(Antigravity)。它支持 **动态协议选择**:根据模型类型自动选择输出协议(Claude 模型 → Anthropic,Gemini 模型 → Gemini)。 ### 1.2 核心能力 | 能力 | 说明 | |------|------| | 动态协议 | claude-* → Anthropic SSE,gemini-* → Gemini 协议 | | 多模型支持 | Gemini 3 Pro、Gemini 2.5 Flash、Claude Sonnet/Opus | | Google OAuth | 使用 Google 账户认证 | | 安全设置 | 自动附加 Safety Settings(关闭内容过滤)| | 思维链 | 支持 reasoning_effort 配置 | | 流式响应 | 真实端到端流式传输 | ### 1.3 支持的模型 | 用户模型名 | 内部 API 名称 | 底层模型 | 输出协议 | |-----------|-------------|---------|---------| | `gemini-3-pro-preview` | `gemini-3-pro-high` | Gemini | Gemini | | `gemini-3-pro-image-preview` | `gemini-3-pro-image` | Gemini | Gemini | | `gemini-3-flash-preview` | `gemini-3-flash` | Gemini | Gemini | | `gemini-2.5-flash` | `gemini-2.5-flash` | Gemini | Gemini | | `gemini-2.5-computer-use-preview-10-2025` | `rev19-uic3-1p` | Gemini | Gemini | | `gemini-claude-sonnet-4-5` | `claude-sonnet-4-5` | Claude | **Anthropic** | | `gemini-claude-sonnet-4-5-thinking` | `claude-sonnet-4-5-thinking` | Claude | **Anthropic** | | `gemini-claude-opus-4-5-thinking` | `claude-opus-4-5-thinking` | Claude | **Anthropic** | --- ## 二、插件架构 ### 2.1 项目结构 ``` antigravity-provider/ ├── plugin/ │ ├── plugin.json # 插件元数据 │ └── config.json # 默认配置 │ ├── src-tauri/src/ # 后端 Rust 代码 │ ├── lib.rs # 插件入口 │ ├── commands.rs # Tauri 命令 │ ├── provider.rs # AntigravityProvider 核心实现 │ ├── credentials.rs # 凭证管理 │ ├── oauth.rs # Google OAuth 流程 │ ├── token_refresh.rs # Token 刷新 │ ├── models.rs # 模型定义和别名映射 │ ├── safety_settings.rs # 安全设置 │ └── converter/ # 协议转换 │ ├── mod.rs │ ├── openai_to_antigravity.rs # OpenAI → Antigravity │ ├── anthropic_to_antigravity.rs # Anthropic → Antigravity │ ├── antigravity_to_anthropic.rs # Antigravity → Anthropic SSE │ └── antigravity_to_gemini.rs # Antigravity → Gemini │ ├── src/ # 前端 React UI │ ├── index.tsx # 插件 UI 入口 │ ├── components/ │ │ ├── CredentialList.tsx # 凭证列表 │ │ ├── CredentialCard.tsx # 凭证卡片 │ │ ├── AntigravityForm.tsx # 凭证添加表单 │ │ ├── OAuthLogin.tsx # Google OAuth 登录 │ │ └── SettingsPanel.tsx # 插件设置 │ └── types/ │ └── index.ts # 类型定义 │ └── .github/ └── workflows/ └── release.yml # 自动构建发布 ``` ### 2.2 plugin.json ```json { "name": "antigravity-provider", "version": "1.0.0", "description": "Antigravity (Google Gemini CLI) OAuth Provider - 支持 Gemini 和 Claude 模型", "author": "Lime Team", "homepage": "https://github.com/aiclientproxy/antigravity-provider", "license": "MIT", "plugin_type": "oauth_provider", "entry": "antigravity-provider-cli", "min_lime_version": "1.0.0", "provider": { "id": "antigravity", "display_name": "Antigravity (Gemini CLI)", "target_protocol": "dynamic", "protocol_rules": { "claude-*": "anthropic", "gemini-*": "gemini" }, "supported_models": [ "gemini-3-pro-*", "gemini-2.5-*", "gemini-claude-*" ], "auth_types": ["oauth"], "credential_schema": { "type": "object", "properties": { "access_token": { "type": "string", "title": "Access Token" }, "refresh_token": { "type": "string", "title": "Refresh Token" }, "expiry_date": { "type": "integer", "title": "过期时间戳" }, "project_id": { "type": "string", "title": "Project ID" }, "email": { "type": "string", "title": "Google 邮箱" } }, "required": ["access_token", "refresh_token"] } }, "binary": { "binary_name": "antigravity-provider-cli", "github_owner": "aiclientproxy", "github_repo": "antigravity-provider", "platform_binaries": { "macos-arm64": "antigravity-provider-aarch64-apple-darwin", "macos-x64": "antigravity-provider-x86_64-apple-darwin", "linux-x64": "antigravity-provider-x86_64-unknown-linux-gnu", "windows-x64": "antigravity-provider-x86_64-pc-windows-msvc.exe" }, "checksum_file": "checksums.txt" }, "ui": { "surfaces": ["oauth_providers"], "icon": "Sparkles", "title": "Antigravity Provider", "entry": "dist/index.js", "styles": "dist/styles.css", "default_width": 900, "default_height": 700, "permissions": [ "database:read", "database:write", "http:request", "crypto:encrypt", "shell:open" ] } } ``` ### 2.3 config.json ```json { "enabled": true, "timeout_ms": 120000, "settings": { "api": { "environment": "daily", "base_url_daily": "https://daily-cloudcode-pa.sandbox.googleapis.com", "base_url_autopush": "https://autopush-cloudcode-pa.sandbox.googleapis.com", "api_version": "v1internal" }, "safety_settings": { "harassment": "OFF", "hate_speech": "OFF", "sexually_explicit": "OFF", "dangerous_content": "OFF", "civic_integrity": "BLOCK_NONE" }, "token_refresh": { "auto_refresh": true, "refresh_skew_seconds": 3000, "max_retry": 3 }, "reasoning": { "default_effort": "medium", "enable_thinking_models": true } } } ``` --- ## 三、后端实现 ### 3.1 核心数据结构 #### 凭证结构 ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AntigravityCredentials { pub access_token: Option, pub refresh_token: Option, pub token_type: Option, pub expiry_date: Option, // 毫秒时间戳 pub expire: Option, // RFC3339 格式 pub scope: Option, pub last_refresh: Option, // RFC3339 格式 pub cred_type: String, // 默认: "antigravity" pub expires_in: Option, // 有效期(秒) pub timestamp: Option, // 获取时间(毫秒) pub enable: Option, pub project_id: Option, pub email: Option, } ``` #### 模型别名映射 ```rust /// 用户友好模型名 → 内部 API 模型名 pub fn map_model_name(model: &str) -> String { let mappings = [ ("gemini-2.5-computer-use-preview-10-2025", "rev19-uic3-1p"), ("gemini-3-pro-image-preview", "gemini-3-pro-image"), ("gemini-3-pro-preview", "gemini-3-pro-high"), ("gemini-3-flash-preview", "gemini-3-flash"), ("gemini-2.5-flash", "gemini-2.5-flash"), ("gemini-claude-sonnet-4-5", "claude-sonnet-4-5"), ("gemini-claude-sonnet-4-5-thinking", "claude-sonnet-4-5-thinking"), ("gemini-claude-opus-4-5-thinking", "claude-opus-4-5-thinking"), ]; for (from, to) in mappings { if model.contains(from) { return to.to_string(); } } model.to_string() } ``` ### 3.2 动态协议选择 ```rust /// 根据模型确定输出协议 pub fn determine_output_protocol(model: &str) -> OutputProtocol { // Claude 模型 → Anthropic 协议 if model.contains("claude") { return OutputProtocol::Anthropic; } // Gemini 模型 → Gemini 协议 OutputProtocol::Gemini } #[derive(Debug, Clone)] pub enum OutputProtocol { Anthropic, // Claude Code 使用 Gemini, // Gemini 客户端使用 } ``` ### 3.3 OAuth 配置 ```rust /// OAuth 2.0 配置(Google) /// 必须通过环境变量配置: /// - ANTIGRAVITY_OAUTH_CLIENT_ID /// - ANTIGRAVITY_OAUTH_CLIENT_SECRET /// /// 获取方式: /// 1. 使用 Antigravity CLI 的默认凭据 /// 2. 从 Google Cloud Console 创建 OAuth 2.0 客户端 fn oauth_client_id() -> String { std::env::var("ANTIGRAVITY_OAUTH_CLIENT_ID") .expect("ANTIGRAVITY_OAUTH_CLIENT_ID environment variable must be set") } fn oauth_client_secret() -> String { std::env::var("ANTIGRAVITY_OAUTH_CLIENT_SECRET") .expect("ANTIGRAVITY_OAUTH_CLIENT_SECRET environment variable must be set") } pub const OAUTH_SCOPES: &[&str] = &[ "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/cclog", "https://www.googleapis.com/auth/experimentsandconfigs", ]; pub const OAUTH_AUTH_URL: &str = "https://accounts.google.com/o/oauth2/auth"; pub const OAUTH_TOKEN_URL: &str = "https://oauth2.googleapis.com/token"; ``` ### 3.4 Token 刷新 ```rust impl AntigravityProvider { /// Token 刷新时间偏移(提前 50 分钟刷新) const REFRESH_SKEW: i64 = 3000; // 秒 /// 检查 Token 是否需要刷新 pub fn needs_refresh(&self, credential: &AntigravityCredentials) -> bool { let now = Utc::now().timestamp(); // 优先使用 expiry_date(毫秒时间戳) if let Some(expiry_date) = credential.expiry_date { let expiry_secs = expiry_date / 1000; return now >= expiry_secs - Self::REFRESH_SKEW; } // 使用 expire(RFC3339 字符串) if let Some(expire) = &credential.expire { if let Ok(expiry) = DateTime::parse_from_rfc3339(expire) { return now >= expiry.timestamp() - Self::REFRESH_SKEW; } } // 使用 expires_in + timestamp if let (Some(expires_in), Some(timestamp)) = (credential.expires_in, credential.timestamp) { let expiry_secs = timestamp / 1000 + expires_in; return now >= expiry_secs - Self::REFRESH_SKEW; } // 默认需要刷新 true } /// 刷新 Token pub async fn refresh_token(&self, credential: &mut AntigravityCredentials) -> Result<()> { let refresh_token = credential.refresh_token.as_ref() .ok_or(Error::MissingRefreshToken)?; let client_id = oauth_client_id(); let client_secret = oauth_client_secret(); let response = self.http_client .post(OAUTH_TOKEN_URL) .form(&[ ("client_id", client_id.as_str()), ("client_secret", client_secret.as_str()), ("refresh_token", refresh_token.as_str()), ("grant_type", "refresh_token"), ]) .send() .await?; let token_response: TokenResponse = response.json().await?; // 更新凭证 credential.access_token = Some(token_response.access_token); credential.expiry_date = Some(Utc::now().timestamp_millis() + token_response.expires_in * 1000); credential.last_refresh = Some(Utc::now().to_rfc3339()); Ok(()) } } ``` ### 3.5 安全设置 ```rust /// 默认安全设置(关闭内容过滤) pub fn default_safety_settings() -> Vec { vec![ SafetySetting { category: "HARM_CATEGORY_HARASSMENT".to_string(), threshold: "OFF".to_string(), }, SafetySetting { category: "HARM_CATEGORY_HATE_SPEECH".to_string(), threshold: "OFF".to_string(), }, SafetySetting { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT".to_string(), threshold: "OFF".to_string(), }, SafetySetting { category: "HARM_CATEGORY_DANGEROUS_CONTENT".to_string(), threshold: "OFF".to_string(), }, SafetySetting { category: "HARM_CATEGORY_CIVIC_INTEGRITY".to_string(), threshold: "BLOCK_NONE".to_string(), }, ] } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SafetySetting { pub category: String, pub threshold: String, } ``` ### 3.6 协议转换 #### OpenAI → Antigravity ```rust /// 将 OpenAI ChatCompletion 请求转换为 Antigravity 格式 pub fn convert_openai_to_antigravity( request: &OpenAiRequest, project_id: Option<&str>, ) -> AntigravityRequest { // 1. 模型映射 let model = map_model_name(&request.model); // 2. 消息转换 let contents = convert_messages(&request.messages); // 3. 系统指令提取 let system_instruction = extract_system_instruction(&request.messages); // 4. 工具转换 let tools = request.tools.as_ref().map(|t| convert_tools(t)); // 5. 生成配置 let generation_config = GenerationConfig { max_output_tokens: request.max_tokens, temperature: request.temperature, top_p: request.top_p, candidate_count: Some(1), stop_sequences: request.stop.clone(), // 思维链配置 thinking_config: request.reasoning_effort.as_ref().map(|effort| { ThinkingConfig { thinking_budget: match effort.as_str() { "low" => 1024, "medium" => 4096, "high" => 16384, _ => 4096, }, } }), }; AntigravityRequest { model, contents, system_instruction, tools, generation_config: Some(generation_config), safety_settings: Some(default_safety_settings()), } } /// 消息格式转换 fn convert_messages(messages: &[OpenAiMessage]) -> Vec { messages .iter() .filter(|m| m.role != "system") // 系统消息单独处理 .map(|msg| { let role = match msg.role.as_str() { "user" => "user", "assistant" => "model", "tool" => "function", _ => "user", }; Content { role: role.to_string(), parts: convert_content_parts(&msg.content, &msg.tool_calls), } }) .collect() } ``` #### Antigravity → Anthropic SSE(Claude 模型) ```rust /// 将 Antigravity 响应转换为 Anthropic SSE 格式 pub struct AntigravityToAnthropicTranslator { message_id: String, model: String, current_index: u32, input_tokens: u32, output_tokens: u32, } impl AntigravityToAnthropicTranslator { pub fn translate_chunk(&mut self, chunk: &GeminiStreamChunk) -> Vec { let mut events = Vec::new(); // 候选内容处理 if let Some(candidates) = &chunk.candidates { for candidate in candidates { if let Some(content) = &candidate.content { for part in &content.parts { // 文本内容 if let Some(text) = &part.text { events.push(AnthropicSseEvent::ContentBlockDelta { index: self.current_index, delta: Delta::TextDelta { text: text.clone() }, }); } // 思维内容(thinking models) if let Some(thought) = &part.thought { events.push(AnthropicSseEvent::ContentBlockDelta { index: self.current_index, delta: Delta::ThinkingDelta { thinking: thought.clone() }, }); } // 工具调用 if let Some(function_call) = &part.function_call { events.push(AnthropicSseEvent::ContentBlockStart { index: self.current_index, content_block: ContentBlock::ToolUse { id: Uuid::new_v4().to_string(), name: function_call.name.clone(), }, }); } } } // 完成原因 if let Some(finish_reason) = &candidate.finish_reason { let stop_reason = match finish_reason.as_str() { "STOP" => "end_turn", "MAX_TOKENS" => "max_tokens", "SAFETY" => "content_filter", "TOOL_CALL" => "tool_use", _ => "end_turn", }; events.push(AnthropicSseEvent::MessageDelta { delta: MessageDelta { stop_reason: Some(stop_reason.to_string()), }, usage: Usage { input_tokens: self.input_tokens, output_tokens: self.output_tokens, }, }); } } } // 使用统计 if let Some(usage) = &chunk.usage_metadata { self.input_tokens = usage.prompt_token_count.unwrap_or(0); self.output_tokens = usage.candidates_token_count.unwrap_or(0); } events } } ``` ### 3.7 API 调用 ```rust impl AntigravityProvider { /// API 基础 URL fn get_base_url(&self) -> &str { match self.config.environment.as_str() { "autopush" => "https://autopush-cloudcode-pa.sandbox.googleapis.com", _ => "https://daily-cloudcode-pa.sandbox.googleapis.com", } } /// 流式 API 调用 pub async fn call_api_stream( &self, request: AntigravityRequest, credential: &AntigravityCredentials, ) -> Result>> { let url = format!( "{}/v1internal/models/{}:streamGenerateContent?alt=sse", self.get_base_url(), request.model ); let response = self.http_client .post(&url) .header("Authorization", format!("Bearer {}", credential.access_token.as_ref().unwrap())) .header("Content-Type", "application/json") .header("X-Goog-Api-Client", "genai-js/0.21.0") .json(&request) .send() .await?; // 解析 SSE 流 Ok(parse_sse_stream(response.bytes_stream())) } } ``` --- ## 四、前端 UI 实现 ### 4.1 插件入口 ```tsx // src/index.tsx import { LimePluginSDK } from '@lime/plugin-sdk'; import { CredentialList } from './components/CredentialList'; import { AntigravityForm } from './components/AntigravityForm'; import { SettingsPanel } from './components/SettingsPanel'; interface PluginProps { sdk: LimePluginSDK; pluginId: string; } export default function AntigravityProviderUI({ sdk, pluginId }: PluginProps) { const [view, setView] = useState<'list' | 'add' | 'settings'>('list'); const [credentials, setCredentials] = useState([]); useEffect(() => { loadCredentials(); }, []); const loadCredentials = async () => { const result = await sdk.database.query( 'SELECT * FROM plugin_credentials WHERE plugin_id = ? ORDER BY created_at DESC', [pluginId] ); setCredentials(result); }; return (
Antigravity Provider 支持 Gemini 3 Pro 和 Claude 模型
{/* 动态协议说明 */}

此 Provider 支持动态协议选择:

  • gemini-* 模型 → Gemini 协议输出
  • claude-* 模型 → Anthropic 协议输出
{view === 'list' && ( )} {view === 'add' && ( { loadCredentials(); setView('list'); }} onCancel={() => setView('list')} /> )} {view === 'settings' && ( setView('list')} /> )}
); } ``` ### 4.2 凭证添加表单 ```tsx // src/components/AntigravityForm.tsx type AddMode = 'oauth' | 'file'; interface AntigravityFormProps { sdk: LimePluginSDK; onSuccess: () => void; onCancel: () => void; } export function AntigravityForm({ sdk, onSuccess, onCancel }: AntigravityFormProps) { const [mode, setMode] = useState('oauth'); const [loading, setLoading] = useState(false); const [projectId, setProjectId] = useState(''); const [name, setName] = useState(''); const handleOAuthLogin = async () => { setLoading(true); try { // 启动 OAuth 流程 const result = await sdk.http.request('/api/antigravity/oauth/start', { method: 'POST', body: JSON.stringify({ name: name || undefined, skipProjectIdFetch: !projectId, }), }); // 打开授权 URL await sdk.shell.open(result.authUrl); // 等待回调 const credential = await sdk.http.request('/api/antigravity/oauth/callback/wait', { method: 'POST', timeout: 120000, // 2 分钟超时 }); sdk.notification.success('OAuth 登录成功'); onSuccess(); } catch (error) { sdk.notification.error(`登录失败: ${error.message}`); } finally { setLoading(false); } }; const handleFileImport = async (filePath: string) => { setLoading(true); try { await sdk.http.request('/api/antigravity/credentials/import', { method: 'POST', body: JSON.stringify({ credsFilePath: filePath, projectId: projectId || undefined, name: name || undefined, }), }); sdk.notification.success('凭证导入成功'); onSuccess(); } catch (error) { sdk.notification.error(`导入失败: ${error.message}`); } finally { setLoading(false); } }; return (
{/* 模式选择 */} Google OAuth 登录 导入凭证文件 {/* 通用配置 */} setName(e.target.value)} placeholder="我的 Antigravity 凭证" /> setProjectId(e.target.value)} placeholder="自动获取或手动输入" /> 留空将自动从 Google 账户获取 {mode === 'oauth' && ( )} {mode === 'file' && ( )}
); } ``` ### 4.3 OAuth 登录模式 ```tsx // src/components/OAuthLogin.tsx interface OAuthModeProps { loading: boolean; onLogin: () => void; } export function OAuthMode({ loading, onLogin }: OAuthModeProps) { return (

点击下方按钮将打开浏览器进行 Google 账户授权。

授权完成后,凭证将自动添加。

请求的权限:

  • Cloud Platform 访问
  • 用户邮箱和个人资料
  • Cloud Code 日志
); } ``` ### 4.4 凭证卡片 ```tsx // src/components/CredentialCard.tsx interface CredentialCardProps { credential: Credential; onRefresh: () => void; onDelete: () => void; } export function CredentialCard({ credential, onRefresh, onDelete }: CredentialCardProps) { const data = JSON.parse(credential.credential_data) as AntigravityCredentials; const isHealthy = credential.status === 'active'; return (
{isHealthy ? '健康' : '异常'}
Google OAuth
{credential.name || '未命名'}
{data.email || '-'}
{data.project_id || '自动'}
{data.expiry_date ? formatDate(new Date(data.expiry_date)) : '-' }
{data.last_refresh || '-'}
{/* 支持的模型 */}
Gemini 3 Pro Gemini 2.5 Flash Claude Sonnet 4.5 Claude Opus 4.5
); } ``` ### 4.5 设置面板 ```tsx // src/components/SettingsPanel.tsx interface SettingsPanelProps { sdk: LimePluginSDK; pluginId: string; onClose: () => void; } export function SettingsPanel({ sdk, pluginId, onClose }: SettingsPanelProps) { const [config, setConfig] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { loadConfig(); }, []); const loadConfig = async () => { const result = await sdk.database.query<{ config: string }>( 'SELECT config FROM plugin_configs WHERE plugin_id = ?', [pluginId] ); if (result.length > 0) { setConfig(JSON.parse(result[0].config)); } setLoading(false); }; const saveConfig = async () => { await sdk.database.execute( 'UPDATE plugin_configs SET config = ? WHERE plugin_id = ?', [JSON.stringify(config), pluginId] ); sdk.notification.success('设置已保存'); }; if (loading) return ; return (

插件设置

{/* API 环境 */} {/* 思维链配置 */} 影响 thinking 模型的思考预算 {/* 安全设置 */} { const value = checked ? 'OFF' : 'BLOCK_MEDIUM_AND_ABOVE'; setConfig({ ...config, settings: { ...config?.settings, safety_settings: { harassment: value, hate_speech: value, sexually_explicit: value, dangerous_content: value, civic_integrity: 'BLOCK_NONE', }, }, }); }} > 关闭所有内容过滤
); } ``` --- ## 五、凭证文件格式 ### 5.1 单凭证格式 **路径**: `~/.antigravity/oauth_creds.json` ```json { "access_token": "ya29.a0AfH6SMC...", "refresh_token": "1//0gXXXXXXXXXXXX...", "token_type": "Bearer", "expiry_date": 1704369600000, "scope": "https://www.googleapis.com/auth/cloud-platform ...", "cred_type": "antigravity", "project_id": "my-project-123", "email": "user@example.com" } ``` ### 5.2 多凭证数组格式 **路径**: `accounts.json`(兼容 antigravity2api-nodejs) ```json [ { "access_token": "ya29.a0AfH6SMC...", "refresh_token": "1//0gXXXXXXXXXXXX...", "expiry_date": 1704369600000, "email": "user1@example.com", "enable": true }, { "access_token": "ya29.b1BgH7TNE...", "refresh_token": "1//0hYYYYYYYYYYYY...", "expiry_date": 1704456000000, "email": "user2@example.com", "enable": true } ] ``` --- ## 六、API 调用流程 ### 6.1 完整调用链路 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ Antigravity Provider 调用流程 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. 客户端请求 (Anthropic/OpenAI 格式) │ │ │ │ │ ▼ │ │ 2. 模型识别 & 协议选择 │ │ ├── gemini-* → 输出 Gemini 协议 │ │ └── claude-* → 输出 Anthropic 协议 │ │ │ │ │ ▼ │ │ 3. 凭证获取 │ │ ├── 从凭证池选择健康凭证 │ │ ├── 检查 Token 是否过期 │ │ └── 必要时刷新 Token │ │ │ │ │ ▼ │ │ 4. 请求转换 │ │ ├── 模型名映射(用户名 → 内部 API 名) │ │ ├── 消息格式转换 │ │ ├── 附加 Safety Settings │ │ └── 配置思维链(reasoning_effort) │ │ │ │ │ ▼ │ │ 5. Antigravity API 调用 │ │ └── POST {base_url}/v1internal/models/{model}:streamGenerateContent │ │ │ │ │ ▼ │ │ 6. 响应转换(根据模型类型) │ │ ├── Gemini 模型 → Gemini SSE 格式 │ │ └── Claude 模型 → Anthropic SSE 格式 │ │ │ │ │ ▼ │ │ 7. 返回客户端 │ │ │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### 6.2 Antigravity API **端点**: `POST {base_url}/v1internal/models/{model}:streamGenerateContent?alt=sse` **请求格式**: ```json { "model": "gemini-3-pro-high", "contents": [ { "role": "user", "parts": [ { "text": "Hello, how are you?" } ] } ], "systemInstruction": { "parts": [ { "text": "You are a helpful assistant." } ] }, "generationConfig": { "maxOutputTokens": 4096, "temperature": 0.7, "topP": 0.9, "candidateCount": 1, "thinkingConfig": { "thinkingBudget": 4096 } }, "safetySettings": [ { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "OFF" }, { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "OFF" }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "OFF" }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "OFF" }, { "category": "HARM_CATEGORY_CIVIC_INTEGRITY", "threshold": "BLOCK_NONE" } ] } ``` **响应格式**: Gemini SSE Stream --- ## 七、错误处理 ### 7.1 错误类型 | 错误码 | 说明 | 处理方式 | |--------|------|---------| | 401 | Token 过期 | 自动刷新 Token 重试 | | 403 | 权限不足 / 账户无访问权限 | 标记凭证异常 | | 429 | 请求限流 | 冷却期后重试 | | 500 | 服务器错误 | 切换凭证重试 | ### 7.2 Token 刷新错误 ```rust pub enum TokenRefreshError { MissingRefreshToken, InvalidRefreshToken, NetworkError(String), AuthorizationRevoked, } ``` --- ## 八、开发指南 ### 8.1 本地开发 ```bash # 克隆仓库 git clone https://github.com/aiclientproxy/antigravity-provider.git cd antigravity-provider # 安装依赖 pnpm install cd src-tauri && cargo build # 前端开发 pnpm dev # 后端开发 cargo watch -x run ``` ### 8.2 测试 ```bash # 单元测试 cargo test # 协议转换测试 cargo test --test converter # 前端测试 pnpm test ``` --- ## 附录 ### A. 环境变量 | 变量 | 说明 | 默认值 | |------|------|--------| | `ANTIGRAVITY_ENVIRONMENT` | API 环境 | `daily` | | `ANTIGRAVITY_DEBUG` | 调试模式 | `false` | | `ANTIGRAVITY_TIMEOUT_MS` | 请求超时 | `120000` | | `ANTIGRAVITY_OAUTH_CLIENT_ID` | OAuth Client ID(必需) | 无,必须设置 | | `ANTIGRAVITY_OAUTH_CLIENT_SECRET` | OAuth Client Secret(必需) | 无,必须设置 | **注意**:OAuth 凭据可以从 Antigravity CLI 获取或从 Google Cloud Console 创建。 ### B. 参考链接 - [Google Cloud AI Platform](https://cloud.google.com/ai-platform) - [Gemini API 文档](https://ai.google.dev/docs) - [Lime 插件开发指南](../prd/credential-provider-plugin-architecture.md)