Skip to content

Обзор архитектуры плагина: Понимание внутреннего дизайна OpenCode Antigravity Auth ​

Что вы узнаете ​

Этот курс проведет вас через архитектурный дизайн и внутренние принципы работы плагина Antigravity Auth. После завершения этого курса вы сможете:

  • Понять структуру модулей плагина и обязанности каждого модуля
  • Овладеть полным циклом обработки запросов от OpenCode до Antigravity API
  • Изучить механизм балансировки нагрузки для управления несколькими аккаунтами
  • Понять принципы работы восстановления сессии
  • Овладеть техническими деталями преобразования формата запросов

Основная ценность плагина ​

Основная роль плагина Antigravity Auth — построить «мост перевода» между OpenCode и Antigravity API:

  1. Преобразование протокола - Преобразование форматов запросов OpenCode в форматы, требуемые Antigravity API
  2. Управление аутентификацией - Безопасное получение и обновление токенов доступа через Google OAuth 2.0 PKCE
  3. Балансировка нагрузки - Объединение нескольких аккаунтов с автоматической ротацией для избежания ограничений скорости
  4. Восстановление ошибок - Автоматическое обнаружение и устранение проблем с прерыванием сессий

Зачем понимать архитектуру?

Понимание архитектуры плагина поможет вам:

  • Быстро определить модуль, в котором возникла проблема
  • Понять область действия параметров конфигурации
  • Оптимизировать стратегии использования нескольких аккаунтов
  • Участвовать в разработке и отладке плагина

Обзор структуры модулей ​

Плагин использует слоистую архитектуру с четким разделением обязанностей для каждого модуля:

mermaid
graph TD
    subgraph Presentation Layer
        A[OpenCode Client]
    end

    subgraph Plugin Layer
        B[plugin.ts - Main Entry]
        C[accounts.ts - AccountManager]
        D[request.ts - Transform]
        E[recovery - Session Recovery]
        F[config - Configuration]
    end

    subgraph Authentication Layer
        G[oauth.ts - OAuth]
        H[auth.ts - Token Mgmt]
        I[server.ts - Callback Server]
    end

    subgraph Transformation Layer
        J[claude.ts - Claude]
        K[gemini.ts - Gemini]
        L[model-resolver - Model Detection]
        M[request-helpers - Schema Clean]
    end

    subgraph Persistence Layer
        N[storage.ts - Disk Storage]
        O[cache.ts - Signature Cache]
    end

    subgraph External Services
        P[Google OAuth]
        Q[Antigravity API]
        R[Gemini CLI API]
    end

    A -->|fetch intercept| B
    B -->|load| C
    B -->|transform| D
    B -->|handle error| E
    B -->|load| F

    B -->|authorize| G
    B -->|refresh| H
    B -->|start| I

    D -->|detect model| L
    D -->|claude| J
    D -->|gemini| K
    D -->|clean| M
    E -->|inject result| D

    C -->|save/load| N
    D -->|get/set| O
    G -->|exchange token| P
    H -->|refresh token| P
    D -->|send request| Q
    D -->|send request| R

Обязанности модулей ​

МодульФайлОбязанности
Главный входplugin.tsПерехватчик fetch, инициализация плагина, обработка событий
Управление аккаунтамиaccounts.tsПул нескольких аккаунтов, стратегия балансировки нагрузки, отслеживание ограничений скорости
Преобразование запросовrequest.tsПреобразование формата запросов, потоковая обработка ответов
Преобразование моделейtransform/Логика преобразования для Claude/Gemini
Аутентификация OAuthantigravity/oauth.tsПроцесс аутентификации PKCE, обмен токенами
Восстановление сессииrecovery/Обнаружение ошибок, автоматическое восстановление прерванных сессий
Управление конфигурациейconfig/Загрузка конфигурации, валидация схемы
Уровень храненияstorage.tsПостоянное хранение аккаунтов (файл JSON)
Уровень кешированияcache.tsКеширование подписей, сокращение избыточных вычислений
Журнал отладкиdebug.tsСтруктурированное журналирование, устранение неполадок

