roomkit 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. roomkit/AGENTS.md +362 -0
  2. roomkit/__init__.py +372 -0
  3. roomkit/_version.py +1 -0
  4. roomkit/ai_docs.py +93 -0
  5. roomkit/channels/__init__.py +194 -0
  6. roomkit/channels/ai.py +238 -0
  7. roomkit/channels/base.py +66 -0
  8. roomkit/channels/transport.py +115 -0
  9. roomkit/channels/websocket.py +85 -0
  10. roomkit/core/__init__.py +0 -0
  11. roomkit/core/_channel_ops.py +252 -0
  12. roomkit/core/_helpers.py +296 -0
  13. roomkit/core/_inbound.py +435 -0
  14. roomkit/core/_room_lifecycle.py +275 -0
  15. roomkit/core/circuit_breaker.py +84 -0
  16. roomkit/core/event_router.py +401 -0
  17. roomkit/core/framework.py +793 -0
  18. roomkit/core/hooks.py +232 -0
  19. roomkit/core/inbound_router.py +57 -0
  20. roomkit/core/locks.py +66 -0
  21. roomkit/core/rate_limiter.py +67 -0
  22. roomkit/core/retry.py +49 -0
  23. roomkit/core/router.py +24 -0
  24. roomkit/core/transcoder.py +85 -0
  25. roomkit/identity/__init__.py +0 -0
  26. roomkit/identity/base.py +27 -0
  27. roomkit/identity/mock.py +49 -0
  28. roomkit/llms.txt +52 -0
  29. roomkit/models/__init__.py +104 -0
  30. roomkit/models/channel.py +99 -0
  31. roomkit/models/context.py +35 -0
  32. roomkit/models/delivery.py +76 -0
  33. roomkit/models/enums.py +170 -0
  34. roomkit/models/event.py +203 -0
  35. roomkit/models/framework_event.py +19 -0
  36. roomkit/models/hook.py +68 -0
  37. roomkit/models/identity.py +81 -0
  38. roomkit/models/participant.py +34 -0
  39. roomkit/models/room.py +33 -0
  40. roomkit/models/task.py +36 -0
  41. roomkit/providers/__init__.py +0 -0
  42. roomkit/providers/ai/__init__.py +0 -0
  43. roomkit/providers/ai/base.py +140 -0
  44. roomkit/providers/ai/mock.py +33 -0
  45. roomkit/providers/anthropic/__init__.py +6 -0
  46. roomkit/providers/anthropic/ai.py +145 -0
  47. roomkit/providers/anthropic/config.py +14 -0
  48. roomkit/providers/elasticemail/__init__.py +6 -0
  49. roomkit/providers/elasticemail/config.py +16 -0
  50. roomkit/providers/elasticemail/email.py +97 -0
  51. roomkit/providers/email/__init__.py +0 -0
  52. roomkit/providers/email/base.py +46 -0
  53. roomkit/providers/email/mock.py +34 -0
  54. roomkit/providers/gemini/__init__.py +6 -0
  55. roomkit/providers/gemini/ai.py +153 -0
  56. roomkit/providers/gemini/config.py +14 -0
  57. roomkit/providers/http/__init__.py +15 -0
  58. roomkit/providers/http/base.py +33 -0
  59. roomkit/providers/http/config.py +14 -0
  60. roomkit/providers/http/mock.py +21 -0
  61. roomkit/providers/http/provider.py +105 -0
  62. roomkit/providers/http/webhook.py +33 -0
  63. roomkit/providers/messenger/__init__.py +15 -0
  64. roomkit/providers/messenger/base.py +33 -0
  65. roomkit/providers/messenger/config.py +17 -0
  66. roomkit/providers/messenger/facebook.py +95 -0
  67. roomkit/providers/messenger/mock.py +21 -0
  68. roomkit/providers/messenger/webhook.py +42 -0
  69. roomkit/providers/openai/__init__.py +6 -0
  70. roomkit/providers/openai/ai.py +155 -0
  71. roomkit/providers/openai/config.py +24 -0
  72. roomkit/providers/pydantic_ai/__init__.py +5 -0
  73. roomkit/providers/pydantic_ai/config.py +14 -0
  74. roomkit/providers/rcs/__init__.py +9 -0
  75. roomkit/providers/rcs/base.py +95 -0
  76. roomkit/providers/rcs/mock.py +78 -0
  77. roomkit/providers/sendgrid/__init__.py +5 -0
  78. roomkit/providers/sendgrid/config.py +13 -0
  79. roomkit/providers/sinch/__init__.py +6 -0
  80. roomkit/providers/sinch/config.py +22 -0
  81. roomkit/providers/sinch/sms.py +192 -0
  82. roomkit/providers/sms/__init__.py +15 -0
  83. roomkit/providers/sms/base.py +67 -0
  84. roomkit/providers/sms/meta.py +401 -0
  85. roomkit/providers/sms/mock.py +24 -0
  86. roomkit/providers/sms/phone.py +77 -0
  87. roomkit/providers/telnyx/__init__.py +21 -0
  88. roomkit/providers/telnyx/config.py +14 -0
  89. roomkit/providers/telnyx/rcs.py +352 -0
  90. roomkit/providers/telnyx/sms.py +231 -0
  91. roomkit/providers/twilio/__init__.py +18 -0
  92. roomkit/providers/twilio/config.py +19 -0
  93. roomkit/providers/twilio/rcs.py +183 -0
  94. roomkit/providers/twilio/sms.py +200 -0
  95. roomkit/providers/voicemeup/__init__.py +15 -0
  96. roomkit/providers/voicemeup/config.py +21 -0
  97. roomkit/providers/voicemeup/sms.py +374 -0
  98. roomkit/providers/whatsapp/__init__.py +0 -0
  99. roomkit/providers/whatsapp/base.py +44 -0
  100. roomkit/providers/whatsapp/mock.py +21 -0
  101. roomkit/py.typed +0 -0
  102. roomkit/realtime/__init__.py +17 -0
  103. roomkit/realtime/base.py +111 -0
  104. roomkit/realtime/memory.py +158 -0
  105. roomkit/sources/__init__.py +35 -0
  106. roomkit/sources/base.py +207 -0
  107. roomkit/sources/websocket.py +260 -0
  108. roomkit/store/__init__.py +0 -0
  109. roomkit/store/base.py +230 -0
  110. roomkit/store/memory.py +293 -0
  111. roomkit-0.1.0.dist-info/METADATA +567 -0
  112. roomkit-0.1.0.dist-info/RECORD +114 -0
  113. roomkit-0.1.0.dist-info/WHEEL +4 -0
  114. roomkit-0.1.0.dist-info/licenses/LICENSE +21 -0
