Контракт адаптера
Контракт адаптера — это контракт, который реализует каждый провайдер LLM, TTS, STT и изображений. Если вы напишете адаптер, удовлетворяющий ему, весь конвейер заработает с вашим провайдером.
Интерфейс
Интерфейс ProviderAdapter имеет стабильный kind, необязательные
объявления модальностей и обязательные методы. Текстовая генерация — базовая
возможность; методы речи, изображений и транскрипции необязательны, поэтому
адаптер только для LLM всё равно остаётся валидным провайдером.
interface ProviderAdapter {
readonly kind: string;
readonly modalities?: readonly ProviderModality[];
readonly capabilities?: {
assistantPrefill?: boolean;
textCompletion?: boolean;
};
validateConfig(): Promise<ValidationResult>;
listModels(signal: AbortSignal): Promise<ModelInfo[]>;
generate(request: GenerationRequest, signal: AbortSignal): AsyncIterable<GenerationEvent>;
speech?(request: SpeechRequest, signal: AbortSignal): AsyncIterable<SpeechEvent>;
image?(request: ImageRequest, signal: AbortSignal): AsyncIterable<ImageEvent>;
transcribe?(request: TranscriptionRequest, signal: AbortSignal): Promise<TranscriptionResult>;
countTokens?(request: TokenCountRequest): Promise<TokenCount>;
}
Обязательное поведение
Контракт требует восемь поведений:
- Проверка конфигурации —
validateConfig()проверяет собственную конфигурацию адаптера без сетевых вызовов и возвращает список проблем. - Перечисление моделей —
listModels(signal)возвращает доступные модели и должен уважать сигнал отмены. - Отмена — каждый длительный метод получает
AbortSignalи должен прерываться незамедлительно при его срабатывании. - Единый поток событий —
generate()выдаёт поток типизированныхGenerationEventи должен завершаться ровно одним терминальным событием,doneилиerror. Генерация речи и изображений использует ту же форму стриминга. - Нормализация ошибок — сбои провайдера сопоставляются со стабильными
кодами
AppErrorс машинночитаемыми кодами и параметрами. HTTP-статусы вышестоящей системы различаются (auth, rate limit, плохая модель, ошибка сервера), а сырые тела ответов вышестоящей системы никогда не пересылаются клиентам. - Таймауты — адаптер не должен полагаться только на сигнал вызывающей
стороны. Ему нужны собственные дедлайны для соединения, тишины
стриминга и чтения всего ответа. SDK поставляет
ProviderTimeouts(по умолчанию: 30 с соединение, 60 с простой, 30 с чтение) иDeadlineController, который комбинирует сигнал вызывающей стороны с переустанавливаемыми дедлайнами и прерывается ошибкойTIMEOUT. - Безопасное логирование — API-ключ предоставляется из защищённого хранилища и никогда не должен логироваться или попадать в диагностику и вывод ошибок.
- Регистрация — адаптеры регистрируются по виду, либо в основном реестре, либо через backend-API Plugin SDK.
Нейтральность к вендорам
Ядро не привязано ни к одному SDK вендора. От новых адаптеров ожидается
использование глобального fetch и парсера SSE из SDK (parseSseStream) для
стриминговых ответов.
Есть ровно одно документированное исключение: адаптер Anthropic использует
@anthropic-ai/sdk, потому что API Anthropic — расширенное мышление и
поддержку бета-заголовков — официальный SDK обрабатывает точнее, чем
написанный вручную fetch-клиент. Это единственный адаптер, подключённый к
библиотеке вендора; всё остальное говорит по HTTP напрямую.
Интеграция с хостом
ProviderRegistry сопоставляет виды провайдеров с фабриками адаптеров.
register возвращает функцию отмены регистрации, create создаёт экземпляр
адаптера и бросает PROVIDER_NOT_FOUND для неизвестных видов, а реестр также
размещает локальный реестр токенизаторов. Объявленные wire-возможности вроде
assistantPrefill используются для проверки профилей подключения — хост
никогда не отбрасывает молча сохранённый оверрайд профиля, который адаптер не
поддерживает.
О реальных поставляемых адаптерах и их назначении см. Адаптеры. О регистрации адаптера из плагина см. backend-API Plugin SDK.