Обзор системы Channel
Система Channel — это многоплатформенный уровень приёма сообщений Elftia, отвечающий за маршрутизацию сообщений из внешних платформ (Discord, Telegram, Slack и др.) в конвейер обработки Agent и обратную маршрутизацию ответов на исходную платформу.
Обзор архитектуры
graph TB
subgraph External Platforms
D[Discord]
T[Telegram]
S[Slack]
O[Other Platforms...]
end
subgraph Channel Plugin Layer
PL[ChannelPluginLoader<br/>Plugin Discovery & Loading]
PR[ChannelPluginRegistry<br/>Instance Management & Event Dispatch]
end
subgraph Message Pipeline
MR[ChannelMessageRouter<br/>Security Pipeline + Trigger Matching]
end
subgraph Security Pipeline
RL[RateLimiter]
IS[InputSanitizer]
PG[PromptGuardian]
UP[UserPermissionService]
CG[ChannelPermissionGate]
end
subgraph Agent Layer
MB[ChannelMagiBridge<br/>Message Format Conversion]
MS[MagiService<br/>Agent Processing]
end
D & T & S & O --> PR
PL --> PR
PR -->|message event| MR
MR --> RL --> IS --> PG --> UP --> CG
MR -->|routeToAgent event| MB
MB --> MS
MS -->|response| MB
MB -->|sendResponse| MR
MR -->|sendMessage| PR
PR --> D & T & S & O
Индекс ключевых файлов
| Файл | Путь | Ответственность |
|---|---|---|
| ChannelPluginLoader | desktop/app/main/services/capabilities/integrations/channel/ChannelPluginLoader.ts | Обнаружение, валидация, загрузка плагинов (два каталога) |
| ChannelPluginRegistry | desktop/app/main/services/capabilities/integrations/channel/ChannelPluginRegistry.ts | Управление фабрикой плагинов и жизненным циклом экземпляров Channel |
| ChannelMessageRouter | desktop/app/main/services/capabilities/integrations/channel/ChannelMessageRouter.ts | Конвейер безопасности, сопоставление триггеров, буферизация сообщений, разбивка ответов |
| ChannelMagiBridge | desktop/app/main/services/agent-core/magi/ChannelMagiBridge.ts | Преобразование сообщений Channel → MagiIncomingMessage |
| ChannelMarketplaceService | desktop/app/main/services/capabilities/integrations/channel/ChannelMarketplaceService.ts | Получение CDN-манифеста, загрузка и установка плагинов |
| ChannelPluginRouter | desktop/app/main/services/routers/ChannelPluginRouter.ts | IPC-маршрутизация (фронтенд ↔ бэкенд) |
| channel-sdk | packages/channel-sdk/src/ | SDK для разработки плагинов (типы, интерфейсы) |
| channel-types | desktop/app/shared/contracts/channel-types.ts | Унифицированные определения типов Channel |
| channel-sdk (re-export) | desktop/app/shared/contracts/channel-sdk.ts | Реэкспорт типов SDK + встроенные вспомогательные функции |
| security-types | desktop/app/shared/contracts/security-types.ts | Определения типов ролей и разрешений пользователей |
| RateLimiter | desktop/app/main/services/platform/security/RateLimiter.ts | Ограничение частоты запросов скользящим окном |
| InputSanitizer | desktop/app/main/services/platform/security/InputSanitizer.ts | Удаление невидимых символов |
| PromptGuardian | desktop/app/main/services/platform/security/PromptGuardian.ts | Обнаружение инъекций промптов на основе AI |
| UserPermissionService | desktop/app/main/services/platform/security/UserPermissionService.ts | Управление доступом на основе ролей |
| ChannelPermissionGate | desktop/app/main/services/platform/security/ChannelPermissionGate.ts | Механизм подтверждения чувствительных операций |
Жизненный цикл плагина
stateDiagram-v2
[*] --> Discovered: ChannelPluginLoader.discover()
Discovered --> Registered: ChannelPluginRegistry.registerPlugin()
Registered --> InstanceCreated: createInstance(id, config)
InstanceCreated --> Connecting: connectInstance(id)
Connecting --> Connected: plugin.connect() success
Connecting --> Error: plugin.connect() failure
Connected --> Disconnected: disconnectInstance(id)
Error --> Connecting: Retry connection
Disconnected --> Connecting: Reconnect
InstanceCreated --> Removed: removeInstance(id)
Disconnected --> Removed: removeInstance(id)
Connected --> Removed: removeInstance(id)
Removed --> [*]
Последовательность запуска
ChannelPluginLoaderсканирует два каталога (bundled + marketplace) и обнаруживает все манифестыelftia-channel.json- Для каждого обнаруженного плагина вызывает
loader.load()для загрузки модуля и получения фабричной функции - Вызывает
registry.registerPlugin(manifest, factory, dir)для регистрации в Registry - Загружает сохранённые конфигурации экземпляров Channel из базы данных
- Вызывает
registry.createInstance(id, config)для каждого экземпляра - Вызывает
registry.connectAll()для экземпляров сenabled && autoConnect ChannelMagiBridge.start()начинает прослушивание событийrouteToAgent
Управление подключениями
connectInstance(id)— вызовplugin.connect(credentials, options), переход состояний:disconnected → connecting → connected | errordisconnectInstance(id)— вызовplugin.disconnect(), переход состояний:connected → disconnectedconnectAll()— конкурентное подключение всехenabled-экземпляров с использованиемPromise.allSettledдля отказоустойчивостиdisconnectAll()— конкурентное отключение всех подключённых экземпляров
IPC-каналы
Все фронтенд-операции реализованы через IPC-каналы ChannelPluginRouter:
| IPC-канал | Направление | Описание |
|---|---|---|
channelPlugin:listInstances | renderer → main | Получить список всех экземпляров Channel |
channelPlugin:createInstance | renderer → main | Создать новый экземпляр (с зашифрованным хранением учётных данных) |
channelPlugin:updateInstance | renderer → main | Обновить конфигурацию экземпляра |
channelPlugin:deleteInstance | renderer → main | Удалить экземпляр и связанное хранилище |
channelPlugin:connect | renderer → main | Подключить указанный экземпляр |
channelPlugin:disconnect | renderer → main | Отключить указанный экземпляр |
channelPlugin:testConnection | renderer → main | Проверить валидность учётных данных |
channelPlugin:getMarketplace | renderer → main | Получить список плагинов Marketplace |
channelPlugin:downloadPlugin | renderer → main | Загрузить и установить плагин из CDN |
channelPlugin:removePlugin | renderer → main | Удалить установленный плагин |
channelPlugin:updateTrigger | renderer → main | Обновить правила триггеров |
channelPlugin:statusChange | main → renderer | Уведомление об изменении статуса экземпляра |
channelPlugin:downloadProgress | main → renderer | Уведомление о прогрессе загрузки плагина |
Сохранение данных
Экземпляры Channel
Конфигурации экземпляров хранятся в таблице magi_channels, управление ведётся через операции channelsUpsert / channelsUpdate / channelsDelete в ChannelPluginRouter.
Хранилище ключ-значение плагина
Каждый экземпляр плагина владеет независимым хранилищем ключ-значение (интерфейс ChannelStorageDb) для платформо-специфичных данных состояния. Базовая реализация — таблицы SQLite с кеширующим слоем в памяти.
Журналы активности сообщений
Входящие и исходящие сообщения записываются в файловую систему в формате JSONL:
{channelDataDir}/{channelId}/conversations/{chatDir}/{YYYY-MM-DD}.jsonl
Запись использует механизм буферизации (сброс каждые 2 секунды) для снижения дисковых операций ввода-вывода.
Следующие шаги
- Channel Plugin SDK — Определения интерфейсов плагинов и формат манифеста
- Маршрутизация сообщений и конвейер безопасности — Подробности конвейера обработки сообщений
- ChannelMagiBridge — Мостовое соединение сообщений от Channel к Agent
- Написание плагина Channel — Создание пользовательского плагина с нуля