Coverage for integrations / channels / extensions / __init__.py: 45.7%

92 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-12 04:49 +0000

1""" 

2Channel Extensions - Phases 7 & 8 

3 

4Additional messaging channel adapters for extended platform support. 

5These adapters follow the same patterns as core adapters (Telegram, Discord, Slack) 

6but target additional platforms for broader integration capabilities. 

7 

8Available Extensions: 

9 

10Phase 7: 

11- Matrix: End-to-end encrypted messaging via Matrix protocol 

12- Teams: Microsoft Teams integration via Bot Framework 

13- LINE: LINE Messaging API for LINE platform 

14- Mattermost: Open-source Slack alternative with WebSocket and REST API 

15- Nextcloud Talk: Nextcloud's communication platform with file sharing 

16 

17Phase 8: 

18- Twitch: Twitch chat and whispers 

19- Zalo: Vietnamese messaging platform OA API 

20- Nostr: Decentralized social protocol 

21- BlueBubbles: iMessage bridge for cross-platform 

22- Voice: Voice calls via Twilio/Vonage 

23- RocketChat: Open-source team chat with REST + Realtime API 

24- WeChat: WeChat Official Account API 

25- Viber: Viber Bot API 

26- Messenger: Facebook Messenger via Meta Graph API 

27- Instagram: Instagram Direct Messages 

28- Twitter: Twitter/X DMs and mentions 

29- Email: IMAP/SMTP email integration 

30 

31Docker Support: 

32 All adapters are designed to work in containerized environments. 

33 Configuration can be passed via environment variables. 

34""" 

35 

36from typing import TYPE_CHECKING 

37 

38# Lazy imports to avoid loading dependencies that may not be installed 

39__all__ = [ 

40 # Phase 7 - Matrix 

41 "MatrixAdapter", "MatrixConfig", "MatrixRoom", "ThreadInfo", "create_matrix_adapter", 

42 # Phase 7 - Teams 

43 "TeamsAdapter", "TeamsConfig", "AdaptiveCard", "ConversationRef", "create_teams_adapter", 

44 # Phase 7 - LINE 

45 "LINEAdapter", "LINEConfig", "FlexBubble", "QuickReplyItem", "create_line_adapter", 

46 # Phase 7 - Mattermost 

47 "MattermostAdapter", "MattermostConfig", "MattermostChannel", "MattermostUser", 

48 "InteractiveMessage", "SlashCommand", "create_mattermost_adapter", 

49 # Phase 7 - Nextcloud 

50 "NextcloudAdapter", "NextcloudConfig", "NextcloudConversation", "NextcloudParticipant", 

51 "NextcloudMessage", "ConversationType", "ParticipantType", "RichObjectParameter", "create_nextcloud_adapter", 

52 # Phase 8 - Twitch 

53 "TwitchAdapter", "TwitchConfig", "create_twitch_adapter", 

54 # Phase 8 - Zalo 

55 "ZaloAdapter", "ZaloConfig", "create_zalo_adapter", 

56 # Phase 8 - Nostr 

57 "NostrAdapter", "NostrConfig", "create_nostr_adapter", 

58 # Phase 8 - BlueBubbles 

59 "BlueBubblesAdapter", "BlueBubblesConfig", "create_bluebubbles_adapter", 

60 # Phase 8 - Voice 

61 "VoiceAdapter", "VoiceConfig", "create_voice_adapter", 

62 # Phase 8 - RocketChat 

63 "RocketChatAdapter", "RocketChatConfig", "create_rocketchat_adapter", 

64 # Phase 8 - WeChat 

65 "WeChatAdapter", "WeChatConfig", "create_wechat_adapter", 

66 # Phase 8 - Viber 

67 "ViberAdapter", "ViberConfig", "create_viber_adapter", 

68 # Phase 8 - Messenger 

69 "MessengerAdapter", "MessengerConfig", "create_messenger_adapter", 

70 # Phase 8 - Instagram 

71 "InstagramAdapter", "InstagramConfig", "create_instagram_adapter", 

72 # Phase 8 - Twitter 

73 "TwitterAdapter", "TwitterConfig", "create_twitter_adapter", 

74 # Phase 8 - Email 

75 "EmailAdapter", "EmailConfig", "create_email_adapter", 

76 # Phase 8 - Tlon (Urbit) 

77 "TlonAdapter", "TlonConfig", "create_tlon_adapter", 

78 # Phase 8 - Open Prose 

79 "OpenProseAdapter", "OpenProseConfig", "create_openprose_adapter", 

80 # Phase 8 - Telegram User 

81 "TelegramUserAdapter", "TelegramUserConfig", "create_telegram_user_adapter", 

82 # Phase 8 - Discord User 

83 "DiscordUserAdapter", "DiscordUserConfig", "create_discord_user_adapter", 

84 # Phase 8 - Zalo User 

85 "ZaloUserAdapter", "ZaloUserConfig", "create_zalo_user_adapter", 

86 # Discovery helper 

87 "get_available_adapters", 

88] 