Поток обработки запросов ​

Когда модельный запрос отправляется из OpenCode, плагин проходит через полную цепочку обработки:

mermaid
sequenceDiagram
    participant OC as OpenCode Client
    participant PL as plugin.ts
    participant AM as AccountManager
    participant RT as Request Transform
    participant AA as Antigravity API

    OC->>PL: fetch(generativeLanguage.googleapis.com)
    PL->>PL: isGenerativeLanguageRequest()
    PL->>AM: getCurrentOrNextForFamily()
    AM-->>PL: { account, token }

    PL->>PL: accessTokenExpired()?
    alt Token Expired
        PL->>PL: refreshAccessToken()
        PL->>AM: updateFromAuth()
    end

    PL->>RT: prepareAntigravityRequest()
    RT->>RT: Detect Model Type
    RT->>RT: Transform Request Format
    RT->>RT: Clean Schema
    RT->>RT: Inject Thinking Config
    RT-->>PL: { request, init, streaming }

    PL->>AA: POST {request} + Bearer Token
    AA-->>PL: SSE Stream
    PL->>PL: transformAntigravityResponse()
    PL-->>OC: Transformed Stream

Подробности шагов ​

Шаг 1: Перехват запроса

  • Плагин перехватывает все запросы к generativelanguage.googleapis.com через перехватчик fetch
  • Использует isGenerativeLanguageRequest() для определения, является ли это запрос, связанный с Antigravity
  • Нецелевые запросы передаются напрямую, чтобы не влиять на другие функции

Шаг 2: Выбор аккаунта

  • Выбирает доступный аккаунт из пула аккаунтов (на основе настроенной стратегии: sticky/round-robin/hybrid)
  • Проверяет, истек ли срок действия токена, и автоматически обновляет при необходимости
  • Применяет смещение PID (если включено), чтобы обеспечить равномерное распределение аккаунтов в сценариях с несколькими агентами

Шаг 3: Преобразование запроса (request.ts)

  • Обнаружение модели: Определяет, является ли модель Claude или Gemini
  • Обработка Thinking:
    • Claude: Удаляет все исторические блоки thinking для избежания конфликтов подписей
    • Gemini: Добавляет конфигурацию thinkingConfig
  • Преобразование инструментов: Преобразует инструменты OpenCode в формат functionDeclarations
  • Очистка схемы: Удаляет неподдерживаемые поля JSON Schema (const, $ref, $defs и т.д.)
  • Обертка запроса: Инкапсулирует в формат { project, model, request: {...} }

Шаг 4: Отправка запроса

  • Добавляет специальные заголовки Antigravity (User-Agent, Client-Metadata)
  • Использует аутентификацию Bearer Token
  • Поддерживает резерные конечные точки (daily → autopush → prod)

Шаг 5: Преобразование ответа

  • Потоковое получение SSE, преобразование построчно
  • Преобразует thought: true в type: "reasoning"
  • Кеширует подпись thinking для последующих запросов
  • Разворачивает внутренний объект response для сохранения согласованности формата

Поток обработки ответов ​

Обработка ответов в основном включает потоковое преобразование и восстановление сессии:

mermaid
flowchart TD
    A[Receive SSE Stream] --> B[Parse SSE Lines]
    B --> C{Is Thinking Block?}
    C -->|Yes| D[thought: true → type: reasoning]
    C -->|No| E[Pass Through]
    D --> F[Cache thoughtSignature]
    E --> F
    F --> G{Has Nested response?}
    G -->|Yes| H[Unwrap Inner Object]
    G -->|No| I[Forward to Client]
    H --> I
    I --> J{Session Error?}
    J -->|Yes| K[Trigger Recovery]
    J -->|No| L[Complete]
    K --> M[detectErrorType]
    M --> N{Recoverable?}
    N -->|Yes| O[Inject Synthetic Messages]
    N -->|No| P[Report Error]
    O --> Q[Send Continue]
    Q --> L

Ключевые механизмы обработки ​

1. Преобразование блоков thinking

Формат блока thinking, возвращаемый Antigravity API:

