Перейти к основному содержимому

Разрешение провайдера во время выполнения

VibeOS имеет общий механизм разрешения провайдера, используемый в:

  • CLI
  • gateway
  • cron-задачах
  • ACP
  • вызовах вспомогательных моделей

Основная реализация:

  • vibeos_cli/runtime_provider.py — разрешение учетных данных, _resolve_custom_runtime()
  • vibeos_cli/auth.py — реестр провайдеров, resolve_provider()
  • vibeos_cli/model_switch.py — общий конвейер переключения /model (CLI + gateway)
  • agent/auxiliary_client.py — маршрутизация вспомогательных моделей
  • providers/ — ABC + точки входа в реестр (ProviderProfile, register_provider, get_provider_profile, list_providers)
  • plugins/model-providers/<name>/ — плагины для каждого провайдера (встроенные), которые объявляют api_mode, base_url, env_vars, fallback_models и регистрируют себя в реестре при первом обращении. Пользовательские плагины в $VIBEOS_HOME/plugins/model-providers/<name>/ переопределяют встроенные с тем же именем.

get_provider_profile() в providers/ возвращает ProviderProfile для заданного идентификатора провайдера. runtime_provider.py вызывает это во время разрешения, чтобы получить канонические base_url, список приоритетов env_vars, api_mode и fallback_models без необходимости дублировать эти данные в нескольких файлах. Добавление нового плагина в plugins/model-providers/<your-provider>/ (или $VIBEOS_HOME/plugins/model-providers/<your-provider>/), который вызывает register_provider(), достаточно, чтобы runtime_provider.py его подхватил — никаких ветвлений в самом механизме разрешения не требуется.

Если вы пытаетесь добавить нового первоклассного провайдера вывода, прочитайте Добавление провайдеров и Руководство по плагину провайдера модели вместе с этой страницей.

Приоритет разрешения​

На высоком уровне разрешение провайдера использует:

  1. явный запрос CLI/времени выполнения
  2. конфигурацию модели/провайдера в config.yaml
  3. переменные окружения
  4. специфичные для провайдера значения по умолчанию или автоматическое разрешение

Этот порядок важен, потому что VibeOS рассматривает сохраненный выбор модели/провайдера как источник истины для обычных запусков. Это предотвращает бесшумное переопределение конечной точки, которую пользователь последний раз выбрал в vibeos model, устаревшим экспортом оболочки.

Провайдеры​

Текущие семейства провайдеров включают (полный встроенный набор см. в plugins/model-providers/):

  • OpenRouter
  • Nous Portal
  • OpenAI Codex
  • Copilot / Copilot ACP
  • Anthropic (нативный)
  • Google / Gemini (gemini)
  • Alibaba / DashScope (alibaba, alibaba-coding-plan)
  • DeepSeek
  • Z.AI
  • Kimi / Moonshot (kimi-coding, kimi-coding-cn)
  • MiniMax (minimax, minimax-cn, minimax-oauth)
  • Kilo Code
  • Hugging Face
  • OpenCode Zen / OpenCode Go
  • AWS Bedrock
  • Azure Foundry
  • NVIDIA NIM
  • xAI (Grok)
  • Arcee
  • GMI Cloud
  • StepFun
  • Qwen OAuth
  • Xiaomi
  • Ollama Cloud
  • LM Studio
  • Tencent TokenHub
  • Custom (provider: custom) — первоклассный провайдер для любой совместимой с OpenAI конечной точки
  • Именованные кастомные провайдеры (список custom_providers в config.yaml)

Результат разрешения во время выполнения​

Механизм разрешения возвращает такие данные, как:

  • provider
  • api_mode
  • base_url
  • api_key
  • source
  • специфичные для провайдера метаданные, такие как информация об истечении/обновлении

Почему это важно​

Этот механизм разрешения является основной причиной, по которой VibeOS может разделять логику аутентификации/выполнения между:

  • vibeos chat
  • обработкой сообщений gateway
  • cron-задачами, запускаемыми в новых сессиях
  • сессиями редактора ACP
  • задачами вспомогательных моделей

OpenRouter и кастомные базовые URL, совместимые с OpenAI​

VibeOS содержит логику для предотвращения утечки неверного ключа API на кастомную конечную точку, когда существует несколько ключей провайдера (например, OPENROUTER_API_KEY и OPENAI_API_KEY).

Ключ API каждого провайдера привязан к своему базовому URL:

  • OPENROUTER_API_KEY отправляется только на конечные точки openrouter.ai
  • OPENAI_API_KEY используется для кастомных конечных точек и в качестве запасного варианта

VibeOS также различает:

  • реальную кастомную конечную точку, выбранную пользователем
  • запасной путь OpenRouter, используемый, когда кастомная конечная точка не настроена

Это различие особенно важно для:

  • локальных серверов моделей
  • совместимых с OpenAI API, отличных от OpenRouter
  • переключения провайдеров без повторного запуска настройки
  • сохраненных в конфигурации кастомных конечных точек, которые должны продолжать работать, даже если OPENAI_BASE_URL не экспортирован в текущей оболочке