89 

90 

91# (channel_name, module_basename, factory_name) — single source of truth 

92# for the adapter registry used by both the lazy __getattr__ and the 

93# runtime discovery helper `get_available_adapters()`. 

94_ADAPTER_REGISTRY = ( 

95 ("matrix", "matrix_adapter", "create_matrix_adapter"), 

96 ("teams", "teams_adapter", "create_teams_adapter"), 

97 ("line", "line_adapter", "create_line_adapter"), 

98 ("mattermost", "mattermost_adapter", "create_mattermost_adapter"), 

99 ("nextcloud", "nextcloud_adapter", "create_nextcloud_adapter"), 

100 ("twitch", "twitch_adapter", "create_twitch_adapter"), 

101 ("zalo", "zalo_adapter", "create_zalo_adapter"), 

102 ("nostr", "nostr_adapter", "create_nostr_adapter"), 

103 ("bluebubbles", "bluebubbles_adapter", "create_bluebubbles_adapter"), 

104 ("voice", "voice_adapter", "create_voice_adapter"), 

105 ("rocketchat", "rocketchat_adapter", "create_rocketchat_adapter"), 

106 ("wechat", "wechat_adapter", "create_wechat_adapter"), 

107 ("viber", "viber_adapter", "create_viber_adapter"), 

108 ("messenger", "messenger_adapter", "create_messenger_adapter"), 

109 ("instagram", "instagram_adapter", "create_instagram_adapter"), 

110 ("twitter", "twitter_adapter", "create_twitter_adapter"), 

111 ("email", "email_adapter", "create_email_adapter"), 

112 ("tlon", "tlon_adapter", "create_tlon_adapter"), 

113 ("openprose", "openprose_adapter", "create_openprose_adapter"), 

114 ("telegram_user", "telegram_user_adapter", "create_telegram_user_adapter"), 

115 ("discord_user", "discord_user_adapter", "create_discord_user_adapter"), 

116 ("zalo_user", "zalo_user_adapter", "create_zalo_user_adapter"), 

117) 

118 

119 

120def get_available_adapters() -> dict: 

121 """Return a mapping of ``{channel_name: create_adapter_factory}`` for every 

122 extension adapter whose backing module imports successfully. 

123 

124 Adapters whose dependencies are not installed are silently skipped so that 

125 callers (marketing_tools, MCP ``list_channels``, admin API) always see a 

126 stable surface. Factories are the ``create_<name>_adapter`` callables 

127 declared by each adapter module; callers are expected to invoke them 

128 with per-channel config. 

129 """ 

130 import importlib 

131 adapters: dict = {} 

132 for channel_name, module_basename, factory_name in _ADAPTER_REGISTRY: 

133 try: 

134 mod = importlib.import_module(f".{module_basename}", __name__) 

135 except Exception: 

136 # Optional-dep / platform-specific adapters can fail to import. 

137 # The discovery surface must stay stable; skip silently. 

138 continue 

139 factory = getattr(mod, factory_name, None) 

140 if callable(factory): 

141 adapters[channel_name] = factory 

142 return adapters 

143 

144 

145def __getattr__(name: str): 

146 """Lazy import of adapters to avoid loading unused dependencies.""" 

147 

148 # Matrix imports 

149 if name in ("MatrixAdapter", "MatrixConfig", "MatrixRoom", "ThreadInfo", "create_matrix_adapter"): 

150 from .matrix_adapter import ( 

151 MatrixAdapter, 

152 MatrixConfig, 

153 MatrixRoom, 

154 ThreadInfo, 

155 create_matrix_adapter, 

156 ) 

157 return locals()[name] 

158 

159 # Teams imports 