json
{ "thought": true, "text": "содержание thinking" }

Плагин преобразует его в формат, совместимый с OpenCode:

json
{ "type": "reasoning", "reasoning": "содержание thinking" }

2. Кеширование подписей

Модели Claude и Gemini 3 требуют совпадения подписей блоков thinking в многоходовых диалогах:

  • Извлекает thoughtSignature из ответа
  • Сохраняет в память и на диск с помощью cacheSignature()
  • Получает и внедряет через getCachedSignature() в следующем запросе

Зачем нужно кеширование подписей?

API Claude и Gemini 3 требуют, чтобы блоки thinking перед вызовами инструментов имели правильные подписи. Кеширование подписей позволяет:

  • Избежать сбоев запросов, вызванных ошибками подписи
  • Сократить избыточную генерацию одинакового содержания thinking
  • Улучшить непрерывность многоходовых диалогов

3. Восстановление сессии

При обнаружении ошибки сессии:

  1. Перехватывает ошибку через событие session.error
  2. Вызывает detectErrorType() для определения возможности восстановления
  3. Для ошибки tool_result_missing:
    • Извлекает ID неудачных tool_use
    • Внедряет синтетические сообщения tool_result
    • Автоматически отправляет "continue" (если включено)
  4. Для ошибок порядка блоков thinking:
    • Анализирует состояние диалога
    • Закрывает поврежденный ход
    • Запускает новый ход для повторной генерации модели

Подробное описание ключевых механизмов ​

Механизм аутентификации OAuth ​

Плагин использует OAuth 2.0 с PKCE (Proof Key for Code Exchange):

mermaid
flowchart LR
    A[User runs opencode auth login] --> B[Generate PKCE Key Pair]
    B --> C[Build Authorization URL]
    C --> D[Start Local Server]
    D --> E[Open Browser Authorization Page]
    E --> F[User Authorizes]
    F --> G[Receive Callback Code]
    G --> H[Exchange Access Token]
    H --> I[Get Project ID]
    I --> J[Store to antigravity-accounts.json]

Безопасность PKCE:

  • Генерирует случайные code_verifier и code_challenge
  • URL авторизации содержит code_challenge для предотвращения атак "человек посередине"
  • Проверяет code_verifier при обмене токенами, чтобы убедиться, что запрос поступает от одного и того же клиента

Управление токенами:

  • Access Token: Срок действия по умолчанию 1 час, автоматическое обновление за 30 минут до истечения
  • Refresh Token: Долгосрочный, используется для получения нового Access Token
  • Сохраняется в ~/.config/opencode/antigravity-accounts.json

Механизм управления несколькими аккаунтами ​

Управление несколькими аккаунтами является одной из основных функций плагина и включает следующие ключевые компоненты:

1. Структура пула аккаунтов

typescript
interface AccountPool {
  version: 3;
  accounts: Account[];
  activeIndex: number;
  activeIndexByFamily: {
    claude: number;
    gemini: number;
  };
}

2. Стратегия выбора аккаунтов

СтратегияОписаниеСценарий использования
stickyСохраняет текущий аккаунт до достижения ограничения скоростиОдиночная сессия, сохранение кеша промптов
round-robinРотация к следующему аккаунту при каждом запросеНесколько параллельных сессий, максимизация пропускной способности
hybridКомплексное решение на основе оценки здоровья + Token bucket + LRUСтратегия по умолчанию, баланс производительности и надежности

3. Отслеживание ограничений скорости

Каждый аккаунт отслеживается независимо по семейству моделей:

  • claude: Квота моделей Claude
  • gemini-antigravity: Квота Gemini Antigravity
  • gemini-cli: Квота Gemini CLI

Состояние ограничения скорости включает:

  • rateLimitResetTimes: Время сброса для каждой квоты
  • cooldownEndAt: Время окончания охлаждения аккаунта
  • consecutiveFailures: Количество последовательных сбоев

4. Двойной пул квот (специфично для Gemini)

Модели Gemini поддерживают два независимых пула квот:

  • Квота Antigravity: Ежедневная песочница
  • Квота Gemini CLI: Производственная среда