roomkit/__init__.py ADDED
@@ -0,0 +1,372 @@
1
+ """RoomKit - Pure async Python library for multi-channel conversations."""
2
+
3
+ from roomkit._version import __version__
4
+ from roomkit.channels import (
5
+ EmailChannel,
6
+ HTTPChannel,
7
+ MessengerChannel,
8
+ RCSChannel,
9
+ SMSChannel,
10
+ WhatsAppChannel,
11
+ )
12
+ from roomkit.channels.ai import AIChannel
13
+ from roomkit.channels.base import Channel
14
+ from roomkit.channels.transport import TransportChannel
15
+ from roomkit.channels.websocket import WebSocketChannel
16
+ from roomkit.core.framework import (
17
+ ChannelNotFoundError,
18
+ ChannelNotRegisteredError,
19
+ IdentityNotFoundError,
20
+ ParticipantNotFoundError,
21
+ RoomKit,
22
+ RoomKitError,
23
+ RoomNotFoundError,
24
+ SourceAlreadyAttachedError,
25
+ SourceNotFoundError,
26
+ )
27
+ from roomkit.core.hooks import HookEngine, HookRegistration
28
+ from roomkit.core.inbound_router import DefaultInboundRoomRouter, InboundRoomRouter
29
+ from roomkit.core.locks import InMemoryLockManager, RoomLockManager
30
+ from roomkit.identity.base import IdentityResolver
31
+ from roomkit.identity.mock import MockIdentityResolver
32
+ from roomkit.models.channel import (
33
+ ChannelBinding,
34
+ ChannelCapabilities,
35
+ ChannelOutput,
36
+ RateLimit,
37
+ RetryPolicy,
38
+ )
39
+ from roomkit.models.context import RoomContext
40
+ from roomkit.models.delivery import (
41
+ DeliveryResult,
42
+ DeliveryStatus,
43
+ InboundMessage,
44
+ InboundResult,
45
+ ProviderResult,
46
+ )
47
+ from roomkit.models.enums import (
48
+ Access,
49
+ ChannelCategory,
50
+ ChannelDirection,
51
+ ChannelMediaType,
52
+ ChannelType,
53
+ DeliveryMode,
54
+ EventStatus,
55
+ EventType,
56
+ HookExecution,
57
+ HookTrigger,
58
+ IdentificationStatus,
59
+ ParticipantRole,
60
+ ParticipantStatus,
61
+ RoomStatus,
62
+ TaskStatus,
63
+ )
64
+ from roomkit.models.event import (
65
+ AudioContent,
66
+ CompositeContent,
67
+ EventContent,
68
+ EventSource,
69
+ LocationContent,
70
+ MediaContent,
71
+ RichContent,
72
+ RoomEvent,
73
+ SystemContent,
74
+ TemplateContent,
75
+ TextContent,
76
+ VideoContent,
77
+ )
78
+ from roomkit.models.framework_event import FrameworkEvent
79
+ from roomkit.models.hook import HookResult, InjectedEvent
80
+ from roomkit.models.identity import Identity, IdentityHookResult, IdentityResult
81
+ from roomkit.models.participant import Participant
82
+ from roomkit.models.room import Room, RoomTimers
83
+ from roomkit.models.task import Observation, Task
84
+ from roomkit.providers.ai.base import (
85
+ AIContext,
86
+ AIImagePart,
87
+ AIMessage,
88
+ AIProvider,
89
+ AIResponse,
90
+ AITextPart,
91
+ AITool,
92
+ AIToolCall,
93
+ ProviderError,
94
+ )
95
+ from roomkit.providers.ai.mock import MockAIProvider
96
+ from roomkit.providers.anthropic.ai import AnthropicAIProvider
97
+ from roomkit.providers.anthropic.config import AnthropicConfig
98
+ from roomkit.providers.elasticemail.config import ElasticEmailConfig
99
+ from roomkit.providers.elasticemail.email import ElasticEmailProvider
100
+ from roomkit.providers.email.base import EmailProvider
101
+ from roomkit.providers.email.mock import MockEmailProvider
102
+ from roomkit.providers.gemini.ai import GeminiAIProvider
103
+ from roomkit.providers.gemini.config import GeminiConfig
104
+ from roomkit.providers.http.base import HTTPProvider
105
+ from roomkit.providers.http.config import HTTPProviderConfig
106
+ from roomkit.providers.http.mock import MockHTTPProvider
107
+ from roomkit.providers.http.provider import WebhookHTTPProvider
108
+ from roomkit.providers.http.webhook import parse_http_webhook
109
+ from roomkit.providers.messenger.base import MessengerProvider
110
+ from roomkit.providers.messenger.config import MessengerConfig
111
+ from roomkit.providers.messenger.facebook import FacebookMessengerProvider
112
+ from roomkit.providers.messenger.mock import MockMessengerProvider
113
+ from roomkit.providers.messenger.webhook import parse_messenger_webhook
114
+ from roomkit.providers.openai.ai import OpenAIAIProvider
115
+ from roomkit.providers.openai.config import OpenAIConfig
116
+ from roomkit.providers.rcs.base import RCSDeliveryResult, RCSProvider
117
+ from roomkit.providers.rcs.mock import MockRCSProvider
118
+ from roomkit.providers.sinch.config import SinchConfig
119
+ from roomkit.providers.sinch.sms import SinchSMSProvider, parse_sinch_webhook
120
+ from roomkit.providers.sms.base import SMSProvider
121
+ from roomkit.providers.sms.meta import WebhookMeta, extract_sms_meta
122
+ from roomkit.providers.sms.mock import MockSMSProvider
123
+ from roomkit.providers.sms.phone import is_valid_phone, normalize_phone
124
+ from roomkit.providers.telnyx.config import TelnyxConfig
125
+ from roomkit.providers.telnyx.rcs import (
126
+ TelnyxRCSConfig,
127
+ TelnyxRCSProvider,
128
+ parse_telnyx_rcs_webhook,
129
+ )
130
+ from roomkit.providers.telnyx.sms import (
131
+ TelnyxSMSProvider,
132
+ parse_telnyx_webhook,
133
+ )
134
+ from roomkit.providers.twilio.config import TwilioConfig
135
+ from roomkit.providers.twilio.rcs import (
136
+ TwilioRCSConfig,
137
+ TwilioRCSProvider,
138
+ parse_twilio_rcs_webhook,
139
+ )
140
+ from roomkit.providers.twilio.sms import TwilioSMSProvider, parse_twilio_webhook
141
+ from roomkit.providers.voicemeup.config import VoiceMeUpConfig
142
+ from roomkit.providers.voicemeup.sms import (
143
+ VoiceMeUpSMSProvider,
144
+ configure_voicemeup_mms,
145
+ parse_voicemeup_webhook,
146
+ )
147
+ from roomkit.providers.whatsapp.base import WhatsAppProvider
148
+ from roomkit.providers.whatsapp.mock import MockWhatsAppProvider
149
+ from roomkit.realtime.base import (
150
+ EphemeralCallback,
151
+ EphemeralEvent,
152
+ EphemeralEventType,
153
+ RealtimeBackend,
154
+ )
155
+ from roomkit.realtime.memory import InMemoryRealtime
156
+ from roomkit.sources.base import (
157
+ BaseSourceProvider,
158
+ EmitCallback,
159
+ SourceHealth,
160
+ SourceProvider,
161
+ SourceStatus,
162
+ )
163
+ from roomkit.store.base import ConversationStore
164
+ from roomkit.store.memory import InMemoryStore
165
+
166
+ # AI documentation helpers (lazy import to avoid file I/O at import time)
167
+
168
+
169
+ def get_llms_txt() -> str:
170
+ """Get the contents of llms.txt for LLM consumption."""
171
+ from roomkit.ai_docs import get_llms_txt as _get_llms_txt
172
+
173
+ return _get_llms_txt()
174
+
175
+
176
+ def get_agents_md() -> str:
177
+ """Get the contents of AGENTS.md for AI coding assistants."""
178
+ from roomkit.ai_docs import get_agents_md as _get_agents_md
179
+
180
+ return _get_agents_md()
181
+
182
+
183
+ def get_ai_context() -> str:
184
+ """Get combined AI context (AGENTS.md + llms.txt)."""
185
+ from roomkit.ai_docs import get_ai_context as _get_ai_context
186
+
187
+ return _get_ai_context()
188
+
189
+
190
+ __all__ = [
191
+ "__version__",
192
+ # Core
193
+ "RoomKit",
194
+ "RoomKitError",
195
+ "RoomNotFoundError",
196
+ "ChannelNotFoundError",
197
+ "ChannelNotRegisteredError",
198
+ "ParticipantNotFoundError",
199
+ "IdentityNotFoundError",
200
+ "SourceAlreadyAttachedError",
201
+ "SourceNotFoundError",
202
+ "RoomLockManager",
203
+ "InMemoryLockManager",
204
+ # Sources (event-driven)
205
+ "BaseSourceProvider",
206
+ "EmitCallback",
207
+ "SourceHealth",
208
+ "SourceProvider",
209
+ "SourceStatus",
210
+ # Routing
211
+ "InboundRoomRouter",
212
+ "DefaultInboundRoomRouter",
213
+ # Channels
214
+ "Channel",
215
+ "TransportChannel",
216
+ "AIChannel",
217
+ "EmailChannel",
218
+ "RCSChannel",
219
+ "SMSChannel",
220
+ "WebSocketChannel",
221
+ "MessengerChannel",
222
+ "HTTPChannel",
223
+ "WhatsAppChannel",
224
+ # Models - Enums
225
+ "Access",
226
+ "ChannelCategory",
227
+ "ChannelDirection",
228
+ "ChannelMediaType",
229
+ "ChannelType",
230
+ "DeliveryMode",
231
+ "EventStatus",
232
+ "EventType",
233
+ "HookExecution",
234
+ "HookTrigger",
235
+ "IdentificationStatus",
236
+ "ParticipantRole",
237
+ "ParticipantStatus",
238
+ "RoomStatus",
239
+ "TaskStatus",
240
+ # Models - Data
241
+ "AudioContent",
242
+ "ChannelBinding",
243
+ "ChannelCapabilities",
244
+ "ChannelOutput",
245
+ "CompositeContent",
246
+ "DeliveryResult",
247
+ "DeliveryStatus",
248
+ "EventContent",
249
+ "EventSource",
250
+ "FrameworkEvent",
251
+ "HookResult",
252
+ "Identity",
253
+ "IdentityHookResult",
254
+ "IdentityResult",
255
+ "InboundMessage",
256
+ "InboundResult",
257
+ "InjectedEvent",
258
+ "LocationContent",
259
+ "MediaContent",
260
+ "Observation",
261
+ "Participant",
262
+ "ProviderResult",
263
+ "RateLimit",
264
+ "RetryPolicy",
265
+ "RichContent",
266
+ "Room",
267
+ "RoomContext",
268
+ "RoomEvent",
269
+ "RoomTimers",
270
+ "SystemContent",
271
+ "Task",
272
+ "TemplateContent",
273
+ "TextContent",
274
+ "VideoContent",
275
+ # Hooks
276
+ "HookEngine",
277
+ "HookRegistration",
278
+ # Provider Errors
279
+ "ProviderError",
280
+ # Provider ABCs
281
+ "AIProvider",
282
+ "EmailProvider",
283
+ "HTTPProvider",
284
+ "MessengerProvider",
285
+ "RCSProvider",
286
+ "SMSProvider",
287
+ "WhatsAppProvider",
288
+ # AI
289
+ "AIContext",
290
+ "AIImagePart",
291
+ "AIMessage",
292
+ "AIResponse",
293
+ "AITextPart",
294
+ "AITool",
295
+ "AIToolCall",
296
+ "MockAIProvider",
297
+ # AI – Anthropic
298
+ "AnthropicAIProvider",
299
+ "AnthropicConfig",
300
+ # AI – Gemini
301
+ "GeminiAIProvider",
302
+ "GeminiConfig",
303
+ # AI – OpenAI
304
+ "OpenAIAIProvider",
305
+ "OpenAIConfig",
306
+ # HTTP – Generic Webhook
307
+ "HTTPProviderConfig",
308
+ "MockHTTPProvider",
309
+ "WebhookHTTPProvider",
310
+ "parse_http_webhook",
311
+ # Email
312
+ "ElasticEmailConfig",
313
+ "ElasticEmailProvider",
314
+ "MockEmailProvider",
315
+ # Messenger
316
+ "FacebookMessengerProvider",
317
+ "MessengerConfig",
318
+ "MockMessengerProvider",
319
+ "parse_messenger_webhook",
320
+ # SMS
321
+ "MockSMSProvider",
322
+ "WebhookMeta",
323
+ "extract_sms_meta",
324
+ "is_valid_phone",
325
+ "normalize_phone",
326
+ # SMS - Sinch
327
+ "SinchConfig",
328
+ "SinchSMSProvider",
329
+ "parse_sinch_webhook",
330
+ # SMS - Telnyx
331
+ "TelnyxConfig",
332
+ "TelnyxSMSProvider",
333
+ "parse_telnyx_webhook",
334
+ # RCS - Telnyx
335
+ "TelnyxRCSConfig",
336
+ "TelnyxRCSProvider",
337
+ "parse_telnyx_rcs_webhook",
338
+ # SMS - Twilio
339
+ "TwilioConfig",
340
+ "TwilioSMSProvider",
341
+ "parse_twilio_webhook",
342
+ # SMS - VoiceMeUp
343
+ "VoiceMeUpConfig",
344
+ "VoiceMeUpSMSProvider",
345
+ "configure_voicemeup_mms",
346
+ "parse_voicemeup_webhook",
347
+ # RCS
348
+ "MockRCSProvider",
349
+ "RCSDeliveryResult",
350
+ # RCS - Twilio
351
+ "TwilioRCSConfig",
352
+ "TwilioRCSProvider",
353
+ "parse_twilio_rcs_webhook",
354
+ # WhatsApp
355
+ "MockWhatsAppProvider",
356
+ # Identity
357
+ "IdentityResolver",
358
+ "MockIdentityResolver",
359
+ # Store
360
+ "ConversationStore",
361
+ "InMemoryStore",
362
+ # Realtime
363
+ "EphemeralCallback",
364
+ "EphemeralEvent",
365
+ "EphemeralEventType",
366
+ "InMemoryRealtime",
367
+ "RealtimeBackend",
368
+ # AI Docs
369
+ "get_agents_md",
370
+ "get_ai_context",
371
+ "get_llms_txt",
372
+ ]
roomkit/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
roomkit/ai_docs.py ADDED
@@ -0,0 +1,93 @@
1
+ """AI documentation helpers for llms.txt and AGENTS.md access."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import resources
6
+ from pathlib import Path
7
+
8
+
9
+ def _find_file(filename: str) -> str:
10
+ """Find and read a file from package or repository root."""
11
+ # Try 1: importlib.resources (installed package)
12
+ try:
13
+ files = resources.files("roomkit")
14
+ return (files / filename).read_text(encoding="utf-8")
15
+ except (FileNotFoundError, TypeError):
16
+ pass
17
+
18
+ # Try 2: package directory (editable install with files copied)
19
+ pkg_dir = Path(__file__).parent
20
+ pkg_path = pkg_dir / filename
21
+ if pkg_path.exists():
22
+ return pkg_path.read_text(encoding="utf-8")
23
+
24
+ # Try 3: repository root (development mode)
25
+ # Go up from src/roomkit to repository root
26
+ repo_root = pkg_dir.parent.parent
27
+ repo_path = repo_root / filename
28
+ if repo_path.exists():
29
+ return repo_path.read_text(encoding="utf-8")
30
+
31
+ raise FileNotFoundError(f"{filename} not found in roomkit package or repository")
32
+
33
+
34
+ def get_llms_txt() -> str:
35
+ """Get the contents of llms.txt for LLM consumption.
36
+
37
+ Returns:
38
+ The llms.txt content as a string.
39
+
40
+ Example:
41
+ >>> from roomkit.ai_docs import get_llms_txt
42
+ >>> content = get_llms_txt()
43
+ >>> print(content[:50])
44
+ # RoomKit
45
+ ...
46
+ """
47
+ return _find_file("llms.txt")
48
+
49
+
50
+ def get_agents_md() -> str:
51
+ """Get the contents of AGENTS.md for AI coding assistants.
52
+
53
+ Returns:
54
+ The AGENTS.md content as a string.
55
+
56
+ Example:
57
+ >>> from roomkit.ai_docs import get_agents_md
58
+ >>> content = get_agents_md()
59
+ >>> print(content[:50])
60
+ # RoomKit
61
+ ...
62
+ """
63
+ return _find_file("AGENTS.md")
64
+
65
+
66
+ def get_ai_context() -> str:
67
+ """Get combined AI context (AGENTS.md + llms.txt summary).
68
+
69
+ Useful for providing complete context to AI assistants.
70
+
71
+ Returns:
72
+ Combined content optimized for AI consumption.
73
+
74
+ Example:
75
+ >>> from roomkit.ai_docs import get_ai_context
76
+ >>> context = get_ai_context()
77
+ >>> # Pass to AI assistant as system context
78
+ """
79
+ agents = get_agents_md()
80
+ llms = get_llms_txt()
81
+
82
+ return f"""# RoomKit AI Context
83
+
84
+ ## Project Guidelines (AGENTS.md)
85
+
86
+ {agents}
87
+
88
+ ---
89
+
90
+ ## Documentation Index (llms.txt)
91
+
92
+ {llms}
93
+ """
@@ -0,0 +1,194 @@
1
+ """Channel implementations and transport-channel factories."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from roomkit.channels.transport import TransportChannel
8
+ from roomkit.models.channel import ChannelCapabilities
9
+ from roomkit.models.enums import ChannelMediaType, ChannelType
10
+
11
+ # ---------------------------------------------------------------------------
12
+ # Capability constants
13
+ # ---------------------------------------------------------------------------
14
+
15
+ SMS_CAPABILITIES = ChannelCapabilities(
16
+ media_types=[ChannelMediaType.TEXT, ChannelMediaType.MEDIA],
17
+ max_length=1600,
18
+ supports_read_receipts=True,
19
+ supports_media=True,
20
+ )
21
+
22
+ EMAIL_CAPABILITIES = ChannelCapabilities(
23
+ media_types=[
24
+ ChannelMediaType.TEXT,
25
+ ChannelMediaType.RICH,
26
+ ChannelMediaType.MEDIA,
27
+ ],
28
+ supports_threading=True,
29
+ supports_rich_text=True,
30
+ supports_media=True,
31
+ )
32
+
33
+ WHATSAPP_CAPABILITIES = ChannelCapabilities(
34
+ media_types=[
35
+ ChannelMediaType.TEXT,
36
+ ChannelMediaType.RICH,
37
+ ChannelMediaType.MEDIA,
38
+ ChannelMediaType.LOCATION,
39
+ ChannelMediaType.TEMPLATE,
40
+ ],
41
+ max_length=4096,
42
+ supports_read_receipts=True,
43
+ supports_reactions=True,
44
+ supports_templates=True,
45
+ supports_rich_text=True,
46
+ supports_buttons=True,
47
+ max_buttons=3,
48
+ supports_quick_replies=True,
49
+ supports_media=True,
50
+ )
51
+
52
+ MESSENGER_CAPABILITIES = ChannelCapabilities(
53
+ media_types=[
54
+ ChannelMediaType.TEXT,
55
+ ChannelMediaType.RICH,
56
+ ChannelMediaType.MEDIA,
57
+ ChannelMediaType.TEMPLATE,
58
+ ],
59
+ max_length=2000,
60
+ supports_read_receipts=True,
61
+ supports_buttons=True,
62
+ max_buttons=3,
63
+ supports_quick_replies=True,
64
+ supports_media=True,
65
+ )
66
+
67
+ HTTP_CAPABILITIES = ChannelCapabilities(
68
+ media_types=[ChannelMediaType.TEXT, ChannelMediaType.RICH],
69
+ )
70
+
71
+ RCS_CAPABILITIES = ChannelCapabilities(
72
+ media_types=[
73
+ ChannelMediaType.TEXT,
74
+ ChannelMediaType.RICH,
75
+ ChannelMediaType.MEDIA,
76
+ ],
77
+ max_length=8000, # RCS supports longer messages
78
+ supports_read_receipts=True,
79
+ supports_typing=True,
80
+ supports_rich_text=True,
81
+ supports_buttons=True,
82
+ supports_quick_replies=True,
83
+ supports_cards=True,
84
+ supports_media=True,
85
+ )
86
+
87
+ # ---------------------------------------------------------------------------
88
+ # Factory functions
89
+ # ---------------------------------------------------------------------------
90
+
91
+
92
+ def SMSChannel(
93
+ channel_id: str,
94
+ *,
95
+ provider: Any = None,
96
+ from_number: str | None = None,
97
+ ) -> TransportChannel:
98
+ """Create an SMS transport channel."""
99
+ return TransportChannel(
100
+ channel_id,
101
+ ChannelType.SMS,
102
+ provider=provider,
103
+ capabilities=SMS_CAPABILITIES,
104
+ recipient_key="phone_number",
105
+ defaults={"from_": from_number},
106
+ )
107
+
108
+
109
+ def EmailChannel(
110
+ channel_id: str,
111
+ *,
112
+ provider: Any = None,
113
+ from_address: str | None = None,
114
+ ) -> TransportChannel:
115
+ """Create an Email transport channel."""
116
+ return TransportChannel(
117
+ channel_id,
118
+ ChannelType.EMAIL,
119
+ provider=provider,
120
+ capabilities=EMAIL_CAPABILITIES,
121
+ recipient_key="email_address",
122
+ defaults={"from_": from_address, "subject": None},
123
+ )
124
+
125
+
126
+ def WhatsAppChannel(
127
+ channel_id: str,
128
+ *,
129
+ provider: Any = None,
130
+ ) -> TransportChannel:
131
+ """Create a WhatsApp transport channel."""
132
+ return TransportChannel(
133
+ channel_id,
134
+ ChannelType.WHATSAPP,
135
+ provider=provider,
136
+ capabilities=WHATSAPP_CAPABILITIES,
137
+ recipient_key="phone_number",
138
+ )
139
+
140
+
141
+ def MessengerChannel(
142
+ channel_id: str,
143
+ *,
144
+ provider: Any = None,
145
+ ) -> TransportChannel:
146
+ """Create a Facebook Messenger transport channel."""
147
+ return TransportChannel(
148
+ channel_id,
149
+ ChannelType.MESSENGER,
150
+ provider=provider,
151
+ capabilities=MESSENGER_CAPABILITIES,
152
+ recipient_key="facebook_user_id",
153
+ )
154
+
155
+
156
+ def HTTPChannel(
157
+ channel_id: str,
158
+ *,
159
+ provider: Any = None,
160
+ ) -> TransportChannel:
161
+ """Create an HTTP webhook transport channel."""
162
+ return TransportChannel(
163
+ channel_id,
164
+ ChannelType.WEBHOOK,
165
+ provider=provider,
166
+ capabilities=HTTP_CAPABILITIES,
167
+ recipient_key="recipient_id",
168
+ )
169
+
170
+
171
+ def RCSChannel(
172
+ channel_id: str,
173
+ *,
174
+ provider: Any = None,
175
+ fallback: bool = True,
176
+ ) -> TransportChannel:
177
+ """Create an RCS (Rich Communication Services) transport channel.
178
+
179
+ Args:
180
+ channel_id: Unique identifier for this channel.
181
+ provider: RCS provider instance (e.g., TwilioRCSProvider).
182
+ fallback: If True (default), allow SMS fallback when RCS unavailable.
183
+
184
+ Returns:
185
+ A TransportChannel configured for RCS messaging.
186
+ """
187
+ return TransportChannel(
188
+ channel_id,
189
+ ChannelType.RCS,
190
+ provider=provider,
191
+ capabilities=RCS_CAPABILITIES,
192
+ recipient_key="phone_number",
193
+ defaults={"fallback": fallback},
194
+ )