160 if name in ("TeamsAdapter", "TeamsConfig", "AdaptiveCard", "ConversationRef", "create_teams_adapter"): 

161 from .teams_adapter import ( 

162 TeamsAdapter, 

163 TeamsConfig, 

164 AdaptiveCard, 

165 ConversationRef, 

166 create_teams_adapter, 

167 ) 

168 return locals()[name] 

169 

170 # LINE imports 

171 if name in ("LINEAdapter", "LINEConfig", "FlexBubble", "QuickReplyItem", "create_line_adapter"): 

172 from .line_adapter import ( 

173 LINEAdapter, 

174 LINEConfig, 

175 FlexBubble, 

176 QuickReplyItem, 

177 create_line_adapter, 

178 ) 

179 return locals()[name] 

180 

181 # Mattermost imports 

182 if name in ("MattermostAdapter", "MattermostConfig", "MattermostChannel", "MattermostUser", 

183 "InteractiveMessage", "SlashCommand", "create_mattermost_adapter"): 

184 from .mattermost_adapter import ( 

185 MattermostAdapter, 

186 MattermostConfig, 

187 MattermostChannel, 

188 MattermostUser, 

189 InteractiveMessage, 

190 SlashCommand, 

191 create_mattermost_adapter, 

192 ) 

193 return locals()[name] 

194 

195 # Nextcloud imports 

196 if name in ("NextcloudAdapter", "NextcloudConfig", "NextcloudConversation", "NextcloudParticipant", 

197 "NextcloudMessage", "ConversationType", "ParticipantType", "RichObjectParameter", 

198 "create_nextcloud_adapter"): 

199 from .nextcloud_adapter import ( 

200 NextcloudAdapter, NextcloudConfig, NextcloudConversation, NextcloudParticipant, 

201 NextcloudMessage, ConversationType, ParticipantType, RichObjectParameter, create_nextcloud_adapter, 

202 ) 

203 return locals()[name] 

204 

205 # Phase 8 - Twitch 

206 if name in ("TwitchAdapter", "TwitchConfig", "create_twitch_adapter"): 

207 from .twitch_adapter import TwitchAdapter, TwitchConfig, create_twitch_adapter 

208 return locals()[name] 

209 

210 # Phase 8 - Zalo 

211 if name in ("ZaloAdapter", "ZaloConfig", "create_zalo_adapter"): 

212 from .zalo_adapter import ZaloAdapter, ZaloConfig, create_zalo_adapter 

213 return locals()[name] 

214 

215 # Phase 8 - Nostr 

216 if name in ("NostrAdapter", "NostrConfig", "create_nostr_adapter"): 

217 from .nostr_adapter import NostrAdapter, NostrConfig, create_nostr_adapter 

218 return locals()[name] 

219 

220 # Phase 8 - BlueBubbles 

221 if name in ("BlueBubblesAdapter", "BlueBubblesConfig", "create_bluebubbles_adapter"): 

222 from .bluebubbles_adapter import BlueBubblesAdapter, BlueBubblesConfig, create_bluebubbles_adapter 

223 return locals()[name] 

224 

225 # Phase 8 - Voice 

226 if name in ("VoiceAdapter", "VoiceConfig", "create_voice_adapter"): 

227 from .voice_adapter import VoiceAdapter, VoiceConfig, create_voice_adapter 

228 return locals()[name] 

229 

230 # Phase 8 - RocketChat 

231 if name in ("RocketChatAdapter", "RocketChatConfig", "create_rocketchat_adapter"): 

232 from .rocketchat_adapter import RocketChatAdapter, RocketChatConfig, create_rocketchat_adapter 

233 return locals()[name] 

234 

235 # Phase 8 - WeChat 

236 if name in ("WeChatAdapter", "WeChatConfig", "create_wechat_adapter"): 

237 from .wechat_adapter import WeChatAdapter, WeChatConfig, create_wechat_adapter 

238 return locals()[name] 

239 

240 # Phase 8 - Viber 

241 if name in ("ViberAdapter", "ViberConfig", "create_viber_adapter"): 

242 from .viber_adapter import ViberAdapter, ViberConfig, create_viber_adapter 

243 return locals()[name] 

244 

245 # Phase 8 - Messenger 

246 if name in ("MessengerAdapter", "MessengerConfig", "create_messenger_adapter"): 