Через конфигурацию quota_fallback:

  • Приоритет основной квоты (определяется суффиксом модели)
  • Попытка использовать резервную квоту при истощении основной
  • Переключение на следующий аккаунт при истощении обоих пулов

5. Оптимизация смещения PID

При включении pid_offset_enabled:

  • Агенты из разных процессов (PID) начинают с разных аккаунтов
  • Избегает конкуренции всех агентов за один и тот же аккаунт
  • Подходит для сценариев с несколькими параллельными агентами

Механизм преобразования запросов ​

Преобразование запросов — самая сложная часть плагина, обрабатывающая различия протоколов между разными моделями:

Ключевые моменты преобразования модели Claude:

  1. Обработка блоков thinking

    typescript
    // Удаление всех исторических блоков thinking (избежание конфликтов подписей)
    const filteredContents = deepFilterThinkingBlocks(contents);
    
    // Создание новой thinkingConfig
    const thinkingConfig = {
      budgetTokens: variantThinkingConfig?.budget || DEFAULT_THINKING_BUDGET,
    };
  2. Очистка схемы инструментов

    • Белый список: type, properties, required, description, enum, items
    • Удаление полей: const, $ref, $defs, default, examples, additionalProperties, $schema, title
    • Специальное преобразование: const: "value" → enum: ["value"]
  3. Внедрение подписи параметров инструмента

    typescript
    injectParameterSignatures(tool, signature) {
      tool.description += `\n\nParameters: ${signature}`;
    }

Ключевые моменты преобразования модели Gemini:

  1. Конфигурация Thinking

    typescript
    // Gemini 3 Pro/Flash
    if (isGemini3Model(model)) {
      request.thinkingConfig = {
        thinkingLevel: "high" | "medium" | "low" | "minimal",
      };
    }
    
    // Gemini 2.5
    else if (isGemini2Model(model)) {
      request.thinkingConfig = {
        thinkingLevel: "high" | "medium" | "low",
      };
    }
  2. Grounding Google Search

    typescript
    if (webSearchConfig) {
      request.generationConfig = {
        ...request.generationConfig,
        dynamicRetrievalConfig: {
          mode: webSearchConfig.mode, // "auto" | "off"
          dynamicRetrievalConfig: {
            scoreThreshold: webSearchConfig.threshold, // 0.0 - 1.0
          },
        },
      };
    }
  3. Конфигурация генерации изображений

    typescript
    if (isImageGenerationModel(model)) {
      request.generationConfig = {
        ...request.generationConfig,
        responseModalities: ["IMAGE", "TEXT"],
      };
    }

Механизм восстановления сессии ​

Механизм восстановления сессии обеспечивает возможность продолжения диалогов после непредвиденных прерываний:

1. Обнаружение ошибок

typescript
function detectErrorType(error: unknown): RecoverableError | null {
  if (errorString.includes("tool_use ids were found without tool_result")) {
    return { type: "tool_result_missing" };
  }
  if (errorString.includes("Expected thinking but found text")) {
    return { type: "thinking_order_error" };
  }
  return null;
}

2. Обнаружение границ хода

typescript
// Граница хода = первое сообщение assistant после сообщения пользователя
function analyzeConversationState(messages: Message[]): ConversationState {
  const lastUserMessage = findLastMessageByRole(messages, "user");
  const firstAssistantAfterUser = messages.find(m =>
    m.role === "assistant" && m.timestamp > lastUserMessage.timestamp
  );

  return {
    isTurnStart: true,
    turnAssistantMessage: firstAssistantAfterUser,
  };
}

3. Внедрение синтетических сообщений

typescript
// Внедрение синтетического tool_result
function createSyntheticErrorResponse(toolUseIds: string[]): Message[] {
  return toolUseIds.map(id => ({
    type: "tool_result",
    tool_use_id: id,
    content: "Operation cancelled",
    isSynthetic: true,
  }));
}

