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
주요 파일 색인
| File | Path | Responsibility |
|---|---|---|
| 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가 두 디렉터리(번들 + marketplace)를 스캔하고 모든elftia-channel.json매니페스트를 발견합니다- 발견된 각 플러그인에 대해
loader.load()를 호출해 모듈을 로드하고 팩토리 함수를 가져옵니다 registry.registerPlugin(manifest, factory, dir)를 호출해 Registry에 등록합니다- 데이터베이스에서 저장된 Channel 인스턴스 구성을 로드합니다
- 각 인스턴스에 대해
registry.createInstance(id, config)를 호출합니다 enabled && autoConnect인 인스턴스에 대해registry.connectAll()을 호출합니다ChannelMagiBridge.start()가routeToAgent이벤트 수신을 시작합니다
연결 관리
connectInstance(id)—plugin.connect(credentials, options)를 호출합니다. 상태 전환:disconnected → connecting → connected | errordisconnectInstance(id)—plugin.disconnect()를 호출합니다. 상태 전환:connected → disconnectedconnectAll()— 내결함성을 위해Promise.allSettled를 사용해 모든enabled인스턴스를 동시에 연결합니다disconnectAll()— 연결된 모든 인스턴스를 동시에 연결 해제합니다
IPC Channel
모든 프런트엔드 작업은 ChannelPluginRouter의 IPC Channel을 통해 구현됩니다.
| IPC Channel | Direction | Description |
|---|---|---|
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 테이블에 저장되며, ChannelPluginRouter의 channelsUpsert / channelsUpdate / channelsDelete 작업을 통해 관리됩니다.
플러그인 K-V 저장소
각 플러그인 인스턴스는 플랫폼별 상태 데이터를 위한 독립적인 키-값 저장소(ChannelStorageDb 인터페이스)를 소유합니다. 기본 구현은 인메모리 캐싱 레이어가 있는 SQLite 테이블입니다.
메시지 활동 로그
인바운드 및 아웃바운드 메시지는 JSONL 형식으로 파일 시스템에 기록됩니다.
{channelDataDir}/{channelId}/conversations/{chatDir}/{YYYY-MM-DD}.jsonl
디스크 I/O를 줄이기 위해 쓰기는 버퍼링 메커니즘(2초마다 플러시)을 사용합니다.
다음 단계
- Channel 플러그인 SDK — 플러그인 인터페이스 정의와 매니페스트 형식
- 메시지 라우팅 및 보안 파이프라인 — 메시지 처리 파이프라인 세부 정보
- ChannelMagiBridge — Channel에서 Agent로 메시지를 브리징
- Channel 플러그인 작성하기 — 처음부터 커스텀 플러그인 작성