Нативный путь Anthropic​

Anthropic теперь не просто «через OpenRouter».

Когда разрешение провайдера выбирает anthropic, VibeOS использует:

  • api_mode = anthropic_messages
  • нативный API Messages от Anthropic
  • agent/anthropic_adapter.py для трансляции

Разрешение учетных данных для нативного Anthropic теперь предпочитает обновляемые учетные данные Claude Code скопированным токенам окружения, когда присутствуют оба. На практике это означает:

  • файлы учетных данных Claude Code рассматриваются как предпочтительный источник, когда они включают обновляемую аутентификацию
  • ручные значения ANTHROPIC_TOKEN / CLAUDE_CODE_OAUTH_TOKEN все еще работают как явные переопределения
  • VibeOS выполняет предварительную проверку обновления учетных данных Anthropic перед вызовами нативного Messages API
  • VibeOS все еще повторяет попытку один раз при 401 после перестроения клиента Anthropic в качестве запасного пути

Путь OpenAI Codex​

Codex использует отдельный путь Responses API:

  • api_mode = codex_responses
  • выделенное разрешение учетных данных и поддержка хранилища аутентификации

Маршрутизация вспомогательных моделей​

Вспомогательные задачи, такие как:

  • vision
  • обобщение извлечения веб-страниц
  • сводки сжатия контекста
  • операции skills hub
  • операции MCP helper
  • сброс памяти

могут использовать свою собственную маршрутизацию провайдера/модели, а не основную диалоговую модель.

Когда вспомогательная задача настроена с провайдером main, VibeOS разрешает ее через тот же общий путь выполнения, что и обычный чат. На практике это означает:

  • управляемые окружением кастомные конечные точки все еще работают
  • кастомные конечные точки, сохраненные через vibeos model / config.yaml, также работают
  • вспомогательная маршрутизация может отличить реальную сохраненную кастомную конечную точку от запасного пути OpenRouter

Запасные модели​

VibeOS поддерживает настроенную цепочку запасных провайдеров — список записей (provider, model), перебираемых по порядку, когда основная модель сталкивается с ошибками. Устаревший словарь fallback_model с одной парой все еще принимается для обратной совместимости (и мигрируется при первой записи).

Как это работает внутри​

  1. Хранение: AIAgent.__init__ сохраняет словарь fallback_model и устанавливает _fallback_activated = False.

  2. Точки срабатывания: _try_activate_fallback() вызывается из трех мест в основном цикле повторных попыток в run_agent.py:

    • После максимального количества повторных попыток при недопустимых ответах API (отсутствие choices, отсутствие содержимого)
    • При не подлежащих повторению клиентских ошибках (HTTP 401, 403, 404)
    • После максимального количества повторных попыток при временных ошибках (HTTP 429, 500, 502, 503)
  3. Поток активации (_try_activate_fallback):

    • Возвращает False немедленно, если уже активирован или не настроен
    • Вызывает resolve_provider_client() из auxiliary_client.py для создания нового клиента с правильной аутентификацией
    • Определяет api_mode: codex_responses для openai-codex, anthropic_messages для anthropic, chat_completions для всего остального
    • Заменяет на месте: self.model, self.provider, self.base_url, self.api_mode, self.client, self._client_kwargs
    • Для запасного варианта anthropic: создает нативный клиент Anthropic вместо совместимого с OpenAI
    • Повторно оценивает кэширование подсказок (включено для моделей Claude на OpenRouter)
    • Устанавливает _fallback_activated = True — предотвращает повторный запуск
    • Сбрасывает счетчик повторных попыток на 0 и продолжает цикл
  4. Поток конфигурации:

    • CLI: cli.py читает CLI_CONFIG["fallback_model"] → передает в AIAgent(fallback_model=...)
    • Gateway: gateway/run.py._load_fallback_model() читает config.yaml → передает в AIAgent
    • Валидация: оба ключа provider и model должны быть непустыми, иначе запасной вариант отключен

Что НЕ поддерживает запасной вариант​

  • Делегирование сабагента (tools/delegate_tool.py): сабагенты наследуют провайдера родителя, но не конфигурацию запасного варианта
  • Вспомогательные задачи: используют свою собственную независимую цепочку автоопределения провайдера (см. Маршрутизацию вспомогательных моделей выше)

Cron-задачи поддерживают запасной вариант: run_job() читает fallback_providers (или устаревший fallback_model) из config.yaml и передает его в AIAgent(fallback_model=...), соответствуя шаблону _load_fallback_model() из gateway. См. Внутреннее устройство Cron.

Тестовое покрытие​

Поведение запасного варианта проверяется в нескольких наборах тестов:

  • tests/run_agent/test_fallback_credential_isolation.py — изоляция учетных данных между основным и запасным вариантами
  • tests/vibeos_cli/test_fallback_cmd.py — команда CLI /fallback
  • tests/gateway/test_fallback_eviction.py — вытеснение отказавших провайдеров в gateway

Связанные документы​