// Закрытие поврежденного хода
function closeToolLoopForThinking(sessionId: string): Message[] {
  return [
    {
      type: "text",
      text: "[Conversation turn closed due to error]",
      isSynthetic: true,
    },
  ];
}

4. Авто-возобновление

При включении auto_resume процесс восстановления автоматически отправляет инструкцию продолжения:

typescript
await client.session.prompt({
  path: { id: sessionID },
  body: { parts: [{ type: "text", text: config.resume_text }] },
  query: { directory },
});

Итоги курса ​

Этот курс предоставил углубленный анализ архитектурного дизайна плагина Antigravity Auth:

Основная архитектура:

  • Слоистый дизайн модулей с четким разделением обязанностей
  • Уровень плагина, уровень аутентификации, уровень преобразования и уровень хранения каждый выполняют свои функции
  • Использование plugin.ts как единой точки входа для координации всех модулей

Поток запросов:

  • Перехват → Выбор аккаунта → Обновление токена → Преобразование запроса → Отправка запроса → Преобразование ответа
  • Каждый шаг имеет детальную обработку ошибок и механизмы повторных попыток

Ключевые механизмы:

  • OAuth 2.0 PKCE: Безопасный поток аутентификации
  • Управление несколькими аккаунтами: Балансировка нагрузки, отслеживание ограничений скорости, двойной пул квот
  • Преобразование запросов: Совместимость протоколов, очистка схемы, обработка Thinking
  • Восстановление сессии: Автоматическое обнаружение ошибок, внедрение синтетических сообщений, авто-возобновление

Понимание этих механизмов поможет вам лучше использовать и оптимизировать конфигурацию плагина, а также участвовать в разработке и отладке плагина.

Следующий урок ​

В следующем уроке мы изучим Внутреннюю спецификацию Antigravity API.

Вы узнаете:

  • Форматы запросов и ответов Antigravity API
  • Функции и параметры каждой конечной точки
  • Значения кодов ошибок и статусов
  • Дополнительные функции и экспериментальные возможности

Приложение: Ссылка на исходный код ​

Нажмите, чтобы раскрыть расположение исходного кода

Последнее обновление: 2026-01-23

ФункцияПуть к файлуНомера строк
Главный вход плагина, перехватчик fetchsrc/plugin.ts654-1334
Менеджер аккаунтов, балансировка нагрузкиsrc/plugin/accounts.ts1-715
Преобразование запросов, потоковая передача ответовsrc/plugin/request.ts1-1664
Преобразование модели Claudesrc/plugin/transform/claude.tsПолный файл
Преобразование модели Geminisrc/plugin/transform/gemini.tsПолный файл
Восстановление сессииsrc/plugin/recovery/index.tsПолный файл
Восстановление блока thinkingsrc/plugin/recovery/thinking-recovery.tsПолный файл
Аутентификация OAuthsrc/antigravity/oauth.ts1-271
Управление токенамиsrc/plugin/token.tsПолный файл
Схема конфигурацииsrc/plugin/config/schema.ts1-373
Хранение аккаунтовsrc/plugin/storage.tsПолный файл
Кеш подписейsrc/plugin/cache.tsПолный файл
Журнал отладкиsrc/plugin/debug.tsПолный файл

Ключевые константы:

  • MAX_OAUTH_ACCOUNTS = 10: Максимальное количество аккаунтов
  • RATE_LIMIT_DEDUP_WINDOW_MS = 2000: Окно дедупликации ограничений скорости (2 секунды)
  • RATE_LIMIT_STATE_RESET_MS = 120000: Время сброса состояния ограничений скорости (2 минуты)
  • FAILURE_COOLDOWN_MS = 30000: Время охлаждения аккаунта (30 секунд)

Ключевые функции:

  • createAntigravityPlugin(): Главная функция входа плагина
  • prepareAntigravityRequest(): Главная функция преобразования запросов
  • transformAntigravityResponse(): Функция преобразования потоковой передачи ответов
  • AccountManager.getCurrentOrNextForFamily(): Функция выбора аккаунтов
  • handleSessionRecovery(): Функция обработки восстановления сессии
  • refreshAccessToken(): Функция обновления токена