247 from .messenger_adapter import MessengerAdapter, MessengerConfig, create_messenger_adapter 

248 return locals()[name] 

249 

250 # Phase 8 - Instagram 

251 if name in ("InstagramAdapter", "InstagramConfig", "create_instagram_adapter"): 

252 from .instagram_adapter import InstagramAdapter, InstagramConfig, create_instagram_adapter 

253 return locals()[name] 

254 

255 # Phase 8 - Twitter 

256 if name in ("TwitterAdapter", "TwitterConfig", "create_twitter_adapter"): 

257 from .twitter_adapter import TwitterAdapter, TwitterConfig, create_twitter_adapter 

258 return locals()[name] 

259 

260 # Phase 8 - Email 

261 if name in ("EmailAdapter", "EmailConfig", "create_email_adapter"): 

262 from .email_adapter import EmailAdapter, EmailConfig, create_email_adapter 

263 return locals()[name] 

264 

265 # Phase 8 - Tlon (Urbit) 

266 if name in ("TlonAdapter", "TlonConfig", "create_tlon_adapter"): 

267 from .tlon_adapter import TlonAdapter, TlonConfig, create_tlon_adapter 

268 return locals()[name] 

269 

270 # Phase 8 - Open Prose 

271 if name in ("OpenProseAdapter", "OpenProseConfig", "create_openprose_adapter"): 

272 from .openprose_adapter import OpenProseAdapter, OpenProseConfig, create_openprose_adapter 

273 return locals()[name] 

274 

275 # Phase 8 - Telegram User 

276 if name in ("TelegramUserAdapter", "TelegramUserConfig", "create_telegram_user_adapter"): 

277 from .telegram_user_adapter import TelegramUserAdapter, TelegramUserConfig, create_telegram_user_adapter 

278 return locals()[name] 

279 

280 # Phase 8 - Discord User 

281 if name in ("DiscordUserAdapter", "DiscordUserConfig", "create_discord_user_adapter"): 

282 from .discord_user_adapter import DiscordUserAdapter, DiscordUserConfig, create_discord_user_adapter 

283 return locals()[name] 

284 

285 # Phase 8 - Zalo User 

286 if name in ("ZaloUserAdapter", "ZaloUserConfig", "create_zalo_user_adapter"): 

287 from .zalo_user_adapter import ZaloUserAdapter, ZaloUserConfig, create_zalo_user_adapter 

288 return locals()[name] 

289 

290 raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 

291 

292 

293# Type hints for IDE support 

294if TYPE_CHECKING: 

295 from .matrix_adapter import ( 

296 MatrixAdapter, 

297 MatrixConfig, 

298 MatrixRoom, 

299 ThreadInfo, 

300 create_matrix_adapter, 

301 ) 

302 from .teams_adapter import ( 

303 TeamsAdapter, 

304 TeamsConfig, 

305 AdaptiveCard, 

306 ConversationRef, 

307 create_teams_adapter, 

308 ) 

309 from .line_adapter import ( 

310 LINEAdapter, 

311 LINEConfig, 

312 FlexBubble, 

313 QuickReplyItem, 

314 create_line_adapter, 

315 ) 

316 from .mattermost_adapter import ( 

317 MattermostAdapter, 

318 MattermostConfig, 

319 MattermostChannel, 

320 MattermostUser, 

321 InteractiveMessage, 

322 SlashCommand, 

323 create_mattermost_adapter, 

324 ) 

325 from .nextcloud_adapter import ( 

326 NextcloudAdapter, 

327 NextcloudConfig, 

328 NextcloudConversation, 

329 NextcloudParticipant, 

330 NextcloudMessage, 

331 ConversationType, 

332 ParticipantType, 

333 RichObjectParameter, 

334 create_nextcloud_adapter, 

335 ) 

336 from .tlon_adapter import TlonAdapter, TlonConfig, create_tlon_adapter 

337 from .openprose_adapter import OpenProseAdapter, OpenProseConfig, create_openprose_adapter 

338 from .telegram_user_adapter import TelegramUserAdapter, TelegramUserConfig, create_telegram_user_adapter 

339 from .discord_user_adapter import DiscordUserAdapter, DiscordUserConfig, create_discord_user_adapter 

340 from .zalo_user_adapter import ZaloUserAdapter, ZaloUserConfig, create_zalo_user_adapter