Обзор
Провайдер телефонии реализуется как самостоятельно регистрирующийся пакет вapi/services/telephony/providers/<name>/. Пакет предоставляет все, что нужно Агентике для подключения провайдера — класс провайдера, фабрику транспорта, конфигурацию аудио, схемы запроса/ответа, опциональные HTTP-маршруты и метаданные форм, используемые для отрисовки его интерфейса конфигурации, — через единый ProviderSpec, регистрируемый при импорте.
Добавление нового провайдера не должно требовать изменений в фабрике, конфигурации аудио, модуле API-маршрутов, модуле пайплайна прогона или во фронтенде. Единственные правки за пределами папки провайдера:
- Одна строка импорта в
api/services/telephony/providers/__init__.py - Одна строка импорта в
api/schemas/telephony_config.py, чтобы добавить классы запроса/ответа в дискриминированное объединениеTelephonyConfigRequest
Структура пакета провайдера
__init__.py, config.py, provider.py, transport.py). Остальные опциональны и обнаруживаются автоматически, если присутствуют:
routes.py— если модуль существует и экспортируетrouter: APIRouter, модуль маршрутов импортируется отложенно и монтируется под/api/v1/telephonyчерезapi.routes.telephonyс помощьюimportlib. Провайдеры, которые только стримят по WebSocket (например, ARI), могут его не создавать.strategies.py— используется транспортами, которым нужна специфичная для провайдера логика перевода звонка/завершения звонка в сериализаторе фреймов (например, переводы через конференцию).serializers.py— обычно реэкспорт из pipecat. Оставляйте файл, даже если это однострочный реэкспорт, чтобы код транспорта импортировал из.serializers— это дает очевидное место для подкласса под собственную реализацию в будущем.
Интерфейс TelephonyProvider
Создайте подкласс TelephonyProvider в provider.py:
api/services/telephony/base.py.
Руководство по реализации
1. Схемы конфигурации
Определите Pydantic-модели для полезной нагрузки учётных данных. Дискриминаторprovider типа Literal — это то, что заставляет схемы корректно диспетчеризоваться через дискриминированное объединение реестра.
2. Фабрика транспорта
Соберите PipecatFastAPIWebsocketTransport для принятых WebSocket-соединений. Всегда загружайте учётные данные через load_credentials_for_transport, чтобы выбиралась правильная строка конфигурации, когда прогон воркфлоу несет telephony_configuration_id (организации с несколькими конфигурациями).
3. Маршруты (опционально)
Если ваш провайдер отправляет вебхуки в Агентику POST-запросами (answer URL, колбэки статуса, колбэки завершения звонка), предоставьте их черезrouter на уровне модуля. Маршруты монтируются автоматически под /api/v1/telephony.
importlib из api.routes.telephony._mount_provider_routers, поэтому ваш модуль маршрутов может свободно импортировать другие бэкенд-сервисы, не создавая циклы импорта при загрузке класса провайдера.
4. Регистрация ProviderSpec
В __init__.py пакета все собирается воедино:
ProviderSpec покрывает все, что нужно нижестоящему коду:
5. Подключите пакет к цепочке импорта реестра
Добавьте одну строку импорта вapi/services/telephony/providers/__init__.py:
6. Добавьте в дискриминированное объединение
Добавьте один блок импорта вapi/schemas/telephony_config.py, чтобы классы запроса/ответа участвовали в объединении TelephonyConfigRequest и форме TelephonyConfigurationResponse:
Фронтенд
Форма конфигурации управляется метаданными. UI вызываетGET /api/v1/organizations/telephony-providers/metadata, получает список провайдеров и определения их ProviderUIField, и отрисовывает каждую форму универсальным способом. Специфичный для провайдера код фронтенда не нужен — форму формирует именно ваше объявление ProviderUIMetadata.
Если вы добавляете новый тип поля, который не поддерживается существующим рендерером (например, загрузка файла), расширьте рендерер в ui/src/app/(authenticated)/telephony-configurations/. На сегодня поддерживаются следующие значения ProviderUIField.type: text, password, textarea, string-array и number.
Особенности форматов аудио
Каждый провайдер объявляет свой формат передачи черезAudioConfig. Распространенные варианты:
- Узкополосная телефония: 8 кГц μ-law, JSON-фреймы в кодировке base64
- Широкополосная телефония: 16 кГц Linear PCM в виде бинарных фреймов
- Asterisk ARI: 8 кГц Linear PCM через externalMedia
Тестирование
Лучшие практики
- Доверяйте реестру — никогда не импортируйте класс другого провайдера напрямую; разрешайте зависимость через хелперы фабрики (
get_default_telephony_provider,get_telephony_provider_by_idи т. д.). - Чувствительные поля — помечайте каждое поле с учётными данными как
sensitive=TrueвProviderUIMetadata. Эндпоинт сохранения маскирует их при чтении и сохраняет исходное значение, когда клиент повторно отправляет замаскированное значение. - Проверка подписи входящих вебхуков — всегда проверяйте подписи входящих вебхуков в
verify_inbound_signature. ВозвратTrue, когда заголовок подписи отсутствует, допустим; возвращайтеFalse, когда подпись присутствует, но недействительна. - Транспорты загружают учётные данные лениво — вызывайте
load_credentials_for_transportсtelephony_configuration_idиз прогона воркфлоу. Не читайте конфигурацию организации по умолчанию изtransport.py. - Логирование — используйте
loguru.logger.
Референсные реализации
Используйте ARI как минимально жизнеспособный пример: провайдер только стримит по WebSocket и не предоставляет HTTP-вебхуки. Если у вашего провайдера есть HTTP-вебхуки, добавьте
routes.py и реализуйте verify_inbound_signature.